| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211 |
- /******************************************************************************
- *
- * 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 "common/bt_target.h"
- #include "common/bt_defs.h"
- #include "stack/btu.h"
- #include "gap_int.h"
- #include "stack/l2cdefs.h"
- #include "l2c_int.h"
- #include <string.h>
- #include "osi/mutex.h"
- #include "osi/allocator.h"
- #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 (const 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_buf_size = GAP_DATA_BUF_SIZE;
- p_ccb->ertm_info.user_tx_buf_size = GAP_DATA_BUF_SIZE;
- p_ccb->ertm_info.fcr_rx_buf_size = L2CAP_INVALID_ERM_BUF_SIZE;
- p_ccb->ertm_info.fcr_tx_buf_size = L2CAP_INVALID_ERM_BUF_SIZE;
- } 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);
- UINT16 copy_len;
- if (!p_ccb) {
- return (GAP_ERR_BAD_HANDLE);
- }
- *p_len = 0;
- if (fixed_queue_is_empty(p_ccb->rx_queue)) {
- return (GAP_NO_DATA_AVAIL);
- }
- osi_mutex_global_lock();
- while (max_len) {
- BT_HDR *p_buf = fixed_queue_try_peek_first(p_ccb->rx_queue);
- if (p_buf == NULL) {
- break;
- }
- 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;
- }
- osi_free(fixed_queue_dequeue(p_ccb->rx_queue, 0));
- }
- p_ccb->rx_queue_size -= *p_len;
- osi_mutex_global_unlock();
- 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 *)fixed_queue_dequeue(p_ccb->rx_queue, 0);
- 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) {
- osi_free (p_buf);
- return (GAP_ERR_BAD_HANDLE);
- }
- if (p_ccb->con_state != GAP_CCB_STATE_CONNECTED) {
- osi_free (p_buf);
- return (GAP_ERR_BAD_STATE);
- }
- if (p_buf->offset < L2CAP_MIN_OFFSET) {
- osi_free (p_buf);
- return (GAP_ERR_BUF_OFFSET);
- }
- fixed_queue_enqueue(p_ccb->tx_queue, p_buf, FIXED_QUEUE_MAX_TIMEOUT);
- 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 *)fixed_queue_dequeue(p_ccb->tx_queue, 0)) != 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 *)osi_malloc(L2CAP_FCR_ERTM_BUF_SIZE)) == NULL) {
- return (GAP_ERR_CONGESTED);
- }
- } else {
- if ((p_buf = (BT_HDR *)osi_malloc(GAP_DATA_BUF_SIZE)) == 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);
- fixed_queue_enqueue(p_ccb->tx_queue, p_buf, FIXED_QUEUE_MAX_TIMEOUT);
- }
- 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 *)fixed_queue_dequeue(p_ccb->tx_queue, 0)) != 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 = p_ccb->ertm_info.user_tx_buf_size
- - 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) {
- osi_free (p_msg);
- return;
- }
- if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED) {
- fixed_queue_enqueue(p_ccb->rx_queue, p_msg, FIXED_QUEUE_MAX_TIMEOUT);
- 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 {
- osi_free (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 *)fixed_queue_dequeue(p_ccb->tx_queue, 0)) != 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->tx_queue = fixed_queue_new(QUEUE_SIZE_MAX);
- p_ccb->rx_queue = fixed_queue_new(QUEUE_SIZE_MAX);
- 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 (!fixed_queue_is_empty(p_ccb->rx_queue)) {
- osi_free(fixed_queue_dequeue(p_ccb->rx_queue, 0));
- }
- fixed_queue_free(p_ccb->rx_queue, NULL);
- p_ccb->rx_queue = NULL;
- while (!fixed_queue_is_empty(p_ccb->tx_queue)) {
- osi_free(fixed_queue_dequeue(p_ccb->tx_queue, 0));
- }
- fixed_queue_free(p_ccb->tx_queue, NULL);
- p_ccb->tx_queue = NULL;
- 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;
- }
- }
- #if (SDP_INCLUDED == TRUE)
- /* Free the security record for this PSM */
- BTM_SecClrService(service_id);
- #endif ///SDP_INCLUDED == TRUE
- 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 *)osi_malloc(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.");
- }
- }
- #endif /* (GAP_CONN_POST_EVT_INCLUDED == TRUE) */
- #endif /* GAP_CONN_INCLUDED */
|