tests: bluetooth: tester: Add support for L2CAP Credits command

This allows IUT to return credits on specified L2CAP channel when
requested by Upper Tester.

Signed-off-by: Szymon Janc <szymon.janc@codecoup.pl>
This commit is contained in:
Szymon Janc 2021-09-09 15:48:15 +02:00 committed by Christopher Friedt
commit 6cfc6fa8e1
2 changed files with 53 additions and 0 deletions

View file

@ -787,6 +787,11 @@ struct l2cap_accept_connection_cmd {
uint16_t result;
} __packed;
#define L2CAP_CREDITS 0x08
struct l2cap_credits_cmd {
uint8_t chan_id;
} __packed;
#define L2CAP_DISCONNECT_EATT_CHANS 0x09
struct l2cap_disconnect_eatt_chans_cmd {
uint8_t address_type;

View file

@ -34,6 +34,7 @@ static struct channel {
uint8_t chan_id; /* Internal number that identifies L2CAP channel. */
struct bt_l2cap_le_chan le;
bool in_use;
struct net_buf *pending_credit;
} channels[CHANNELS];
/* TODO Extend to support multiple servers */
@ -58,6 +59,14 @@ static int recv_cb(struct bt_l2cap_chan *l2cap_chan, struct net_buf *buf)
tester_send(BTP_SERVICE_ID_L2CAP, L2CAP_EV_DATA_RECEIVED,
CONTROLLER_INDEX, recv_cb_buf, sizeof(*ev) + buf->len);
if (!chan->pending_credit) {
/* no need for extra ref, as when returning EINPROGRESS user
* becomes owner of the netbuf
*/
chan->pending_credit = buf;
return -EINPROGRESS;
}
return 0;
}
@ -97,6 +106,12 @@ static void disconnected_cb(struct bt_l2cap_chan *l2cap_chan)
struct channel *chan = CONTAINER_OF(l2cap_chan, struct channel, le);
struct bt_conn_info info;
/* release netbuf on premature disconnection */
if (chan->pending_credit) {
net_buf_unref(chan->pending_credit);
chan->pending_credit = NULL;
}
(void)memset(&ev, 0, sizeof(struct l2cap_disconnected_ev));
/* TODO: ev.result */
@ -138,6 +153,8 @@ static struct channel *get_free_channel()
}
chan = &channels[i];
(void)memset(chan, 0, sizeof(*chan));
chan->chan_id = i;
channels[i].in_use = true;
@ -404,6 +421,33 @@ fail:
BTP_STATUS_FAILED);
}
static void credits(uint8_t *data, uint16_t len)
{
const struct l2cap_credits_cmd *cmd = (void *)data;
struct channel *chan = &channels[cmd->chan_id];
if (!chan->in_use) {
goto fail;
}
if (chan->pending_credit) {
if (bt_l2cap_chan_recv_complete(&chan->le.chan,
chan->pending_credit) < 0) {
goto fail;
}
chan->pending_credit = NULL;
}
tester_rsp(BTP_SERVICE_ID_L2CAP, L2CAP_CREDITS, CONTROLLER_INDEX,
BTP_STATUS_SUCCESS);
return;
fail:
tester_rsp(BTP_SERVICE_ID_L2CAP, L2CAP_CREDITS, CONTROLLER_INDEX,
BTP_STATUS_FAILED);
}
static void supported_commands(uint8_t *data, uint16_t len)
{
uint8_t cmds[2];
@ -416,6 +460,7 @@ static void supported_commands(uint8_t *data, uint16_t len)
tester_set_bit(cmds, L2CAP_DISCONNECT);
tester_set_bit(cmds, L2CAP_LISTEN);
tester_set_bit(cmds, L2CAP_SEND_DATA);
tester_set_bit(cmds, L2CAP_CREDITS);
#if defined(CONFIG_BT_EATT)
tester_set_bit(cmds, L2CAP_DISCONNECT_EATT_CHANS);
#endif
@ -442,6 +487,9 @@ void tester_handle_l2cap(uint8_t opcode, uint8_t index, uint8_t *data,
case L2CAP_LISTEN:
listen(data, len);
return;
case L2CAP_CREDITS:
credits(data, len);
return;
#if defined(CONFIG_BT_EATT)
case L2CAP_DISCONNECT_EATT_CHANS:
disconnect_eatt_chans(data, len);