Skip to content

Commit 5227651

Browse files
eatt: Inital support for multiple EATT channels per connection
Extend ble_eatt struct with channel array and channel count. Add helper functions for channel indexing and lookup. Update ble_eatt_find to search all channels for matching CID. Add channel allocation logic on connect event. Replace direct channel access with indexed lookup. Refactor ble_eatt_tx and L2CAP ev-handler to support multiple channels.
1 parent 11d53b6 commit 5227651

File tree

1 file changed

+122
-17
lines changed

1 file changed

+122
-17
lines changed

nimble/host/src/ble_eatt.c

Lines changed: 122 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@
3535
struct ble_eatt {
3636
SLIST_ENTRY(ble_eatt) next;
3737
uint16_t conn_handle;
38-
struct ble_l2cap_chan *chan;
38+
struct ble_l2cap_chan *chan[MYNEWT_VAL(BLE_EATT_CHAN_PER_CONN)];
3939
uint8_t client_op;
40+
uint8_t channels_to_connect;
4041

4142
/* Packet transmit queue */
4243
STAILQ_HEAD(, os_mbuf_pkthdr) eatt_tx_q;
@@ -122,16 +123,78 @@ ble_eatt_find_by_conn_handle_and_busy_op(uint16_t conn_handle, uint8_t op)
122123
static struct ble_eatt *
123124
ble_eatt_find(uint16_t conn_handle, uint16_t cid)
124125
{
126+
int i;
125127
struct ble_eatt *eatt;
126128

127129
SLIST_FOREACH(eatt, &g_ble_eatt_list, next) {
128-
if ((eatt->conn_handle == conn_handle) &&
129-
(eatt->chan) &&
130-
(eatt->chan->scid == cid)) {
130+
if (eatt->conn_handle == conn_handle) {
131+
for (i = 0; i < MYNEWT_VAL(BLE_EATT_CHAN_PER_CONN); i++) {
132+
if (eatt->chan[i] && eatt->chan[i]->scid == cid) {
131133
return eatt;
132134
}
133135
}
136+
}
137+
}
138+
return NULL;
139+
}
140+
141+
static size_t
142+
ble_eatt_used_channels(uint16_t conn_handle)
143+
{
144+
int i;
145+
size_t used_chans = 0;
146+
struct ble_eatt *eatt;
147+
148+
eatt = ble_eatt_find_by_conn_handle(conn_handle);
149+
if (!eatt) {
150+
BLE_EATT_LOG_ERROR("ble_eatt_used_channels: No eatt for given conn handle\n");
151+
}
152+
153+
for (i = 0; i < MYNEWT_VAL(BLE_EATT_CHAN_PER_CONN); i++) {
154+
if (eatt->chan[i] != NULL) {
155+
used_chans++;
156+
}
157+
}
158+
159+
return used_chans;
160+
}
161+
162+
static int
163+
ble_eatt_free_channel_idx(struct ble_eatt *eatt)
164+
{
165+
int i;
166+
167+
for (i = 0; i < MYNEWT_VAL(BLE_EATT_CHAN_PER_CONN); i++) {
168+
if (eatt->chan[i] == NULL)
169+
return i;
170+
}
171+
172+
return -1;
173+
}
174+
175+
static struct ble_l2cap_chan *
176+
ble_eatt_find_chan(struct ble_eatt *eatt, struct ble_l2cap_chan *chan)
177+
{
178+
int i;
179+
180+
for (i = 0; i < MYNEWT_VAL(BLE_EATT_CHAN_PER_CONN); i++) {
181+
if (eatt->chan[i] == chan) {
182+
return eatt->chan[i];
183+
}
184+
}
185+
return NULL;
186+
}
134187

188+
static struct ble_l2cap_chan *
189+
ble_eatt_channel_find_by_cid(struct ble_eatt *eatt, uint16_t cid)
190+
{
191+
int i;
192+
193+
for (i = 0; i < MYNEWT_VAL(BLE_EATT_CHAN_PER_CONN); i++) {
194+
if (eatt->chan[i] && eatt->chan[i]->scid == cid) {
195+
return eatt->chan[i];
196+
}
197+
}
135198
return NULL;
136199
}
137200

@@ -160,6 +223,7 @@ ble_eatt_prepare_rx_sdu(struct ble_l2cap_chan *chan)
160223
static void
161224
ble_eatt_wakeup_cb(struct ble_npl_event *ev)
162225
{
226+
int i;
163227
struct ble_eatt *eatt;
164228
struct os_mbuf *txom;
165229
struct os_mbuf_pkthdr *omp;
@@ -173,14 +237,24 @@ ble_eatt_wakeup_cb(struct ble_npl_event *ev)
173237
STAILQ_REMOVE_HEAD(&eatt->eatt_tx_q, omp_next);
174238

175239
txom = OS_MBUF_PKTHDR_TO_MBUF(omp);
176-
ble_l2cap_get_chan_info(eatt->chan, &info);
240+
241+
/* Look for the already established channel.
242+
* Send necessary data, then break.
243+
*/
244+
for (i = 0; i < MYNEWT_VAL(BLE_EATT_CHAN_PER_CONN); i++) {
245+
if (eatt->chan[i] != NULL) {
246+
ble_l2cap_get_chan_info(eatt->chan[i], &info);
177247
ble_eatt_tx(eatt->conn_handle, info.dcid, txom);
248+
break;
249+
}
250+
}
178251
}
179252
}
180253

181254
static struct ble_eatt *
182255
ble_eatt_alloc(void)
183256
{
257+
int i;
184258
struct ble_eatt *eatt;
185259

186260
eatt = os_memblock_get(&ble_eatt_conn_pool);
@@ -192,7 +266,9 @@ ble_eatt_alloc(void)
192266
SLIST_INSERT_HEAD(&g_ble_eatt_list, eatt, next);
193267

194268
eatt->conn_handle = BLE_HS_CONN_HANDLE_NONE;
195-
eatt->chan = NULL;
269+
for (i = 0; i < MYNEWT_VAL(BLE_EATT_CHAN_PER_CONN); i++) {
270+
eatt->chan[i] = NULL;
271+
}
196272
eatt->client_op = 0;
197273

198274
STAILQ_INIT(&eatt->eatt_tx_q);
@@ -221,7 +297,9 @@ ble_eatt_l2cap_event_fn(struct ble_l2cap_event *event, void *arg)
221297
{
222298
struct ble_eatt *eatt = arg;
223299
struct ble_gap_conn_desc desc;
300+
struct ble_l2cap_chan *channel;
224301
uint8_t opcode;
302+
int chan_idx;
225303
int rc;
226304

227305
switch (event->type) {
@@ -231,7 +309,15 @@ ble_eatt_l2cap_event_fn(struct ble_l2cap_event *event, void *arg)
231309
ble_eatt_free(eatt);
232310
return 0;
233311
}
234-
eatt->chan = event->connect.chan;
312+
chan_idx = ble_eatt_free_channel_idx(eatt);
313+
if (chan_idx > 0) {
314+
eatt->chan[chan_idx] = event->connect.chan;
315+
} else {
316+
BLE_EATT_LOG_ERROR("eatt: Connect event: No free channels\n");
317+
ble_eatt_free(eatt);
318+
return 0;
319+
}
320+
235321
break;
236322
case BLE_L2CAP_EVENT_COC_DISCONNECTED:
237323
BLE_EATT_LOG_DEBUG("eatt: Disconnected \n");
@@ -266,7 +352,11 @@ ble_eatt_l2cap_event_fn(struct ble_l2cap_event *event, void *arg)
266352
ble_npl_eventq_put(ble_hs_evq_get(), &eatt->wakeup_ev);
267353
break;
268354
case BLE_L2CAP_EVENT_COC_DATA_RECEIVED:
269-
assert(eatt->chan == event->receive.chan);
355+
channel = ble_eatt_find_chan(eatt, event->receive.chan);
356+
if (channel == NULL) {
357+
BLE_EATT_LOG_ERROR("eatt: receive: Invalid channel\n");
358+
ble_eatt_free(eatt);
359+
}
270360
opcode = event->receive.sdu_rx->om_data[0];
271361
if (ble_eatt_supported_rsp(opcode)) {
272362
ble_npl_eventq_put(ble_hs_evq_get(), &eatt->wakeup_ev);
@@ -279,7 +369,7 @@ ble_eatt_l2cap_event_fn(struct ble_l2cap_event *event, void *arg)
279369
* • The Signed Write Without Response sub-procedure shall only be
280370
* supported on the LE Fixed Channel Unenhanced ATT bearer.
281371
*/
282-
ble_l2cap_disconnect(eatt->chan);
372+
ble_l2cap_disconnect(channel);
283373
return BLE_HS_EREJECT;
284374
}
285375

@@ -293,11 +383,11 @@ ble_eatt_l2cap_event_fn(struct ble_l2cap_event *event, void *arg)
293383
* encryption.
294384
*/
295385
if (!desc.sec_state.encrypted) {
296-
ble_l2cap_disconnect(eatt->chan);
386+
ble_l2cap_disconnect(channel);
297387
return BLE_HS_EREJECT;
298388
}
299389

300-
ble_eatt_att_rx_cb(event->receive.conn_handle, eatt->chan->scid, &event->receive.sdu_rx);
390+
ble_eatt_att_rx_cb(event->receive.conn_handle, channel->scid, &event->receive.sdu_rx);
301391
if (event->receive.sdu_rx) {
302392
os_mbuf_free_chain(event->receive.sdu_rx);
303393
event->receive.sdu_rx = NULL;
@@ -306,7 +396,7 @@ ble_eatt_l2cap_event_fn(struct ble_l2cap_event *event, void *arg)
306396
/* Receiving L2CAP data is no longer possible, terminate connection */
307397
rc = ble_eatt_prepare_rx_sdu(event->receive.chan);
308398
if (rc) {
309-
ble_l2cap_disconnect(eatt->chan);
399+
ble_l2cap_disconnect(channel);
310400
return BLE_HS_ENOMEM;
311401
}
312402
break;
@@ -337,8 +427,8 @@ ble_eatt_setup_cb(struct ble_npl_event *ev)
337427
BLE_EATT_LOG_DEBUG("eatt: connecting eatt on conn_handle 0x%04x\n", eatt->conn_handle);
338428

339429
rc = ble_l2cap_enhanced_connect(eatt->conn_handle, BLE_EATT_PSM,
340-
MYNEWT_VAL(BLE_EATT_MTU), 1, &om,
341-
ble_eatt_l2cap_event_fn, eatt);
430+
MYNEWT_VAL(BLE_EATT_MTU), eatt->channels_to_connect,
431+
&om, ble_eatt_l2cap_event_fn, eatt);
342432
if (rc) {
343433
BLE_EATT_LOG_ERROR("eatt: Failed to connect EATT on conn_handle 0x%04x (status=%d)\n",
344434
eatt->conn_handle, rc);
@@ -441,6 +531,7 @@ ble_eatt_gap_event(struct ble_gap_event *event, void *arg)
441531
uint16_t
442532
ble_eatt_get_available_chan_cid(uint16_t conn_handle, uint8_t op)
443533
{
534+
int i;
444535
struct ble_eatt * eatt;
445536

446537
eatt = ble_eatt_find_not_busy(conn_handle);
@@ -450,7 +541,13 @@ ble_eatt_get_available_chan_cid(uint16_t conn_handle, uint8_t op)
450541

451542
eatt->client_op = op;
452543

453-
return eatt->chan->scid;
544+
for (i = 0; i < MYNEWT_VAL(BLE_EATT_CHAN_PER_CONN); i++) {
545+
if (eatt->chan[i] != NULL) {
546+
return eatt->chan[i]->scid;
547+
}
548+
}
549+
550+
return BLE_L2CAP_CID_ATT;
454551
}
455552

456553
void
@@ -472,17 +569,25 @@ int
472569
ble_eatt_tx(uint16_t conn_handle, uint16_t cid, struct os_mbuf *txom)
473570
{
474571
struct ble_eatt *eatt;
572+
static struct ble_l2cap_chan *channel;
475573
int rc;
476574

477575
BLE_EATT_LOG_DEBUG("eatt: %s, size %d ", __func__, OS_MBUF_PKTLEN(txom));
478576
eatt = ble_eatt_find(conn_handle, cid);
479-
if (!eatt || !eatt->chan) {
577+
if (!eatt) {
578+
BLE_EATT_LOG_ERROR("Eatt not available");
579+
rc = BLE_HS_ENOENT;
580+
goto error;
581+
}
582+
583+
channel = ble_eatt_channel_find_by_cid(eatt, cid);
584+
if (!channel) {
480585
BLE_EATT_LOG_ERROR("Eatt not available");
481586
rc = BLE_HS_ENOENT;
482587
goto error;
483588
}
484589

485-
rc = ble_l2cap_send(eatt->chan, txom);
590+
rc = ble_l2cap_send(channel, txom);
486591
if (rc == 0) {
487592
goto done;
488593
}

0 commit comments

Comments
 (0)