/******************************************************************************* ** ** Function llcp_util_send_connect ** ** Description Send CONNECT PDU ** ** Returns tLLCP_STATUS ** ******************************************************************************/ tLLCP_STATUS llcp_util_send_connect (tLLCP_DLCB *p_dlcb, tLLCP_CONNECTION_PARAMS *p_params) { BT_HDR *p_msg; UINT8 *p; UINT16 miu_len = 0, rw_len = 0, sn_len = 0; if (p_params->miu != LLCP_DEFAULT_MIU) { miu_len = 4; /* TYPE, LEN, 2 bytes MIU */ } if (p_params->rw != LLCP_DEFAULT_RW) { rw_len = 3; /* TYPE, LEN, 1 byte RW */ p_params->rw &= 0x0F; /* only 4 bits */ } if ((strlen (p_params->sn)) && (p_dlcb->remote_sap == LLCP_SAP_SDP)) { sn_len = (UINT16) (2 + strlen (p_params->sn)); /* TYPE, LEN, SN */ } p_msg = (BT_HDR*) GKI_getpoolbuf (LLCP_POOL_ID); if (p_msg) { p_msg->len = LLCP_PDU_HEADER_SIZE + miu_len + rw_len + sn_len; p_msg->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE; p = (UINT8 *) (p_msg + 1) + p_msg->offset; UINT16_TO_BE_STREAM (p, LLCP_GET_PDU_HEADER (p_dlcb->remote_sap, LLCP_PDU_CONNECT_TYPE, p_dlcb->local_sap)); if (miu_len) { UINT8_TO_BE_STREAM (p, LLCP_MIUX_TYPE); UINT8_TO_BE_STREAM (p, LLCP_MIUX_LEN); UINT16_TO_BE_STREAM (p, p_params->miu - LLCP_DEFAULT_MIU); } if (rw_len) { UINT8_TO_BE_STREAM (p, LLCP_RW_TYPE); UINT8_TO_BE_STREAM (p, LLCP_RW_LEN); UINT8_TO_BE_STREAM (p, p_params->rw); } if (sn_len) { UINT8_TO_BE_STREAM (p, LLCP_SN_TYPE); UINT8_TO_BE_STREAM (p, sn_len - 2); memcpy (p, p_params->sn, sn_len - 2); } GKI_enqueue (&llcp_cb.lcb.sig_xmit_q, p_msg); llcp_link_check_send_data (); return LLCP_STATUS_SUCCESS; } return LLCP_STATUS_FAIL; }
/******************************************************************************* ** ** Function llcp_sdp_check_send_snl ** ** Description Enqueue Service Name Lookup PDU into sig_xmit_q for transmitting ** ** ** Returns void ** *******************************************************************************/ void llcp_sdp_check_send_snl (void) { UINT8 *p; if (llcp_cb.sdp_cb.p_snl) { LLCP_TRACE_DEBUG0 ("SDP: llcp_sdp_check_send_snl ()"); llcp_cb.sdp_cb.p_snl->len += LLCP_PDU_HEADER_SIZE; llcp_cb.sdp_cb.p_snl->offset -= LLCP_PDU_HEADER_SIZE; p = (UINT8 *) (llcp_cb.sdp_cb.p_snl + 1) + llcp_cb.sdp_cb.p_snl->offset; UINT16_TO_BE_STREAM (p, LLCP_GET_PDU_HEADER (LLCP_SAP_SDP, LLCP_PDU_SNL_TYPE, LLCP_SAP_SDP )); GKI_enqueue (&llcp_cb.lcb.sig_xmit_q, llcp_cb.sdp_cb.p_snl); llcp_cb.sdp_cb.p_snl = NULL; } #if(NFC_NXP_NOT_OPEN_INCLUDED == TRUE) else { /* Notify DTA after sending out SNL with SDRES not to send SNLs in AGF PDU */ if ((llcp_cb.p_dta_cback) && (llcp_cb.dta_snl_resp)) { llcp_cb.dta_snl_resp = FALSE; (*llcp_cb.p_dta_cback) (); } } #endif }
/******************************************************************************* ** ** 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 llcp_util_send_frmr ** ** Description Send FRMR PDU ** ** Returns tLLCP_STATUS ** *******************************************************************************/ tLLCP_STATUS llcp_util_send_frmr (tLLCP_DLCB *p_dlcb, UINT8 flags, UINT8 ptype, UINT8 sequence) { BT_HDR *p_msg; UINT8 *p; p_msg = (BT_HDR*) GKI_getpoolbuf (LLCP_POOL_ID); if (p_msg) { p_msg->len = LLCP_PDU_FRMR_SIZE; p_msg->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE; p = (UINT8 *) (p_msg + 1) + p_msg->offset; UINT16_TO_BE_STREAM (p, LLCP_GET_PDU_HEADER (p_dlcb->remote_sap, LLCP_PDU_FRMR_TYPE, p_dlcb->local_sap)); UINT8_TO_BE_STREAM (p, (flags << 4) | ptype); UINT8_TO_BE_STREAM (p, sequence); UINT8_TO_BE_STREAM (p, (p_dlcb->next_tx_seq << 4) | p_dlcb->next_rx_seq); UINT8_TO_BE_STREAM (p, (p_dlcb->rcvd_ack_seq << 4) | p_dlcb->sent_ack_seq); GKI_enqueue (&llcp_cb.lcb.sig_xmit_q, p_msg); llcp_link_check_send_data (); return LLCP_STATUS_SUCCESS; } else { LLCP_TRACE_ERROR0 ("llcp_util_send_frmr (): Out of resource"); return LLCP_STATUS_FAIL; } }
/******************************************************************************* ** ** Function llcp_util_send_ui ** ** Description Send UI PDU ** ** Returns tLLCP_STATUS ** *******************************************************************************/ tLLCP_STATUS llcp_util_send_ui (UINT8 ssap, UINT8 dsap, tLLCP_APP_CB *p_app_cb, BT_HDR *p_msg) { UINT8 *p; tLLCP_STATUS status = LLCP_STATUS_SUCCESS; p_msg->offset -= LLCP_PDU_HEADER_SIZE; p_msg->len += LLCP_PDU_HEADER_SIZE; p = (UINT8 *) (p_msg + 1) + p_msg->offset; UINT16_TO_BE_STREAM (p, LLCP_GET_PDU_HEADER (dsap, LLCP_PDU_UI_TYPE, ssap)); GKI_enqueue (&p_app_cb->ui_xmit_q, p_msg); llcp_cb.total_tx_ui_pdu++; llcp_link_check_send_data (); if ( (p_app_cb->is_ui_tx_congested) ||(p_app_cb->ui_xmit_q.count >= llcp_cb.ll_tx_congest_start) ||(llcp_cb.overall_tx_congested) ||(llcp_cb.total_tx_ui_pdu >= llcp_cb.max_num_ll_tx_buff) ) { /* set congested here so overall congestion check routine will not report event again, */ /* or notify uncongestion later */ p_app_cb->is_ui_tx_congested = TRUE; LLCP_TRACE_WARNING2 ("Logical link (SAP=0x%X) congested: ui_xmit_q.count=%d", ssap, p_app_cb->ui_xmit_q.count); status = LLCP_STATUS_CONGESTED; } return status; }
/******************************************************************************* ** ** 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_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)); if (NULL != p) { p->p_param = p_param; GKI_enqueue (&btm_cb.ble_ctr_cb.conn_pending_q, p); } else { BTM_TRACE_ERROR ("%s: Failed to get memory", __FUNCTION__); } }
/******************************************************************************* ** ** Function bta_pan_data_buf_ind_cback ** ** Description data indication callback from pan profile ** ** ** Returns void ** *******************************************************************************/ static void bta_pan_data_buf_ind_cback(UINT16 handle, BD_ADDR src, BD_ADDR dst, UINT16 protocol, BT_HDR *p_buf, BOOLEAN ext, BOOLEAN forward) { tBTA_PAN_SCB *p_scb; BT_HDR * p_event; BT_HDR *p_new_buf; if ( sizeof(tBTA_PAN_DATA_PARAMS) > p_buf->offset ) { /* offset smaller than data structure in front of actual data */ p_new_buf = (BT_HDR *)GKI_getpoolbuf( PAN_POOL_ID ); if(!p_new_buf) { APPL_TRACE_WARNING0("Cannot get a PAN GKI buffer"); GKI_freebuf( p_buf ); return; } else { memcpy( (UINT8 *)(p_new_buf+1)+sizeof(tBTA_PAN_DATA_PARAMS), (UINT8 *)(p_buf+1)+p_buf->offset, p_buf->len ); p_new_buf->len = p_buf->len; p_new_buf->offset = sizeof(tBTA_PAN_DATA_PARAMS); GKI_freebuf( p_buf ); } } else { p_new_buf = p_buf; } /* copy params into the space before the data */ bdcpy(((tBTA_PAN_DATA_PARAMS *)p_new_buf)->src, src); bdcpy(((tBTA_PAN_DATA_PARAMS *)p_new_buf)->dst, dst); ((tBTA_PAN_DATA_PARAMS *)p_new_buf)->protocol = protocol; ((tBTA_PAN_DATA_PARAMS *)p_new_buf)->ext = ext; ((tBTA_PAN_DATA_PARAMS *)p_new_buf)->forward = forward; if((p_scb = bta_pan_scb_by_handle(handle)) == NULL) { GKI_freebuf( p_new_buf ); return; } GKI_enqueue(&p_scb->data_queue, p_new_buf); if ((p_event = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) { p_event->layer_specific = handle; p_event->event = BTA_PAN_RX_FROM_BNEP_READY_EVT; bta_sys_sendmsg(p_event); } }
/******************************************************************************* ** ** Function llcp_util_send_cc ** ** Description Send CC PDU ** ** Returns tLLCP_STATUS ** ******************************************************************************/ tLLCP_STATUS llcp_util_send_cc (tLLCP_DLCB *p_dlcb, tLLCP_CONNECTION_PARAMS *p_params) { BT_HDR *p_msg; UINT8 *p; UINT16 miu_len = 0, rw_len = 0; if (p_params->miu != LLCP_DEFAULT_MIU) { miu_len = 4; } if (p_params->rw != LLCP_DEFAULT_RW) { rw_len = 3; p_params->rw &= 0x0F; } p_msg = (BT_HDR*) GKI_getpoolbuf (LLCP_POOL_ID); if (p_msg) { p_msg->len = LLCP_PDU_HEADER_SIZE + miu_len + rw_len; p_msg->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE; p = (UINT8 *) (p_msg + 1) + p_msg->offset; UINT16_TO_BE_STREAM (p, LLCP_GET_PDU_HEADER (p_dlcb->remote_sap, LLCP_PDU_CC_TYPE, p_dlcb->local_sap)); if (miu_len) { UINT8_TO_BE_STREAM (p, LLCP_MIUX_TYPE); UINT8_TO_BE_STREAM (p, LLCP_MIUX_LEN); UINT16_TO_BE_STREAM (p, p_params->miu - LLCP_DEFAULT_MIU); } if (rw_len) { UINT8_TO_BE_STREAM (p, LLCP_RW_TYPE); UINT8_TO_BE_STREAM (p, LLCP_RW_LEN); UINT8_TO_BE_STREAM (p, p_params->rw); } GKI_enqueue (&llcp_cb.lcb.sig_xmit_q, p_msg); llcp_link_check_send_data (); return LLCP_STATUS_SUCCESS; } return LLCP_STATUS_FAIL; }
/******************************************************************************* ** ** 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 btusb_lite_hci_cmd_cplt_evt_send ** ** Description Send an HCI VSC Cmd Complete. ** ** Returns Void ** *******************************************************************************/ static void btusb_lite_hci_cmd_cplt_evt_send(struct btusb *p_dev, UINT16 opcode, UINT8 *p_param, UINT8 param_len) { BT_HDR *p_msg; UINT16 size = param_len + 5; UINT8 *p; /* Get a buffer from the pool */ p_msg = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + size); if(unlikely(!p_msg)) { BTUSB_ERR("Unable to get GKI buffer\n"); return; } if (unlikely(dbgflags & BTUSB_GKI_CHK_MSG) && unlikely(GKI_buffer_status(p_msg) != BUF_STATUS_UNLINKED)) { BTUSB_ERR("buffer != BUF_STATUS_UNLINKED 0x%p\n", p_msg); return; } p_msg->offset = 0; p_msg->event = HCIT_TYPE_EVENT; p_msg->len = size; p_msg->layer_specific = BTUSB_LS_GKI_BUFFER; p = (UINT8 *)(p_msg + 1) + p_msg->offset; p = btusb_lite_hci_write_evt_header(p, HCI_COMMAND_COMPLETE_EVT, size - 2); UINT8_TO_STREAM(p, BTUSB_LITE_HCI_NUM_CMD); /* HCI Num Command */ UINT16_TO_STREAM(p, opcode); /* HCI OpCode */ if (p_param) { ARRAY_TO_STREAM(p, p_param, param_len) } /* InQ for user-space to read */ GKI_enqueue(&p_dev->rx_queue, p_msg); /* if the process is polling, indicate RX event */ wake_up_interruptible(&p_dev->rx_wait_q); }
/******************************************************************************* ** ** Function llcp_sdp_check_send_snl ** ** Description Enqueue Service Name Lookup PDU into sig_xmit_q for transmitting ** ** ** Returns void ** *******************************************************************************/ void llcp_sdp_check_send_snl (void) { UINT8 *p; if (llcp_cb.sdp_cb.p_snl) { LLCP_TRACE_DEBUG0 ("SDP: llcp_sdp_check_send_snl ()"); llcp_cb.sdp_cb.p_snl->len += LLCP_PDU_HEADER_SIZE; llcp_cb.sdp_cb.p_snl->offset -= LLCP_PDU_HEADER_SIZE; p = (UINT8 *) (llcp_cb.sdp_cb.p_snl + 1) + llcp_cb.sdp_cb.p_snl->offset; UINT16_TO_BE_STREAM (p, LLCP_GET_PDU_HEADER (LLCP_SAP_SDP, LLCP_PDU_SNL_TYPE, LLCP_SAP_SDP )); GKI_enqueue (&llcp_cb.lcb.sig_xmit_q, llcp_cb.sdp_cb.p_snl); llcp_cb.sdp_cb.p_snl = NULL; } }
/******************************************************************************* ** ** Function llcp_util_send_disc ** ** Description Send DISC PDU ** ** Returns void ** *******************************************************************************/ void llcp_util_send_disc (UINT8 dsap, UINT8 ssap) { BT_HDR *p_msg; UINT8 *p; p_msg = (BT_HDR*) GKI_getpoolbuf (LLCP_POOL_ID); if (p_msg) { p_msg->len = LLCP_PDU_DISC_SIZE; p_msg->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE; p = (UINT8 *) (p_msg + 1) + p_msg->offset; UINT16_TO_BE_STREAM (p, LLCP_GET_PDU_HEADER (dsap, LLCP_PDU_DISC_TYPE, ssap)); GKI_enqueue (&llcp_cb.lcb.sig_xmit_q, p_msg); llcp_link_check_send_data (); } }
/******************************************************************************* ** ** Function bta_av_dup_audio_buf ** ** Description dup the audio data to the q_info.a2d of other audio channels ** ** Returns void ** *******************************************************************************/ void bta_av_dup_audio_buf(tBTA_AV_SCB *p_scb, BT_HDR *p_buf) { tBTA_AV_SCB *p_scbi; BUFFER_Q *pq; int i; UINT16 size, copy_size; BT_HDR *p_new; if(!p_buf) return; if(bta_av_cb.audio_open_cnt >= 2) { size = GKI_get_buf_size(p_buf); copy_size = BT_HDR_SIZE + p_buf->len + p_buf->offset; /* more than one audio channel is connected */ for(i=0; i<BTA_AV_NUM_STRS; i++) { p_scbi = bta_av_cb.p_scb[i]; if( (p_scb->hdi != i) && /* not the original channel */ (bta_av_cb.conn_audio & BTA_AV_HNDL_TO_MSK(i)) && /* connected audio */ p_scbi && p_scbi->co_started ) /* scb is used and started */ { /* enqueue the data only when the stream is started */ p_new = (BT_HDR *)GKI_getbuf(size); if(p_new) { memcpy(p_new, p_buf, copy_size); pq = &p_scbi->q_info.a2d; GKI_enqueue(pq, p_new); if(pq->count > p_bta_av_cfg->audio_mqs) { bta_av_co_audio_drop(p_scbi->hndl); GKI_freebuf(GKI_dequeue(pq)); } } } } } }
/******************************************************************************* ** ** 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 llcp_util_send_rr_rnr ** ** Description Send RR or RNR PDU ** ** Returns void ** *******************************************************************************/ void llcp_util_send_rr_rnr (tLLCP_DLCB *p_dlcb) { BT_HDR *p_msg; UINT8 *p; UINT8 pdu_type; UINT8 pdu_size; UINT8 rcv_seq; /* if no indication of change in local busy or rx congestion */ if ((p_dlcb->flags & LLCP_DATA_LINK_FLAG_PENDING_RR_RNR) == 0) { /* if all ack is sent */ if (p_dlcb->sent_ack_seq == p_dlcb->next_rx_seq) { /* we don't need to send RR/RNR */ return; } else { /* if rx flow off because of local busy or congestion */ if ( (p_dlcb->local_busy) ||(p_dlcb->is_rx_congested) ||(llcp_cb.overall_rx_congested) ) { /* don't send RR/RNR */ return; } } } if ( (p_dlcb->local_busy) ||(p_dlcb->is_rx_congested) ||(llcp_cb.overall_rx_congested) ) { LLCP_TRACE_DEBUG3 ("llcp_util_send_rr_rnr (): local_busy=%d,is_rx_congested=%d,overall_rx_congested=%d", p_dlcb->local_busy, p_dlcb->is_rx_congested, llcp_cb.overall_rx_congested); /* if local_busy or rx congested then do not update receive sequence number to flow off */ pdu_type = LLCP_PDU_RNR_TYPE; pdu_size = LLCP_PDU_RNR_SIZE; rcv_seq = p_dlcb->sent_ack_seq; } else { pdu_type = LLCP_PDU_RR_TYPE; pdu_size = LLCP_PDU_RR_SIZE; p_dlcb->sent_ack_seq = p_dlcb->next_rx_seq; rcv_seq = p_dlcb->sent_ack_seq; } p_msg = (BT_HDR*) GKI_getpoolbuf (LLCP_POOL_ID); if (p_msg) { p_dlcb->flags &= ~LLCP_DATA_LINK_FLAG_PENDING_RR_RNR; p_msg->len = pdu_size; p_msg->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE; p = (UINT8 *) (p_msg + 1) + p_msg->offset; UINT16_TO_BE_STREAM (p, LLCP_GET_PDU_HEADER (p_dlcb->remote_sap, pdu_type, p_dlcb->local_sap)); UINT8_TO_BE_STREAM (p, rcv_seq); #if (BT_TRACE_VERBOSE == TRUE) LLCP_TRACE_DEBUG5 ("LLCP TX - N(S,R):(NA,%d) V(S,SA,R,RA):(%d,%d,%d,%d)", p_dlcb->next_rx_seq, p_dlcb->next_tx_seq, p_dlcb->rcvd_ack_seq, p_dlcb->next_rx_seq, p_dlcb->sent_ack_seq); #endif GKI_enqueue (&llcp_cb.lcb.sig_xmit_q, p_msg); llcp_link_check_send_data (); } else { LLCP_TRACE_ERROR0 ("llcp_util_send_rr_rnr (): Out of resource"); } }
/******************************************************************************* ** ** 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_WARNING5 ("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, l2cb.rcv_hold_q.count); p_msg->layer_specific = 2; GKI_enqueue (&l2cb.rcv_hold_q, p_msg); if (l2cb.rcv_hold_q.count == 1) btu_start_timer (&l2cb.rcv_hold_tle, BTU_TTYPE_L2CAP_HOLD, BT_1SEC_TIMEOUT); return; } else { L2CAP_TRACE_ERROR5 ("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, l2cb.rcv_hold_q.count); } GKI_freebuf (p_msg); return; } } else { L2CAP_TRACE_WARNING1 ("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; #if (L2CAP_HOST_FLOW_CTRL == TRUE) /* Send ack if we hit the threshold */ if (++p_lcb->link_pkts_unacked >= p_lcb->link_ack_thresh) btu_hcif_send_host_rdy_for_data(); #endif /* Extract the length and CID */ STREAM_TO_UINT16 (l2cap_len, p); STREAM_TO_UINT16 (rcv_cid, p); /* 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_WARNING1 ("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_WARNING0 ("L2CAP - got incorrect hci header" ); GKI_freebuf (p_msg); return; } if (l2cap_len != p_msg->len) { L2CAP_TRACE_WARNING2 ("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) { process_l2cap_cmd (p_lcb, p, l2cap_len); GKI_freebuf (p_msg); } else if (rcv_cid == L2CAP_CONNECTIONLESS_CID) { /* process_connectionless_data (p_lcb); */ STREAM_TO_UINT16 (psm, p); L2CAP_TRACE_DEBUG1( "GOT CONNECTIONLESS DATA PSM:%d", psm ) ; #if (TCS_BCST_SETUP_INCLUDED == TRUE && TCS_INCLUDED == TRUE) if (psm == TCS_PSM_INTERCOM || psm == TCS_PSM_CORDLESS) { p_msg->offset += L2CAP_BCST_OVERHEAD; p_msg->len -= L2CAP_BCST_OVERHEAD; tcs_proc_bcst_msg( p_lcb->remote_bd_addr, p_msg ) ; GKI_freebuf (p_msg); } else #endif #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) { 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) ) { /* If no CCB for this channel, allocate one */ if (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)(p_lcb->remote_bd_addr, p_msg); } else GKI_freebuf (p_msg); } #endif else { 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 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); }