|
34 | 34 |
|
35 | 35 | struct ble_eatt { |
36 | 36 | SLIST_ENTRY(ble_eatt) next; |
37 | | - uint16_t conn_handle; |
38 | 37 | struct ble_l2cap_chan *chan; |
39 | | - uint8_t chan_num; |
40 | 38 | uint8_t used_channels; |
| 39 | + uint16_t conn_handle; |
| 40 | + bool collision_ctrl; |
41 | 41 | uint8_t client_op; |
| 42 | + uint8_t chan_num; |
42 | 43 | uint8_t accept_chans; |
43 | 44 |
|
44 | 45 | /* Packet transmit queue */ |
45 | 46 | STAILQ_HEAD(, os_mbuf_pkthdr) eatt_tx_q; |
46 | | - |
| 47 | + struct os_callout collision_co; |
47 | 48 | struct ble_npl_event setup_ev; |
48 | 49 | struct ble_npl_event wakeup_ev; |
49 | 50 |
|
@@ -147,6 +148,7 @@ ble_eatt_used_channels(uint16_t conn_handle) |
147 | 148 | struct ble_eatt *eatt; |
148 | 149 | size_t used_channels = 0; |
149 | 150 |
|
| 151 | + |
150 | 152 | SLIST_FOREACH(eatt, &g_ble_eatt_list, next) { |
151 | 153 | if (eatt->conn_handle == conn_handle) { |
152 | 154 | used_channels += eatt->used_channels; |
@@ -199,6 +201,11 @@ ble_eatt_wakeup_cb(struct ble_npl_event *ev) |
199 | 201 | } |
200 | 202 | } |
201 | 203 |
|
| 204 | +static void |
| 205 | +ble_eatt_collision_ev(struct os_event *ev) |
| 206 | +{ |
| 207 | + BLE_EATT_LOG_DEBUG("eatt: Collision delay expired\n"); |
| 208 | +} |
202 | 209 | #if (MYNEWT_VAL(BLE_EATT_AUTO_CONNECT)) |
203 | 210 | void |
204 | 211 | ble_eatt_auto_conn_cb(struct os_event *ev) |
@@ -231,7 +238,8 @@ ble_eatt_alloc(void) |
231 | 238 | eatt->used_channels = 0; |
232 | 239 |
|
233 | 240 | STAILQ_INIT(&eatt->eatt_tx_q); |
234 | | - |
| 241 | + os_callout_init(&eatt->collision_co, os_eventq_dflt_get(), |
| 242 | + ble_eatt_collision_ev, NULL); |
235 | 243 | os_callout_init(&eatt->auto_conn_delay, os_eventq_dflt_get(), |
236 | 244 | ble_eatt_auto_conn_cb, NULL); |
237 | 245 | ble_npl_event_init(&eatt->setup_ev, ble_eatt_setup_cb, eatt); |
@@ -259,25 +267,49 @@ ble_eatt_l2cap_event_fn(struct ble_l2cap_event *event, void *arg) |
259 | 267 | { |
260 | 268 | struct ble_eatt *eatt = arg; |
261 | 269 | struct ble_gap_conn_desc desc; |
262 | | - uint8_t free_channels; |
263 | 270 | uint8_t opcode; |
| 271 | + uint8_t free_channels; |
| 272 | + uint8_t coll_delay; |
| 273 | + uint8_t rand_part; |
264 | 274 | int rc; |
265 | 275 |
|
266 | 276 | switch (event->type) { |
267 | 277 | case BLE_L2CAP_EVENT_COC_CONNECTED: |
268 | 278 | eatt = ble_eatt_find_by_conn_handle(event->connect.conn_handle); |
| 279 | + |
269 | 280 | BLE_EATT_LOG_DEBUG("eatt: Connected event | conn_handle: %d | scid: %d | dcid: %d\n", |
270 | 281 | event->connect.conn_handle, event->connect.chan->scid, |
271 | 282 | event->connect.chan->dcid); |
272 | 283 |
|
| 284 | + if (event->connect.status == BLE_HS_ENOMEM && eatt->collision_ctrl) { |
| 285 | + BLE_EATT_LOG_DEBUG("eatt: Connection collision\n"); |
| 286 | + |
| 287 | + rc = ble_gap_conn_find(event->connect.conn_handle, &desc); |
| 288 | + assert(rc == 0); |
| 289 | + |
| 290 | + rc = ble_hs_hci_rand(&rand_part, 1); |
| 291 | + if (rc != 0) { |
| 292 | + return rc; |
| 293 | + } |
| 294 | + |
| 295 | + coll_delay = (rand_part % 5) + 2 * (desc.conn_latency + 1) * desc.conn_itvl; |
| 296 | + |
| 297 | + os_callout_reset(&eatt->collision_co, OS_TICKS_PER_SEC / 1000 * coll_delay); |
| 298 | + |
| 299 | + return 0; |
| 300 | + } |
| 301 | + |
273 | 302 | if (event->connect.status) { |
274 | | - ble_eatt_free(eatt); |
| 303 | + eatt->used_channels--; |
275 | 304 | return 0; |
276 | 305 | } |
277 | 306 |
|
278 | 307 | eatt->chan = event->connect.chan; |
279 | 308 | eatt->conn_handle = event->connect.conn_handle; |
280 | 309 |
|
| 310 | + /* Delete collision callout on successfull connection */ |
| 311 | + os_callout_stop(&eatt->collision_co); |
| 312 | + eatt->collision_ctrl = false; |
281 | 313 |
|
282 | 314 | /* Increase used channel number on connected event */ |
283 | 315 | eatt->used_channels++; |
@@ -317,7 +349,7 @@ ble_eatt_l2cap_event_fn(struct ble_l2cap_event *event, void *arg) |
317 | 349 |
|
318 | 350 | if (free_channels == 0) { |
319 | 351 | BLE_EATT_LOG_ERROR("eatt: Accept event | No free channel slots\n"); |
320 | | - eatt->no_res_error = BLE_L2CAP_COC_ERR_NO_RESOURCES; |
| 352 | + eatt->collision_ctrl = true; |
321 | 353 | return BLE_HS_ENOMEM; |
322 | 354 | } |
323 | 355 | } |
@@ -657,9 +689,16 @@ ble_eatt_connect(uint16_t conn_handle, uint8_t chan_num) |
657 | 689 | } |
658 | 690 |
|
659 | 691 | /* |
660 | | - * Warn about exceeding the number |
661 | | - * of maximum per-conn EATT connections. |
| 692 | + * 5.3 Vol 3, Part G, Sec. 5.4 L2CAP collision mitigation |
| 693 | + * Peripheral shall wait some time before retrying connection. |
| 694 | + * Central may reconnect without any delay. |
| 695 | + * To reconnect user has to call ble_eatt_connect again. |
662 | 696 | */ |
| 697 | + if (desc.role == BLE_GAP_ROLE_SLAVE && os_callout_queued(&eatt->collision_co)) { |
| 698 | + BLE_EATT_LOG_WARN("ble_eatt_connect: Connection collision\n"); |
| 699 | + return; |
| 700 | + } |
| 701 | + |
663 | 702 | if (chan_num == 0 || chan_num > MYNEWT_VAL(BLE_EATT_CHAN_PER_CONN)) { |
664 | 703 | BLE_EATT_LOG_WARN("ble_eatt_connect | Invalid channel number\n"); |
665 | 704 | return; |
|
0 commit comments