Bluetooth/tester: connect L2CAP using Enhanced Credit Flow Control

This change adds field to L2CAP connect command allowing to choose
ECFC in L2CAP connect() function and adds required logic to perform
such connection.

Signed-off-by: Krzysztof Kopyściński <krzysztof.kopyscinski@codecoup.pl>
This commit is contained in:
Krzysztof Kopyściński 2021-04-02 14:17:22 +02:00 committed by Anas Nashif
commit 97f992c470

View file

@ -29,6 +29,7 @@ NET_BUF_POOL_FIXED_DEFINE(data_pool, CHANNELS, DATA_BUF_SIZE, NULL);
static struct channel { static struct channel {
uint8_t chan_id; /* Internal number that identifies L2CAP channel. */ uint8_t chan_id; /* Internal number that identifies L2CAP channel. */
struct bt_l2cap_le_chan le; struct bt_l2cap_le_chan le;
bool in_use;
} channels[CHANNELS]; } channels[CHANNELS];
/* TODO Extend to support multiple servers */ /* TODO Extend to support multiple servers */
@ -128,30 +129,35 @@ static struct channel *get_free_channel()
struct channel *chan; struct channel *chan;
for (i = 0U; i < CHANNELS; i++) { for (i = 0U; i < CHANNELS; i++) {
if (channels[i].le.chan.state != BT_L2CAP_DISCONNECTED) { if (channels[i].in_use) {
continue; continue;
} }
chan = &channels[i]; chan = &channels[i];
chan->chan_id = i; chan->chan_id = i;
channels[i].in_use = true;
return chan; return chan;
} }
return NULL; return NULL;
} }
static void connect(uint8_t *data, uint16_t len) static void connect(uint8_t *data, uint16_t len)
{ {
const struct l2cap_connect_cmd *cmd = (void *) data; const struct l2cap_connect_cmd *cmd = (void *) data;
struct l2cap_connect_rp *rp; struct l2cap_connect_rp *rp;
struct bt_conn *conn; struct bt_conn *conn;
struct channel *chan; struct channel *chan = NULL;
struct bt_l2cap_chan *allocated_channels[5] = {};
uint16_t mtu = sys_le16_to_cpu(cmd->mtu); uint16_t mtu = sys_le16_to_cpu(cmd->mtu);
uint8_t buf[sizeof(*rp) + 1]; uint8_t buf[sizeof(*rp) + CHANNELS];
uint8_t i = 0;
int err; int err;
if (cmd->num > 1 || mtu > DATA_MTU) { if (cmd->num > CHANNELS || mtu > DATA_MTU) {
goto fail; goto fail;
} }
@ -160,29 +166,49 @@ static void connect(uint8_t *data, uint16_t len)
goto fail; goto fail;
} }
chan = get_free_channel();
if (!chan) {
goto fail;
}
chan->le.chan.ops = &l2cap_ops;
chan->le.rx.mtu = mtu;
err = bt_l2cap_chan_connect(conn, &chan->le.chan, cmd->psm);
if (err < 0) {
goto fail;
}
rp = (void *)buf; rp = (void *)buf;
rp->num = 1U;
rp->chan_id[0] = chan->chan_id; for (i = 0U; i < cmd->num; i++) {
chan = get_free_channel();
if (!chan) {
goto fail;
}
chan->le.chan.ops = &l2cap_ops;
chan->le.rx.mtu = mtu;
rp->chan_id[i] = chan->chan_id;
allocated_channels[i] = &chan->le.chan;
}
if (cmd->num == 1) {
err = bt_l2cap_chan_connect(conn, &chan->le.chan, cmd->psm);
if (err < 0) {
goto fail;
}
} else if (cmd->num > 1) {
#if defined(CONFIG_BT_L2CAP_ECRED)
err = bt_l2cap_ecred_chan_connect(conn, allocated_channels,
cmd->psm);
if (err < 0) {
goto fail;
}
#endif
} else {
LOG_ERR("Invalid 'num' parameter value");
goto fail;
}
rp->num = cmd->num;
tester_send(BTP_SERVICE_ID_L2CAP, L2CAP_CONNECT, CONTROLLER_INDEX, tester_send(BTP_SERVICE_ID_L2CAP, L2CAP_CONNECT, CONTROLLER_INDEX,
(uint8_t *)rp, sizeof(buf)); (uint8_t *)rp, sizeof(*rp) + rp->num);
return; return;
fail: fail:
while (i >= 0) {
channels[i].in_use = false;
i--;
}
tester_rsp(BTP_SERVICE_ID_L2CAP, L2CAP_CONNECT, CONTROLLER_INDEX, tester_rsp(BTP_SERVICE_ID_L2CAP, L2CAP_CONNECT, CONTROLLER_INDEX,
BTP_STATUS_FAILED); BTP_STATUS_FAILED);
} }