Skip to content

Commit 17c202d

Browse files
sjancrlubos
authored andcommitted
[nrf fromlist] 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. Upstream PR #: 80911 Signed-off-by: Szymon Janc <szymon.janc@codecoup.pl>
1 parent 1c79ce0 commit 17c202d

File tree

5 files changed

+205
-13
lines changed

5 files changed

+205
-13
lines changed

include/zephyr/bluetooth/l2cap.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
* @{
1919
*/
2020

21+
#include <stdint.h>
2122
#include <sys/types.h>
2223

2324
#include <zephyr/sys/atomic.h>
@@ -552,6 +553,26 @@ int bt_l2cap_ecred_chan_connect(struct bt_conn *conn,
552553
*/
553554
int bt_l2cap_ecred_chan_reconfigure(struct bt_l2cap_chan **chans, uint16_t mtu);
554555

556+
/** @brief Reconfigure Enhanced Credit Based L2CAP channels
557+
*
558+
* Experimental API to reconfigure with explicit MPS and MTU values.
559+
*
560+
* Reconfigure up to 5 L2CAP channels. Channels must be from the same bt_conn.
561+
* Once reconfiguration is completed each channel reconfigured() callback will
562+
* be called. MTU cannot be decreased on any of provided channels.
563+
*
564+
* @kconfig_dep{CONFIG_BT_L2CAP_RECONFIGURE_EXPLICIT}
565+
*
566+
* @param chans Array of channel objects. Null-terminated. Elements after the
567+
* first 5 are silently ignored.
568+
* @param mtu Channel MTU to reconfigure to.
569+
* @param mps Channel MPS to reconfigure to.
570+
*
571+
* @return 0 in case of success or negative value in case of error.
572+
*/
573+
int bt_l2cap_ecred_chan_reconfigure_explicit(struct bt_l2cap_chan **chans, uint16_t mtu,
574+
uint16_t mps);
575+
555576
/** @brief Connect L2CAP channel
556577
*
557578
* Connect L2CAP channel by PSM, once the connection is completed channel

subsys/bluetooth/host/Kconfig.l2cap

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,12 @@ config BT_L2CAP_SEG_RECV
7070
This API enforces conformance with L2CAP TS, but is otherwise as
7171
flexible and semantically simple as possible.
7272

73+
config BT_L2CAP_RECONFIGURE_EXPLICIT
74+
bool "L2CAP Explicit reconfigure API [EXPERIMENTAL]"
75+
select EXPERIMENTAL
76+
help
77+
78+
Enable API for explicit reconfiguration of an L2CAP channel's MTU and
79+
MPS.
80+
7381
endmenu

subsys/bluetooth/host/l2cap.c

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ LOG_MODULE_REGISTER(bt_l2cap, CONFIG_BT_L2CAP_LOG_LEVEL);
4141

4242
#define L2CAP_LE_MIN_MTU 23
4343
#define L2CAP_ECRED_MIN_MTU 64
44+
#define L2CAP_ECRED_MIN_MPS 64
4445

4546
#define L2CAP_LE_MAX_CREDITS (CONFIG_BT_BUF_ACL_RX_COUNT - 1)
4647

@@ -3032,6 +3033,105 @@ int bt_l2cap_ecred_chan_reconfigure(struct bt_l2cap_chan **chans, uint16_t mtu)
30323033
return 0;
30333034
}
30343035

3036+
#if defined(CONFIG_BT_L2CAP_RECONFIGURE_EXPLICIT)
3037+
int bt_l2cap_ecred_chan_reconfigure_explicit(struct bt_l2cap_chan **chans, uint16_t mtu,
3038+
uint16_t mps)
3039+
{
3040+
struct bt_l2cap_ecred_reconf_req *req;
3041+
struct bt_conn *conn = NULL;
3042+
struct bt_l2cap_le_chan *ch;
3043+
struct net_buf *buf;
3044+
bool multiple_chan;
3045+
uint8_t ident;
3046+
int i;
3047+
3048+
LOG_DBG("chans %p mtu 0x%04x mps 0x%04x", chans, mtu, mps);
3049+
3050+
if (!chans) {
3051+
return -EINVAL;
3052+
}
3053+
3054+
if (chans[0] == NULL) {
3055+
return -EINVAL;
3056+
}
3057+
3058+
if (mps < L2CAP_ECRED_MIN_MPS || mps > BT_L2CAP_RX_MTU) {
3059+
return -EINVAL;
3060+
}
3061+
3062+
multiple_chan = chans[1] != NULL;
3063+
3064+
for (i = 0; i < L2CAP_ECRED_CHAN_MAX_PER_REQ; i++) {
3065+
if (!chans[i]) {
3066+
break;
3067+
}
3068+
3069+
/* validate that all channels are from same connection */
3070+
if (conn) {
3071+
if (conn != chans[i]->conn) {
3072+
return -EINVAL;
3073+
}
3074+
} else {
3075+
conn = chans[i]->conn;
3076+
}
3077+
3078+
/* validate MTU is not decreased */
3079+
if (mtu < BT_L2CAP_LE_CHAN(chans[i])->rx.mtu) {
3080+
return -EINVAL;
3081+
}
3082+
3083+
/* MPS is not allowed to decrease when reconfiguring multiple channels.
3084+
* Core Specification 3.A.4.27 v6.0
3085+
*/
3086+
if (multiple_chan && mps < BT_L2CAP_LE_CHAN(chans[i])->rx.mps) {
3087+
return -EINVAL;
3088+
}
3089+
}
3090+
3091+
if (!conn) {
3092+
return -ENOTCONN;
3093+
}
3094+
3095+
if (conn->type != BT_CONN_TYPE_LE) {
3096+
return -EINVAL;
3097+
}
3098+
3099+
/* allow only 1 request at time */
3100+
if (l2cap_find_pending_reconf(conn)) {
3101+
return -EBUSY;
3102+
}
3103+
3104+
ident = get_ident();
3105+
3106+
buf = l2cap_create_le_sig_pdu(BT_L2CAP_ECRED_RECONF_REQ, ident,
3107+
sizeof(*req) + (i * sizeof(uint16_t)));
3108+
if (!buf) {
3109+
return -ENOMEM;
3110+
}
3111+
3112+
req = net_buf_add(buf, sizeof(*req));
3113+
req->mtu = sys_cpu_to_le16(mtu);
3114+
req->mps = sys_cpu_to_le16(mps);
3115+
3116+
for (int j = 0; j < i; j++) {
3117+
ch = BT_L2CAP_LE_CHAN(chans[j]);
3118+
3119+
ch->ident = ident;
3120+
ch->pending_rx_mtu = mtu;
3121+
3122+
net_buf_add_le16(buf, ch->rx.cid);
3123+
};
3124+
3125+
/* We set the RTX timer on one of the supplied channels, but when the
3126+
* request resolves or times out we will act on all the channels in the
3127+
* supplied array, using the ident field to find them.
3128+
*/
3129+
l2cap_chan_send_req(chans[0], buf, L2CAP_CONN_TIMEOUT);
3130+
3131+
return 0;
3132+
}
3133+
#endif /* defined(CONFIG_BT_L2CAP_RECONFIGURE_EXPLICIT) */
3134+
30353135
#endif /* defined(CONFIG_BT_L2CAP_ECRED) */
30363136

