Skip to content

Commit 8dcac02

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 8dcac02

File tree

1 file changed

+126
-18
lines changed

1 file changed

+126
-18
lines changed

nimble/host/src/ble_eatt.c

Lines changed: 126 additions & 18 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,79 @@ 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(
151+
"ble_eatt_used_channels: No eatt for given conn handle\n");
152+
}
153+
154+
for (i = 0; i < MYNEWT_VAL(BLE_EATT_CHAN_PER_CONN); i++) {
155+
if (eatt->chan[i] != NULL) {
156+
used_chans++;
157+
}
158+
}
159+
160+
return used_chans;
161+
}
162+
163+
static int
164+
ble_eatt_free_channel_idx(struct ble_eatt *eatt)
165+
{
166+
int i;
167+
168+
for (i = 0; i < MYNEWT_VAL(BLE_EATT_CHAN_PER_CONN); i++) {
169+
if (eatt->chan[i] == NULL)
170+
return i;
171+
}
172+
173+
return -1;
174+
}
175+
176+
static struct ble_l2cap_chan *
177+
ble_eatt_find_chan(struct ble_eatt *eatt, struct ble_l2cap_chan *chan)
178+
{
179+
int i;
180+
181+
for (i = 0; i < MYNEWT_VAL(BLE_EATT_CHAN_PER_CONN); i++) {
182+
if (eatt->chan[i] == chan) {
183+
return eatt->chan[i];
184+
}
185+
}
186+
return NULL;
187+
}
134188

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

@@ -160,6 +224,7 @@ ble_eatt_prepare_rx_sdu(struct ble_l2cap_chan *chan)
160224
static void
161225
ble_eatt_wakeup_cb(struct ble_npl_event *ev)
162226
{
227+
int i;
163228
struct ble_eatt *eatt;
164229
struct os_mbuf *txom;
165230
struct os_mbuf_pkthdr *omp;
@@ -173,14 +238,24 @@ ble_eatt_wakeup_cb(struct ble_npl_event *ev)
173238
STAILQ_REMOVE_HEAD(&eatt->eatt_tx_q, omp_next);
174239

175240
txom = OS_MBUF_PKTHDR_TO_MBUF(omp);
176-
ble_l2cap_get_chan_info(eatt->chan, &info);
241+
242+
/* Look for the already established channel.
243+
* Send necessary data, then break.
244+
*/
245+
for (i = 0; i < MYNEWT_VAL(BLE_EATT_CHAN_PER_CONN); i++) {
246+
if (eatt->chan[i] != NULL) {
247+
ble_l2cap_get_chan_info(eatt->chan[i], &info);
177248
ble_eatt_tx(eatt->conn_handle, info.dcid, txom);
249+
break;
250+
}
251+
}
178252
}
179253
}
180254

