pkg/nimble/netif: fix randomized conn intervals

This commit is contained in:
Hauke Petersen 2021-07-01 09:36:32 +02:00
parent c5a1012695
commit 46f6bf1987
3 changed files with 41 additions and 54 deletions

View File

@ -42,6 +42,7 @@ extern "C" {
typedef struct { typedef struct {
struct ble_l2cap_chan *coc; /**< l2cap context as exposed by NimBLE */ struct ble_l2cap_chan *coc; /**< l2cap context as exposed by NimBLE */
uint16_t gaphandle; /**< GAP handle exposed by NimBLE */ uint16_t gaphandle; /**< GAP handle exposed by NimBLE */
uint16_t itvl; /**< currently used connection interval */
uint16_t state; /**< the current state of the context */ uint16_t state; /**< the current state of the context */
uint8_t addr[BLE_ADDR_LEN]; /**< BLE address of connected peer uint8_t addr[BLE_ADDR_LEN]; /**< BLE address of connected peer
(in network byte order) */ (in network byte order) */
@ -181,10 +182,10 @@ void nimble_netif_conn_free(int handle, uint8_t *addr);
* *
* @param[in] handle connection handle * @param[in] handle connection handle
* *
* @return used connection interval on success, multiples of 1.25ms * @return used connection interval in milliseconds on success
* @return 0 if unable to get connection interval * @return 0 if unable to get connection interval
*/ */
uint16_t nimble_netif_conn_get_itvl(int handle); uint16_t nimble_netif_conn_get_itvl_ms(int handle);
/** /**
* @brief Check if the given connection interval is used, taking the minimal * @brief Check if the given connection interval is used, taking the minimal
@ -200,17 +201,6 @@ uint16_t nimble_netif_conn_get_itvl(int handle);
*/ */
bool nimble_netif_conn_itvl_used(uint16_t itvl, int skip_handle); bool nimble_netif_conn_itvl_used(uint16_t itvl, int skip_handle);
/**
* @brief Check if connection interval used by the given connection is valid
*
* @param[in] handle connection to verify
*
* @return true if the connection interval of the given connection collides
* with the connection interval of another BLE connection
* @return false if the connection interval of the given connection is valid
*/
bool nimble_netif_conn_itvl_invalid(int handle);
/** /**
* @brief Generate a pseudorandom connection interval from the given range * @brief Generate a pseudorandom connection interval from the given range
* *

View File

@ -364,20 +364,32 @@ static int _on_l2cap_server_evt(struct ble_l2cap_event *event, void *arg)
conn = nimble_netif_conn_get(handle); conn = nimble_netif_conn_get(handle);
assert(conn); assert(conn);
/* in the unlikely event the L2CAP connection establishment fails,
* we close the GAP connection */
if (event->connect.status != 0) { if (event->connect.status != 0) {
/* in the unlikely event the L2CAP connection establishment
* fails, we close the GAP connection */
ble_gap_terminate(conn->gaphandle, BLE_ERR_REM_USER_CONN_TERM); ble_gap_terminate(conn->gaphandle, BLE_ERR_REM_USER_CONN_TERM);
break; break;
} }
/* we need to update the state to keep everything in sync */
conn->coc = event->connect.chan; conn->coc = event->connect.chan;
conn->state |= NIMBLE_NETIF_L2CAP_SERVER; conn->state |= NIMBLE_NETIF_L2CAP_SERVER;
conn->state &= ~(NIMBLE_NETIF_ADV | NIMBLE_NETIF_CONNECTING); conn->state &= ~(NIMBLE_NETIF_ADV | NIMBLE_NETIF_CONNECTING);
/* in case conn itvl spacing is enabled, make sure that the conn
* itvl of the new connection is sufficiently spaced */
if ((NIMBLE_NETIF_CONN_ITVL_SPACING > 0) &&
nimble_netif_conn_itvl_used(conn->itvl, handle)) {
ble_gap_terminate(conn->gaphandle, BLE_ERR_REM_USER_CONN_TERM);
break;
}
_notify(handle, NIMBLE_NETIF_CONNECTED_SLAVE, conn->addr); _notify(handle, NIMBLE_NETIF_CONNECTED_SLAVE, conn->addr);
break; break;
case BLE_L2CAP_EVENT_COC_DISCONNECTED: case BLE_L2CAP_EVENT_COC_DISCONNECTED:
conn = nimble_netif_conn_from_gaphandle(event->disconnect.conn_handle); conn = nimble_netif_conn_from_gaphandle(event->disconnect.conn_handle);
assert(conn && (conn->state & NIMBLE_NETIF_L2CAP_SERVER)); assert(conn && (conn->state & NIMBLE_NETIF_L2CAP_SERVER));
conn->coc = NULL;
conn->state &= ~NIMBLE_NETIF_L2CAP_CONNECTED; conn->state &= ~NIMBLE_NETIF_L2CAP_CONNECTED;
break; break;
case BLE_L2CAP_EVENT_COC_ACCEPT: { case BLE_L2CAP_EVENT_COC_ACCEPT: {
@ -411,9 +423,21 @@ static void _on_gap_connected(nimble_netif_conn_t *conn, uint16_t conn_handle)
(void)res; (void)res;
conn->gaphandle = conn_handle; conn->gaphandle = conn_handle;
conn->itvl = desc.conn_itvl;
bluetil_addr_swapped_cp(desc.peer_id_addr.val, conn->addr); bluetil_addr_swapped_cp(desc.peer_id_addr.val, conn->addr);
} }
static void _on_gap_param_update(int handle, nimble_netif_conn_t *conn)
{
struct ble_gap_conn_desc desc;
int res = ble_gap_conn_find(conn->gaphandle, &desc);
assert(res == 0) ;
(void)res;
conn->itvl = desc.conn_itvl;
_notify(handle, NIMBLE_NETIF_CONN_UPDATED, conn->addr);
}
static int _on_gap_master_evt(struct ble_gap_event *event, void *arg) static int _on_gap_master_evt(struct ble_gap_event *event, void *arg)
{ {
int res = 0; int res = 0;
@ -458,7 +482,7 @@ static int _on_gap_master_evt(struct ble_gap_event *event, void *arg)
break; break;
} }
case BLE_GAP_EVENT_CONN_UPDATE: case BLE_GAP_EVENT_CONN_UPDATE:
_notify(handle, NIMBLE_NETIF_CONN_UPDATED, conn->addr); _on_gap_param_update(handle, conn);
break; break;
case BLE_GAP_EVENT_CONN_UPDATE_REQ: case BLE_GAP_EVENT_CONN_UPDATE_REQ:
case BLE_GAP_EVENT_MTU: case BLE_GAP_EVENT_MTU:
@ -485,11 +509,6 @@ static int _on_gap_slave_evt(struct ble_gap_event *event, void *arg)
_notify(handle, NIMBLE_NETIF_ABORT_SLAVE, addr); _notify(handle, NIMBLE_NETIF_ABORT_SLAVE, addr);
break; break;
} }
if ((NIMBLE_NETIF_CONN_ITVL_SPACING > 0) &&
nimble_netif_conn_itvl_invalid(handle)) {
nimble_netif_close(handle);
break;
}
_on_gap_connected(conn, event->connect.conn_handle); _on_gap_connected(conn, event->connect.conn_handle);
assert(conn->state == NIMBLE_NETIF_ADV); assert(conn->state == NIMBLE_NETIF_ADV);
conn->state = NIMBLE_NETIF_GAP_SLAVE; conn->state = NIMBLE_NETIF_GAP_SLAVE;
@ -507,7 +526,7 @@ static int _on_gap_slave_evt(struct ble_gap_event *event, void *arg)
break; break;
} }
case BLE_GAP_EVENT_CONN_UPDATE: case BLE_GAP_EVENT_CONN_UPDATE:
_notify(handle, NIMBLE_NETIF_CONN_UPDATED, conn->addr); _on_gap_param_update(handle, conn);
break; break;
case BLE_GAP_EVENT_CONN_UPDATE_REQ: case BLE_GAP_EVENT_CONN_UPDATE_REQ:
/* nothing to do here */ /* nothing to do here */

View File

@ -222,33 +222,24 @@ unsigned nimble_netif_conn_count(uint16_t filter)
return cnt; return cnt;
} }
uint16_t nimble_netif_conn_get_itvl(int handle) uint16_t nimble_netif_conn_get_itvl_ms(int handle)
{ {
assert((handle >= 0) && (handle < CONN_CNT)); if ((handle == 0) || (handle >= CONN_CNT)) {
struct ble_gap_conn_desc desc;
if (!(_conn[handle].state & NIMBLE_NETIF_GAP_CONNECTED)) {
return 0;
}
int res = ble_gap_conn_find(_conn[handle].gaphandle, &desc);
if (res != 0) {
return 0; return 0;
} }
return desc.conn_itvl; return ((_conn[handle].itvl * BLE_HCI_CONN_ITVL) / 1000);
} }
bool nimble_netif_conn_itvl_used(uint16_t itvl, int skip_handle) bool nimble_netif_conn_itvl_used(uint16_t itvl, int skip_handle)
{ {
for (unsigned i = 0; i < CONN_CNT; i++) { for (int handle = 0; handle < CONN_CNT; handle++) {
if (i != skip_handle) { if ((handle != skip_handle) && (_conn[handle].itvl != 0)) {
uint16_t conn_itvl = nimble_netif_conn_get_itvl(i); uint16_t diff = (_conn[handle].itvl < itvl)
if (conn_itvl != 0) { ? itvl - _conn[handle].itvl
uint16_t diff = (conn_itvl < itvl) ? itvl - conn_itvl : _conn[handle].itvl - itvl;
: conn_itvl - itvl; if (diff < NIMBLE_NETIF_CONN_ITVL_SPACING) {
if (diff < NIMBLE_NETIF_CONN_ITVL_SPACING) { return true;
return true;
}
} }
} }
} }
@ -256,19 +247,6 @@ bool nimble_netif_conn_itvl_used(uint16_t itvl, int skip_handle)
return false; return false;
} }
bool nimble_netif_conn_itvl_invalid(int handle)
{
if (NIMBLE_NETIF_CONN_ITVL_SPACING == 0) {
return false;
}
uint16_t to_check = nimble_netif_conn_get_itvl(handle);
if (to_check == 0) {
return false;
}
return nimble_netif_conn_itvl_used(to_check, handle);
}
uint16_t nimble_netif_conn_gen_itvl(uint16_t min, uint16_t max) uint16_t nimble_netif_conn_gen_itvl(uint16_t min, uint16_t max)
{ {
assert(min <= max); assert(min <= max);