/******************************************************************************* ** ** 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 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 L2CAP_TRACE_DEBUG ("L2CAP - rcv_cid CID: 0x%04x\n", rcv_cid); /* 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); #if (CLASSIC_BT_INCLUDED == TRUE) process_l2cap_cmd (p_lcb, p, l2cap_len); #endif ///CLASSIC_BT_INCLUDED == TRUE 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) { #if (CLASSIC_BT_INCLUDED == TRUE) l2c_fcr_proc_pdu (p_ccb, p_msg); #endif ///CLASSIC_BT_INCLUDED == TRUE } 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) { #if (CLASSIC_BT_INCLUDED == TRUE) l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DATA, p_msg); #endif ///CLASSIC_BT_INCLUDED == TRUE } 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)) { #if (CLASSIC_BT_INCLUDED == TRUE) l2c_fcr_proc_pdu (p_ccb, p_msg); #endif ///CLASSIC_BT_INCLUDED == TRUE } else { GKI_freebuf (p_msg); } } } } }