30373137
int bt_l2cap_chan_connect(struct bt_conn *conn, struct bt_l2cap_chan *chan,

tests/bluetooth/tester/prj.conf

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ CONFIG_BT_BONDABLE=y
1616
CONFIG_BT_ATT_PREPARE_COUNT=12
1717
CONFIG_BT_GATT_CLIENT=y
1818
CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y
19+
CONFIG_BT_L2CAP_SEG_RECV=y
20+
CONFIG_BT_L2CAP_RECONFIGURE_EXPLICIT=y
1921
CONFIG_BT_DEVICE_NAME="Tester"
2022
CONFIG_BT_DEVICE_NAME_MAX=32
2123
CONFIG_BT_DEVICE_NAME_DYNAMIC=y
@@ -33,7 +35,6 @@ CONFIG_BT_GATT_DYNAMIC_DB=y
3335
CONFIG_BT_EXT_ADV=y
3436
CONFIG_BT_PER_ADV=y
3537
CONFIG_BT_PER_ADV_SYNC=y
36-
CONFIG_BT_BUF_ACL_RX_SIZE=100
3738
CONFIG_BT_RX_STACK_SIZE=4096
3839

3940
CONFIG_BT_TESTING=y

tests/bluetooth/tester/src/btp_l2cap.c

Lines changed: 74 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,15 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL);
1919

2020
#include "btp/btp.h"
2121

