Bluetooth: L2CAP_BR: Enable Retransmission and Flow control

Enable signaling channel configuration for retransmission and Flow
control feature.

Send I-frame and S-frame. Support retransmission and Flow control for
sending.
Receive and handle I-frame and S-frame.

Signed-off-by: Lyle Zhu <lyle.zhu@nxp.com>
This commit is contained in:
Lyle Zhu 2024-09-20 20:58:52 +08:00 committed by Anas Nashif
commit d2a10833dd
6 changed files with 4230 additions and 171 deletions

View file

@ -271,12 +271,110 @@ struct bt_l2cap_le_chan {
*/
#define BT_L2CAP_LE_CHAN(_ch) CONTAINER_OF(_ch, struct bt_l2cap_le_chan, chan)
/** L2CAP Endpoint Link Mode. Basic mode. */
#define BT_L2CAP_BR_LINK_MODE_BASIC 0x00
/** L2CAP Endpoint Link Mode. Retransmission mode. */
#define BT_L2CAP_BR_LINK_MODE_RET 0x01
/** L2CAP Endpoint Link Mode. Flow control mode. */
#define BT_L2CAP_BR_LINK_MODE_FC 0x02
/** L2CAP Endpoint Link Mode. Enhance retransmission mode. */
#define BT_L2CAP_BR_LINK_MODE_ERET 0x03
/** L2CAP Endpoint Link Mode. Streaming mode. */
#define BT_L2CAP_BR_LINK_MODE_STREAM 0x04
/** Frame Check Sequence type. No FCS. */
#define BT_L2CAP_BR_FCS_NO 0x00
/** Frame Check Sequence type. 16-bit FCS. */
#define BT_L2CAP_BR_FCS_16BIT 0x01
/** @brief BREDR L2CAP Endpoint structure. */
struct bt_l2cap_br_endpoint {
/** Endpoint Channel Identifier (CID) */
uint16_t cid;
/** Endpoint Maximum Transmission Unit */
uint16_t mtu;
#if defined(CONFIG_BT_L2CAP_RET_FC) || defined(__DOXYGEN__)
/** Endpoint Link Mode.
* The value is defined as BT_L2CAP_BR_LINK_MODE_*
*/
uint8_t mode;
/** Whether Endpoint Link Mode is optional
* If the `optional` is true, the `mode` could be
* changed according to the extended feature and
* peer configuration from L2CAP configuration
* response and request.
* Otherwise, if the channel configuration process
* does not meet the set mode, the L2CAP channel
* will be disconnected.
*/
bool optional;
/** Endpoint Maximum Transmit
* The field is used to set the max retransmission
* count.
* For `RET`, `FC`, and `ERET`, it should be not
* less 1.
* For `STREAM`, it should be 0.
*/
uint8_t max_transmit;
/** Endpoint Retransmission Timeout
* The field is configured by
* `@kconfig{BT_L2CAP_BR_RET_TIMEOUT}`
* The field should be no more than the field
* `monitor_timeout`.
*/
uint16_t ret_timeout;
/** Endpoint Monitor Timeout
* The field is configured by
* `@kconfig{BT_L2CAP_BR_MONITOR_TIMEOUT}`
*/
uint16_t monitor_timeout;
/** Endpoint Maximum PDU payload Size */
uint16_t mps;
/** Endpoint Maximum Window Size
* MAX supported window size is configured by
* `@kconfig{BT_L2CAP_MAX_WINDOW_SIZE}`. The field
* should be no more then `CONFIG_BT_L2CAP_MAX_WINDOW_SIZE`.
*/
uint16_t max_window;
/** Endpoint FCS Type
* The value is defined as BT_L2CAP_BR_FCS_*
* The default setting should be BT_L2CAP_BR_FCS_16BIT.
* For FC and RET, the FCS type should be
* BT_L2CAP_BR_FCS_16BIT.
* For ERET and STREAM, the FCS type is optional. If
* the field is not default value, the local will include
* FCS option in configuration request packet if both side
* support `FCS Option`.
*/
uint8_t fcs;
/** Endpoint Extended Control.
* If this field is true, and both side support
* `Extended Window size feature`, the local will
* include `extended window size` option in configuration
* request packet.
*/
bool extended_control;
#endif /* CONFIG_BT_L2CAP_RET_FC */
};
/** I-Frame transmission window for none `BASIC` mode L2cap connected channel. */
struct bt_l2cap_br_window {
sys_snode_t node;
/** tx seq */
uint16_t tx_seq;
/** data len */
uint16_t len;
/** data address */
uint8_t *data;
/** Transmit Counter */
uint8_t transmit_counter;
/** SAR flag */
uint8_t sar;
/** srej flag */
bool srej;
/* Save PDU state */
struct net_buf_simple_state pdu;
};
/** @brief BREDR L2CAP Channel structure. */
@ -307,6 +405,81 @@ struct bt_l2cap_br_chan {
atomic_t _pdu_ready_lock;
/** @internal Queue of net bufs not yet sent to lower layer */
struct k_fifo _pdu_tx_queue;
#if defined(CONFIG_BT_L2CAP_RET_FC) || defined(__DOXYGEN__)
/** @internal Total length of TX SDU */
uint16_t _sdu_total_len;
/** @internal Holds the remaining length of current sending buffer */
size_t _pdu_remaining;
/** @internal Holds the sending buffer. */
struct net_buf *_pdu_buf;
/** @internal TX windows for outstanding frame */
sys_slist_t _pdu_outstanding;
/** @internal PDU restore state */
struct net_buf_simple_state _pdu_state;
/** @internal Free TX windows */
struct k_fifo _free_tx_win;
/** @internal TX windows */
struct bt_l2cap_br_window tx_win[CONFIG_BT_L2CAP_MAX_WINDOW_SIZE];
/** Segment SDU packet from upper layer */
struct net_buf *_sdu;
/** @internal RX SDU */
uint16_t _sdu_len;
#if defined(CONFIG_BT_L2CAP_SEG_RECV) || defined(__DOXYGEN__)
uint16_t _sdu_len_done;
#endif /* CONFIG_BT_L2CAP_SEG_RECV */
/** @internal variables and sequence numbers */
/** @internal The sending peer uses the following variables and sequence
* numbers.
*/
/** @internal The send sequence number used to sequentially number each
* new I-frame transmitted.
*/
uint16_t tx_seq;
/** @internal The sequence number to be used in the next new I-frame
* transmitted.
*/
uint16_t next_tx_seq;
/** @internal The sequence number of the next I-frame expected to be
* acknowledged by the receiving peer.
*/
uint16_t expected_ack_seq;
/** @internal The receiving peer uses the following variables and sequence
* numbers.
*/
/** @internal The sequence number sent in an acknowledgment frame to
* request transmission of I-frame with TxSeq = ReqSeq and acknowledge
* receipt of I-frames up to and including (ReqSeq-1).
*/
uint16_t req_seq;
/** @internal The value of TxSeq expected in the next I-frame.
*/
uint16_t expected_tx_seq;
/** @internal When segmented I-frames are buffered this is used to delay
* acknowledgment of received I-frame so that new I-frame transmissions do
* not cause buffer overflow.
*/
uint16_t buffer_seq;
/** @internal States of Enhanced Retransmission Mode */
/** @internal Holds the number of times an S-frame operation is retried
*/
uint16_t retry_count;
/** @internal save the ReqSeq of a SREJ frame */
uint16_t srej_save_req_seq;
/** @internal Retransmission Timer */
struct k_work_delayable ret_work;
/** @internal Monitor Timer */
struct k_work_delayable monitor_work;
#endif /* CONFIG_BT_L2CAP_RET_FC */
};
/** @brief L2CAP Channel operations structure.

View file

@ -13,6 +13,7 @@ config BT_CLASSIC
select BT_CENTRAL
select BT_SMP
select BT_L2CAP_DYNAMIC_CHANNEL
select CRC
select EXPERIMENTAL
help
This option enables Bluetooth BR/EDR support
@ -43,6 +44,85 @@ config BT_MAX_SCO_CONN
Maximum number of simultaneous Bluetooth synchronous connections
supported. The minimum (and default) number is 1.
config BT_L2CAP_RET
bool "Bluetooth L2CAP retransmission mode [EXPERIMENTAL]"
select EXPERIMENTAL
help
This option enables Bluetooth L2CAP retransmission mode
config BT_L2CAP_FC
bool "Bluetooth L2CAP flow control mode [EXPERIMENTAL]"
select EXPERIMENTAL
help
This option enables Bluetooth L2CAP flow control mode
config BT_L2CAP_ENH_RET
bool "Bluetooth L2CAP enhance retransmission [EXPERIMENTAL]"
select EXPERIMENTAL
help
This option enables Bluetooth L2CAP enhance retransmission
config BT_L2CAP_STREAM
bool "Bluetooth L2CAP streaming mode [EXPERIMENTAL]"
select EXPERIMENTAL
help
This option enables Bluetooth L2CAP streaming mode
config BT_L2CAP_RET_FC
def_bool BT_L2CAP_RET || BT_L2CAP_FC || BT_L2CAP_ENH_RET || BT_L2CAP_STREAM
if BT_L2CAP_RET_FC
config BT_L2CAP_FCS
bool "Bluetooth L2CAP FCS Option [EXPERIMENTAL]"
select EXPERIMENTAL
depends on BT_L2CAP_STREAM || BT_L2CAP_ENH_RET
help
This option enables Bluetooth L2CAP FCS Option
config BT_L2CAP_EXT_WIN_SIZE
bool "Bluetooth L2CAP Extended window size Option [EXPERIMENTAL]"
select EXPERIMENTAL
depends on BT_L2CAP_STREAM || BT_L2CAP_ENH_RET
help
This option enables Bluetooth L2CAP Extended window size Option
config BT_L2CAP_MPS
int "Bluetooth L2CAP MPS for retransmission and Flow control"
default 48
range 48 BT_L2CAP_TX_MTU
help
Bluetooth L2CAP MPS for retransmission and Flow control
config BT_L2CAP_MAX_WINDOW_SIZE
int "Maximum Windows Size of Retransmission and Flow Control"
default 1
range 1 32
help
Maximum Windows Size of Retransmission and Flow Control.
The minimum (and default) number is 1.
config BT_L2CAP_BR_RET_TIMEOUT
int "Retransmission timeout (milliseconds)"
default 2000
range 1000 2000
help
The Retransmission timeout shall be three times the value of flush timeout,
subject to a minimum of 1000 milliseconds and maximum of 2000 milliseconds.
config BT_L2CAP_BR_MONITOR_TIMEOUT
int "Monitor timeout (milliseconds)"
default 12000 if BT_L2CAP_ENH_RET
default BT_L2CAP_BR_RET_TIMEOUT
range BT_L2CAP_BR_RET_TIMEOUT 12000
help
If a flush timeout exists on the link for Enhanced Retransmission mode and
both sides of the link are configured to the same flush timeout value then the
monitor timeout shall be set to a value at least as large as the Retransmission
timeout otherwise the value of the Monitor timeout shall be six times the value
of flush timeout, subject to a minimum of the retransmission timeout value and
a maximum of 12000 milliseconds.
endif # BT_L2CAP_RET_FC
config BT_RFCOMM
bool "Bluetooth RFCOMM protocol support [EXPERIMENTAL]"
select EXPERIMENTAL

File diff suppressed because it is too large Load diff

View file

@ -70,3 +70,6 @@ struct bt_l2cap_chan *bt_l2cap_br_lookup_tx_cid(struct bt_conn *conn,
/* Get remote supported fixed channels */
uint8_t bt_l2cap_br_get_remote_fixed_chan(struct bt_conn *conn);
/* L2CAP data receiving complete. */
int bt_l2cap_br_chan_recv_complete(struct bt_l2cap_chan *chan);

View file

@ -134,11 +134,6 @@ struct bt_l2cap_conf_opt_qos {
uint32_t delay_variation;
} __packed;
#define BT_L2CAP_RET_FC_MODE_BASIC 0x00
#define BT_L2CAP_RET_FC_MODE_RET 0x01
#define BT_L2CAP_RET_FC_MODE_FC 0x02
#define BT_L2CAP_RET_FC_MODE_ENH_RET 0x03
#define BT_L2CAP_RET_FC_MODE_STREAM 0x04
struct bt_l2cap_conf_opt_ret_fc {
uint8_t mode;
uint8_t tx_windows_size;
@ -154,6 +149,19 @@ struct bt_l2cap_conf_opt_fcs {
uint8_t type;
} __packed;
struct bt_l2cap_conf_opt_ext_flow_spec {
uint8_t identifier;
uint8_t service_type;
uint16_t sdu;
uint32_t sdu_inter_arrival_time;
uint32_t access_latency;
uint32_t flush_timeout;
} __packed;
struct bt_l2cap_conf_opt_ext_win_size {
uint16_t max_windows_size;
} __packed;
#define BT_L2CAP_DISCONN_REQ 0x06
struct bt_l2cap_disconn_req {
uint16_t dcid;
@ -185,6 +193,188 @@ struct bt_l2cap_info_rsp {
uint8_t data[0];
} __packed;
/* I Frame Standard Control Field Format definition */
#define BT_L2CAP_I_FRAME_STD_CONTROL_GET_TYPE(control) ((control) & 0x01)
#define BT_L2CAP_I_FRAME_STD_CONTROL_GET_TX_SEQ(control) (((control) >> 0x01) & 0x3f)
#define BT_L2CAP_I_FRAME_STD_CONTROL_GET_R(control) (((control) >> 0x07) & 0x01)
#define BT_L2CAP_I_FRAME_STD_CONTROL_GET_REQ_SEQ(control) (((control) >> 0x08) & 0x3f)
#define BT_L2CAP_I_FRAME_STD_CONTROL_GET_SAR(control) (((control) >> 0x0e) & 0x03)
#define BT_L2CAP_I_FRAME_STD_CONTROL_SET(tx_seq, r, req_seq, sar) \
((((tx_seq) & 0x3f) << 0x01) | (((r) & 0x01) << 0x07) | (((req_seq) & 0x3f) << 0x08) | \
(((sar) & 0x03) << 0x0e))
/* I Frame Enhanced Control Field Format definition */
#define BT_L2CAP_I_FRAME_ENH_CONTROL_GET_TYPE(control) ((control) & 0x01)
#define BT_L2CAP_I_FRAME_ENH_CONTROL_GET_TX_SEQ(control) (((control) >> 0x01) & 0x3f)
#define BT_L2CAP_I_FRAME_ENH_CONTROL_GET_F(control) (((control) >> 0x07) & 0x01)
#define BT_L2CAP_I_FRAME_ENH_CONTROL_GET_REQ_SEQ(control) (((control) >> 0x08) & 0x3f)
#define BT_L2CAP_I_FRAME_ENH_CONTROL_GET_SAR(control) (((control) >> 0x0e) & 0x03)
#define BT_L2CAP_I_FRAME_ENH_CONTROL_SET(tx_seq, f, req_seq, sar) \
((((tx_seq) & 0x3f) << 0x01) | (((f) & 0x01) << 0x07) | (((req_seq) & 0x3f) << 0x08) | \
(((sar) & 0x03) << 0x0e))
/* I Frame Extended Control Field Format definition */
#define BT_L2CAP_I_FRAME_EXT_CONTROL_GET_TYPE(control) ((control) & 0x01)
#define BT_L2CAP_I_FRAME_EXT_CONTROL_GET_F(control) (((control) >> 0x01) & 0x01)
#define BT_L2CAP_I_FRAME_EXT_CONTROL_GET_REQ_SEQ(control) (((control) >> 0x02) & 0x3fff)
#define BT_L2CAP_I_FRAME_EXT_CONTROL_GET_SAR(control) (((control) >> 0x10) & 0x03)
#define BT_L2CAP_I_FRAME_EXT_CONTROL_GET_TX_SEQ(control) (((control) >> 0x12) & 0x3fff)
#define BT_L2CAP_I_FRAME_EXT_CONTROL_SET(f, tx_seq, sar, req_seq) \
((((f) & 0x01) << 0x01) | (((req_seq) & 0x3fff) << 0x02) | (((sar) & 0x03) << 0x10) | \
(((tx_seq) & 0x3fff) << 0x12))
/* S Frame Standard Control Field Format definition */
#define BT_L2CAP_S_FRAME_STD_CONTROL_GET_TYPE(control) ((control) & 0x01)
#define BT_L2CAP_S_FRAME_STD_CONTROL_GET_S(control) (((control) >> 0x02) & 0x03)
#define BT_L2CAP_S_FRAME_STD_CONTROL_GET_R(control) (((control) >> 0x07) & 0x01)
#define BT_L2CAP_S_FRAME_STD_CONTROL_GET_REQ_SEQ(control) (((control) >> 0x08) & 0x3f)
#define BT_L2CAP_S_FRAME_STD_CONTROL_SET(s, r, req_seq) \
(((1) & 0x01) | (((s) & 0x03) << 0x02) | (((r) & 0x01) << 0x07) | \
(((req_seq) & 0x3f) << 0x08))
/* S Frame Enhanced Control Field Format definition */
#define BT_L2CAP_S_FRAME_ENH_CONTROL_GET_TYPE(control) ((control) & 0x01)
#define BT_L2CAP_S_FRAME_ENH_CONTROL_GET_S(control) (((control) >> 0x02) & 0x03)
#define BT_L2CAP_S_FRAME_ENH_CONTROL_GET_P(control) (((control) >> 0x04) & 0x01)
#define BT_L2CAP_S_FRAME_ENH_CONTROL_GET_F(control) (((control) >> 0x07) & 0x01)
#define BT_L2CAP_S_FRAME_ENH_CONTROL_GET_REQ_SEQ(control) (((control) >> 0x08) & 0x3f)
#define BT_L2CAP_S_FRAME_ENH_CONTROL_SET(s, p, f, req_seq) \
(((1) & 0x01) | (((s) & 0x03) << 0x02) | (((p) & 0x01) << 0x04) | (((f) & 0x01) << 0x07) | \
(((req_seq) & 0x3f) << 0x08))
/* S Frame Extended Control Field Format definition */
#define BT_L2CAP_S_FRAME_EXT_CONTROL_GET_TYPE(control) ((control) & 0x01)
#define BT_L2CAP_S_FRAME_EXT_CONTROL_GET_F(control) (((control) >> 0x01) & 0x01)
#define BT_L2CAP_S_FRAME_EXT_CONTROL_GET_REQ_SEQ(control) (((control) >> 0x02) & 0x3fff)
#define BT_L2CAP_S_FRAME_EXT_CONTROL_GET_S(control) (((control) >> 0x10) & 0x03)
#define BT_L2CAP_S_FRAME_EXT_CONTROL_GET_P(control) (((control) >> 0x12) & 0x01)
#define BT_L2CAP_S_FRAME_EXT_CONTROL_SET(f, req_seq, s, p) \
(((1) & 0x01) | (((f) & 0x01) << 0x01) | (((req_seq) & 0x3fff) << 0x02) | \
(((s) & 0x03) << 0x10) | (((p) & 0x01) << 0x12))
#define BT_L2CAP_CONTROL_TYPE_I 0x00
#define BT_L2CAP_CONTROL_TYPE_S 0x01
#define BT_L2CAP_CONTROL_SEQ_MAX 0x40
#define BT_L2CAP_EXT_CONTROL_SEQ_MAX 0x4000
#define BT_L2CAP_CONTROL_SAR_UNSEG 0x00
#define BT_L2CAP_CONTROL_SAR_START 0x01
#define BT_L2CAP_CONTROL_SAR_END 0x02
#define BT_L2CAP_CONTROL_SAR_CONTI 0x03
#define BT_L2CAP_CONTROL_S_RR 0x00
#define BT_L2CAP_CONTROL_S_REJ 0x01
#define BT_L2CAP_CONTROL_S_RNR 0x02
#define BT_L2CAP_CONTROL_S_SREJ 0x03
#define BT_L2CAP_RT_FC_SDU_LEN_SIZE 2
#define BT_L2CAP_STD_CONTROL_SIZE 2
#define BT_L2CAP_ENH_CONTROL_SIZE 2
#define BT_L2CAP_EXT_CONTROL_SIZE 4
#define BT_L2CAP_FCS_SIZE 2
#if defined(CONFIG_BT_L2CAP_RET_FC)
/**
*
* @brief Helper to calculate L2CAP SDU header size.
* Useful for creating buffer pools.
*
* @param mtu Required BT_L2CAP_*_SDU.
*
* @return Header size of the L2CAP channel.
*/
static inline size_t bt_l2cap_br_get_ret_fc_hdr_size(struct bt_l2cap_br_chan *chan)
{
if (chan->tx.mode != BT_L2CAP_BR_LINK_MODE_BASIC) {
if (chan->tx.extended_control) {
return BT_L2CAP_EXT_CONTROL_SIZE + BT_L2CAP_RT_FC_SDU_LEN_SIZE;
} else {
return BT_L2CAP_STD_CONTROL_SIZE + BT_L2CAP_RT_FC_SDU_LEN_SIZE;
}
}
return 0;
}
static inline size_t bt_l2cap_br_get_ret_fc_tail_size(struct bt_l2cap_br_chan *chan)
{
if (chan->tx.mode != BT_L2CAP_BR_LINK_MODE_BASIC) {
if (chan->tx.fcs == BT_L2CAP_BR_FCS_16BIT) {
return BT_L2CAP_FCS_SIZE;
}
}
return 0;
}
/**
*
* @brief Helper to calculate L2CAP SDU header size.
* Useful for creating buffer pools.
*
* @param chan the BR channel object point to `struct bt_l2cap_br_chan`.
*
* @return Header size of the L2CAP channel.
*/
#define BT_L2CAP_RT_FC_SDU_HDR_SIZE(chan) bt_l2cap_br_get_ret_fc_hdr_size(chan)
/**
*
* @brief Helper to calculate L2CAP SDU tail size.
* Useful for creating buffer pools.
*
* @param chan the BR channel object point to `struct bt_l2cap_br_chan`.
*
* @return Header size of the L2CAP channel.
*/
#define BT_L2CAP_RT_FC_SDU_TAIL_SIZE(chan) bt_l2cap_br_get_ret_fc_tail_size(chan)
/**
*
* @brief Helper to calculate needed buffer size for L2CAP SDUs.
* Useful for creating buffer pools.
*
* @param chan the BR channel object point to `struct bt_l2cap_br_chan`.
* @param mtu Required BT_L2CAP_*_SDU.
*
* @return Needed buffer size to match the requested L2CAP SDU MTU.
*/
#define BT_L2CAP_RT_FC_SDU_BUF_SIZE(chan, mtu) \
(BT_L2CAP_BUF_SIZE(BT_L2CAP_RT_FC_SDU_HDR_SIZE((chan)) + (mtu) + \
BT_L2CAP_RT_FC_SDU_TAIL_SIZE((chan))))
/**
*
* @brief Helper to calculate needed buffer size for L2CAP SDUs.
* Useful for creating buffer pools.
*
* @param mtu Required BT_L2CAP_*_SDU.
*
* @return Needed buffer size to match the requested L2CAP SDU MTU.
*/
#define BT_L2CAP_RT_FC_MAX_SDU_BUF_SIZE(mtu) \
BT_L2CAP_BUF_SIZE((mtu) + BT_L2CAP_EXT_CONTROL_SIZE + BT_L2CAP_RT_FC_SDU_LEN_SIZE + \
BT_L2CAP_FCS_SIZE)
/**
* @brief Headroom needed for outgoing L2CAP PDUs if channel in one of
* following mode, including retransmission, flow control, enhance
* retransmission, and streaming.
*
* @param chan the BR channel object point to `struct bt_l2cap_br_chan`.
*/
#define BT_L2CAP_RET_FC_SDU_CHAN_SEND_RESERVE(chan) (BT_L2CAP_RT_FC_SDU_HDR_SIZE(chan))
#endif /* CONFIG_BT_L2CAP_RET_FC */
#define BR_CHAN(_ch) CONTAINER_OF(_ch, struct bt_l2cap_br_chan, chan)
/* Add channel to the connection */

View file

@ -2417,6 +2417,10 @@ int bt_l2cap_chan_recv_complete(struct bt_l2cap_chan *chan, struct net_buf *buf)
return -ENOTCONN;
}
if (IS_ENABLED(CONFIG_BT_CLASSIC) && conn->type == BT_CONN_TYPE_BR) {
return bt_l2cap_br_chan_recv_complete(chan);
}
if (conn->type != BT_CONN_TYPE_LE) {
return -ENOTSUP;
}