mirror of
https://github.com/espressif/esp-nimble.git
synced 2026-08-28 04:40:05 +00:00
apps/bttester: Add support for Enhanced L2CAP COC
This commit is contained in:
@@ -37,7 +37,7 @@ pkg.deps:
|
||||
- "@apache-mynewt-nimble/nimble/host/services/gap"
|
||||
- "@apache-mynewt-nimble/nimble/host/services/gatt"
|
||||
- "@apache-mynewt-nimble/nimble/host/services/dis"
|
||||
- "@apache-mynewt-nimble/nimble/host/store/ram"
|
||||
- "@apache-mynewt-nimble/nimble/host/store/config"
|
||||
- "@apache-mynewt-nimble/nimble/transport/ram"
|
||||
- "@apache-mynewt-core/hw/drivers/uart"
|
||||
- "@apache-mynewt-core/hw/drivers/rtt"
|
||||
|
||||
@@ -747,10 +747,13 @@ struct l2cap_connect_cmd {
|
||||
u8_t address_type;
|
||||
u8_t address[6];
|
||||
u16_t psm;
|
||||
u16_t mtu;
|
||||
u8_t num;
|
||||
} __packed;
|
||||
|
||||
struct l2cap_connect_rp {
|
||||
u8_t chan_id;
|
||||
u8_t num;
|
||||
u8_t chan_ids[0];
|
||||
} __packed;
|
||||
|
||||
#define L2CAP_DISCONNECT 0x03
|
||||
@@ -772,6 +775,8 @@ struct l2cap_send_data_cmd {
|
||||
struct l2cap_listen_cmd {
|
||||
u16_t psm;
|
||||
u8_t transport;
|
||||
u16_t mtu;
|
||||
u16_t response;
|
||||
} __packed;
|
||||
|
||||
#define L2CAP_ACCEPT_CONNECTION 0x06
|
||||
@@ -780,6 +785,15 @@ struct l2cap_accept_connection_cmd {
|
||||
u16_t result;
|
||||
} __packed;
|
||||
|
||||
#define L2CAP_RECONFIGURE 0x07
|
||||
struct l2cap_reconfigure_cmd {
|
||||
u8_t address_type;
|
||||
u8_t address[6];
|
||||
u16_t mtu;
|
||||
u8_t num;
|
||||
u8_t idxs[];
|
||||
} __packed;
|
||||
|
||||
/* events */
|
||||
#define L2CAP_EV_CONNECTION_REQ 0x80
|
||||
struct l2cap_connection_req_ev {
|
||||
@@ -793,6 +807,10 @@ struct l2cap_connection_req_ev {
|
||||
struct l2cap_connected_ev {
|
||||
u8_t chan_id;
|
||||
u16_t psm;
|
||||
u16_t peer_mtu;
|
||||
u16_t peer_mps;
|
||||
u16_t our_mtu;
|
||||
u16_t our_mps;
|
||||
u8_t address_type;
|
||||
u8_t address[6];
|
||||
} __packed;
|
||||
@@ -813,6 +831,15 @@ struct l2cap_data_received_ev {
|
||||
u8_t data[0];
|
||||
} __packed;
|
||||
|
||||
#define L2CAP_EV_RECONFIGURED 0x84
|
||||
struct l2cap_reconfigured_ev {
|
||||
u8_t chan_id;
|
||||
u16_t peer_mtu;
|
||||
u16_t peer_mps;
|
||||
u16_t our_mtu;
|
||||
u16_t our_mps;
|
||||
} __packed;
|
||||
|
||||
/* MESH Service */
|
||||
/* commands */
|
||||
#define MESH_READ_SUPPORTED_COMMANDS 0x01
|
||||
|
||||
+311
-110
@@ -33,11 +33,13 @@
|
||||
#include "host/ble_gap.h"
|
||||
#include "host/ble_l2cap.h"
|
||||
|
||||
#include "../../../nimble/host/src/ble_l2cap_priv.h"
|
||||
|
||||
#include "bttester.h"
|
||||
|
||||
#define CONTROLLER_INDEX 0
|
||||
#define CHANNELS MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
|
||||
#define TESTER_COC_MTU (230)
|
||||
#define TESTER_COC_MTU MYNEWT_VAL(BTTESTER_L2CAP_COC_MTU)
|
||||
#define TESTER_COC_BUF_COUNT (3 * MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM))
|
||||
|
||||
static os_membuf_t tester_sdu_coc_mem[
|
||||
@@ -55,59 +57,6 @@ static struct channel {
|
||||
|
||||
static u8_t recv_cb_buf[TESTER_COC_MTU + sizeof(struct l2cap_data_received_ev)];
|
||||
|
||||
struct channel *find_channel(struct ble_l2cap_chan *chan) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CHANNELS; ++i) {
|
||||
if (channels[i].chan == chan) {
|
||||
return &channels[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
tester_l2cap_coc_recv(struct ble_l2cap_chan *chan, struct os_mbuf *sdu)
|
||||
{
|
||||
SYS_LOG_DBG("LE CoC SDU received, chan: 0x%08lx, data len %d",
|
||||
(uint32_t) chan, OS_MBUF_PKTLEN(sdu));
|
||||
|
||||
os_mbuf_free_chain(sdu);
|
||||
sdu = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0);
|
||||
assert(sdu != NULL);
|
||||
|
||||
ble_l2cap_recv_ready(chan, sdu);
|
||||
}
|
||||
|
||||
static void recv_cb(uint16_t conn_handle, struct ble_l2cap_chan *chan,
|
||||
struct os_mbuf *buf, void *arg)
|
||||
{
|
||||
struct l2cap_data_received_ev *ev = (void *) recv_cb_buf;
|
||||
struct channel *channel = arg;
|
||||
|
||||
ev->chan_id = channel->chan_id;
|
||||
ev->data_length = buf->om_len;
|
||||
memcpy(ev->data, buf->om_data, buf->om_len);
|
||||
|
||||
tester_send(BTP_SERVICE_ID_L2CAP, L2CAP_EV_DATA_RECEIVED,
|
||||
CONTROLLER_INDEX, recv_cb_buf, sizeof(*ev) + buf->om_len);
|
||||
|
||||
tester_l2cap_coc_recv(chan, buf);
|
||||
}
|
||||
|
||||
static void unstalled_cb(uint16_t conn_handle, struct ble_l2cap_chan *chan,
|
||||
int status, void *arg)
|
||||
{
|
||||
if (status) {
|
||||
tester_rsp(BTP_SERVICE_ID_L2CAP, L2CAP_SEND_DATA,
|
||||
CONTROLLER_INDEX, BTP_STATUS_FAILED);
|
||||
} else {
|
||||
tester_rsp(BTP_SERVICE_ID_L2CAP, L2CAP_SEND_DATA,
|
||||
CONTROLLER_INDEX, BTP_STATUS_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
static struct channel *get_free_channel(void)
|
||||
{
|
||||
u8_t i;
|
||||
@@ -127,25 +76,118 @@ static struct channel *get_free_channel(void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct channel *find_channel(struct ble_l2cap_chan *chan)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CHANNELS; ++i) {
|
||||
if (channels[i].chan == chan) {
|
||||
return &channels[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct channel *get_channel(uint8_t chan_id)
|
||||
{
|
||||
if (chan_id >= CHANNELS) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &channels[chan_id];
|
||||
}
|
||||
|
||||
static void
|
||||
tester_l2cap_coc_recv(struct ble_l2cap_chan *chan, struct os_mbuf *sdu)
|
||||
{
|
||||
SYS_LOG_DBG("LE CoC SDU received, chan: 0x%08lx, data len %d",
|
||||
(uint32_t) chan, OS_MBUF_PKTLEN(sdu));
|
||||
|
||||
os_mbuf_free_chain(sdu);
|
||||
sdu = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0);
|
||||
assert(sdu != NULL);
|
||||
|
||||
ble_l2cap_recv_ready(chan, sdu);
|
||||
}
|
||||
|
||||
static void recv_cb(uint16_t conn_handle, struct ble_l2cap_chan *chan,
|
||||
struct os_mbuf *buf, void *arg)
|
||||
{
|
||||
struct l2cap_data_received_ev *ev = (void *) recv_cb_buf;
|
||||
struct channel *channel = find_channel(chan);
|
||||
assert(channel != NULL);
|
||||
|
||||
ev->chan_id = channel->chan_id;
|
||||
ev->data_length = OS_MBUF_PKTLEN(buf);
|
||||
|
||||
if (ev->data_length > TESTER_COC_MTU) {
|
||||
SYS_LOG_ERR("Too large sdu received, truncating data");
|
||||
ev->data_length = TESTER_COC_MTU;
|
||||
}
|
||||
os_mbuf_copydata(buf, 0, ev->data_length, ev->data);
|
||||
|
||||
tester_send(BTP_SERVICE_ID_L2CAP, L2CAP_EV_DATA_RECEIVED,
|
||||
CONTROLLER_INDEX, recv_cb_buf, sizeof(*ev) + ev->data_length);
|
||||
|
||||
tester_l2cap_coc_recv(chan, buf);
|
||||
}
|
||||
|
||||
static void unstalled_cb(uint16_t conn_handle, struct ble_l2cap_chan *chan,
|
||||
int status, void *arg)
|
||||
{
|
||||
if (status) {
|
||||
tester_rsp(BTP_SERVICE_ID_L2CAP, L2CAP_SEND_DATA,
|
||||
CONTROLLER_INDEX, BTP_STATUS_FAILED);
|
||||
} else {
|
||||
tester_rsp(BTP_SERVICE_ID_L2CAP, L2CAP_SEND_DATA,
|
||||
CONTROLLER_INDEX, BTP_STATUS_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
static void reconfigured_ev(uint16_t conn_handle, struct ble_l2cap_chan *chan,
|
||||
struct ble_l2cap_chan_info *chan_info,
|
||||
int status)
|
||||
{
|
||||
struct l2cap_reconfigured_ev ev;
|
||||
struct channel *channel;
|
||||
|
||||
if (status != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
channel = find_channel(chan);
|
||||
assert(channel != NULL);
|
||||
|
||||
ev.chan_id = channel->chan_id;
|
||||
ev.peer_mtu = chan_info->peer_coc_mtu;
|
||||
ev.peer_mps = chan_info->peer_l2cap_mtu;
|
||||
ev.our_mtu = chan_info->our_coc_mtu;
|
||||
ev.our_mps = chan_info->our_l2cap_mtu;
|
||||
|
||||
tester_send(BTP_SERVICE_ID_L2CAP, L2CAP_EV_RECONFIGURED,
|
||||
CONTROLLER_INDEX, (u8_t *) &ev, sizeof(ev));
|
||||
}
|
||||
|
||||
static void connected_cb(uint16_t conn_handle, struct ble_l2cap_chan *chan,
|
||||
void *arg)
|
||||
struct ble_l2cap_chan_info *chan_info, void *arg)
|
||||
{
|
||||
struct l2cap_connected_ev ev;
|
||||
struct ble_gap_conn_desc desc;
|
||||
struct channel *channel;
|
||||
struct channel *channel = find_channel(chan);
|
||||
|
||||
channel = get_free_channel();
|
||||
if (!channel) {
|
||||
assert(0);
|
||||
if (channel == NULL) {
|
||||
channel = get_free_channel();
|
||||
}
|
||||
|
||||
channel->chan = chan;
|
||||
channel->state = 0;
|
||||
|
||||
ev.chan_id = channel->chan_id;
|
||||
ev.psm = chan_info->psm;
|
||||
ev.peer_mtu = chan_info->peer_coc_mtu;
|
||||
ev.peer_mps = chan_info->peer_l2cap_mtu;
|
||||
ev.our_mtu = chan_info->our_coc_mtu;
|
||||
ev.our_mps = chan_info->our_l2cap_mtu;
|
||||
channel->state = 1;
|
||||
channel->chan = chan;
|
||||
/* TODO: ev.psm */
|
||||
|
||||
if (!ble_gap_conn_find(conn_handle, &desc)) {
|
||||
ev.address_type = desc.peer_ota_addr.type;
|
||||
@@ -158,7 +200,7 @@ static void connected_cb(uint16_t conn_handle, struct ble_l2cap_chan *chan,
|
||||
}
|
||||
|
||||
static void disconnected_cb(uint16_t conn_handle, struct ble_l2cap_chan *chan,
|
||||
void *arg)
|
||||
struct ble_l2cap_chan_info *chan_info, void *arg)
|
||||
{
|
||||
struct l2cap_disconnected_ev ev;
|
||||
struct ble_gap_conn_desc desc;
|
||||
@@ -167,14 +209,12 @@ static void disconnected_cb(uint16_t conn_handle, struct ble_l2cap_chan *chan,
|
||||
memset(&ev, 0, sizeof(struct l2cap_disconnected_ev));
|
||||
|
||||
channel = find_channel(chan);
|
||||
if (channel != NULL) {
|
||||
channel->state = 0;
|
||||
channel->chan = chan;
|
||||
assert(channel != NULL);
|
||||
|
||||
ev.chan_id = channel->chan_id;
|
||||
/* TODO: ev.result */
|
||||
/* TODO: ev.psm */
|
||||
}
|
||||
channel->state = 0;
|
||||
channel->chan = chan;
|
||||
ev.chan_id = channel->chan_id;
|
||||
ev.psm = chan_info->psm;
|
||||
|
||||
if (!ble_gap_conn_find(conn_handle, &desc)) {
|
||||
ev.address_type = desc.peer_ota_addr.type;
|
||||
@@ -208,39 +248,51 @@ static int
|
||||
tester_l2cap_event(struct ble_l2cap_event *event, void *arg)
|
||||
{
|
||||
struct ble_l2cap_chan_info chan_info;
|
||||
int accept_response;
|
||||
|
||||
switch (event->type) {
|
||||
case BLE_L2CAP_EVENT_COC_CONNECTED:
|
||||
case BLE_L2CAP_EVENT_COC_CONNECTED:
|
||||
if (ble_l2cap_get_chan_info(event->connect.chan, &chan_info)) {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (event->connect.status) {
|
||||
console_printf("LE COC error: %d\n", event->connect.status);
|
||||
disconnected_cb(event->connect.conn_handle,
|
||||
event->connect.chan, arg);
|
||||
event->connect.chan, &chan_info, arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ble_l2cap_get_chan_info(event->connect.chan, &chan_info);
|
||||
|
||||
console_printf("LE COC connected, conn: %d, chan: 0x%08lx, scid: 0x%04x, "
|
||||
"dcid: 0x%04x, our_mtu: 0x%04x, peer_mtu: 0x%04x\n",
|
||||
event->connect.conn_handle,
|
||||
(uint32_t) event->connect.chan,
|
||||
chan_info.scid,
|
||||
chan_info.dcid,
|
||||
chan_info.our_l2cap_mtu,
|
||||
chan_info.peer_l2cap_mtu);
|
||||
console_printf("LE COC connected, conn: %d, chan: 0x%08lx, "
|
||||
"psm: 0x%02x, scid: 0x%04x, dcid: 0x%04x, "
|
||||
"our_mps: %d, our_mtu: %d, peer_mps: %d, "
|
||||
"peer_mtu: %d\n", event->connect.conn_handle,
|
||||
(uint32_t) event->connect.chan, chan_info.psm,
|
||||
chan_info.scid, chan_info.dcid,
|
||||
chan_info.our_l2cap_mtu, chan_info.our_coc_mtu,
|
||||
chan_info.peer_l2cap_mtu, chan_info.peer_coc_mtu);
|
||||
|
||||
connected_cb(event->connect.conn_handle,
|
||||
event->connect.chan, arg);
|
||||
event->connect.chan, &chan_info, arg);
|
||||
|
||||
return 0;
|
||||
case BLE_L2CAP_EVENT_COC_DISCONNECTED:
|
||||
if (ble_l2cap_get_chan_info(event->disconnect.chan,
|
||||
&chan_info)) {
|
||||
assert(0);
|
||||
}
|
||||
console_printf("LE CoC disconnected, chan: 0x%08lx\n",
|
||||
(uint32_t) event->disconnect.chan);
|
||||
|
||||
disconnected_cb(event->disconnect.conn_handle,
|
||||
event->disconnect.chan, arg);
|
||||
event->disconnect.chan, &chan_info, arg);
|
||||
return 0;
|
||||
case BLE_L2CAP_EVENT_COC_ACCEPT:
|
||||
accept_response = POINTER_TO_INT(arg);
|
||||
if (accept_response) {
|
||||
return accept_response;
|
||||
}
|
||||
|
||||
console_printf("LE CoC accept, chan: 0x%08lx, handle: %u, sdu_size: %u\n",
|
||||
(uint32_t) event->accept.chan,
|
||||
event->accept.conn_handle,
|
||||
@@ -254,7 +306,8 @@ tester_l2cap_event(struct ble_l2cap_event *event, void *arg)
|
||||
console_printf("LE CoC data received, chan: 0x%08lx, handle: %u, sdu_len: %u\n",
|
||||
(uint32_t) event->receive.chan,
|
||||
event->receive.conn_handle,
|
||||
event->receive.sdu_rx->om_len);
|
||||
OS_MBUF_PKTLEN(event->receive.sdu_rx));
|
||||
|
||||
recv_cb(event->receive.conn_handle, event->receive.chan,
|
||||
event->receive.sdu_rx, arg);
|
||||
return 0;
|
||||
@@ -263,10 +316,49 @@ tester_l2cap_event(struct ble_l2cap_event *event, void *arg)
|
||||
(uint32_t) event->tx_unstalled.chan,
|
||||
event->tx_unstalled.conn_handle,
|
||||
event->tx_unstalled.status);
|
||||
|
||||
unstalled_cb(event->tx_unstalled.conn_handle,
|
||||
event->tx_unstalled.chan,
|
||||
event->tx_unstalled.status, arg);
|
||||
return 0;
|
||||
case BLE_L2CAP_EVENT_COC_RECONFIG_COMPLETED:
|
||||
if (ble_l2cap_get_chan_info(event->reconfigured.chan,
|
||||
&chan_info)) {
|
||||
assert(0);
|
||||
}
|
||||
console_printf("LE CoC reconfigure completed status 0x%02x, "
|
||||
"chan: 0x%08lx\n", event->reconfigured.status,
|
||||
(uint32_t) event->reconfigured.chan);
|
||||
|
||||
if (event->reconfigured.status == 0) {
|
||||
console_printf("\t our_mps: %d our_mtu %d\n",
|
||||
chan_info.our_l2cap_mtu, chan_info.our_coc_mtu);
|
||||
}
|
||||
|
||||
reconfigured_ev(event->reconfigured.conn_handle,
|
||||
event->reconfigured.chan,
|
||||
&chan_info,
|
||||
event->reconfigured.status);
|
||||
return 0;
|
||||
case BLE_L2CAP_EVENT_COC_PEER_RECONFIGURED:
|
||||
if (ble_l2cap_get_chan_info(event->reconfigured.chan,
|
||||
&chan_info)) {
|
||||
assert(0);
|
||||
}
|
||||
console_printf("LE CoC peer reconfigured status 0x%02x, "
|
||||
"chan: 0x%08lx\n", event->reconfigured.status,
|
||||
(uint32_t) event->reconfigured.chan);
|
||||
|
||||
if (event->reconfigured.status == 0) {
|
||||
console_printf("\t peer_mps: %d peer_mtu %d\n",
|
||||
chan_info.peer_l2cap_mtu, chan_info.peer_coc_mtu);
|
||||
}
|
||||
|
||||
reconfigured_ev(event->reconfigured.conn_handle,
|
||||
event->reconfigured.chan,
|
||||
&chan_info,
|
||||
event->reconfigured.status);
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -275,45 +367,67 @@ tester_l2cap_event(struct ble_l2cap_event *event, void *arg)
|
||||
static void connect(u8_t *data, u16_t len)
|
||||
{
|
||||
const struct l2cap_connect_cmd *cmd = (void *) data;
|
||||
struct l2cap_connect_rp rp;
|
||||
u8_t rp_buf[sizeof(struct l2cap_connect_rp) + cmd->num];
|
||||
struct l2cap_connect_rp *rp = (void *) rp_buf;
|
||||
struct ble_gap_conn_desc desc;
|
||||
struct channel *chan;
|
||||
struct os_mbuf *sdu_rx;
|
||||
struct os_mbuf *sdu_rx[cmd->num];
|
||||
ble_addr_t *addr = (void *) data;
|
||||
uint16_t mtu = htole16(cmd->mtu);
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
SYS_LOG_DBG("connect: type: %d addr: %s", addr->type, bt_hex(addr->val, 6));
|
||||
|
||||
if (mtu == 0 || mtu > TESTER_COC_MTU) {
|
||||
mtu = TESTER_COC_MTU;
|
||||
}
|
||||
|
||||
rc = ble_gap_conn_find_by_addr(addr, &desc);
|
||||
if (rc) {
|
||||
SYS_LOG_ERR("GAP conn find failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
chan = get_free_channel();
|
||||
if (!chan) {
|
||||
SYS_LOG_ERR("No free channels");
|
||||
rp->num = cmd->num;
|
||||
|
||||
for (i = 0; i < cmd->num; i++) {
|
||||
chan = get_free_channel();
|
||||
if (!chan) {
|
||||
SYS_LOG_ERR("No free channels");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rp->chan_ids[i] = chan->chan_id;
|
||||
|
||||
sdu_rx[i] = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0);
|
||||
if (sdu_rx[i] == NULL) {
|
||||
SYS_LOG_ERR("Failed to alloc buf");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd->num == 1) {
|
||||
rc = ble_l2cap_connect(desc.conn_handle, htole16(cmd->psm),
|
||||
mtu, sdu_rx[0],
|
||||
tester_l2cap_event, NULL);
|
||||
} else if (cmd->num > 1) {
|
||||
rc = ble_l2cap_enhanced_connect(desc.conn_handle,
|
||||
htole16(cmd->psm), mtu,
|
||||
cmd->num, sdu_rx,
|
||||
tester_l2cap_event, NULL);
|
||||
} else {
|
||||
SYS_LOG_ERR("Invalid 'num' parameter value");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sdu_rx = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0);
|
||||
if (sdu_rx == NULL) {
|
||||
SYS_LOG_ERR("Failed to alloc buf");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = ble_l2cap_connect(desc.conn_handle, htole16(cmd->psm),
|
||||
TESTER_COC_MTU, sdu_rx,
|
||||
tester_l2cap_event, chan);
|
||||
if (rc) {
|
||||
SYS_LOG_ERR("L2CAP connect failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rp.chan_id = chan->chan_id;
|
||||
|
||||
tester_send(BTP_SERVICE_ID_L2CAP, L2CAP_CONNECT, CONTROLLER_INDEX,
|
||||
(u8_t *) &rp, sizeof(rp));
|
||||
(u8_t *) rp, sizeof(rp_buf));
|
||||
|
||||
return;
|
||||
|
||||
@@ -322,7 +436,7 @@ fail:
|
||||
BTP_STATUS_FAILED);
|
||||
}
|
||||
|
||||
static void disconnect(u8_t *data, u16_t len)
|
||||
static void disconnect(const u8_t *data, u16_t len)
|
||||
{
|
||||
const struct l2cap_disconnect_cmd *cmd = (void *) data;
|
||||
struct channel *chan;
|
||||
@@ -331,7 +445,8 @@ static void disconnect(u8_t *data, u16_t len)
|
||||
|
||||
SYS_LOG_DBG("");
|
||||
|
||||
chan = &channels[cmd->chan_id];
|
||||
chan = get_channel(cmd->chan_id);
|
||||
assert(chan != NULL);
|
||||
|
||||
err = ble_l2cap_disconnect(chan->chan);
|
||||
if (err) {
|
||||
@@ -346,16 +461,21 @@ rsp:
|
||||
status);
|
||||
}
|
||||
|
||||
static void send_data(u8_t *data, u16_t len)
|
||||
static void send_data(const u8_t *data, u16_t len)
|
||||
{
|
||||
const struct l2cap_send_data_cmd *cmd = (void *) data;
|
||||
struct channel *chan = &channels[cmd->chan_id];
|
||||
struct os_mbuf *sdu_tx = NULL;
|
||||
int rc;
|
||||
u16_t data_len = sys_le16_to_cpu(cmd->data_len);
|
||||
struct channel *chan = get_channel(cmd->chan_id);
|
||||
|
||||
SYS_LOG_DBG("cmd->chan_id=%d", cmd->chan_id);
|
||||
|
||||
if (!chan) {
|
||||
SYS_LOG_ERR("Invalid channel\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* FIXME: For now, fail if data length exceeds buffer length */
|
||||
if (data_len > TESTER_COC_MTU) {
|
||||
SYS_LOG_ERR("Data length exceeds buffer length");
|
||||
@@ -386,16 +506,48 @@ fail:
|
||||
BTP_STATUS_FAILED);
|
||||
}
|
||||
|
||||
static void listen(u8_t *data, u16_t len)
|
||||
static int
|
||||
l2cap_coc_err2hs_err(uint16_t coc_err)
|
||||
{
|
||||
switch (coc_err) {
|
||||
case BLE_L2CAP_COC_ERR_UNKNOWN_LE_PSM:
|
||||
return BLE_HS_ENOTSUP;
|
||||
case BLE_L2CAP_COC_ERR_NO_RESOURCES:
|
||||
return BLE_HS_ENOMEM;
|
||||
case BLE_L2CAP_COC_ERR_INSUFFICIENT_AUTHEN:
|
||||
return BLE_HS_EAUTHEN;
|
||||
case BLE_L2CAP_COC_ERR_INSUFFICIENT_AUTHOR:
|
||||
return BLE_HS_EAUTHOR;
|
||||
case BLE_L2CAP_COC_ERR_INSUFFICIENT_ENC:
|
||||
return BLE_HS_EENCRYPT;
|
||||
case BLE_L2CAP_COC_ERR_INSUFFICIENT_KEY_SZ:
|
||||
return BLE_HS_EENCRYPT_KEY_SZ;
|
||||
case BLE_L2CAP_COC_ERR_UNACCEPTABLE_PARAMETERS:
|
||||
return BLE_HS_EINVAL;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void listen(const u8_t *data, u16_t len)
|
||||
{
|
||||
const struct l2cap_listen_cmd *cmd = (void *) data;
|
||||
uint16_t mtu = htole16(cmd->mtu);
|
||||
uint16_t rsp = htole16(cmd->response);
|
||||
int rc;
|
||||
|
||||
SYS_LOG_DBG("");
|
||||
|
||||
if (mtu == 0 || mtu > TESTER_COC_MTU) {
|
||||
mtu = TESTER_COC_MTU;
|
||||
}
|
||||
|
||||
rsp = l2cap_coc_err2hs_err(rsp);
|
||||
|
||||
/* TODO: Handle cmd->transport flag */
|
||||
rc = ble_l2cap_create_server(cmd->psm, TESTER_COC_MTU,
|
||||
tester_l2cap_event, NULL);
|
||||
rc = ble_l2cap_create_server(cmd->psm, mtu, tester_l2cap_event,
|
||||
INT_TO_POINTER(rsp));
|
||||
if (rc) {
|
||||
goto fail;
|
||||
}
|
||||
@@ -409,6 +561,51 @@ fail:
|
||||
BTP_STATUS_FAILED);
|
||||
}
|
||||
|
||||
static void reconfigure(const u8_t *data, u16_t len)
|
||||
{
|
||||
const struct l2cap_reconfigure_cmd *cmd = (void *) data;
|
||||
uint16_t mtu = htole16(cmd->mtu);
|
||||
struct ble_gap_conn_desc desc;
|
||||
ble_addr_t *addr = (void *) data;
|
||||
struct ble_l2cap_chan *chans[cmd->num];
|
||||
struct channel *channel;
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
SYS_LOG_DBG("");
|
||||
|
||||
if (mtu == 0 || mtu > TESTER_COC_MTU) {
|
||||
mtu = TESTER_COC_MTU;
|
||||
}
|
||||
|
||||
rc = ble_gap_conn_find_by_addr(addr, &desc);
|
||||
if (rc) {
|
||||
SYS_LOG_ERR("GAP conn find failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (i = 0; i < cmd->num; ++i) {
|
||||
channel = get_channel(cmd->idxs[i]);
|
||||
if (channel == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
chans[i] = channel->chan;
|
||||
}
|
||||
|
||||
rc = ble_l2cap_reconfig(chans, cmd->num, mtu);
|
||||
if (rc) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
tester_rsp(BTP_SERVICE_ID_L2CAP, L2CAP_RECONFIGURE, CONTROLLER_INDEX,
|
||||
BTP_STATUS_SUCCESS);
|
||||
return;
|
||||
|
||||
fail:
|
||||
tester_rsp(BTP_SERVICE_ID_L2CAP, L2CAP_RECONFIGURE, CONTROLLER_INDEX,
|
||||
BTP_STATUS_FAILED);
|
||||
}
|
||||
|
||||
static void supported_commands(u8_t *data, u16_t len)
|
||||
{
|
||||
u8_t cmds[1];
|
||||
@@ -421,6 +618,7 @@ static void supported_commands(u8_t *data, u16_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_RECONFIGURE);
|
||||
|
||||
tester_send(BTP_SERVICE_ID_L2CAP, L2CAP_READ_SUPPORTED_COMMANDS,
|
||||
CONTROLLER_INDEX, (u8_t *) rp, sizeof(cmds));
|
||||
@@ -445,6 +643,9 @@ void tester_handle_l2cap(u8_t opcode, u8_t index, u8_t *data,
|
||||
case L2CAP_LISTEN:
|
||||
listen(data, len);
|
||||
return;
|
||||
case L2CAP_RECONFIGURE:
|
||||
reconfigure(data, len);
|
||||
return;
|
||||
default:
|
||||
tester_rsp(BTP_SERVICE_ID_L2CAP, opcode, index,
|
||||
BTP_STATUS_UNKNOWN_CMD);
|
||||
|
||||
@@ -71,6 +71,10 @@ syscfg.defs:
|
||||
description: Enable logging BTP traffic
|
||||
value: 0
|
||||
|
||||
BTTESTER_L2CAP_COC_MTU:
|
||||
description: Maximum MTU size the application can handle
|
||||
value: 230
|
||||
|
||||
syscfg.vals:
|
||||
OS_MAIN_STACK_SIZE: 512
|
||||
SHELL_TASK: 0
|
||||
@@ -86,6 +90,8 @@ syscfg.vals:
|
||||
|
||||
BLE_L2CAP_COC_MAX_NUM: 2
|
||||
BLE_L2CAP_SIG_MAX_PROCS: 2
|
||||
BLE_L2CAP_ENHANCED_COC: 1
|
||||
BLE_VERSION: 52
|
||||
# Some testcases require MPS < MTU
|
||||
BLE_L2CAP_COC_MPS: 100
|
||||
BLE_RPA_TIMEOUT: 30
|
||||
|
||||
Reference in New Issue
Block a user