/******************************************************************************* ** ** 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 || p_clcb->cl_op_uuid != GATT_UUID_GAP_DEVICE_NAME) { 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); }
/******************************************************************************* ** ** Function gap_ble_cl_read_request ** ** Description utility function to start a read request for a GAP charactersitic ** ** Returns TRUE if read started, else FALSE if GAP is busy ** *******************************************************************************/ BOOLEAN gap_ble_cl_read_request(tGAP_CLCB *p_clcb, UINT16 uuid, void * p_cback) { tGATT_READ_PARAM param; 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) { GAP_TRACE_ERROR ("GAP_BleReadPeerPrefConnParams: GATT_Read Failed"); /* release the link here */ GATT_Disconnect(p_clcb->conn_id); return(FALSE); } else { p_clcb->p_cback = p_cback; p_clcb->cl_op_uuid = uuid; return TRUE; } }
/******************************************************************************* ** ** 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_DEV_NAME_CBACK *p_cback) { tGAP_CLCB *p_clcb = NULL; BOOLEAN status = TRUE; if (p_cback == NULL) return(FALSE); if ((p_clcb = gap_find_clcb_by_bd_addr (peer_bda)) == NULL) { if ((p_clcb = gap_clcb_alloc(0, peer_bda)) == NULL) { GAP_TRACE_ERROR("GAP_BleReadPeerDevName max connection reached"); return FALSE; } p_clcb->connected = FALSE; } GAP_TRACE_EVENT ("GAP_BleReadPeerDevName() - 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->cl_op_uuid); /* For now we only handle one at a time */ if (p_clcb->cl_op_uuid != 0) return(FALSE); /* hold the link here */ if( BTM_IsInquiryActive()|| BTM_IsRnrActive() ) { status = GATT_Connect(gap_cb.gatt_if, p_clcb->bda, TRUE, BT_TRANSPORT_LE); } if(status) { if (p_clcb->connected) { return gap_ble_cl_read_request(p_clcb, GATT_UUID_GAP_DEVICE_NAME, (void *)p_cback); } p_clcb->p_cback = (void *)p_cback; /* Mark currently active operation */ p_clcb->cl_op_uuid = GATT_UUID_GAP_DEVICE_NAME; } return FALSE; }
/******************************************************************************* ** ** 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_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) { tGAP_CLCB *p_clcb = gap_find_clcb_by_bd_addr (peer_bda); if (p_clcb == NULL) { if ((p_clcb = gap_clcb_alloc(0, peer_bda)) == NULL) { GAP_TRACE_ERROR("GAP_BleReadPeerPrefConnParams max connection reached"); return FALSE; } p_clcb->connected = FALSE; } GAP_TRACE_API ("GAP_BleReadPeerPrefConnParams() - 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->cl_op_uuid); /* For now we only handle one at a time */ if (p_clcb->cl_op_uuid != 0) return(FALSE); /* hold the link here */ if (GATT_Connect(gap_cb.gatt_if, p_clcb->bda, TRUE, BT_TRANSPORT_LE)) { if (p_clcb->connected) { return gap_ble_cl_read_request(p_clcb, GATT_UUID_GAP_PREF_CONN_PARAM, NULL); } /* Mark currently active operation */ p_clcb->cl_op_uuid = GATT_UUID_GAP_PREF_CONN_PARAM; return(TRUE); } else return FALSE; }
/******************************************************************************* ** ** 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; 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 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)) != 0)) { p_ccb->connection_id = cid; return (p_ccb->gap_handle); } else { gap_release_ccb (p_ccb); return (GAP_INVALID_HANDLE); } } }
/******************************************************************************* ** ** 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); UINT16 cl_op_uuid; UNUSED(gatt_if); UNUSED(transport); GAP_TRACE_EVENT ("gap_ble_c_connect_cback: from %08x%04x connected:%d conn_id=%d reason = 0x%04x", (bda[0]<<24)+(bda[1]<<16)+(bda[2]<<8)+bda[3], (bda[4]<<8)+bda[5], connected, conn_id, reason); if (connected) { if (p_clcb == NULL) { if ((p_clcb = gap_clcb_alloc(conn_id, bda))== NULL) { GAP_TRACE_ERROR ("gap_ble_c_connect_cback: no_resource"); return; } } p_clcb->conn_id = conn_id; p_clcb->connected = TRUE; } else { if (p_clcb != NULL) p_clcb->connected = FALSE; } if (p_clcb) { cl_op_uuid = p_clcb->cl_op_uuid; GAP_TRACE_EVENT ("cl_op_uuid=0x%04x", cl_op_uuid ); if (p_clcb->connected) { p_clcb->cl_op_uuid = 0; if (cl_op_uuid == GATT_UUID_GAP_DEVICE_NAME) { GAP_BleReadPeerDevName (bda, (tGAP_BLE_DEV_NAME_CBACK *)p_clcb->p_cback); } else if (cl_op_uuid == GATT_UUID_GAP_PREF_CONN_PARAM) { GAP_BleReadPeerPrefConnParams(bda); } } /* current link disconnect */ else { gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL); memset(p_clcb, 0, sizeof(tGAP_CLCB)); } } }