|
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 |
|
203 | 210 | #if (MYNEWT_VAL(BLE_EATT_AUTO_CONNECT)) |
204 | 211 | void |
@@ -232,7 +239,7 @@ ble_eatt_alloc(void) |
232 | 239 | eatt->used_channels = 0; |
233 | 240 |
|
234 | 241 | STAILQ_INIT(&eatt->eatt_tx_q); |
235 | | - |
| 242 | + os_callout_init(&eatt->collision_co, os_eventq_dflt_get(), |
236 | 243 | #if (MYNEWT_VAL(BLE_EATT_AUTO_CONNECT)) |
237 | 244 | os_callout_init(&eatt->auto_conn_delay, os_eventq_dflt_get(), |
238 | 245 | ble_eatt_auto_conn_cb, NULL); |
@@ -262,25 +269,49 @@ ble_eatt_l2cap_event_fn(struct ble_l2cap_event *event, void *arg) |
262 | 269 | { |
263 | 270 | struct ble_eatt *eatt = arg; |
264 | 271 | struct ble_gap_conn_desc desc; |
265 | | - uint8_t free_channels; |
266 | 272 | uint8_t opcode; |
| 273 | + uint8_t free_channels; |
| 274 | + uint8_t coll_delay; |
| 275 | + uint8_t rand_part; |
267 | 276 | int rc; |
268 | 277 |
|
269 | 278 | switch (event->type) { |
270 | 279 | case BLE_L2CAP_EVENT_COC_CONNECTED: |
271 | 280 | eatt = ble_eatt_find_by_conn_handle(event->connect.conn_handle); |
| 281 | + |
272 | 282 | BLE_EATT_LOG_DEBUG("eatt: Connected event | conn_handle: %d | scid: %d | dcid: %d\n", |
273 | 283 | event->connect.conn_handle, event->connect.chan->scid, |
274 | 284 | event->connect.chan->dcid); |
275 | 285 |
|
| 286 | + if (event->connect.status == BLE_HS_ENOMEM && eatt->collision_ctrl) { |
| 287 | + BLE_EATT_LOG_DEBUG("eatt: Connection collision\n"); |
| 288 | + |
| 289 | + rc = ble_gap_conn_find(event->connect.conn_handle, &desc); |
| 290 | + assert(rc == 0); |
| 291 | + |
| 292 | + rc = ble_hs_hci_rand(&rand_part, 1); |
| 293 | + if (rc != 0) { |
| 294 | + return rc; |
| 295 | + } |
| 296 | + |
| 297 | + coll_delay = (rand_part % 5) + 2 * (desc.conn_latency + 1) * desc.conn_itvl; |
| 298 | + |
| 299 | + os_callout_reset(&eatt->collision_co, OS_TICKS_PER_SEC / 1000 * coll_delay); |
| 300 | + |
| 301 | + return 0; |
| 302 | + } |
| 303 | + |
276 | 304 | if (event->connect.status) { |
277 | | - ble_eatt_free(eatt); |
| 305 | + eatt->used_channels--; |
278 | 306 | return 0; |
279 | 307 | } |
280 | 308 |
|
281 | 309 | eatt->chan = event->connect.chan; |
282 | 310 | eatt->conn_handle = event->connect.conn_handle; |
283 | 311 |
|
| 312 | + /* Delete collision callout on successfull connection */ |
| 313 | + os_callout_stop(&eatt->collision_co); |
| 314 | + eatt->collision_ctrl = false; |
284 | 315 |
|
285 | 316 | /* Increase used channel number on connected event */ |
286 | 317 | eatt->used_channels++; |
@@ -320,7 +351,7 @@ ble_eatt_l2cap_event_fn(struct ble_l2cap_event *event, void *arg) |
320 | 351 |
|
321 | 352 | if (free_channels == 0) { |
322 | 353 | BLE_EATT_LOG_ERROR("eatt: Accept event | No free channel slots\n"); |
323 | | - eatt->no_res_error = BLE_L2CAP_COC_ERR_NO_RESOURCES; |
| 354 | + eatt->collision_ctrl = true; |
324 | 355 | return BLE_HS_ENOMEM; |
325 | 356 | } |
326 | 357 | } |
@@ -659,9 +690,16 @@ ble_eatt_connect(uint16_t conn_handle, uint8_t chan_num) |
659 | 690 | } |
660 | 691 |
|
661 | 692 | /* |
662 | | - * Warn about exceeding the number |
663 | | - * of maximum per-conn EATT connections. |
| 693 | + * 5.3 Vol 3, Part G, Sec. 5.4 L2CAP collision mitigation |
| 694 | + * Peripheral shall wait some time before retrying connection. |
| 695 | + * Central may reconnect without any delay. |
| 696 | + * To reconnect user has to call ble_eatt_connect again. |
664 | 697 | */ |
| 698 | + if (desc.role == BLE_GAP_ROLE_SLAVE && os_callout_queued(&eatt->collision_co)) { |
| 699 | + BLE_EATT_LOG_WARN("ble_eatt_connect: Connection collision\n"); |
| 700 | + return; |
| 701 | + } |
| 702 | + |
665 | 703 | if (chan_num == 0 || chan_num > MYNEWT_VAL(BLE_EATT_CHAN_PER_CONN)) { |
666 | 704 | BLE_EATT_LOG_WARN("ble_eatt_connect | Invalid channel number\n"); |
667 | 705 | return; |
|
0 commit comments