Loading system/stack/l2cap/l2c_csm.cc +8 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include <base/functional/callback.h> #include <bluetooth/log.h> #include <com_android_bluetooth_flags.h> #include <frameworks/proto_logging/stats/enums/bluetooth/enums.pb.h> #include <string> Loading Loading @@ -74,6 +75,13 @@ static void l2c_csm_send_config_req(tL2C_CCB* p_ccb) { if (p_ccb->p_rcb->ertm_info.preferred_mode != L2CAP_FCR_BASIC_MODE) { config.fcr_present = true; config.fcr = kDefaultErtmOptions; if (com::android::bluetooth::flags::l2cap_fcs_option_fix()) { /* Later l2cu_process_our_cfg_req() will check if remote supports it, and if not, it will be * cleared as per spec. */ config.fcs_present = true; config.fcs = 1; } } p_ccb->our_cfg = config; l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONFIG_REQ, &config); Loading system/stack/l2cap/l2c_fcr.cc +44 −29 Original line number Diff line number Diff line Loading @@ -280,6 +280,8 @@ static void prepare_I_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf, bool is_retransmissi uint16_t ctrl_word; bool set_f_bit = p_fcrb->send_f_rsp; uint8_t fcs_len = l2cu_get_fcs_len(p_ccb); p_fcrb->send_f_rsp = false; if (is_retransmission) { Loading Loading @@ -317,8 +319,9 @@ static void prepare_I_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf, bool is_retransmissi /* Compute the FCS and add to the end of the buffer if not bypassed */ /* length field in l2cap header has to include FCS length */ p = ((uint8_t*)(p_buf + 1)) + p_buf->offset; UINT16_TO_STREAM(p, p_buf->len + L2CAP_FCS_LEN - L2CAP_PKT_OVERHEAD); UINT16_TO_STREAM(p, p_buf->len + fcs_len - L2CAP_PKT_OVERHEAD); if (fcs_len != 0) { /* Calculate the FCS */ fcs = l2c_fcr_tx_get_fcs(p_buf); Loading @@ -331,7 +334,8 @@ static void prepare_I_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf, bool is_retransmissi UINT16_TO_STREAM(p, fcs); p_buf->len += L2CAP_FCS_LEN; p_buf->len += fcs_len; } if (is_retransmission) { log::verbose( Loading Loading @@ -397,16 +401,20 @@ void l2c_fcr_send_S_frame(tL2C_CCB* p_ccb, uint16_t function_code, uint16_t pf_b /* Set the pointer to the beginning of the data */ p = (uint8_t*)(p_buf + 1) + p_buf->offset; uint8_t fcs_len = l2cu_get_fcs_len(p_ccb); /* Put in the L2CAP header */ UINT16_TO_STREAM(p, L2CAP_FCR_OVERHEAD + L2CAP_FCS_LEN); UINT16_TO_STREAM(p, L2CAP_FCR_OVERHEAD + fcs_len); UINT16_TO_STREAM(p, p_ccb->remote_cid); UINT16_TO_STREAM(p, ctrl_word); if (fcs_len != 0) { /* Compute the FCS and add to the end of the buffer if not bypassed */ fcs = l2c_fcr_tx_get_fcs(p_buf); UINT16_TO_STREAM(p, fcs); p_buf->len += L2CAP_FCS_LEN; p_buf->len += fcs_len; } /* Now, the HCI transport header */ p_buf->layer_specific = L2CAP_NON_FLUSHABLE_PKT; Loading Loading @@ -462,7 +470,9 @@ void l2c_fcr_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf) { uint16_t ctrl_word; /* Check the length */ min_pdu_len = (uint16_t)(L2CAP_FCS_LEN + L2CAP_FCR_OVERHEAD); uint8_t fcs_len = l2cu_get_fcs_len(p_ccb); min_pdu_len = (uint16_t)(fcs_len + L2CAP_FCR_OVERHEAD); if (p_buf->len < min_pdu_len) { log::warn("Rx L2CAP PDU: CID: 0x{:04x} Len too short: {}", p_ccb->local_cid, p_buf->len); Loading Loading @@ -514,18 +524,20 @@ void l2c_fcr_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf) { p_ccb->fcrb.last_ack_sent, fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q), p_ccb->fcrb.num_tries); if (fcs_len != 0) { /* Verify FCS if using */ p = ((uint8_t*)(p_buf + 1)) + p_buf->offset + p_buf->len - L2CAP_FCS_LEN; p = ((uint8_t*)(p_buf + 1)) + p_buf->offset + p_buf->len - fcs_len; /* Extract and drop the FCS from the packet */ STREAM_TO_UINT16(fcs, p); p_buf->len -= L2CAP_FCS_LEN; p_buf->len -= fcs_len; if (l2c_fcr_rx_get_fcs(p_buf) != fcs) { log::warn("Rx L2CAP PDU: CID: 0x{:04x} BAD FCS", p_ccb->local_cid); osi_free(p_buf); return; } } /* Get the control word */ p = ((uint8_t*)(p_buf + 1)) + p_buf->offset; Loading Loading @@ -1466,6 +1478,7 @@ BT_HDR* l2c_fcr_get_next_xmit_sdu_seg(tL2C_CCB* p_ccb, uint16_t max_packet_lengt } prepare_I_frame(p_ccb, p_xmit, false); uint8_t fcs_len = l2cu_get_fcs_len(p_ccb); if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) { BT_HDR* p_wack = l2c_fcr_clone_buf(p_xmit, HCI_DATA_PREAMBLE_SIZE, p_xmit->len); Loading @@ -1475,14 +1488,14 @@ BT_HDR* l2c_fcr_get_next_xmit_sdu_seg(tL2C_CCB* p_ccb, uint16_t max_packet_lengt p_xmit->len); /* We will not save the FCS in case we reconfigure and change options */ p_xmit->len -= L2CAP_FCS_LEN; p_xmit->len -= fcs_len; /* Pretend we sent it and it got lost */ fixed_queue_enqueue(p_ccb->fcrb.waiting_for_ack_q, p_xmit); return NULL; } else { /* We will not save the FCS in case we reconfigure and change options */ p_wack->len -= L2CAP_FCS_LEN; p_wack->len -= fcs_len; p_wack->layer_specific = p_xmit->layer_specific; fixed_queue_enqueue(p_ccb->fcrb.waiting_for_ack_q, p_wack); Loading Loading @@ -1793,6 +1806,8 @@ uint8_t l2c_fcr_process_peer_cfg_req(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) { } } uint8_t fcs_len = l2cu_get_fcs_len(p_ccb); /* Configuration for FCR channels so make any adjustments and fwd to upper * layer */ if (fcr_ok == L2CAP_PEER_CFG_OK) { Loading @@ -1807,7 +1822,7 @@ uint8_t l2c_fcr_process_peer_cfg_req(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) { } max_retrans_size = BT_DEFAULT_BUFFER_SIZE - sizeof(BT_HDR) - L2CAP_MIN_OFFSET - L2CAP_SDU_LEN_OFFSET - L2CAP_FCS_LEN; L2CAP_SDU_LEN_OFFSET - fcs_len; /* Ensure the MPS is not bigger than the MTU */ if ((p_cfg->fcr.mps == 0) || (p_cfg->fcr.mps > p_ccb->peer_cfg.mtu)) { Loading system/stack/l2cap/l2c_int.h +1 −0 Original line number Diff line number Diff line Loading @@ -762,6 +762,7 @@ void l2cu_release_ble_rcb(tL2C_RCB* p_rcb); tL2C_RCB* l2cu_allocate_ble_rcb(uint16_t psm); tL2C_RCB* l2cu_find_ble_rcb_by_psm(uint16_t psm); uint8_t l2cu_get_fcs_len(tL2C_CCB* p_ccb); uint8_t l2cu_process_peer_cfg_req(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg); void l2cu_process_peer_cfg_rsp(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg); void l2cu_process_our_cfg_req(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg); Loading system/stack/l2cap/l2c_utils.cc +29 −0 Original line number Diff line number Diff line Loading @@ -1849,6 +1849,30 @@ tL2C_RCB* l2cu_find_ble_rcb_by_psm(uint16_t psm) { return NULL; } /************************************************************************************* * * Function l2cu_get_fcs_len * * Description This function is called to determine FCS len in S/I Frames. * * * Returns 0 or L2CAP_FCS_LEN: 0 is returned when both sides configure `No FCS` * **************************************************************************************/ uint8_t l2cu_get_fcs_len(tL2C_CCB* p_ccb) { log::verbose("our.fcs_present: {} our.fcs: {}, peer.fcs_present: {} peer.fcs: {}", p_ccb->our_cfg.fcs_present, p_ccb->our_cfg.fcs, p_ccb->peer_cfg.fcs_present, p_ccb->peer_cfg.fcs); if (com::android::bluetooth::flags::l2cap_fcs_option_fix() && (p_ccb->peer_cfg.fcs_present && p_ccb->peer_cfg.fcs == 0x00) && (p_ccb->our_cfg.fcs_present && p_ccb->our_cfg.fcs == 0x00)) { return 0; } return L2CAP_FCS_LEN; } /******************************************************************************* * * Function l2cu_process_peer_cfg_req Loading Loading @@ -1884,6 +1908,11 @@ uint8_t l2cu_process_peer_cfg_req(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) { p_cfg->fcr.mode = L2CAP_FCR_BASIC_MODE; } if (com::android::bluetooth::flags::l2cap_fcs_option_fix() && p_cfg->fcs_present) { p_ccb->peer_cfg.fcs_present = 1; p_ccb->peer_cfg.fcs = p_cfg->fcs; } if (!p_cfg->mtu_present && required_remote_mtu > L2CAP_DEFAULT_MTU) { // We reject if we have a MTU requirement higher than default MTU p_cfg->mtu = required_remote_mtu; Loading Loading
system/stack/l2cap/l2c_csm.cc +8 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include <base/functional/callback.h> #include <bluetooth/log.h> #include <com_android_bluetooth_flags.h> #include <frameworks/proto_logging/stats/enums/bluetooth/enums.pb.h> #include <string> Loading Loading @@ -74,6 +75,13 @@ static void l2c_csm_send_config_req(tL2C_CCB* p_ccb) { if (p_ccb->p_rcb->ertm_info.preferred_mode != L2CAP_FCR_BASIC_MODE) { config.fcr_present = true; config.fcr = kDefaultErtmOptions; if (com::android::bluetooth::flags::l2cap_fcs_option_fix()) { /* Later l2cu_process_our_cfg_req() will check if remote supports it, and if not, it will be * cleared as per spec. */ config.fcs_present = true; config.fcs = 1; } } p_ccb->our_cfg = config; l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONFIG_REQ, &config); Loading
system/stack/l2cap/l2c_fcr.cc +44 −29 Original line number Diff line number Diff line Loading @@ -280,6 +280,8 @@ static void prepare_I_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf, bool is_retransmissi uint16_t ctrl_word; bool set_f_bit = p_fcrb->send_f_rsp; uint8_t fcs_len = l2cu_get_fcs_len(p_ccb); p_fcrb->send_f_rsp = false; if (is_retransmission) { Loading Loading @@ -317,8 +319,9 @@ static void prepare_I_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf, bool is_retransmissi /* Compute the FCS and add to the end of the buffer if not bypassed */ /* length field in l2cap header has to include FCS length */ p = ((uint8_t*)(p_buf + 1)) + p_buf->offset; UINT16_TO_STREAM(p, p_buf->len + L2CAP_FCS_LEN - L2CAP_PKT_OVERHEAD); UINT16_TO_STREAM(p, p_buf->len + fcs_len - L2CAP_PKT_OVERHEAD); if (fcs_len != 0) { /* Calculate the FCS */ fcs = l2c_fcr_tx_get_fcs(p_buf); Loading @@ -331,7 +334,8 @@ static void prepare_I_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf, bool is_retransmissi UINT16_TO_STREAM(p, fcs); p_buf->len += L2CAP_FCS_LEN; p_buf->len += fcs_len; } if (is_retransmission) { log::verbose( Loading Loading @@ -397,16 +401,20 @@ void l2c_fcr_send_S_frame(tL2C_CCB* p_ccb, uint16_t function_code, uint16_t pf_b /* Set the pointer to the beginning of the data */ p = (uint8_t*)(p_buf + 1) + p_buf->offset; uint8_t fcs_len = l2cu_get_fcs_len(p_ccb); /* Put in the L2CAP header */ UINT16_TO_STREAM(p, L2CAP_FCR_OVERHEAD + L2CAP_FCS_LEN); UINT16_TO_STREAM(p, L2CAP_FCR_OVERHEAD + fcs_len); UINT16_TO_STREAM(p, p_ccb->remote_cid); UINT16_TO_STREAM(p, ctrl_word); if (fcs_len != 0) { /* Compute the FCS and add to the end of the buffer if not bypassed */ fcs = l2c_fcr_tx_get_fcs(p_buf); UINT16_TO_STREAM(p, fcs); p_buf->len += L2CAP_FCS_LEN; p_buf->len += fcs_len; } /* Now, the HCI transport header */ p_buf->layer_specific = L2CAP_NON_FLUSHABLE_PKT; Loading Loading @@ -462,7 +470,9 @@ void l2c_fcr_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf) { uint16_t ctrl_word; /* Check the length */ min_pdu_len = (uint16_t)(L2CAP_FCS_LEN + L2CAP_FCR_OVERHEAD); uint8_t fcs_len = l2cu_get_fcs_len(p_ccb); min_pdu_len = (uint16_t)(fcs_len + L2CAP_FCR_OVERHEAD); if (p_buf->len < min_pdu_len) { log::warn("Rx L2CAP PDU: CID: 0x{:04x} Len too short: {}", p_ccb->local_cid, p_buf->len); Loading Loading @@ -514,18 +524,20 @@ void l2c_fcr_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf) { p_ccb->fcrb.last_ack_sent, fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q), p_ccb->fcrb.num_tries); if (fcs_len != 0) { /* Verify FCS if using */ p = ((uint8_t*)(p_buf + 1)) + p_buf->offset + p_buf->len - L2CAP_FCS_LEN; p = ((uint8_t*)(p_buf + 1)) + p_buf->offset + p_buf->len - fcs_len; /* Extract and drop the FCS from the packet */ STREAM_TO_UINT16(fcs, p); p_buf->len -= L2CAP_FCS_LEN; p_buf->len -= fcs_len; if (l2c_fcr_rx_get_fcs(p_buf) != fcs) { log::warn("Rx L2CAP PDU: CID: 0x{:04x} BAD FCS", p_ccb->local_cid); osi_free(p_buf); return; } } /* Get the control word */ p = ((uint8_t*)(p_buf + 1)) + p_buf->offset; Loading Loading @@ -1466,6 +1478,7 @@ BT_HDR* l2c_fcr_get_next_xmit_sdu_seg(tL2C_CCB* p_ccb, uint16_t max_packet_lengt } prepare_I_frame(p_ccb, p_xmit, false); uint8_t fcs_len = l2cu_get_fcs_len(p_ccb); if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) { BT_HDR* p_wack = l2c_fcr_clone_buf(p_xmit, HCI_DATA_PREAMBLE_SIZE, p_xmit->len); Loading @@ -1475,14 +1488,14 @@ BT_HDR* l2c_fcr_get_next_xmit_sdu_seg(tL2C_CCB* p_ccb, uint16_t max_packet_lengt p_xmit->len); /* We will not save the FCS in case we reconfigure and change options */ p_xmit->len -= L2CAP_FCS_LEN; p_xmit->len -= fcs_len; /* Pretend we sent it and it got lost */ fixed_queue_enqueue(p_ccb->fcrb.waiting_for_ack_q, p_xmit); return NULL; } else { /* We will not save the FCS in case we reconfigure and change options */ p_wack->len -= L2CAP_FCS_LEN; p_wack->len -= fcs_len; p_wack->layer_specific = p_xmit->layer_specific; fixed_queue_enqueue(p_ccb->fcrb.waiting_for_ack_q, p_wack); Loading Loading @@ -1793,6 +1806,8 @@ uint8_t l2c_fcr_process_peer_cfg_req(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) { } } uint8_t fcs_len = l2cu_get_fcs_len(p_ccb); /* Configuration for FCR channels so make any adjustments and fwd to upper * layer */ if (fcr_ok == L2CAP_PEER_CFG_OK) { Loading @@ -1807,7 +1822,7 @@ uint8_t l2c_fcr_process_peer_cfg_req(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) { } max_retrans_size = BT_DEFAULT_BUFFER_SIZE - sizeof(BT_HDR) - L2CAP_MIN_OFFSET - L2CAP_SDU_LEN_OFFSET - L2CAP_FCS_LEN; L2CAP_SDU_LEN_OFFSET - fcs_len; /* Ensure the MPS is not bigger than the MTU */ if ((p_cfg->fcr.mps == 0) || (p_cfg->fcr.mps > p_ccb->peer_cfg.mtu)) { Loading
system/stack/l2cap/l2c_int.h +1 −0 Original line number Diff line number Diff line Loading @@ -762,6 +762,7 @@ void l2cu_release_ble_rcb(tL2C_RCB* p_rcb); tL2C_RCB* l2cu_allocate_ble_rcb(uint16_t psm); tL2C_RCB* l2cu_find_ble_rcb_by_psm(uint16_t psm); uint8_t l2cu_get_fcs_len(tL2C_CCB* p_ccb); uint8_t l2cu_process_peer_cfg_req(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg); void l2cu_process_peer_cfg_rsp(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg); void l2cu_process_our_cfg_req(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg); Loading
system/stack/l2cap/l2c_utils.cc +29 −0 Original line number Diff line number Diff line Loading @@ -1849,6 +1849,30 @@ tL2C_RCB* l2cu_find_ble_rcb_by_psm(uint16_t psm) { return NULL; } /************************************************************************************* * * Function l2cu_get_fcs_len * * Description This function is called to determine FCS len in S/I Frames. * * * Returns 0 or L2CAP_FCS_LEN: 0 is returned when both sides configure `No FCS` * **************************************************************************************/ uint8_t l2cu_get_fcs_len(tL2C_CCB* p_ccb) { log::verbose("our.fcs_present: {} our.fcs: {}, peer.fcs_present: {} peer.fcs: {}", p_ccb->our_cfg.fcs_present, p_ccb->our_cfg.fcs, p_ccb->peer_cfg.fcs_present, p_ccb->peer_cfg.fcs); if (com::android::bluetooth::flags::l2cap_fcs_option_fix() && (p_ccb->peer_cfg.fcs_present && p_ccb->peer_cfg.fcs == 0x00) && (p_ccb->our_cfg.fcs_present && p_ccb->our_cfg.fcs == 0x00)) { return 0; } return L2CAP_FCS_LEN; } /******************************************************************************* * * Function l2cu_process_peer_cfg_req Loading Loading @@ -1884,6 +1908,11 @@ uint8_t l2cu_process_peer_cfg_req(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) { p_cfg->fcr.mode = L2CAP_FCR_BASIC_MODE; } if (com::android::bluetooth::flags::l2cap_fcs_option_fix() && p_cfg->fcs_present) { p_ccb->peer_cfg.fcs_present = 1; p_ccb->peer_cfg.fcs = p_cfg->fcs; } if (!p_cfg->mtu_present && required_remote_mtu > L2CAP_DEFAULT_MTU) { // We reject if we have a MTU requirement higher than default MTU p_cfg->mtu = required_remote_mtu; Loading