1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

pkg/nimble/netif: use random connection intervals

This commit is contained in:
Hauke Petersen 2021-04-21 20:33:41 +02:00
parent 4d6d46534d
commit 402bd20ec9
5 changed files with 192 additions and 3 deletions

View File

@ -68,6 +68,7 @@ endif
ifneq (,$(filter nimble_netif,$(USEMODULE)))
FEATURES_REQUIRED += ble_nimble_netif
USEMODULE += random
USEMODULE += l2util
USEMODULE += bluetil_addr
ifneq (,$(filter gnrc_ipv6_%,$(USEMODULE)))

View File

@ -102,6 +102,37 @@ extern "C" {
#define NIMBLE_NETIF_MTU (1280U)
#endif
/**
* @brief Set to > 0 to enforce different connection intervals for each of the
* nodes BLE connections
*
* Enabling this option will enforce that every BLE connection a node maintains,
* independent of the nodes role, uses a different connection interval. The
* value of NIMBLE_NETIF_CONN_ITVL_SPACING specifies the minimum spacing between
* connection intervals as multiple of 1,25ms. E.g. a value of 2 will force each
* connection to use a connection interval that is at least 2.5ms different from
* all other used connection intervals.
*
* If a node is the coordinator of a connection, it will generate a connection
* interval for each new connection based on a random value by adhering to the
* spacing constraint.
*
* If a node is the subordinate of a new connection, it will check if the given
* connection interval is fulfilling the spacing constraint with respect to
* already existing connections of that node. If the connection interval of the
* new connection is not properly spaced, the node will drop the connection
* right away, giving the coordinator node the possibly to reconnect with a
* different connection interval.
*/
#ifndef NIMBLE_NETIF_CONN_ITVL_SPACING
#define NIMBLE_NETIF_CONN_ITVL_SPACING 0
#endif
/**
* @brief Minimum spacing of connection interval when using randomized
* intervals, in multiples of 1.25ms
*/
/**
* @brief Return codes used by the NimBLE netif module
*/
@ -183,16 +214,18 @@ void nimble_netif_eventcb(nimble_netif_eventcb_t cb);
*
* @param[in] addr address of the advertising BLE slave, in the NimBLE
* addr format (little endian)
* @param[in] conn_params connection (timing) parameters
* @param[in] conn_params connection (timing) parameters, set to NULL to use
* NimBLEs default parameters
* @param[in] timeout connect timeout [in ms]
*
* @return the used connection handle on success
* @return NIMBLE_NETIF_BUSY if already connected to the given address or if
* a connection setup procedure is in progress
* @return NIMBLE_NETIF_NOMEM if no connection context memory is available
* @return NIMBLE_NETIF_NOTFOUND if unable to find valid connection interval
*/
int nimble_netif_connect(const ble_addr_t *addr,
const struct ble_gap_conn_params *conn_params,
struct ble_gap_conn_params *conn_params,
uint32_t timeout);
/**

View File

@ -23,6 +23,7 @@
#define NIMBLE_NETIF_CONN_H
#include <stdint.h>
#include <stdbool.h>
#include "nimble_netif.h"
@ -175,6 +176,57 @@ int nimble_netif_conn_start_adv(void);
*/
void nimble_netif_conn_free(int handle, uint8_t *addr);
/**
* @brief Get the used connection interval for the given connection handle
*
* @param[in] handle connection handle
*
* @return used connection interval on success, multiples of 1.25ms
* @return 0 if unable to get connection interval
*/
uint16_t nimble_netif_conn_get_itvl(int handle);
/**
* @brief Check if the given connection interval is used, taking the minimal
* spacing as defined by NIMBLE_NETIF_CONN_ITVL_SPACING into account
*
* @param[in] itvl connection interval to check, multiples of 1.25ms
* @param[in] skip_handle do not compare against connection interval for this
* handle, set to NIMBLE_NETIF_CONN_INVALID to check
* all
*
* @return true if given interval is used
* @return false if given interval is not used
*/
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
*
* If the NIMBLE_NETIF_CONN_ITVL_SPACING option is enabled, this function
* ensures that the generated connection interval is spaced at least
* NIMBLE_NETIF_CONN_ITVL_SPACING from the connection interval of each open
* BLE connection.
*
* @param[in] min minimum connection interval
* @param[in] max maximum connection interval
*
* @return generated connection interval on success, multiples of 1.25ms
* @return 0 if no valid connection interval could be generated
*/
uint16_t nimble_netif_conn_gen_itvl(uint16_t min, uint16_t max);
/**
* @brief Find the connection context with a given GAP handle and return a
* pointer to it

View File

@ -485,6 +485,11 @@ static int _on_gap_slave_evt(struct ble_gap_event *event, void *arg)
_notify(handle, NIMBLE_NETIF_ABORT_SLAVE, addr);
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);
assert(conn->state == NIMBLE_NETIF_ADV);
conn->state = NIMBLE_NETIF_GAP_SLAVE;
@ -537,12 +542,15 @@ void nimble_netif_eventcb(nimble_netif_eventcb_t cb)
}
int nimble_netif_connect(const ble_addr_t *addr,
const struct ble_gap_conn_params *conn_params,
struct ble_gap_conn_params *conn_params,
uint32_t timeout)
{
assert(addr);
assert(_eventcb);
uint16_t itvl_min = 0;
uint16_t itvl_max = 0;
/* the netif_conn module expects addresses in network byte order */
uint8_t addrn[BLE_ADDR_LEN];
bluetil_addr_swapped_cp(addr->val, addrn);
@ -559,11 +567,31 @@ int nimble_netif_connect(const ble_addr_t *addr,
return NIMBLE_NETIF_NOMEM;
}
if ((conn_params != NULL)
&& (conn_params->itvl_min != conn_params->itvl_max)) {
/* we need to save the min/max intervals in order to restore them
* later on */
itvl_min = conn_params->itvl_min;
itvl_max = conn_params->itvl_max;
uint16_t itvl = nimble_netif_conn_gen_itvl(itvl_min, itvl_max);
if (itvl == 0) {
return NIMBLE_NETIF_NOTFOUND;
}
conn_params->itvl_min = itvl;
conn_params->itvl_max = itvl;
}
int res = ble_gap_connect(nimble_riot_own_addr_type, addr, timeout,
conn_params, _on_gap_master_evt, (void *)handle);
assert(res == 0);
(void)res;
if (itvl_min != itvl_max) {
conn_params->itvl_min = itvl_min;
conn_params->itvl_max = itvl_max;
}
_notify(handle, NIMBLE_NETIF_INIT_MASTER, addrn);
return handle;

View File

@ -21,6 +21,7 @@
#include <assert.h>
#include "nimble_netif_conn.h"
#include "random.h"
#define ENABLE_DEBUG 0
#include "debug.h"
@ -220,3 +221,77 @@ unsigned nimble_netif_conn_count(uint16_t filter)
return cnt;
}
uint16_t nimble_netif_conn_get_itvl(int handle)
{
assert((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 desc.conn_itvl;
}
bool nimble_netif_conn_itvl_used(uint16_t itvl, int skip_handle)
{
for (unsigned i = 0; i < CONN_CNT; i++) {
if (i != skip_handle) {
uint16_t conn_itvl = nimble_netif_conn_get_itvl(i);
if (conn_itvl != 0) {
uint16_t diff = (conn_itvl < itvl) ? itvl - conn_itvl
: conn_itvl - itvl;
if (diff < NIMBLE_NETIF_CONN_ITVL_SPACING) {
return true;
}
}
}
}
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)
{
assert(min <= max);
uint16_t start = random_uint32_range(min, max);
if (NIMBLE_NETIF_CONN_ITVL_SPACING == 0) {
return start;
}
for (uint16_t itvl = start;
itvl <= max;
itvl += NIMBLE_NETIF_CONN_ITVL_SPACING) {
if (!nimble_netif_conn_itvl_used(itvl, NIMBLE_NETIF_CONN_INVALID)) {
return itvl;
}
}
for (uint16_t itvl = start - NIMBLE_NETIF_CONN_ITVL_SPACING;
itvl >= min;
itvl -= NIMBLE_NETIF_CONN_ITVL_SPACING) {
if (!nimble_netif_conn_itvl_used(itvl, NIMBLE_NETIF_CONN_INVALID)) {
return itvl;
}
}
return 0;
}