Sending and receiving an ACL package for bluedroid source code analysis (2)
For more information, see my personal website:Http://stackvoid.com/
The previous section describes the data stream entry. This article analyzes the processing functions of L2CAP.
Processing at The L2CAP Layer
Our music data, through the L2CAP entry function l2c_data_write layer-by-layer "test", has successfully entered the L2CAP. Next let's take a look at how the L2CAP layer processes the data.
First, we enter the state machine at The L2CAP layer.
1 void l2c_csm_execute (tL2C_CCB *p_ccb, UINT16 event, void *p_data) 2 { 3 switch (p_ccb->chnl_state) 4 { 5 case CST_CLOSED: 6 l2c_csm_closed (p_ccb, event, p_data); 7 break; 8 9 case CST_ORIG_W4_SEC_COMP:10 l2c_csm_orig_w4_sec_comp (p_ccb, event, p_data);11 break;12 13 case CST_TERM_W4_SEC_COMP:14 l2c_csm_term_w4_sec_comp (p_ccb, event, p_data);15 break;16 17 case CST_W4_L2CAP_CONNECT_RSP:18 l2c_csm_w4_l2cap_connect_rsp (p_ccb, event, p_data);19 break;20 21 case CST_W4_L2CA_CONNECT_RSP:22 l2c_csm_w4_l2ca_connect_rsp (p_ccb, event, p_data);23 break;24 25 case CST_CONFIG:26 l2c_csm_config (p_ccb, event, p_data);27 break;28 29 case CST_OPEN:30 l2c_csm_open (p_ccb, event, p_data);31 break;32 33 case CST_W4_L2CAP_DISCONNECT_RSP:34 l2c_csm_w4_l2cap_disconnect_rsp (p_ccb, event, p_data);35 break;36 37 case CST_W4_L2CA_DISCONNECT_RSP:38 l2c_csm_w4_l2ca_disconnect_rsp (p_ccb, event, p_data);39 break;40 41 default:42 break;43 }44 }
The specific Channel status information is as follows:
1 typedef enum 2 { 3 CST_CLOSED, /* Channel is in clodes state */ 4 CST_ORIG_W4_SEC_COMP, /* Originator waits security clearence */ 5 CST_TERM_W4_SEC_COMP, /* Acceptor waits security clearence */ 6 CST_W4_L2CAP_CONNECT_RSP, /* Waiting for peer conenct response */ 7 CST_W4_L2CA_CONNECT_RSP, /* Waiting for upper layer connect rsp */ 8 CST_CONFIG, /* Negotiating configuration */ 9 CST_OPEN, /* Data transfer state */10 CST_W4_L2CAP_DISCONNECT_RSP, /* Waiting for peer disconnect rsp */11 CST_W4_L2CA_DISCONNECT_RSP /* Waiting for upper layer disc rsp */12 } tL2C_CHNL_STATE;
The l2c_csm_execute function uses the chnl_state field in p_ccb to determine the next data packet trend. As shown in:
CST_CLOSED status: This case is used to process events in the CLOSED status of the Channel. This status only exists in the initial establishment process of The L2CAP Link.
If the event is L2CEVT_LP_DISCONNECT_IND, the current Link is disconnected, and the ccb of the current Channel is released;
- If the event is L2CEVT_LP_CONNECT_CFM, set p_ccb-> chnl_state to CST_ORIG_W4_SEC_COMP. Next we will introduce this.
- If it is L2CEVT_LP_CONNECT_CFM_NEG, the current Link fails,
- For L2CEVT_SEC_COMP, Security is cleared successfully.
- If it is L2CEVT_L2CA_CONNECT_REQ, it indicates the connect request from the upper layer. If it is in the sniff status, cancel sniff first.
- L2CEVT_SEC_COMP_NEG indicates Security fails. Clear the current CCB and return
- L2CEVT_L2CAP_CONNECT_REQ indicates that it is a Peer connect request. Since the connection is successful, timer is terminated.
- L2CEVT_L2CA_DATA_WRITE. If our data passes through here from the upper layer and it is CST_CLOSED, because the current Channel is not set up, and the upper layer has already threw the data to L2CAP, data can only be discarded (data streams cannot be reversed ).
L2CEVT_L2CA_DISCONNECT_REQ: this Event will be used to process the link to be disconnected on the upper layer.
CST_ORIG_W4_SEC_COMP status: Originator (the application established by the link is initiated in my understanding) waits for the security gap, and the events to be handled during this gap. Similar to CST_CLOSED, the source code is very easy to read and will not be analyzed again here. Note: For an L2CEVT_SEC_COMP event (security-related), p_ccb-> chnl_state is set to CST_W4_L2CAP_CONNECT_RSP.
- CST_TERM_W4_SEC_COMP status: the Acceptor (receiver) is waiting for the security gap. The source code is easy to read and will not be analyzed in detail. Note that the processing of an event L2CEVT_SEC_COMP changes p_ccb-> chnl_state to fail.
- CST_W4_L2CAP_CONNECT_RSP: Wait for the Peer connect Response (Response) after the Step 2 or 3 on the secure link ). Obtain the confirm, pending, and rejected connection information of peer connect for further judgment.
- CST_CONFIG: Discuss the configuration process.
- CST_OPEN: the Channel is OPEN. We can send the data transmitted from the upper layer. Our music data is sent from this case.
- CST_W4_L2CAP_DISCONNECT_RSP: Response waiting for the peer device to disconnect
- CST_W4_L2CA_DISCONNECT_RSP: Wait for the upper-layer disc rsp
After analyzing this pile of data packets, we listened to the music in the case of CST_OPEN, because several other cases were completed when link was created.
Our music data packet follows the CST_OPEN case, which calls the l2c_csm_open function. Next we will continue to analyze this function.
Our music data packets are transferred in the l2c_csm_open function. After various selection and judgment, we finally use the L2CEVT_L2CA_DATA_WRITE case. This case calls l2c_enqueue_peer_data to transfer the data to the xmit_hold_q queue of the current ccb and store the data packet. The l2c_link_check_send_pkts function sends data packets. Next we will continue to analyze these two functions.
1 // l2c_csm_open process various events in the OPEN Channel state. 2 static void l2c_csm_open (tL2C_CCB * p_ccb, UINT16 Event, void * p_data) 3 {4 UINT16 local_cid = p_ccb-> local_cid; 5 bytes * p_cfg; 6 bytes tempstate; 7 UINT8 tempcfgdone; 8 UINT8 bytes _result; 9 10 # if (BT_TRACE_VERBOSE = TRUE) 11 L2CAP_TRACE_EVENT2 ("L2CAP-LCID: 0x % 04x st: OPEN evt: % s ", p_ccb-> local_cid, l2c_csm_get_event_name (Event); 12 # else 13 L2CAP_TRACE_EVENT1 ("L2CAP-st: OPEN evt: % d", event); 14 # endif 15 16 # if (L2CAP_UCD_INCLUDED = TRUE) // The default UCD is off 17 if (local_cid = L2CAP_CONNECTIONLESS_CID) 18 {19/* check if this event can be processed by UCD */20 if (l2c_ucd_process_event (p_ccb, event, p_data) 21 {22/* The event is processed by UCD state machine */23 return; 24} 25} 26 # endif 27 28 sw Itch (event) 29 {30 case L2CEVT_LP_DISCONNECT_IND: // the Link is disconnected, and the natural Channel does not exist, various tasks of clearing CCB 31 L2CAP_TRACE_API1 ("L2CAP-Calling Disconnect_Ind_Cb (), CID: 0x % 04x No Conf Needed", p_ccb-> local_cid); 32 l2cu_release_ccb (p_ccb ); // release the current CCB 33 if (p_ccb-> p_rcb) 34 (* p_ccb-> p_rcb-> api. pL2CA_DisconnectInd_Cb) (local_cid, FALSE); 35 break; 36 37 case L2CEVT_LP_QOS_VIOLATION_IND:/* QOS violation */38/* Tell upper layer. if service guaranteed, then clear the channel */39 if (p_ccb-> p_rcb-> api. pL2CA_QoSViolationInd_Cb) 40 (* p_ccb-> p_rcb-> api. authorization) (p_ccb-> p_lcb-> remote_bd_addr); 41 break; 42 43 case L2CEVT_L2CAP_CONFIG_REQ:/* Peer config request */44 p_cfg = (tL2CAP_CFG_INFO *) p_data; 45 46 tempstate = p_ccb-> chnl_state; 47 tempcfgdone = p_ccb-> config_done; 48 p_ccb -> Chnl_state = CST_CONFIG; // if the data in the data stream is L2CEVT_L2CAP_CONFIG_REQ, go to CST_CONFIG and continue to process 49 p_ccb-> config_done & = ~ Pai_done_mask; 50 // start a timer. After a period of time, check cfg status 51 // If the configuration is l2cap_peer_assist_unacceptable, continue to configure 52 // If the configuration is disconnected, the current Channel is directly disconnected. 53 btu_start_timer (& p_ccb-> timer_entry, delimiter, L2CAP_CHNL_CFG_TIMEOUT); 54 55 if (partition _result = partition (p_ccb, p_cfg) = L2CAP_PEER_CFG_ OK) 56 {57 (* p_ccb-> p_rcb-> api. pL2CA_ConfigInd_Cb) (p_ccb-> local_cid, p_cfg); 58} 59 60/* Error in config parameters: reset state and config flag */61 else if (pai_result = l2cap_peer_assist_unacceptable) 62 {63 btu_stop_timer (& P_ccb-> timer_entry); 64 p_ccb-> chnl_state = tempstate; 65 p_ccb-> config_done = tempcfgdone; 66 l2cu_send_peer_config_rsp (p_ccb, p_cfg ); 67} 68 else/* l2cap_peer_assist_disconnect */69 {70/* Disconnect if channels are incompatible 71 * Note this shoshould not occur if reconfigure 72 * since this showould have never passed original config. 73 */74 l2cu_disconnect_chnl (p_ccb); 75} 76 break; 77 78 Case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnected request */79 // btla-specific ++ 80/* Make sure we are not in sniff mode */81 # if btm_pwr_mgr_encoded DED = TRUE 82 {83 tBTM_PM_PWR_MD settings; 84 settings. mode = physical; 85 BTM_SetPowerMode (physical, p_ccb-> p_lcb-> remote_bd_addr, & settings); 86} 87 # else 88 physical (p_ccb-> p_lcb-> remote_bd_addr ); 89 # endif 90 // btla-specific -- 91 92 p_ccb-> chnl_state = success; // send Disconnect to Peer. We need to send Response 93 btu_start_timer (& p_ccb-> timer_entry, btu_ttype_l2cap_nl ch, california); 94 L2CAP_TRACE_API1 ("L2CAP-Calling Disconnect_Ind_Cb (), CID: 0x % 04x Conf Needed", p_ccb-> local_cid); 95 (* p_ccb-> p_rcb-> api. pL2CA_DisconnectInd_Cb) (p_ccb-> local_cid, TRUE); 96 break; 97 98 c Ase L2CEVT_L2CAP_DATA:/* Peer data packet rcvd */99 // receives data from the Peer. Of course, you must send the data to the upper-layer application through callback. The callback is defined in 100 // pL2CA_DataInd_Cb, 101 of the data received by the upper layer (* p_ccb-> p_rcb-> api. pL2CA_DataInd_Cb) (p_ccb-> local_cid, (BT_HDR *) p_data); 102 break; 103 104 case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */105/* Make sure we are not in sniff mode */106 # if btm_pwr_mgr_bounded DED = TRUE107 {108 tBTM_PM_PWR_MD settin Gs; 109 settings. mode = physical; 110 BTM_SetPowerMode (physical, p_ccb-> p_lcb-> remote_bd_addr, & settings); 111} 112 # else113 physical (p_ccb-> p_lcb-> remote_bd_addr ); 114 # endif115 116 bytes (p_ccb); 117 p_ccb-> chnl_state = bytes; 118 btu_start_timer (& p_ccb-> timer_entry, average, L2CAP_CHNL_DISCONNECT_TOUT); 119 break; 120 121 case L2CEVT_L2CA_DATA_WRITE:/* Upper layer data to send * // mike mark l2c122 // the Upper layer sends the data to the lower layer 123 // Our music data follows this case (why? See the parameters of the entire function.) 124 // first, the data is queued. The following will show the analysis function 125 l2c_enqueue_peer_data (p_ccb, (BT_HDR *) p_data ); 126 // call l2c_link_check_send_pkts to send our music data packet 127 l2c_link_check_send_pkts (p_ccb-> p_lcb, NULL, NULL); 128 break; 129 130 case L2CEVT_L2CA_CONFIG_REQ: /* Upper layer config req */131 p_ccb-> chnl_state = CST_CONFIG; 132 p_ccb-> config_done & = ~ Pai_done_mask; 133 bytes (p_ccb, (tL2CAP_CFG_INFO *) p_data); 134 bytes (p_ccb, (Limit *) p_data); 135 btu_start_timer (& p_ccb-> timer_entry, limit, limit ); 136 break; 137 case L2CEVT_TIMEOUT: 138/* Process the monitor/retransmission time-outs in flow control/retrans mode */139 if (p_ccb-> peer_cfg.fcr.mode = L2CAP_FCR_ERTM_MODE) 141 l2c_fcr_proc_tout (p_ccb); 142 break; 143 144 case L2CEVT_ACK_TIMEOUT: 145 l2c_fcr_proc_ack_tout (p_ccb); 146 break; 147} 148}
OK. In the next article, we will analyze the functions of data packets in the queue.
For more information, see my personal website:Http://stackvoid.com/