Bluetooth: Tester: Use BT_L2CAP_SEG_RECV for L2CAP tests
This API gives better control on L2CAP COC credits and suits better for Upper Tester implementation. Co-authored-by: Szymon Janc <szymon.janc@codecoup.pl> Signed-off-by: Aleksander Wasaznik <aleksander.wasaznik@nordicsemi.no>
This commit is contained in:
parent
c002b1dc9e
commit
5a8daffc32
7 changed files with 276 additions and 35 deletions
|
@ -18,6 +18,7 @@
|
|||
* @{
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <zephyr/sys/atomic.h>
|
||||
|
@ -83,6 +84,42 @@ extern "C" {
|
|||
*/
|
||||
#define BT_L2CAP_SDU_BUF_SIZE(mtu) BT_L2CAP_BUF_SIZE(BT_L2CAP_SDU_HDR_SIZE + (mtu))
|
||||
|
||||
/** @brief L2CAP ECRED minimum MTU
|
||||
*
|
||||
* The minimum MTU for an L2CAP Enhanced Credit Based Connection.
|
||||
*
|
||||
* This requirement is inferred from text in Core 3.A.4.25 v6.0:
|
||||
*
|
||||
* L2CAP implementations shall support a minimum MTU size of 64
|
||||
* octets for these channels.
|
||||
*/
|
||||
#define BT_L2CAP_ECRED_MIN_MTU 64
|
||||
|
||||
/** @brief L2CAP ECRED minimum MPS
|
||||
*
|
||||
* The minimum MPS for an L2CAP Enhanced Credit Based Connection.
|
||||
*
|
||||
* This requirement is inferred from text in Core 3.A.4.25 v6.0:
|
||||
*
|
||||
* L2CAP implementations shall support a minimum MPS of 64 and may
|
||||
* support an MPS up to 65533 octets for these channels.
|
||||
*/
|
||||
#define BT_L2CAP_ECRED_MIN_MPS 64
|
||||
|
||||
/** @brief The maximum number of channels in ECRED L2CAP signaling PDUs
|
||||
*
|
||||
* Currently, this is the maximum number of channels referred to in the
|
||||
* following PDUs:
|
||||
* - L2CAP_CREDIT_BASED_CONNECTION_REQ
|
||||
* - L2CAP_CREDIT_BASED_RECONFIGURE_REQ
|
||||
*
|
||||
* @warning The commonality is inferred between the PDUs. The Bluetooth
|
||||
* specification treats these as separate numbers and does now
|
||||
* guarantee the same limit for potential future ECRED L2CAP signaling
|
||||
* PDUs.
|
||||
*/
|
||||
#define BT_L2CAP_ECRED_CHAN_MAX_PER_REQ 5
|
||||
|
||||
struct bt_l2cap_chan;
|
||||
|
||||
/** @typedef bt_l2cap_chan_destroy_t
|
||||
|
@ -557,6 +594,52 @@ int bt_l2cap_ecred_chan_connect(struct bt_conn *conn,
|
|||
*/
|
||||
int bt_l2cap_ecred_chan_reconfigure(struct bt_l2cap_chan **chans, uint16_t mtu);
|
||||
|
||||
/** @brief Reconfigure Enhanced Credit Based L2CAP channels
|
||||
*
|
||||
* Experimental API to reconfigure L2CAP ECRED channels with explicit MPS and
|
||||
* MTU values.
|
||||
*
|
||||
* Pend a L2CAP ECRED reconfiguration for up to 5 channels. All provided
|
||||
* channels must share the same @ref bt_conn.
|
||||
*
|
||||
* This API cannot decrease the MTU of any channel, and it cannot decrease the
|
||||
* MPS of any channel when more than one channel is provided.
|
||||
*
|
||||
* There is no dedicated callback for this operation, but whenever a peer
|
||||
* responds to a reconfiguration request, each affected channel's
|
||||
* reconfigured() callback is invoked.
|
||||
*
|
||||
* This function may block.
|
||||
*
|
||||
* @warning Known issue: The implementation returns -EBUSY if there already is
|
||||
* an ongoing reconfigure operation on the same connection. The caller may try
|
||||
* again later. There is no event signaling when the existing operation
|
||||
* finishes.
|
||||
*
|
||||
* @warning Known issue: The implementation returns -ENOMEM when unable to
|
||||
* allocate. The caller may try again later. There is no event signaling the
|
||||
* availability of buffers.
|
||||
*
|
||||
* @kconfig_dep{CONFIG_BT_L2CAP_RECONFIGURE_EXPLICIT}
|
||||
*
|
||||
* @param chans Array of channels to reconfigure. Must be non-empty and
|
||||
* contain at most 5 (@ref BT_L2CAP_ECRED_CHAN_MAX_PER_REQ)
|
||||
* elements.
|
||||
* @param chan_count Number of channels in the array.
|
||||
* @param mtu Desired MTU. Must be at least @ref BT_L2CAP_ECRED_MIN_MTU.
|
||||
* @param mps Desired MPS. Must be in range @ref BT_L2CAP_ECRED_MIN_MPS
|
||||
* to @ref BT_L2CAP_RX_MTU.
|
||||
*
|
||||
* @retval 0 Successfully pended operation.
|
||||
* @retval -EINVAL Bad arguments. See above requirements.
|
||||
* @retval -ENOTCONN Connection object is not in connected state.
|
||||
* @retval -EBUSY Another outgoing reconfiguration is pending on the same
|
||||
* connection.
|
||||
* @retval -ENOMEM Host is out of buffers.
|
||||
*/
|
||||
int bt_l2cap_ecred_chan_reconfigure_explicit(struct bt_l2cap_chan **chans, size_t chan_count,
|
||||
uint16_t mtu, uint16_t mps);
|
||||
|
||||
/** @brief Connect L2CAP channel
|
||||
*
|
||||
* Connect L2CAP channel by PSM, once the connection is completed channel
|
||||
|
|
|
@ -62,7 +62,6 @@ config BT_L2CAP_SEG_RECV
|
|||
bool "L2CAP Receive segment direct API [EXPERIMENTAL]"
|
||||
select EXPERIMENTAL
|
||||
help
|
||||
|
||||
Enable API for direct receiving of L2CAP SDU segments, bypassing the
|
||||
Host's fixed-function SDU re-assembler, RX SDU buffer management and
|
||||
credit issuer.
|
||||
|
@ -70,4 +69,11 @@ config BT_L2CAP_SEG_RECV
|
|||
This API enforces conformance with L2CAP TS, but is otherwise as
|
||||
flexible and semantically simple as possible.
|
||||
|
||||
config BT_L2CAP_RECONFIGURE_EXPLICIT
|
||||
bool "L2CAP Explicit reconfigure API [EXPERIMENTAL]"
|
||||
select EXPERIMENTAL
|
||||
help
|
||||
Enable API for explicit reconfiguration of an L2CAP channel's MTU and
|
||||
MPS.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -3668,7 +3668,7 @@ int bt_eatt_connect(struct bt_conn *conn, size_t num_channels)
|
|||
}
|
||||
|
||||
while (offset < i) {
|
||||
/* bt_l2cap_ecred_chan_connect() uses the first L2CAP_ECRED_CHAN_MAX_PER_REQ
|
||||
/* bt_l2cap_ecred_chan_connect() uses the first BT_L2CAP_ECRED_CHAN_MAX_PER_REQ
|
||||
* elements of the array or until a null-terminator is reached.
|
||||
*/
|
||||
err = bt_l2cap_ecred_chan_connect(conn, &chan[offset], BT_EATT_PSM);
|
||||
|
@ -3676,7 +3676,7 @@ int bt_eatt_connect(struct bt_conn *conn, size_t num_channels)
|
|||
return err;
|
||||
}
|
||||
|
||||
offset += L2CAP_ECRED_CHAN_MAX_PER_REQ;
|
||||
offset += BT_L2CAP_ECRED_CHAN_MAX_PER_REQ;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -3767,7 +3767,7 @@ int bt_eatt_reconfigure(struct bt_conn *conn, uint16_t mtu)
|
|||
}
|
||||
|
||||
while (offset < i) {
|
||||
/* bt_l2cap_ecred_chan_reconfigure() uses the first L2CAP_ECRED_CHAN_MAX_PER_REQ
|
||||
/* bt_l2cap_ecred_chan_reconfigure() uses the first BT_L2CAP_ECRED_CHAN_MAX_PER_REQ
|
||||
* elements of the array or until a null-terminator is reached.
|
||||
*/
|
||||
err = bt_l2cap_ecred_chan_reconfigure(&chans[offset], mtu);
|
||||
|
@ -3775,7 +3775,7 @@ int bt_eatt_reconfigure(struct bt_conn *conn, uint16_t mtu)
|
|||
return err;
|
||||
}
|
||||
|
||||
offset += L2CAP_ECRED_CHAN_MAX_PER_REQ;
|
||||
offset += BT_L2CAP_ECRED_CHAN_MAX_PER_REQ;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -40,7 +40,6 @@ LOG_MODULE_REGISTER(bt_l2cap, CONFIG_BT_L2CAP_LOG_LEVEL);
|
|||
#define CHAN_RX(_w) CONTAINER_OF(_w, struct bt_l2cap_le_chan, rx_work)
|
||||
|
||||
#define L2CAP_LE_MIN_MTU 23
|
||||
#define L2CAP_ECRED_MIN_MTU 64
|
||||
|
||||
#define L2CAP_LE_MAX_CREDITS (CONFIG_BT_BUF_ACL_RX_COUNT - 1)
|
||||
|
||||
|
@ -58,6 +57,10 @@ LOG_MODULE_REGISTER(bt_l2cap, CONFIG_BT_L2CAP_LOG_LEVEL);
|
|||
|
||||
#define L2CAP_CONN_TIMEOUT K_SECONDS(40)
|
||||
#define L2CAP_DISC_TIMEOUT K_SECONDS(2)
|
||||
/** @brief Local L2CAP RTX (Response Timeout eXpired)
|
||||
*
|
||||
* Specification-allowed range for the value of RTX is 1 to 60 seconds.
|
||||
*/
|
||||
#define L2CAP_RTX_TIMEOUT K_SECONDS(2)
|
||||
|
||||
#if defined(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL)
|
||||
|
@ -613,15 +616,15 @@ static void l2cap_le_encrypt_change(struct bt_l2cap_chan *chan, uint8_t status)
|
|||
|
||||
#if defined(CONFIG_BT_L2CAP_ECRED)
|
||||
if (le->ident) {
|
||||
struct bt_l2cap_chan *echan[L2CAP_ECRED_CHAN_MAX_PER_REQ];
|
||||
struct bt_l2cap_chan *echan[BT_L2CAP_ECRED_CHAN_MAX_PER_REQ];
|
||||
struct bt_l2cap_chan *ch;
|
||||
int i = 0;
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER(&chan->conn->channels, ch, node) {
|
||||
if (le->ident == BT_L2CAP_LE_CHAN(ch)->ident) {
|
||||
__ASSERT(i < L2CAP_ECRED_CHAN_MAX_PER_REQ,
|
||||
"There can only be L2CAP_ECRED_CHAN_MAX_PER_REQ channels "
|
||||
"from the same request.");
|
||||
__ASSERT(i < BT_L2CAP_ECRED_CHAN_MAX_PER_REQ,
|
||||
"There can only be BT_L2CAP_ECRED_CHAN_MAX_PER_REQ "
|
||||
"channels from the same request.");
|
||||
atomic_clear_bit(ch->status, BT_L2CAP_STATUS_ENCRYPT_PENDING);
|
||||
echan[i++] = ch;
|
||||
}
|
||||
|
@ -1518,14 +1521,14 @@ static void le_ecred_conn_req(struct bt_l2cap *l2cap, uint8_t ident,
|
|||
struct net_buf *buf)
|
||||
{
|
||||
struct bt_conn *conn = l2cap->chan.chan.conn;
|
||||
struct bt_l2cap_chan *chan[L2CAP_ECRED_CHAN_MAX_PER_REQ];
|
||||
struct bt_l2cap_chan *chan[BT_L2CAP_ECRED_CHAN_MAX_PER_REQ];
|
||||
struct bt_l2cap_le_chan *ch = NULL;
|
||||
struct bt_l2cap_server *server;
|
||||
struct bt_l2cap_ecred_conn_req *req;
|
||||
struct bt_l2cap_ecred_conn_rsp *rsp;
|
||||
uint16_t mtu, mps, credits, result = BT_L2CAP_LE_SUCCESS;
|
||||
uint16_t psm = 0x0000;
|
||||
uint16_t scid, dcid[L2CAP_ECRED_CHAN_MAX_PER_REQ];
|
||||
uint16_t scid, dcid[BT_L2CAP_ECRED_CHAN_MAX_PER_REQ];
|
||||
int i = 0;
|
||||
uint8_t req_cid_count;
|
||||
bool rsp_queued = false;
|
||||
|
@ -1544,7 +1547,7 @@ static void le_ecred_conn_req(struct bt_l2cap *l2cap, uint8_t ident,
|
|||
|
||||
if (buf->len > sizeof(dcid)) {
|
||||
LOG_ERR("Too large LE conn req packet size");
|
||||
req_cid_count = L2CAP_ECRED_CHAN_MAX_PER_REQ;
|
||||
req_cid_count = BT_L2CAP_ECRED_CHAN_MAX_PER_REQ;
|
||||
result = BT_L2CAP_LE_ERR_INVALID_PARAMS;
|
||||
goto response;
|
||||
}
|
||||
|
@ -1556,7 +1559,7 @@ static void le_ecred_conn_req(struct bt_l2cap *l2cap, uint8_t ident,
|
|||
|
||||
LOG_DBG("psm 0x%02x mtu %u mps %u credits %u", psm, mtu, mps, credits);
|
||||
|
||||
if (mtu < L2CAP_ECRED_MIN_MTU || mps < L2CAP_ECRED_MIN_MTU) {
|
||||
if (mtu < BT_L2CAP_ECRED_MIN_MTU || mps < BT_L2CAP_ECRED_MIN_MTU) {
|
||||
LOG_ERR("Invalid ecred conn req params. mtu %u mps %u", mtu, mps);
|
||||
result = BT_L2CAP_LE_ERR_INVALID_PARAMS;
|
||||
goto response;
|
||||
|
@ -1646,7 +1649,7 @@ static void le_ecred_reconf_req(struct bt_l2cap *l2cap, uint8_t ident,
|
|||
struct net_buf *buf)
|
||||
{
|
||||
struct bt_conn *conn = l2cap->chan.chan.conn;
|
||||
struct bt_l2cap_chan *chans[L2CAP_ECRED_CHAN_MAX_PER_REQ];
|
||||
struct bt_l2cap_chan *chans[BT_L2CAP_ECRED_CHAN_MAX_PER_REQ];
|
||||
struct bt_l2cap_ecred_reconf_req *req;
|
||||
struct bt_l2cap_ecred_reconf_rsp *rsp;
|
||||
uint16_t mtu, mps;
|
||||
|
@ -1664,18 +1667,18 @@ static void le_ecred_reconf_req(struct bt_l2cap *l2cap, uint8_t ident,
|
|||
mtu = sys_le16_to_cpu(req->mtu);
|
||||
mps = sys_le16_to_cpu(req->mps);
|
||||
|
||||
if (mps < L2CAP_ECRED_MIN_MTU) {
|
||||
if (mps < BT_L2CAP_ECRED_MIN_MTU) {
|
||||
result = BT_L2CAP_RECONF_OTHER_UNACCEPT;
|
||||
goto response;
|
||||
}
|
||||
|
||||
if (mtu < L2CAP_ECRED_MIN_MTU) {
|
||||
if (mtu < BT_L2CAP_ECRED_MIN_MTU) {
|
||||
result = BT_L2CAP_RECONF_INVALID_MTU;
|
||||
goto response;
|
||||
}
|
||||
|
||||
/* The specification only allows up to 5 CIDs in this packet */
|
||||
if (buf->len > (L2CAP_ECRED_CHAN_MAX_PER_REQ * sizeof(scid))) {
|
||||
if (buf->len > (BT_L2CAP_ECRED_CHAN_MAX_PER_REQ * sizeof(scid))) {
|
||||
result = BT_L2CAP_RECONF_OTHER_UNACCEPT;
|
||||
goto response;
|
||||
}
|
||||
|
@ -2908,7 +2911,7 @@ int bt_l2cap_ecred_chan_connect(struct bt_conn *conn,
|
|||
}
|
||||
|
||||
/* Init non-null channels */
|
||||
for (i = 0; i < L2CAP_ECRED_CHAN_MAX_PER_REQ; i++) {
|
||||
for (i = 0; i < BT_L2CAP_ECRED_CHAN_MAX_PER_REQ; i++) {
|
||||
if (!chan[i]) {
|
||||
break;
|
||||
}
|
||||
|
@ -2962,7 +2965,7 @@ int bt_l2cap_ecred_chan_reconfigure(struct bt_l2cap_chan **chans, uint16_t mtu)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < L2CAP_ECRED_CHAN_MAX_PER_REQ; i++) {
|
||||
for (i = 0; i < BT_L2CAP_ECRED_CHAN_MAX_PER_REQ; i++) {
|
||||
if (!chans[i]) {
|
||||
break;
|
||||
}
|
||||
|
@ -3035,6 +3038,94 @@ int bt_l2cap_ecred_chan_reconfigure(struct bt_l2cap_chan **chans, uint16_t mtu)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_L2CAP_RECONFIGURE_EXPLICIT)
|
||||
int bt_l2cap_ecred_chan_reconfigure_explicit(struct bt_l2cap_chan **chans, size_t chan_count,
|
||||
uint16_t mtu, uint16_t mps)
|
||||
{
|
||||
struct bt_l2cap_ecred_reconf_req *req;
|
||||
struct bt_conn *conn = NULL;
|
||||
struct net_buf *buf;
|
||||
uint8_t ident;
|
||||
|
||||
LOG_DBG("chans %p chan_count %u mtu 0x%04x mps 0x%04x", chans, chan_count, mtu, mps);
|
||||
|
||||
if (!chans || !IN_RANGE(chan_count, 1, BT_L2CAP_ECRED_CHAN_MAX_PER_REQ)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!IN_RANGE(mps, BT_L2CAP_ECRED_MIN_MPS, BT_L2CAP_RX_MTU)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < chan_count; i++) {
|
||||
/* validate that all channels are from same connection */
|
||||
if (conn) {
|
||||
if (conn != chans[i]->conn) {
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
conn = chans[i]->conn;
|
||||
}
|
||||
|
||||
/* validate MTU is not decreased */
|
||||
if (mtu < BT_L2CAP_LE_CHAN(chans[i])->rx.mtu) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* MPS is not allowed to decrease when reconfiguring multiple channels.
|
||||
* Core Specification 3.A.4.27 v6.0
|
||||
*/
|
||||
if (chan_count > 1 && mps < BT_L2CAP_LE_CHAN(chans[i])->rx.mps) {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!conn) {
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
if (conn->type != BT_CONN_TYPE_LE) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* allow only 1 request at time */
|
||||
if (l2cap_find_pending_reconf(conn)) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ident = get_ident();
|
||||
|
||||
buf = l2cap_create_le_sig_pdu(BT_L2CAP_ECRED_RECONF_REQ, ident,
|
||||
sizeof(*req) + (chan_count * sizeof(uint16_t)));
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
req = net_buf_add(buf, sizeof(*req));
|
||||
req->mtu = sys_cpu_to_le16(mtu);
|
||||
req->mps = sys_cpu_to_le16(mps);
|
||||
|
||||
for (size_t i = 0; i < chan_count; i++) {
|
||||
struct bt_l2cap_le_chan *ch;
|
||||
|
||||
ch = BT_L2CAP_LE_CHAN(chans[i]);
|
||||
|
||||
ch->ident = ident;
|
||||
ch->pending_rx_mtu = mtu;
|
||||
|
||||
net_buf_add_le16(buf, ch->rx.cid);
|
||||
};
|
||||
|
||||
/* We set the RTX timer on one of the supplied channels, but when the
|
||||
* request resolves or times out we will act on all the channels in the
|
||||
* supplied array, using the ident field to find them.
|
||||
*/
|
||||
l2cap_chan_send_req(chans[0], buf, L2CAP_CONN_TIMEOUT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* defined(CONFIG_BT_L2CAP_RECONFIGURE_EXPLICIT) */
|
||||
|
||||
#endif /* defined(CONFIG_BT_L2CAP_ECRED) */
|
||||
|
||||
int bt_l2cap_chan_connect(struct bt_conn *conn, struct bt_l2cap_chan *chan,
|
||||
|
|
|
@ -134,8 +134,6 @@ struct bt_l2cap_ecred_conn_rsp {
|
|||
uint16_t dcid[0];
|
||||
} __packed;
|
||||
|
||||
#define L2CAP_ECRED_CHAN_MAX_PER_REQ 5
|
||||
|
||||
#define BT_L2CAP_ECRED_RECONF_REQ 0x19
|
||||
struct bt_l2cap_ecred_reconf_req {
|
||||
uint16_t mtu;
|
||||
|
|
|
@ -16,6 +16,8 @@ CONFIG_BT_BONDABLE=y
|
|||
CONFIG_BT_ATT_PREPARE_COUNT=12
|
||||
CONFIG_BT_GATT_CLIENT=y
|
||||
CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y
|
||||
CONFIG_BT_L2CAP_SEG_RECV=y
|
||||
CONFIG_BT_L2CAP_RECONFIGURE_EXPLICIT=y
|
||||
CONFIG_BT_DEVICE_NAME="Tester"
|
||||
CONFIG_BT_DEVICE_NAME_MAX=32
|
||||
CONFIG_BT_DEVICE_NAME_DYNAMIC=y
|
||||
|
@ -35,7 +37,6 @@ CONFIG_BT_GATT_DYNAMIC_DB=y
|
|||
CONFIG_BT_EXT_ADV=y
|
||||
CONFIG_BT_PER_ADV=y
|
||||
CONFIG_BT_PER_ADV_SYNC=y
|
||||
CONFIG_BT_BUF_ACL_RX_SIZE=100
|
||||
CONFIG_BT_RX_STACK_SIZE=4096
|
||||
|
||||
CONFIG_BT_TESTING=y
|
||||
|
|
|
@ -19,14 +19,15 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL);
|
|||
|
||||
#include "btp/btp.h"
|
||||
|
||||
#define DATA_MTU_INITIAL 128
|
||||
#define DATA_MTU 256
|
||||
#define DATA_BUF_SIZE BT_L2CAP_SDU_BUF_SIZE(DATA_MTU)
|
||||
#define L2CAP_MPS 96
|
||||
#define DATA_MTU (3 * L2CAP_MPS)
|
||||
#define DATA_MTU_INITIAL (2 * L2CAP_MPS)
|
||||
|
||||
#define CHANNELS 2
|
||||
#define SERVERS 1
|
||||
|
||||
NET_BUF_POOL_FIXED_DEFINE(data_pool, CHANNELS, DATA_BUF_SIZE, CONFIG_BT_CONN_TX_USER_DATA_SIZE,
|
||||
NULL);
|
||||
NET_BUF_POOL_FIXED_DEFINE(data_pool, CHANNELS, BT_L2CAP_SDU_BUF_SIZE(DATA_MTU),
|
||||
CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
|
||||
|
||||
static bool authorize_flag;
|
||||
static uint8_t req_keysize;
|
||||
|
@ -36,18 +37,51 @@ static struct channel {
|
|||
struct bt_l2cap_le_chan le;
|
||||
bool in_use;
|
||||
bool hold_credit;
|
||||
#if defined(CONFIG_BT_L2CAP_SEG_RECV)
|
||||
unsigned int pending_credits;
|
||||
uint8_t recv_cb_buf[DATA_MTU + sizeof(struct btp_l2cap_data_received_ev)];
|
||||
#else
|
||||
struct net_buf *pending_credit;
|
||||
#endif
|
||||
} channels[CHANNELS];
|
||||
|
||||
/* TODO Extend to support multiple servers */
|
||||
static struct bt_l2cap_server servers[SERVERS];
|
||||
|
||||
#if defined(CONFIG_BT_L2CAP_SEG_RECV)
|
||||
static void seg_recv_cb(struct bt_l2cap_chan *l2cap_chan, size_t sdu_len, off_t seg_offset,
|
||||
struct net_buf_simple *seg)
|
||||
{
|
||||
struct btp_l2cap_data_received_ev *ev;
|
||||
struct bt_l2cap_le_chan *l2cap_le_chan =
|
||||
CONTAINER_OF(l2cap_chan, struct bt_l2cap_le_chan, chan);
|
||||
struct channel *chan = CONTAINER_OF(l2cap_le_chan, struct channel, le);
|
||||
|
||||
ev = (void *)chan->recv_cb_buf;
|
||||
memcpy(&ev->data[seg_offset], seg->data, seg->len);
|
||||
|
||||
/* complete SDU received */
|
||||
if (seg_offset + seg->len == sdu_len) {
|
||||
ev->chan_id = chan->chan_id;
|
||||
ev->data_length = sys_cpu_to_le16(sdu_len);
|
||||
|
||||
tester_event(BTP_SERVICE_ID_L2CAP, BTP_L2CAP_EV_DATA_RECEIVED, chan->recv_cb_buf,
|
||||
sizeof(*ev) + sdu_len);
|
||||
}
|
||||
|
||||
if (chan->hold_credit) {
|
||||
chan->pending_credits++;
|
||||
} else {
|
||||
bt_l2cap_chan_give_credits(l2cap_chan, 1);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static struct net_buf *alloc_buf_cb(struct bt_l2cap_chan *chan)
|
||||
{
|
||||
return net_buf_alloc(&data_pool, K_FOREVER);
|
||||
}
|
||||
|
||||
static uint8_t recv_cb_buf[DATA_BUF_SIZE + sizeof(struct btp_l2cap_data_received_ev)];
|
||||
static uint8_t recv_cb_buf[DATA_MTU + sizeof(struct btp_l2cap_data_received_ev)];
|
||||
|
||||
static int recv_cb(struct bt_l2cap_chan *l2cap_chan, struct net_buf *buf)
|
||||
{
|
||||
|
@ -73,6 +107,7 @@ static int recv_cb(struct bt_l2cap_chan *l2cap_chan, struct net_buf *buf)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void connected_cb(struct bt_l2cap_chan *l2cap_chan)
|
||||
{
|
||||
|
@ -111,11 +146,13 @@ static void disconnected_cb(struct bt_l2cap_chan *l2cap_chan)
|
|||
struct channel *chan = CONTAINER_OF(l2cap_le_chan, struct channel, le);
|
||||
struct bt_conn_info info;
|
||||
|
||||
#if !defined(CONFIG_BT_L2CAP_SEG_RECV)
|
||||
/* release netbuf on premature disconnection */
|
||||
if (chan->pending_credit) {
|
||||
net_buf_unref(chan->pending_credit);
|
||||
chan->pending_credit = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
(void)memset(&ev, 0, sizeof(struct btp_l2cap_disconnected_ev));
|
||||
|
||||
|
@ -160,12 +197,16 @@ static void reconfigured_cb(struct bt_l2cap_chan *l2cap_chan)
|
|||
#endif
|
||||
|
||||
static const struct bt_l2cap_chan_ops l2cap_ops = {
|
||||
.alloc_buf = alloc_buf_cb,
|
||||
.recv = recv_cb,
|
||||
.connected = connected_cb,
|
||||
.disconnected = disconnected_cb,
|
||||
#if defined(CONFIG_BT_L2CAP_SEG_RECV)
|
||||
.seg_recv = seg_recv_cb,
|
||||
#else
|
||||
.alloc_buf = alloc_buf_cb,
|
||||
.recv = recv_cb,
|
||||
#endif
|
||||
.connected = connected_cb,
|
||||
.disconnected = disconnected_cb,
|
||||
#if defined(CONFIG_BT_L2CAP_ECRED)
|
||||
.reconfigured = reconfigured_cb,
|
||||
.reconfigured = reconfigured_cb,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -222,10 +263,15 @@ static uint8_t connect(const void *cmd, uint16_t cmd_len,
|
|||
}
|
||||
chan->le.chan.ops = &l2cap_ops;
|
||||
chan->le.rx.mtu = mtu;
|
||||
#if defined(CONFIG_BT_L2CAP_SEG_RECV)
|
||||
chan->le.rx.mps = L2CAP_MPS;
|
||||
#endif
|
||||
rp->chan_id[i] = chan->chan_id;
|
||||
allocated_channels[i] = &chan->le.chan;
|
||||
|
||||
chan->hold_credit = cp->options & BTP_L2CAP_CONNECT_OPT_HOLD_CREDIT;
|
||||
|
||||
bt_l2cap_chan_give_credits(&chan->le.chan, 1);
|
||||
}
|
||||
|
||||
if (cp->num == 1 && !ecfc) {
|
||||
|
@ -289,6 +335,7 @@ static uint8_t reconfigure(const void *cmd, uint16_t cmd_len,
|
|||
{
|
||||
const struct btp_l2cap_reconfigure_cmd *cp = cmd;
|
||||
uint16_t mtu;
|
||||
uint16_t mps;
|
||||
struct bt_conn *conn;
|
||||
int err;
|
||||
struct bt_l2cap_chan *reconf_channels[CHANNELS + 1] = {};
|
||||
|
@ -321,7 +368,8 @@ static uint8_t reconfigure(const void *cmd, uint16_t cmd_len,
|
|||
return BTP_STATUS_FAILED;
|
||||
}
|
||||
|
||||
err = bt_l2cap_ecred_chan_reconfigure(reconf_channels, mtu);
|
||||
mps = MIN(L2CAP_MPS, BT_L2CAP_RX_MTU);
|
||||
err = bt_l2cap_ecred_chan_reconfigure_explicit(reconf_channels, cp->num, mtu, mps);
|
||||
if (err) {
|
||||
bt_conn_unref(conn);
|
||||
return BTP_STATUS_FAILED;
|
||||
|
@ -454,9 +502,14 @@ static int accept(struct bt_conn *conn, struct bt_l2cap_server *server,
|
|||
|
||||
chan->le.chan.ops = &l2cap_ops;
|
||||
chan->le.rx.mtu = DATA_MTU_INITIAL;
|
||||
#if defined(CONFIG_BT_L2CAP_SEG_RECV)
|
||||
chan->le.rx.mps = L2CAP_MPS;
|
||||
#endif
|
||||
|
||||
*l2cap_chan = &chan->le.chan;
|
||||
|
||||
bt_l2cap_chan_give_credits(&chan->le.chan, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -524,7 +577,15 @@ static uint8_t credits(const void *cmd, uint16_t cmd_len,
|
|||
if (!chan->in_use) {
|
||||
return BTP_STATUS_FAILED;
|
||||
}
|
||||
#if defined(CONFIG_BT_L2CAP_SEG_RECV)
|
||||
if (chan->pending_credits) {
|
||||
if (bt_l2cap_chan_give_credits(&chan->le.chan, chan->pending_credits) < 0) {
|
||||
return BTP_STATUS_FAILED;
|
||||
}
|
||||
|
||||
chan->pending_credits = 0;
|
||||
}
|
||||
#else
|
||||
if (chan->pending_credit) {
|
||||
if (bt_l2cap_chan_recv_complete(&chan->le.chan,
|
||||
chan->pending_credit) < 0) {
|
||||
|
@ -533,6 +594,7 @@ static uint8_t credits(const void *cmd, uint16_t cmd_len,
|
|||
|
||||
chan->pending_credit = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return BTP_STATUS_SUCCESS;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue