|
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