@@ -40,10 +40,13 @@ struct ble_eatt {
40
40
uint8_t chan_num ;
41
41
uint8_t used_channels ;
42
42
uint8_t accept_channels ;
43
+ uint8_t collision_ctrl ;
44
+ uint8_t retry_count ;
43
45
44
46
/* Packet transmit queue */
45
47
STAILQ_HEAD (, os_mbuf_pkthdr ) eatt_tx_q ;
46
48
49
+ struct os_callout collision_co ;
47
50
struct ble_npl_event setup_ev ;
48
51
struct ble_npl_event wakeup_ev ;
49
52
@@ -199,6 +202,17 @@ ble_eatt_wakeup_cb(struct ble_npl_event *ev)
199
202
}
200
203
}
201
204
205
+ static void
206
+ ble_eatt_collision_ev (struct os_event * ev )
207
+ {
208
+ struct os_callout * co = (struct os_callout * )ev ;
209
+ struct ble_eatt * eatt = CONTAINER_OF (co , struct ble_eatt , collision_co );
210
+
211
+ if (eatt -> retry_count < 2 ) {
212
+ ble_eatt_connect (eatt -> conn_handle , eatt -> chan_num );
213
+ }
214
+ }
215
+
202
216
#if (MYNEWT_VAL (BLE_EATT_AUTO_CONNECT ))
203
217
void
204
218
ble_eatt_auto_conn_cb (struct os_event * ev )
@@ -231,6 +245,9 @@ ble_eatt_alloc(void)
231
245
232
246
STAILQ_INIT (& eatt -> eatt_tx_q );
233
247
248
+ os_callout_init (& eatt -> collision_co , os_eventq_dflt_get (),
249
+ ble_eatt_collision_ev , NULL );
250
+
234
251
#if (MYNEWT_VAL (BLE_EATT_AUTO_CONNECT ))
235
252
os_callout_init (& eatt -> auto_conn_delay , os_eventq_dflt_get (),
236
253
ble_eatt_auto_conn_cb , NULL );
@@ -261,6 +278,8 @@ ble_eatt_l2cap_event_fn(struct ble_l2cap_event *event, void *arg)
261
278
struct ble_eatt * eatt = arg ;
262
279
struct ble_gap_conn_desc desc ;
263
280
uint8_t free_channels ;
281
+ uint8_t collision_delay ;
282
+ uint8_t collision_rand_time ;
264
283
uint8_t opcode ;
265
284
int rc ;
266
285
@@ -271,13 +290,39 @@ ble_eatt_l2cap_event_fn(struct ble_l2cap_event *event, void *arg)
271
290
event -> connect .conn_handle , event -> connect .chan -> scid ,
272
291
event -> connect .chan -> dcid , event -> connect .status );
273
292
293
+ if (event -> connect .status == BLE_HS_ENOMEM && eatt -> collision_ctrl ) {
294
+ BLE_EATT_LOG_DEBUG ("eatt: Connect collision handle: %d\n" ,
295
+ event -> connect .conn_handle );
296
+
297
+ rc = ble_gap_conn_find (event -> connect .conn_handle , & desc );
298
+ assert (rc == 0 );
299
+
300
+ rc = ble_hs_hci_rand (& collision_rand_time , 1 );
301
+ if (rc != 0 ) {
302
+ return rc ;
303
+ }
304
+
305
+ collision_delay = (collision_rand_time % 5 ) + 2 * (desc .conn_latency + 1 ) * desc .conn_itvl ;
306
+
307
+ os_callout_reset (& eatt -> collision_co , collision_delay );
308
+
309
+ eatt -> retry_count ++ ;
310
+ eatt -> used_channels -- ;
311
+
312
+ return 0 ;
313
+ }
314
+
274
315
if (event -> connect .status ) {
275
- ble_eatt_free ( eatt ) ;
316
+ eatt -> used_channels -- ;
276
317
return 0 ;
277
318
}
278
319
eatt -> chan = event -> connect .chan ;
279
320
eatt -> conn_handle = event -> connect .conn_handle ;
280
321
322
+ /* Delete collision callout on successful connection */
323
+ os_callout_stop (& eatt -> collision_co );
324
+ eatt -> collision_ctrl = false;
325
+
281
326
eatt -> used_channels ++ ;
282
327
BLE_EATT_LOG_DEBUG ("eatt: Channels already used for this connection %d\n" ,
283
328
eatt -> used_channels );
@@ -319,6 +364,7 @@ ble_eatt_l2cap_event_fn(struct ble_l2cap_event *event, void *arg)
319
364
free_channels = MYNEWT_VAL (BLE_EATT_CHAN_PER_CONN ) - ble_eatt_used_channels (eatt -> conn_handle );
320
365
321
366
if (free_channels == 0 ) {
367
+ eatt -> collision_ctrl = true;
322
368
BLE_EATT_LOG_ERROR ("eatt: Accept event | No free channels for "
323
369
"conn_handle: %d\n" , event -> accept .conn_handle );
324
370
return BLE_HS_ENOMEM ;
@@ -418,6 +464,8 @@ ble_eatt_setup_cb(struct ble_npl_event *ev)
418
464
419
465
BLE_EATT_LOG_DEBUG ("eatt: connecting eatt on conn_handle 0x%04x\n" , eatt -> conn_handle );
420
466
467
+ eatt -> used_channels += eatt -> chan_num ;
468
+
421
469
rc = ble_l2cap_enhanced_connect (eatt -> conn_handle , BLE_EATT_PSM ,
422
470
MYNEWT_VAL (BLE_EATT_MTU ),
423
471
eatt -> chan_num , & om ,
@@ -653,7 +701,18 @@ ble_eatt_connect(uint16_t conn_handle, uint8_t chan_num)
653
701
}
654
702
655
703
/*
704
+ * 5.3 Vol 3, Part G, Sec. 5.4 L2CAP collision mitigation
705
+ * Peripheral shall wait some time before retrying connection.
706
+ * Central may reconnect without any delay.
707
+ * To reconnect user has to call ble_eatt_connect again.
708
+ */
709
+ if (desc .role == BLE_GAP_ROLE_SLAVE && os_callout_queued (& eatt -> collision_co )) {
710
+ BLE_EATT_LOG_WARN ("ble_eatt_connect: Connection collision for handle %d\n" ,
711
+ conn_handle );
656
712
return BLE_HS_EALREADY ;
713
+ }
714
+
715
+ /*
657
716
* Warn about exceeding the number
658
717
* of maximum per-conn EATT connections.
659
718
*/
0 commit comments