181255
static struct ble_eatt *
182256
ble_eatt_alloc(void)
183257
{
258+
int i;
184259
struct ble_eatt *eatt;
185260

186261
eatt = os_memblock_get(&ble_eatt_conn_pool);
@@ -192,7 +267,9 @@ ble_eatt_alloc(void)
192267
SLIST_INSERT_HEAD(&g_ble_eatt_list, eatt, next);
193268

194269
eatt->conn_handle = BLE_HS_CONN_HANDLE_NONE;
195-
eatt->chan = NULL;
270+
for (i = 0; i < MYNEWT_VAL(BLE_EATT_CHAN_PER_CONN); i++) {
271+
eatt->chan[i] = NULL;
272+
}
196273
eatt->client_op = 0;
197274

198275
STAILQ_INIT(&eatt->eatt_tx_q);
@@ -221,7 +298,9 @@ ble_eatt_l2cap_event_fn(struct ble_l2cap_event *event, void *arg)
221298
{
222299
struct ble_eatt *eatt = arg;
223300
struct ble_gap_conn_desc desc;
301+
struct ble_l2cap_chan *channel;
224302
uint8_t opcode;
303+
int chan_idx;
225304
int rc;
226305

227306
switch (event->type) {
@@ -231,7 +310,15 @@ ble_eatt_l2cap_event_fn(struct ble_l2cap_event *event, void *arg)
231310
ble_eatt_free(eatt);
232311
return 0;
233312
}
234-
eatt->chan = event->connect.chan;
313+
chan_idx = ble_eatt_free_channel_idx(eatt);
314+
if (chan_idx > 0) {
315+
eatt->chan[chan_idx] = event->connect.chan;
316+
} else {
317+
BLE_EATT_LOG_ERROR("eatt: Connect event: No free channels\n");
318+
ble_eatt_free(eatt);
319+
return 0;
320+
}
321+
235322
break;
236323
case BLE_L2CAP_EVENT_COC_DISCONNECTED:
237324
BLE_EATT_LOG_DEBUG("eatt: Disconnected \n");
@@ -266,7 +353,11 @@ ble_eatt_l2cap_event_fn(struct ble_l2cap_event *event, void *arg)
266353
ble_npl_eventq_put(ble_hs_evq_get(), &eatt->wakeup_ev);
267354
break;
268355
case BLE_L2CAP_EVENT_COC_DATA_RECEIVED:
269-
assert(eatt->chan == event->receive.chan);
356+
channel = ble_eatt_find_chan(eatt, event->receive.chan);
357+
if (channel == NULL) {
358+
BLE_EATT_LOG_ERROR("eatt: receive: Invalid channel\n");
359+
ble_eatt_free(eatt);
360+
}
270361
opcode = event->receive.sdu_rx->om_data[0];
271362
if (ble_eatt_supported_rsp(opcode)) {
272363
ble_npl_eventq_put(ble_hs_evq_get(), &eatt->wakeup_ev);
@@ -279,7 +370,7 @@ ble_eatt_l2cap_event_fn(struct ble_l2cap_event *event, void *arg)
279370
* • The Signed Write Without Response sub-procedure shall only be
280371
* supported on the LE Fixed Channel Unenhanced ATT bearer.
281372
*/
282-
ble_l2cap_disconnect(eatt->chan);
373+
ble_l2cap_disconnect(channel);
283374
return BLE_HS_EREJECT;
284375
}
285376

@@ -293,11 +384,12 @@ ble_eatt_l2cap_event_fn(struct ble_l2cap_event *event, void *arg)
293384
* encryption.
294385
*/
295386
if (!desc.sec_state.encrypted) {
296-
ble_l2cap_disconnect(eatt->chan);
387+
ble_l2cap_disconnect(channel);
297388
return BLE_HS_EREJECT;
298389
}
299390

300-
ble_eatt_att_rx_cb(event->receive.conn_handle, eatt->chan->scid, &event->receive.sdu_rx);
391+
ble_eatt_att_rx_cb(event->receive.conn_handle, channel->scid,
392+
&event->receive.sdu_rx);
301393
if (event->receive.sdu_rx) {
302394
os_mbuf_free_chain(event->receive.sdu_rx);
303395
event->receive.sdu_rx = NULL;
@@ -306,7 +398,7 @@ ble_eatt_l2cap_event_fn(struct ble_l2cap_event *event, void *arg)
306398
/* Receiving L2CAP data is no longer possible, terminate connection */
307399
rc = ble_eatt_prepare_rx_sdu(event->receive.chan);
308400
if (rc) {
309-
ble_l2cap_disconnect(eatt->chan);
401+
ble_l2cap_disconnect(channel);
310402
return BLE_HS_ENOMEM;
311403
}
312404
break;
@@ -336,9 +428,10 @@ ble_eatt_setup_cb(struct ble_npl_event *ev)
336428

337429
BLE_EATT_LOG_DEBUG("eatt: connecting eatt on conn_handle 0x%04x\n", eatt->conn_handle);
338430

339-
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);
431+
rc = ble_l2cap_enhanced_connect(
432+
eatt->conn_handle, BLE_EATT_PSM, MYNEWT_VAL(BLE_EATT_MTU),
433+
eatt->channels_to_connect, &om, ble_eatt_l2cap_event_fn, eatt);
434+
342435
if (rc) {
343436
BLE_EATT_LOG_ERROR("eatt: Failed to connect EATT on conn_handle 0x%04x (status=%d)\n",
344437
eatt->conn_handle, rc);
@@ -441,6 +534,7 @@ ble_eatt_gap_event(struct ble_gap_event *event, void *arg)
441534
uint16_t
442535
ble_eatt_get_available_chan_cid(uint16_t conn_handle, uint8_t op)
443536
{
537+
int i;
444538
struct ble_eatt * eatt;
445539

446540
eatt = ble_eatt_find_not_busy(conn_handle);
@@ -450,7 +544,13 @@ ble_eatt_get_available_chan_cid(uint16_t conn_handle, uint8_t op)
450544

451545
eatt->client_op = op;
452546

453-
return eatt->chan->scid;
547+
for (i = 0; i < MYNEWT_VAL(BLE_EATT_CHAN_PER_CONN); i++) {
548+
if (eatt->chan[i] != NULL) {
549+
return eatt->chan[i]->scid;
550+
}
551+
}
552+
553+
return BLE_L2CAP_CID_ATT;
454554
}
455555

456556
void
@@ -472,17 +572,25 @@ int
472572
ble_eatt_tx(uint16_t conn_handle, uint16_t cid, struct os_mbuf *txom)
473573
{
474574
struct ble_eatt *eatt;
575+
static struct ble_l2cap_chan *channel;
475576
int rc;
476577

477578
BLE_EATT_LOG_DEBUG("eatt: %s, size %d ", __func__, OS_MBUF_PKTLEN(txom));
478579
eatt = ble_eatt_find(conn_handle, cid);
479-
if (!eatt || !eatt->chan) {
580+
if (!eatt) {
581+
BLE_EATT_LOG_ERROR("Eatt not available");
582+
rc = BLE_HS_ENOENT;
583+
goto error;
584+
}
585+
586+
channel = ble_eatt_channel_find_by_cid(eatt, cid);
587+
if (!channel) {
480588
BLE_EATT_LOG_ERROR("Eatt not available");
481589
rc = BLE_HS_ENOENT;
482590
goto error;
483591
}
484592

485-
rc = ble_l2cap_send(eatt->chan, txom);
593+
rc = ble_l2cap_send(channel, txom);
486594
if (rc == 0) {
487595
goto done;
488596
}

0 commit comments

Comments
 (0)