22-
#define DATA_MTU_INITIAL 128
23-
#define DATA_MTU 256
24-
#define DATA_BUF_SIZE BT_L2CAP_SDU_BUF_SIZE(DATA_MTU)
22+
#define L2CAP_MPS 96
23+
#define DATA_MTU (3 * L2CAP_MPS)
24+
#define DATA_MTU_INITIAL (2 * L2CAP_MPS)
25+
2526
#define CHANNELS 2
2627
#define SERVERS 1
2728

28-
NET_BUF_POOL_FIXED_DEFINE(data_pool, CHANNELS, DATA_BUF_SIZE, CONFIG_BT_CONN_TX_USER_DATA_SIZE,
29-
NULL);
29+
NET_BUF_POOL_FIXED_DEFINE(data_pool, CHANNELS, BT_L2CAP_SDU_BUF_SIZE(DATA_MTU),
30+
CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
3031

3132
static bool authorize_flag;
3233
static uint8_t req_keysize;
@@ -36,18 +37,51 @@ static struct channel {
3637
struct bt_l2cap_le_chan le;
3738
bool in_use;
3839
bool hold_credit;
40+
#if defined(CONFIG_BT_L2CAP_SEG_RECV)
41+
unsigned int pending_credits;
42+
uint8_t recv_cb_buf[DATA_MTU + sizeof(struct btp_l2cap_data_received_ev)];
43+
#else
3944
struct net_buf *pending_credit;
45+
#endif
4046
} channels[CHANNELS];
4147

4248
/* TODO Extend to support multiple servers */
4349
static struct bt_l2cap_server servers[SERVERS];
4450

51+
#if defined(CONFIG_BT_L2CAP_SEG_RECV)
52+
static void seg_recv_cb(struct bt_l2cap_chan *l2cap_chan, size_t sdu_len, off_t seg_offset,
53+
struct net_buf_simple *seg)
54+
{
55+
struct btp_l2cap_data_received_ev *ev;
56+
struct bt_l2cap_le_chan *l2cap_le_chan =
57+
CONTAINER_OF(l2cap_chan, struct bt_l2cap_le_chan, chan);
58+
struct channel *chan = CONTAINER_OF(l2cap_le_chan, struct channel, le);
59+
60+
ev = (void *)chan->recv_cb_buf;
61+
memcpy(&ev->data[seg_offset], seg->data, seg->len);
62+
63+
/* complete SDU received */
64+
if (seg_offset + seg->len == sdu_len) {
65+
ev->chan_id = chan->chan_id;
66+
ev->data_length = sys_cpu_to_le16(sdu_len);
67+
68+
tester_event(BTP_SERVICE_ID_L2CAP, BTP_L2CAP_EV_DATA_RECEIVED, chan->recv_cb_buf,
69+
sizeof(*ev) + sdu_len);
70+
}
71+
72+
if (chan->hold_credit) {
73+
chan->pending_credits++;
74+
} else {
75+
bt_l2cap_chan_give_credits(l2cap_chan, 1);
76+
}
77+
}
78+
#else
4579
static struct net_buf *alloc_buf_cb(struct bt_l2cap_chan *chan)
4680
{
4781
return net_buf_alloc(&data_pool, K_FOREVER);
4882
}
4983

50-
static uint8_t recv_cb_buf[DATA_BUF_SIZE + sizeof(struct btp_l2cap_data_received_ev)];
84+
static uint8_t recv_cb_buf[DATA_MTU + sizeof(struct btp_l2cap_data_received_ev)];
5185

5286
static int recv_cb(struct bt_l2cap_chan *l2cap_chan, struct net_buf *buf)
5387
{
@@ -73,6 +107,7 @@ static int recv_cb(struct bt_l2cap_chan *l2cap_chan, struct net_buf *buf)
73107

74108
return 0;
75109
}
110+
#endif
76111

77112
static void connected_cb(struct bt_l2cap_chan *l2cap_chan)
78113
{
@@ -111,11 +146,13 @@ static void disconnected_cb(struct bt_l2cap_chan *l2cap_chan)
111146
struct channel *chan = CONTAINER_OF(l2cap_le_chan, struct channel, le);
112147
struct bt_conn_info info;
113148

149+
#if !defined(CONFIG_BT_L2CAP_SEG_RECV)
114150
/* release netbuf on premature disconnection */
115151
if (chan->pending_credit) {
116152
net_buf_unref(chan->pending_credit);
117153
chan->pending_credit = NULL;
118154
}
155+
#endif
119156

120157
(void)memset(&ev, 0, sizeof(struct btp_l2cap_disconnected_ev));
121158

@@ -160,12 +197,16 @@ static void reconfigured_cb(struct bt_l2cap_chan *l2cap_chan)
160197
#endif
161198

162199
static const struct bt_l2cap_chan_ops l2cap_ops = {
163-
.alloc_buf = alloc_buf_cb,
164-
.recv = recv_cb,
165-
.connected = connected_cb,
166-
.disconnected = disconnected_cb,
200+
#if defined(CONFIG_BT_L2CAP_SEG_RECV)
201+
.seg_recv = seg_recv_cb,
202+
#else
203+
.alloc_buf = alloc_buf_cb,
204+
.recv = recv_cb,
205+
#endif
206+
.connected = connected_cb,
207+
.disconnected = disconnected_cb,
167208
#if defined(CONFIG_BT_L2CAP_ECRED)
168-
.reconfigured = reconfigured_cb,
209+
.reconfigured = reconfigured_cb,
169210
#endif
170211
};
171212

@@ -222,10 +263,15 @@ static uint8_t connect(const void *cmd, uint16_t cmd_len,
222263
}
223264
chan->le.chan.ops = &l2cap_ops;
224265
chan->le.rx.mtu = mtu;
266+
#if defined(CONFIG_BT_L2CAP_SEG_RECV)
267+
chan->le.rx.mps = L2CAP_MPS;
268+
#endif
225269
rp->chan_id[i] = chan->chan_id;
226270
allocated_channels[i] = &chan->le.chan;
227271

228272
chan->hold_credit = cp->options & BTP_L2CAP_CONNECT_OPT_HOLD_CREDIT;
273+
274+
bt_l2cap_chan_give_credits(&chan->le.chan, 1);
229275
}
230276

231277
if (cp->num == 1 && !ecfc) {
@@ -289,6 +335,7 @@ static uint8_t reconfigure(const void *cmd, uint16_t cmd_len,
289335
{
290336
const struct btp_l2cap_reconfigure_cmd *cp = cmd;
291337
uint16_t mtu;
338+
uint16_t mps;
292339
struct bt_conn *conn;
293340
int err;
294341
struct bt_l2cap_chan *reconf_channels[CHANNELS + 1] = {};
@@ -321,7 +368,8 @@ static uint8_t reconfigure(const void *cmd, uint16_t cmd_len,
321368
return BTP_STATUS_FAILED;
322369
}
323370

324-
err = bt_l2cap_ecred_chan_reconfigure(reconf_channels, mtu);
371+
mps = MIN(L2CAP_MPS, BT_L2CAP_RX_MTU);
372+
err = bt_l2cap_ecred_chan_reconfigure_explicit(reconf_channels, mtu, mps);
325373
if (err) {
326374
bt_conn_unref(conn);
327375
return BTP_STATUS_FAILED;
@@ -454,9 +502,14 @@ static int accept(struct bt_conn *conn, struct bt_l2cap_server *server,
454502

455503
chan->le.chan.ops = &l2cap_ops;
456504
chan->le.rx.mtu = DATA_MTU_INITIAL;
505+
#if defined(CONFIG_BT_L2CAP_SEG_RECV)
506+
chan->le.rx.mps = L2CAP_MPS;
507+
#endif
457508

458509
*l2cap_chan = &chan->le.chan;
459510

511+
bt_l2cap_chan_give_credits(&chan->le.chan, 1);
512+
460513
return 0;
461514
}
462515

@@ -524,7 +577,15 @@ static uint8_t credits(const void *cmd, uint16_t cmd_len,
524577
if (!chan->in_use) {
525578
return BTP_STATUS_FAILED;
526579
}
580+
#if defined(CONFIG_BT_L2CAP_SEG_RECV)
581+
if (chan->pending_credits) {
582+
if (bt_l2cap_chan_give_credits(&chan->le.chan, chan->pending_credits) < 0) {
583+
return BTP_STATUS_FAILED;
584+
}
527585

586+
chan->pending_credits = 0;
587+
}
588+
#else
528589
if (chan->pending_credit) {
529590
if (bt_l2cap_chan_recv_complete(&chan->le.chan,
530591
chan->pending_credit) < 0) {
@@ -533,6 +594,7 @@ static uint8_t credits(const void *cmd, uint16_t cmd_len,
533594

534595
chan->pending_credit = NULL;
535596
}
597+
#endif
536598

537599
return BTP_STATUS_SUCCESS;
538600
}

0 commit comments

Comments
 (0)