mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-26 06:53:52 +01:00
pkg/nimble: add netif wrapper
This commit is contained in:
parent
1cb54659c3
commit
6bbe16601a
@ -71,6 +71,9 @@ nimble_drivers_nrf5x:
|
||||
nimble_addr:
|
||||
"$(MAKE)" -C $(TDIR)/addr/
|
||||
|
||||
nimble_netif:
|
||||
"$(MAKE)" -C $(TDIR)/netif/
|
||||
|
||||
nimble_scanlist:
|
||||
"$(MAKE)" -C $(TDIR)/scanlist
|
||||
|
||||
|
||||
@ -34,6 +34,7 @@ ifneq (,$(filter nimble_controller,$(USEMODULE)))
|
||||
endif
|
||||
endif
|
||||
|
||||
# RIOT specific submodule dependencies
|
||||
ifneq (,$(filter nimble_addr,$(USEMODULE)))
|
||||
USEMODULE += bluetil_addr
|
||||
endif
|
||||
@ -42,3 +43,21 @@ ifneq (,$(filter nimble_scanlist,$(USEMODULE)))
|
||||
USEMODULE += nimble_addr
|
||||
USEMODULE += bluetil_ad
|
||||
endif
|
||||
|
||||
ifneq (,$(filter nimble_netif,$(USEMODULE)))
|
||||
USEMODULE += l2util
|
||||
USEMODULE += bluetil_addr
|
||||
ifneq (,$(filter gnrc_ipv6_%,$(USEMODULE)))
|
||||
USEMODULE += nimble_svc_ipss
|
||||
endif
|
||||
ifneq (,$(filter gnrc_ipv6_router_default,$(USEMODULE)))
|
||||
USEMODULE += gnrc_ipv6_nib_6lr
|
||||
USEMODULE += gnrc_sixlowpan
|
||||
USEMODULE += gnrc_sixlowpan_iphc
|
||||
endif
|
||||
ifneq (,$(filter gnrc_ipv6_default,$(USEMODULE)))
|
||||
USEMODULE += gnrc_ipv6_nib_6ln
|
||||
USEMODULE += gnrc_sixlowpan
|
||||
USEMODULE += gnrc_sixlowpan_iphc
|
||||
endif
|
||||
endif
|
||||
|
||||
@ -76,6 +76,18 @@ endif
|
||||
ifneq (,$(filter nimble_addr,$(USEMODULE)))
|
||||
INCLUDES += -I$(RIOTPKG)/nimble/addr/include
|
||||
endif
|
||||
ifneq (,$(filter nimble_netif,$(USEMODULE)))
|
||||
INCLUDES += -I$(RIOTPKG)/nimble/netif/include
|
||||
|
||||
# configure NimBLE's internals
|
||||
NIMBLE_MAX_CONN ?= 3
|
||||
CFLAGS += -DMYNEWT_VAL_MSYS_1_BLOCK_SIZE=264
|
||||
CFLAGS += -DMYNEWT_VAL_BLE_L2CAP_COC_MAX_NUM=$(NIMBLE_MAX_CONN)
|
||||
CFLAGS += -DMYNEWT_VAL_BLE_MAX_CONNECTIONS=$(NIMBLE_MAX_CONN)
|
||||
# NimBLEs internal buffer need to hold one IPv6 MTU per connection
|
||||
# for the internal MTU of 256 byte, we need 10 mbufs per connection...
|
||||
CFLAGS += -DMYNEWT_VAL_MSYS_1_BLOCK_COUNT=35
|
||||
endif
|
||||
ifneq (,$(filter nimble_scanlist,$(USEMODULE)))
|
||||
INCLUDES += -I$(RIOTPKG)/nimble/scanlist/include
|
||||
endif
|
||||
|
||||
@ -100,6 +100,11 @@ void nimble_riot_init(void)
|
||||
assert(res == 0);
|
||||
(void)res;
|
||||
|
||||
#ifdef MODULE_NIMBLE_NETIF
|
||||
extern void nimble_netif_init(void);
|
||||
nimble_netif_init();
|
||||
#endif
|
||||
|
||||
/* initialize the configured, build-in services */
|
||||
#ifdef MODULE_NIMBLE_SVC_GAP
|
||||
ble_svc_gap_init();
|
||||
|
||||
3
pkg/nimble/netif/Makefile
Normal file
3
pkg/nimble/netif/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = nimble_netif
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
232
pkg/nimble/netif/include/nimble_netif.h
Normal file
232
pkg/nimble/netif/include/nimble_netif.h
Normal file
@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2019 Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup pkg_nimble_netif GNRC netif Implementation
|
||||
* @ingroup ble_nimble
|
||||
* @brief GNRC netif implementation for NimBLE, enabling the integration
|
||||
* of NimBLE into GNRC
|
||||
*
|
||||
* # About
|
||||
* This NimBLE submodule provides a GNRC netif wrapper for integrating NimBLE
|
||||
* with GNRC and other network stacks using netif (e.g. CCNlite).
|
||||
*
|
||||
* # Concept
|
||||
* According to the IPv6-over-BLE standards (RFC7668 and IPSP), this module
|
||||
* exposes a (configurable) number of point-to-point BLE connections as a single
|
||||
* network device to BLE. Unicast traffic is only send using the corresponding
|
||||
* BLE connection. Multicast and Broadcast packets are duplicated and send via
|
||||
* each open BLE connection.
|
||||
*
|
||||
* # Structure
|
||||
* The netif implementation is able to handle multiple connections
|
||||
* simultaneously. The maximum number of concurrent connections is configured
|
||||
* during compile time, using NimBLEs MYNEWT_VAL_BLE_MAX_CONNECTIONS option.
|
||||
* Dependent on this value, the netif implementation takes care of allocation
|
||||
* all the memory needed. The API of this submodule uses simply integer values
|
||||
* to reference the used connection context (like file descriptors in linux).
|
||||
*
|
||||
* Like any other GNRC network device, the NimBLE netif wrapper runs in its own
|
||||
* thread. This thread is started and configured by the common netif code. All
|
||||
* send and get/set operations are handled by this thread. For efficiency
|
||||
* reasons, receiving of data is however handled completely in the NimBLE host
|
||||
* thread, from where the received data is directly passed on to the
|
||||
* corresponding GNRC thread.
|
||||
*
|
||||
* Although the wrapper hooks into GNRC using the netif interface, it does need
|
||||
* to implement parts of the netdev interface as well. This is done where
|
||||
* needed.
|
||||
*
|
||||
* # Usage
|
||||
* This submodule is designed to work fully asynchronous, in the same way as the
|
||||
* NimBLE interfaces are designed. All functions in this submodule will only
|
||||
* trigger the intended action. Once this action is complete, the module will
|
||||
* report the result asynchronously using the configured callback.
|
||||
*
|
||||
* So before using this module, make sure to register a callback using the
|
||||
* @ref nimble_netif_eventcb() function.
|
||||
*
|
||||
* After this, this module provides functions for managing BLE connections to
|
||||
* other devices. Once these connections are established, this module takes care
|
||||
* of mapping IP packets to the corresponding connections.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief GNRC netif implementation for NimBLE
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*/
|
||||
|
||||
#ifndef NIMBLE_NETIF_H
|
||||
#define NIMBLE_NETIF_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "net/ble.h"
|
||||
|
||||
#include "host/ble_hs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Default L2CAP channel ID to use
|
||||
*/
|
||||
#ifndef NIMBLE_NETIF_CID
|
||||
#define NIMBLE_NETIF_CID (BLE_L2CAP_CID_IPSP)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Default MTU size supported by the NimBLE netif wrapper
|
||||
*/
|
||||
/* NOTE: We do not use the @ref IPV6_MIN_MTU define here, as the iov6.h header
|
||||
pulls in some other RIOT headers that clash with NimBLE header (e.g.
|
||||
* byteorder.h vs. endian.h) */
|
||||
#ifndef NIMBLE_NETIF_MTU
|
||||
#define NIMBLE_NETIF_MTU (1280U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Return codes used by the NimBLE netif module
|
||||
*/
|
||||
enum {
|
||||
NIMBLE_NETIF_OK = 0, /**< everything went fine */
|
||||
NIMBLE_NETIF_NOTCONN = -1, /**< not connected */
|
||||
NIMBLE_NETIF_DEVERR = -2, /**< internal BLE stack error */
|
||||
NIMBLE_NETIF_BUSY = -3, /**< network device is busy */
|
||||
NIMBLE_NETIF_NOMEM = -4, /**< insufficient memory */
|
||||
NIMBLE_NETIF_NOTADV = -5, /**< not advertising */
|
||||
NIMBLE_NETIF_NOTFOUND = -6, /**< no fitting entry found */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Event types triggered by the NimBLE netif module
|
||||
*/
|
||||
typedef enum {
|
||||
NIMBLE_NETIF_CONNECTED_MASTER, /**< connection established as master */
|
||||
NIMBLE_NETIF_CONNECTED_SLAVE, /**< connection established as slave */
|
||||
NIMBLE_NETIF_CLOSED_MASTER, /**< connection closed (we were master) */
|
||||
NIMBLE_NETIF_CLOSED_SLAVE, /**< connection closed (we were slave) */
|
||||
NIMBLE_NETIF_CONNECT_ABORT, /**< connection establishment aborted */
|
||||
NIMBLE_NETIF_CONN_UPDATED, /**< connection parameter update done */
|
||||
} nimble_netif_event_t;
|
||||
|
||||
/**
|
||||
* @brief Flags describing the state of a single connection context
|
||||
*/
|
||||
enum {
|
||||
NIMBLE_NETIF_L2CAP_CLIENT = 0x0001, /**< L2CAP client */
|
||||
NIMBLE_NETIF_L2CAP_SERVER = 0x0002, /**< L2CAP server */
|
||||
NIMBLE_NETIF_L2CAP_CONNECTED = 0x0003, /**< L2CAP is connected */
|
||||
NIMBLE_NETIF_GAP_MASTER = 0x0010, /**< GAP master */
|
||||
NIMBLE_NETIF_GAP_SLAVE = 0x0020, /**< GAP slave */
|
||||
NIMBLE_NETIF_GAP_CONNECTED = 0x0030, /**< GAP is connected */
|
||||
NIMBLE_NETIF_ADV = 0x0100, /**< currently advertising */
|
||||
NIMBLE_NETIF_CONNECTING = 0x4000, /**< connection in progress */
|
||||
NIMBLE_NETIF_UNUSED = 0x8000, /**< context unused */
|
||||
NIMBLE_NETIF_ANY = 0xffff, /**< match any state */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Event callback signature used for asynchronous event signaling
|
||||
*
|
||||
* @note The event callback is always executed in NimBLE's host thread
|
||||
*
|
||||
* @param[in] handle handle to the connection that triggered the event
|
||||
* @param[in] event type of the event
|
||||
*/
|
||||
typedef void(*nimble_netif_eventcb_t)(int handle, nimble_netif_event_t event);
|
||||
|
||||
/**
|
||||
* @brief Initialize the netif implementation, spawns the netif thread
|
||||
*
|
||||
* This function is meant to be called once during system initialization, i.e.
|
||||
* auto-init.
|
||||
*/
|
||||
void nimble_netif_init(void);
|
||||
|
||||
/**
|
||||
* @brief Register a global event callback, servicing all NimBLE connections
|
||||
*
|
||||
* @note The event callback is always executed in NimBLE's host thread
|
||||
*
|
||||
* @param[in] cb event callback to register, may be NULL
|
||||
*/
|
||||
void nimble_netif_eventcb(nimble_netif_eventcb_t cb);
|
||||
|
||||
/**
|
||||
* @brief Open a BLE connection as BLE master
|
||||
*
|
||||
* @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] timeout connect timeout
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
int nimble_netif_connect(const ble_addr_t *addr,
|
||||
const struct ble_gap_conn_params *conn_params,
|
||||
uint32_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Close the connection with the given handle
|
||||
*
|
||||
* @param[in] handle handle for the connection to be closed
|
||||
*
|
||||
* @return NIMBLE_NETIF_OK on success
|
||||
* @return NIMBLE_NETIF_NOTFOUND if the handle is invalid
|
||||
* @return NIMBLE_NETIF_NOTCONN if context for given handle is not connected
|
||||
*/
|
||||
int nimble_netif_close(int handle);
|
||||
|
||||
/**
|
||||
* @brief Accept incoming connections by starting to advertise this node
|
||||
*
|
||||
* @param[in] ad advertising data (in BLE AD format)
|
||||
* @param[in] ad_len length of @p ad in bytes
|
||||
* @param[in] adv_params advertising (timing) parameters to use
|
||||
*
|
||||
* @return NIMBLE_NETIF_OK on success
|
||||
* @return NIMBLE_NETIF_BUSY if already advertising
|
||||
* @return NIMBLE_NETIF_NOMEM on insufficient connection memory
|
||||
*/
|
||||
int nimble_netif_accept(const uint8_t *ad, size_t ad_len,
|
||||
const struct ble_gap_adv_params *adv_params);
|
||||
|
||||
/**
|
||||
* @brief Stop accepting incoming connections (stop advertising)
|
||||
* *
|
||||
* @return NIMBLE_NETIF_OK on success
|
||||
* @return NIMBLE_NETIF_NOTADV if not currently advertising
|
||||
*/
|
||||
int nimble_netif_accept_stop(void);
|
||||
|
||||
/**
|
||||
* @brief Update the connection parameters for the given connection
|
||||
*
|
||||
* @param[in] handle connection handle
|
||||
* @param[in] conn_params new connection parameters to apply
|
||||
*
|
||||
* @return NIMBLE_NETIF_OK on success
|
||||
* @return NIMBLE_NETIF_NOTCONN if handle does not point to a connection
|
||||
* @return NIMBLE_NETIF_DEVERR if applying the given parameters failed
|
||||
*/
|
||||
int nimble_netif_update(int handle,
|
||||
const struct ble_gap_upd_params *conn_params);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NIMBLE_NETIF_H */
|
||||
/** @} */
|
||||
223
pkg/nimble/netif/include/nimble_netif_conn.h
Normal file
223
pkg/nimble/netif/include/nimble_netif_conn.h
Normal file
@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2019 Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup pkg_nimble_netif_conn Connection State Management for netif
|
||||
* @ingroup pkg_nimble_netif
|
||||
* @brief Helper module for managing the memory needed to store the
|
||||
* BLE connection state for the netif wrapper
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Connection allocation and maintenance for NimBLE netif
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*/
|
||||
|
||||
#ifndef NIMBLE_NETIF_CONN_H
|
||||
#define NIMBLE_NETIF_CONN_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "nimble_netif.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Value for marking a handle invalid
|
||||
*/
|
||||
#define NIMBLE_NETIF_CONN_INVALID (-1)
|
||||
|
||||
/**
|
||||
* @brief Memory layout for holding the relevant connection information
|
||||
*/
|
||||
typedef struct {
|
||||
struct ble_l2cap_chan *coc; /**< l2cap context as exposed by NimBLE */
|
||||
uint16_t gaphandle; /**< GAP handle exposed by NimBLE */
|
||||
uint16_t state; /**< the current state of the context */
|
||||
uint8_t addr[BLE_ADDR_LEN]; /**< BLE address of connected peer
|
||||
(in network byte order) */
|
||||
} nimble_netif_conn_t;
|
||||
|
||||
/**
|
||||
* @brief Iterator function signature used by @ref nimble_netif_conn_foreach()
|
||||
*
|
||||
* @param[in] conn connection context of the current entry
|
||||
* @param[in] handle handle of the current entry
|
||||
* @param[in] arg user supplied argument
|
||||
*
|
||||
* @return 0 to continue
|
||||
* @return != 0 to stop iterating
|
||||
*/
|
||||
typedef int (*nimble_netif_conn_iter_t)(nimble_netif_conn_t *conn,
|
||||
int handle, void *arg);
|
||||
|
||||
/**
|
||||
* @brief Initialize the connection state manager
|
||||
*
|
||||
* This functions is typically called by @ref nimble_netif_init().
|
||||
*/
|
||||
void nimble_netif_conn_init(void);
|
||||
|
||||
/**
|
||||
* @brief Get the connection context corresponding to the given handle
|
||||
*
|
||||
* @param[in] handle handle to a connection context
|
||||
*
|
||||
* @return pointer to the corresponding connection context
|
||||
* @return NULL if handle in invalid
|
||||
*/
|
||||
nimble_netif_conn_t *nimble_netif_conn_get(int handle);
|
||||
|
||||
/**
|
||||
* @brief Get the handle to the context that is currently advertising
|
||||
*
|
||||
* @return handle to the currently advertising context
|
||||
* @return NIMBLE_NETIF_CONN_INVALID if not advertising
|
||||
*/
|
||||
int nimble_netif_conn_get_adv(void);
|
||||
|
||||
/**
|
||||
* @brief Get the handle to the context that is busy connecting
|
||||
*
|
||||
* @return handle to the busy context
|
||||
* @return NIMBLE_NETIF_CONN_INVALID if not busy connecting
|
||||
*/
|
||||
int nimble_netif_conn_get_connecting(void);
|
||||
|
||||
/**
|
||||
* @brief Find the connection to the peer with the given BLE address
|
||||
*
|
||||
* @param[in] addr BLE address, in network byte order
|
||||
*
|
||||
* @return handle to the matching connection context
|
||||
* @return NIMBLE_NETIF_CONN_INVALID if no matching connection was found
|
||||
*/
|
||||
int nimble_netif_conn_get_by_addr(const uint8_t *addr);
|
||||
|
||||
/**
|
||||
* @brief Find the connection using the given NimBLE GAP handle
|
||||
*
|
||||
* @param[in] gaphandle GAP handle as exposed by NimBLE
|
||||
*
|
||||
* @return handle to the matching connection context
|
||||
* @return NIMBLE_NETIF_CONN_INVALID if no matching connection was found
|
||||
*/
|
||||
int nimble_netif_conn_get_by_gaphandle(uint16_t gaphandle);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Iterate over all connection contexts that match the filter condition
|
||||
*
|
||||
* @warning Do not call any other nimble_netif_conn function from within the
|
||||
* callback, this will lead to a deadlock!
|
||||
*
|
||||
* @param[in] filter filter mask
|
||||
* @param[in] cb callback called on each filtered entry
|
||||
* @param[in] arg user argument
|
||||
*/
|
||||
void nimble_netif_conn_foreach(uint16_t filter,
|
||||
nimble_netif_conn_iter_t cb, void *arg);
|
||||
|
||||
/**
|
||||
* @brief Count the number of connections contexts for which the given filter
|
||||
* applies
|
||||
*
|
||||
* @param[in] filter filter mask
|
||||
*
|
||||
* @return number of contexts for which the filter applied
|
||||
*/
|
||||
|
||||
unsigned nimble_netif_conn_count(uint16_t filter);
|
||||
|
||||
/**
|
||||
* @brief Allocate an unused context for starting a connection
|
||||
*
|
||||
* @param[in] addr the BLE address of the peer node, in network byte
|
||||
* order
|
||||
*
|
||||
* @return handle used for the new connection
|
||||
*/
|
||||
int nimble_netif_conn_start_connection(const uint8_t *addr);
|
||||
|
||||
/**
|
||||
* @brief Reserve a unused context for the purpose of accepting a new
|
||||
* connection
|
||||
*
|
||||
* @return handle of the reserved context
|
||||
* @return NIMBLE_NETIF_CONN_INVALID if no unused context was available
|
||||
*/
|
||||
int nimble_netif_conn_start_adv(void);
|
||||
|
||||
/**
|
||||
* @brief Free the connection context with the given handle
|
||||
*/
|
||||
void nimble_netif_conn_free(int handle);
|
||||
|
||||
/**
|
||||
* @brief Find the connection context with a given GAP handle and return a
|
||||
* pointer to it
|
||||
*
|
||||
* @param[in] gh GAP handle used by NimBLE
|
||||
*
|
||||
* @return Pointer to the selected context
|
||||
* @return NULL if no fitting context was found
|
||||
*/
|
||||
static inline
|
||||
nimble_netif_conn_t *nimble_netif_conn_from_gaphandle(uint16_t gh)
|
||||
{
|
||||
return nimble_netif_conn_get(nimble_netif_conn_get_by_gaphandle(gh));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convenience function to check if any context is currently in the
|
||||
* connecting state (@ref NIMBLE_NETIF_CONNECTING)
|
||||
*
|
||||
* @return != 0 if true
|
||||
* @return 0 if false
|
||||
*/
|
||||
static inline int nimble_netif_conn_connecting(void)
|
||||
{
|
||||
return (nimble_netif_conn_get_connecting() != NIMBLE_NETIF_CONN_INVALID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convenience function to check if we are currently connected to a
|
||||
* peer with the given address
|
||||
*
|
||||
* @param[in] addr BLE address, in network byte order
|
||||
*
|
||||
* @return != 0 if true
|
||||
* @return 0 if false
|
||||
*/
|
||||
static inline int nimble_netif_conn_connected(const uint8_t *addr)
|
||||
{
|
||||
return (nimble_netif_conn_get_by_addr(addr) != NIMBLE_NETIF_CONN_INVALID);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convenience function to check if any context is currently in the
|
||||
* advertising state (@ref NIMBLE_NETIF_ADV)
|
||||
*
|
||||
* @return != 0 if true
|
||||
* @return 0 if false
|
||||
*/
|
||||
static inline int nimble_netif_conn_is_adv(void)
|
||||
{
|
||||
return (nimble_netif_conn_get_adv() != NIMBLE_NETIF_CONN_INVALID);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NIMBLE_NETIF_CONN_H */
|
||||
/** @} */
|
||||
630
pkg/nimble/netif/nimble_netif.c
Normal file
630
pkg/nimble/netif/nimble_netif.c
Normal file
@ -0,0 +1,630 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2019 Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup pkg_nimble_netif
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief GNRC netif wrapper for NimBLE
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "assert.h"
|
||||
#include "thread.h"
|
||||
#include "thread_flags.h"
|
||||
|
||||
#include "net/ble.h"
|
||||
#include "net/bluetil/addr.h"
|
||||
#include "net/gnrc/netif.h"
|
||||
#include "net/gnrc/netif/hdr.h"
|
||||
#include "net/gnrc/netreg.h"
|
||||
#include "net/gnrc/pktbuf.h"
|
||||
#include "net/gnrc/nettype.h"
|
||||
|
||||
#include "nimble_netif.h"
|
||||
#include "nimble_netif_conn.h"
|
||||
#include "nimble_riot.h"
|
||||
#include "host/ble_gap.h"
|
||||
#include "host/util/util.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
#ifdef MODULE_GNRC_SIXLOWPAN
|
||||
#define NETTYPE GNRC_NETTYPE_SIXLOWPAN
|
||||
#elif defined(MODULE_GNRC_IPV6)
|
||||
#define NETTYPE GNRC_NETTYPE_IPV6
|
||||
#else
|
||||
#define NETTYPE GNRC_NETTYPE_UNDEF
|
||||
#endif
|
||||
|
||||
/* buffer configuration
|
||||
* - we need one RX and one TX buffer per connection */
|
||||
#define MTU_SIZE (NIMBLE_NETIF_MTU)
|
||||
#define MBUF_OVHD (sizeof(struct os_mbuf) + \
|
||||
sizeof(struct os_mbuf_pkthdr))
|
||||
#define MBUF_SIZE (MBUF_OVHD + MYNEWT_VAL_BLE_L2CAP_COC_MPS)
|
||||
#define MBUF_CNT (MYNEWT_VAL_BLE_MAX_CONNECTIONS * 2 * \
|
||||
((MTU_SIZE + (MBUF_SIZE - 1)) / MBUF_SIZE))
|
||||
|
||||
/* thread flag used for signaling transmit readiness */
|
||||
#define FLAG_TX_UNSTALLED (1u << 13)
|
||||
|
||||
/* allocate a stack for the netif device */
|
||||
static char _stack[THREAD_STACKSIZE_DEFAULT];
|
||||
static thread_t *_netif_thread;
|
||||
|
||||
/* keep the actual device state */
|
||||
static gnrc_netif_t *_nimble_netif = NULL;
|
||||
static gnrc_nettype_t _nettype = NETTYPE;
|
||||
|
||||
/* keep a reference to the event callback */
|
||||
static nimble_netif_eventcb_t _eventcb;
|
||||
|
||||
/* allocation of memory for buffering IP packets when handing them to NimBLE */
|
||||
static os_membuf_t _mem[OS_MEMPOOL_SIZE(MBUF_CNT, MBUF_SIZE)];
|
||||
static struct os_mempool _mem_pool;
|
||||
static struct os_mbuf_pool _mbuf_pool;
|
||||
|
||||
/* notify the user about state changes for a connection context */
|
||||
static void _notify(int handle, nimble_netif_event_t event)
|
||||
{
|
||||
if (_eventcb) {
|
||||
_eventcb(handle, event);
|
||||
}
|
||||
}
|
||||
|
||||
static void _netif_init(gnrc_netif_t *netif)
|
||||
{
|
||||
(void)netif;
|
||||
|
||||
/* save the threads context pointer, so we can set its flags */
|
||||
_netif_thread = (thread_t *)thread_get(thread_getpid());
|
||||
|
||||
#ifdef MODULE_GNRC_SIXLOWPAN
|
||||
/* we disable fragmentation for this device, as the L2CAP layer takes care
|
||||
* of this */
|
||||
_nimble_netif->sixlo.max_frag_size = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int _send_pkt(nimble_netif_conn_t *conn, gnrc_pktsnip_t *pkt)
|
||||
{
|
||||
int res;
|
||||
int num_bytes = 0;
|
||||
|
||||
if (conn == NULL || conn->coc == NULL) {
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
/* copy the data into a newly allocated mbuf */
|
||||
struct os_mbuf *sdu = os_mbuf_get_pkthdr(&_mbuf_pool, 0);
|
||||
if (sdu == NULL) {
|
||||
return -ENOBUFS;
|
||||
}
|
||||
while (pkt) {
|
||||
res = os_mbuf_append(sdu, pkt->data, pkt->size);
|
||||
if (res != 0) {
|
||||
os_mbuf_free_chain(sdu);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
num_bytes += (int)pkt->size;
|
||||
pkt = pkt->next;
|
||||
}
|
||||
|
||||
/* send packet via the given L2CAP COC */
|
||||
do {
|
||||
res = ble_l2cap_send(conn->coc, sdu);
|
||||
if (res == BLE_HS_EBUSY) {
|
||||
thread_flags_wait_all(FLAG_TX_UNSTALLED);
|
||||
}
|
||||
} while (res == BLE_HS_EBUSY);
|
||||
|
||||
if ((res != 0) && (res != BLE_HS_ESTALLED)) {
|
||||
os_mbuf_free_chain(sdu);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
return num_bytes;
|
||||
}
|
||||
|
||||
static int _netif_send_iter(nimble_netif_conn_t *conn,
|
||||
int handle, void *arg)
|
||||
{
|
||||
(void)handle;
|
||||
_send_pkt(conn, (gnrc_pktsnip_t *)arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _netif_send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt)
|
||||
{
|
||||
assert(pkt->type == GNRC_NETTYPE_NETIF);
|
||||
|
||||
(void)netif;
|
||||
int res;
|
||||
|
||||
gnrc_netif_hdr_t *hdr = (gnrc_netif_hdr_t *)pkt->data;
|
||||
/* if packet is bcast or mcast, we send it to every connected node */
|
||||
if (hdr->flags &
|
||||
(GNRC_NETIF_HDR_FLAGS_BROADCAST | GNRC_NETIF_HDR_FLAGS_MULTICAST)) {
|
||||
nimble_netif_conn_foreach(NIMBLE_NETIF_L2CAP_CONNECTED,
|
||||
_netif_send_iter, pkt->next);
|
||||
res = (int)gnrc_pkt_len(pkt->next);
|
||||
}
|
||||
/* send unicast */
|
||||
else {
|
||||
int handle = nimble_netif_conn_get_by_addr(
|
||||
gnrc_netif_hdr_get_dst_addr(hdr));
|
||||
nimble_netif_conn_t *conn = nimble_netif_conn_get(handle);
|
||||
res = _send_pkt(conn, pkt->next);
|
||||
}
|
||||
|
||||
/* release the packet in GNRC's packet buffer */
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* not used, we pass incoming data to GNRC directly from the NimBLE thread */
|
||||
static gnrc_pktsnip_t *_netif_recv(gnrc_netif_t *netif)
|
||||
{
|
||||
(void)netif;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const gnrc_netif_ops_t _nimble_netif_ops = {
|
||||
.init = _netif_init,
|
||||
.send = _netif_send,
|
||||
.recv = _netif_recv,
|
||||
.get = gnrc_netif_get_from_netdev,
|
||||
.set = gnrc_netif_set_from_netdev,
|
||||
.msg_handler = NULL,
|
||||
};
|
||||
|
||||
static inline int _netdev_init(netdev_t *dev)
|
||||
{
|
||||
_nimble_netif = dev->context;
|
||||
|
||||
/* get our own address from the controller */
|
||||
uint8_t tmp[6];
|
||||
int res = ble_hs_id_copy_addr(nimble_riot_own_addr_type, tmp, NULL);
|
||||
assert(res == 0);
|
||||
(void)res;
|
||||
|
||||
bluetil_addr_swapped_cp(tmp, _nimble_netif->l2addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int _netdev_get(netdev_t *dev, netopt_t opt,
|
||||
void *value, size_t max_len)
|
||||
{
|
||||
(void)dev;
|
||||
int res = -ENOTSUP;
|
||||
|
||||
switch (opt) {
|
||||
case NETOPT_ADDRESS:
|
||||
assert(max_len >= BLE_ADDR_LEN);
|
||||
memcpy(value, _nimble_netif->l2addr, BLE_ADDR_LEN);
|
||||
res = BLE_ADDR_LEN;
|
||||
break;
|
||||
case NETOPT_ADDR_LEN:
|
||||
case NETOPT_SRC_LEN:
|
||||
assert(max_len == sizeof(uint16_t));
|
||||
*((uint16_t *)value) = BLE_ADDR_LEN;
|
||||
res = sizeof(uint16_t);
|
||||
break;
|
||||
case NETOPT_MAX_PACKET_SIZE:
|
||||
assert(max_len >= sizeof(uint16_t));
|
||||
*((uint16_t *)value) = MTU_SIZE;
|
||||
res = sizeof(uint16_t);
|
||||
break;
|
||||
case NETOPT_PROTO:
|
||||
assert(max_len == sizeof(gnrc_nettype_t));
|
||||
*((gnrc_nettype_t *)value) = _nettype;
|
||||
res = sizeof(gnrc_nettype_t);
|
||||
break;
|
||||
case NETOPT_DEVICE_TYPE:
|
||||
assert(max_len == sizeof(uint16_t));
|
||||
*((uint16_t *)value) = NETDEV_TYPE_BLE;
|
||||
res = sizeof(uint16_t);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int _netdev_set(netdev_t *dev, netopt_t opt,
|
||||
const void *value, size_t val_len)
|
||||
{
|
||||
(void)dev;
|
||||
int res = -ENOTSUP;
|
||||
|
||||
switch (opt) {
|
||||
case NETOPT_PROTO:
|
||||
assert(val_len == sizeof(_nettype));
|
||||
memcpy(&_nettype, value, sizeof(_nettype));
|
||||
res = sizeof(_nettype);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static const netdev_driver_t _nimble_netdev_driver = {
|
||||
.send = NULL,
|
||||
.recv = NULL,
|
||||
.init = _netdev_init,
|
||||
.isr = NULL,
|
||||
.get = _netdev_get,
|
||||
.set = _netdev_set,
|
||||
};
|
||||
|
||||
static netdev_t _nimble_netdev_dummy = {
|
||||
.driver = &_nimble_netdev_driver,
|
||||
};
|
||||
|
||||
static void _on_data(nimble_netif_conn_t *conn, struct ble_l2cap_event *event)
|
||||
{
|
||||
struct os_mbuf *rxb = event->receive.sdu_rx;
|
||||
size_t rx_len = (size_t)OS_MBUF_PKTLEN(rxb);
|
||||
|
||||
/* allocate netif header */
|
||||
gnrc_pktsnip_t *if_snip = gnrc_netif_hdr_build(conn->addr, BLE_ADDR_LEN,
|
||||
_nimble_netif->l2addr,
|
||||
BLE_ADDR_LEN);
|
||||
if (if_snip == NULL) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* we need to add the device PID to the netif header */
|
||||
gnrc_netif_hdr_t *netif_hdr = (gnrc_netif_hdr_t *)if_snip->data;
|
||||
netif_hdr->if_pid = _nimble_netif->pid;
|
||||
|
||||
/* allocate space in the pktbuf to store the packet */
|
||||
gnrc_pktsnip_t *payload = gnrc_pktbuf_add(if_snip, NULL, rx_len, _nettype);
|
||||
if (payload == NULL) {
|
||||
gnrc_pktbuf_release(if_snip);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* copy payload from mbuf into pktbuffer */
|
||||
int res = os_mbuf_copydata(rxb, 0, rx_len, payload->data);
|
||||
if (res != 0) {
|
||||
gnrc_pktbuf_release(payload);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* finally dispatch the receive packet to GNRC */
|
||||
if (!gnrc_netapi_dispatch_receive(payload->type, GNRC_NETREG_DEMUX_CTX_ALL,
|
||||
payload)) {
|
||||
gnrc_pktbuf_release(payload);
|
||||
}
|
||||
|
||||
end:
|
||||
/* free the mbuf and allocate a new one for receiving new data */
|
||||
os_mbuf_free_chain(rxb);
|
||||
rxb = os_mbuf_get_pkthdr(&_mbuf_pool, 0);
|
||||
/* due to buffer provisioning, there should always be enough space */
|
||||
assert(rxb != NULL);
|
||||
ble_l2cap_recv_ready(event->receive.chan, rxb);
|
||||
}
|
||||
|
||||
static int _on_l2cap_client_evt(struct ble_l2cap_event *event, void *arg)
|
||||
{
|
||||
int handle = (int)arg;
|
||||
nimble_netif_conn_t *conn = nimble_netif_conn_get(handle);
|
||||
assert(conn && (conn->state & NIMBLE_NETIF_GAP_MASTER));
|
||||
|
||||
switch (event->type) {
|
||||
case BLE_L2CAP_EVENT_COC_CONNECTED:
|
||||
conn->coc = event->connect.chan;
|
||||
conn->state |= NIMBLE_NETIF_L2CAP_CLIENT;
|
||||
conn->state &= ~NIMBLE_NETIF_CONNECTING;
|
||||
_notify(handle, NIMBLE_NETIF_CONNECTED_MASTER);
|
||||
break;
|
||||
case BLE_L2CAP_EVENT_COC_DISCONNECTED:
|
||||
assert(conn->coc);
|
||||
conn->coc = NULL;
|
||||
conn->state &= ~NIMBLE_NETIF_L2CAP_CONNECTED;
|
||||
break;
|
||||
case BLE_L2CAP_EVENT_COC_ACCEPT:
|
||||
/* this event should never be triggered for the L2CAP client */
|
||||
assert(0);
|
||||
break;
|
||||
case BLE_L2CAP_EVENT_COC_DATA_RECEIVED:
|
||||
_on_data(conn, event);
|
||||
break;
|
||||
case BLE_L2CAP_EVENT_COC_TX_UNSTALLED:
|
||||
thread_flags_set(_netif_thread, FLAG_TX_UNSTALLED);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _on_l2cap_server_evt(struct ble_l2cap_event *event, void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
int handle;
|
||||
nimble_netif_conn_t *conn;
|
||||
|
||||
switch (event->type) {
|
||||
case BLE_L2CAP_EVENT_COC_CONNECTED:
|
||||
handle = nimble_netif_conn_get_by_gaphandle(event->connect.conn_handle);
|
||||
conn = nimble_netif_conn_get(handle);
|
||||
assert(conn);
|
||||
conn->coc = event->connect.chan;
|
||||
conn->state |= NIMBLE_NETIF_L2CAP_SERVER;
|
||||
conn->state &= ~(NIMBLE_NETIF_ADV | NIMBLE_NETIF_CONNECTING);
|
||||
_notify(handle, NIMBLE_NETIF_CONNECTED_SLAVE);
|
||||
break;
|
||||
case BLE_L2CAP_EVENT_COC_DISCONNECTED:
|
||||
conn = nimble_netif_conn_from_gaphandle(event->disconnect.conn_handle);
|
||||
assert(conn && conn->coc);
|
||||
conn->coc = NULL;
|
||||
conn->state &= ~NIMBLE_NETIF_L2CAP_CONNECTED;
|
||||
break;
|
||||
case BLE_L2CAP_EVENT_COC_ACCEPT: {
|
||||
struct os_mbuf *sdu_rx = os_mbuf_get_pkthdr(&_mbuf_pool, 0);
|
||||
/* there should always be enough buffer space */
|
||||
assert(sdu_rx != NULL);
|
||||
ble_l2cap_recv_ready(event->accept.chan, sdu_rx);
|
||||
break;
|
||||
}
|
||||
case BLE_L2CAP_EVENT_COC_DATA_RECEIVED:
|
||||
conn = nimble_netif_conn_from_gaphandle(event->receive.conn_handle);
|
||||
assert(conn);
|
||||
_on_data(conn, event);
|
||||
break;
|
||||
case BLE_L2CAP_EVENT_COC_TX_UNSTALLED:
|
||||
thread_flags_set(_netif_thread, FLAG_TX_UNSTALLED);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _on_gap_connected(nimble_netif_conn_t *conn, uint16_t conn_handle)
|
||||
{
|
||||
struct ble_gap_conn_desc desc;
|
||||
int res = ble_gap_conn_find(conn_handle, &desc);
|
||||
assert(res == 0);
|
||||
(void)res;
|
||||
|
||||
conn->gaphandle = conn_handle;
|
||||
bluetil_addr_swapped_cp(desc.peer_id_addr.val, conn->addr);
|
||||
}
|
||||
|
||||
static int _on_gap_master_evt(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
int res = 0;
|
||||
int handle = (int)arg;
|
||||
nimble_netif_conn_t *conn = nimble_netif_conn_get(handle);
|
||||
assert(conn);
|
||||
|
||||
switch (event->type) {
|
||||
case BLE_GAP_EVENT_CONNECT: {
|
||||
if (event->connect.status != 0) {
|
||||
nimble_netif_conn_free(handle);
|
||||
_notify(handle, NIMBLE_NETIF_CONNECT_ABORT);
|
||||
return 0;
|
||||
}
|
||||
_on_gap_connected(conn, event->connect.conn_handle);
|
||||
conn->state |= NIMBLE_NETIF_GAP_MASTER;
|
||||
|
||||
struct os_mbuf *sdu_rx = os_mbuf_get_pkthdr(&_mbuf_pool, 0);
|
||||
/* we should never run out of buffer space... */
|
||||
assert(sdu_rx != NULL);
|
||||
res = ble_l2cap_connect(event->connect.conn_handle,
|
||||
NIMBLE_NETIF_CID, MTU_SIZE, sdu_rx,
|
||||
_on_l2cap_client_evt, (void *)handle);
|
||||
/* should always success as well */
|
||||
assert(res == 0);
|
||||
break;
|
||||
}
|
||||
case BLE_GAP_EVENT_DISCONNECT:
|
||||
nimble_netif_conn_free(handle);
|
||||
_notify(handle, NIMBLE_NETIF_CLOSED_MASTER);
|
||||
break;
|
||||
case BLE_GAP_EVENT_CONN_UPDATE:
|
||||
_notify(handle, NIMBLE_NETIF_CONN_UPDATED);
|
||||
break;
|
||||
case BLE_GAP_EVENT_CONN_UPDATE_REQ:
|
||||
case BLE_GAP_EVENT_MTU:
|
||||
/* nothing to do here */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _on_gap_slave_evt(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
int handle = (int)arg;
|
||||
nimble_netif_conn_t *conn = nimble_netif_conn_get(handle);
|
||||
assert(conn);
|
||||
|
||||
switch (event->type) {
|
||||
case BLE_GAP_EVENT_CONNECT: {
|
||||
if (event->connect.status != 0) {
|
||||
nimble_netif_conn_free(handle);
|
||||
_notify(handle, NIMBLE_NETIF_CONNECT_ABORT);
|
||||
break;
|
||||
}
|
||||
_on_gap_connected(conn, event->connect.conn_handle);
|
||||
assert(conn->state == NIMBLE_NETIF_ADV);
|
||||
conn->state = NIMBLE_NETIF_GAP_SLAVE;
|
||||
break;
|
||||
}
|
||||
case BLE_GAP_EVENT_DISCONNECT:
|
||||
nimble_netif_conn_free(handle);
|
||||
_notify(handle, NIMBLE_NETIF_CLOSED_SLAVE);
|
||||
break;
|
||||
case BLE_GAP_EVENT_CONN_UPDATE:
|
||||
_notify(handle, NIMBLE_NETIF_CONN_UPDATED);
|
||||
break;
|
||||
case BLE_GAP_EVENT_CONN_UPDATE_REQ:
|
||||
/* nothing to do here */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nimble_netif_init(void)
|
||||
{
|
||||
int res;
|
||||
(void)res;
|
||||
|
||||
/* setup the connection context table */
|
||||
nimble_netif_conn_init();
|
||||
|
||||
/* initialize of BLE related buffers */
|
||||
res = os_mempool_init(&_mem_pool, MBUF_CNT, MBUF_SIZE, _mem, "nim_gnrc");
|
||||
assert(res == 0);
|
||||
res = os_mbuf_pool_init(&_mbuf_pool, &_mem_pool, MBUF_SIZE, MBUF_CNT);
|
||||
assert(res == 0);
|
||||
|
||||
res = ble_l2cap_create_server(NIMBLE_NETIF_CID, MTU_SIZE,
|
||||
_on_l2cap_server_evt, NULL);
|
||||
assert(res == 0);
|
||||
(void)res;
|
||||
|
||||
gnrc_netif_create(_stack, sizeof(_stack), GNRC_NETIF_PRIO,
|
||||
"nimble_netif", &_nimble_netdev_dummy, &_nimble_netif_ops);
|
||||
}
|
||||
|
||||
void nimble_netif_eventcb(nimble_netif_eventcb_t cb)
|
||||
{
|
||||
_eventcb = cb;
|
||||
}
|
||||
|
||||
int nimble_netif_connect(const ble_addr_t *addr,
|
||||
const struct ble_gap_conn_params *conn_params,
|
||||
uint32_t timeout)
|
||||
{
|
||||
assert(addr);
|
||||
assert(_eventcb);
|
||||
|
||||
/* the netif_conn module expects addresses in network byte order */
|
||||
uint8_t addrn[BLE_ADDR_LEN];
|
||||
bluetil_addr_swapped_cp(addr->val, addrn);
|
||||
|
||||
/* check that there is no open connection with the given address */
|
||||
if (nimble_netif_conn_connected(addrn) ||
|
||||
nimble_netif_conn_connecting()) {
|
||||
return NIMBLE_NETIF_BUSY;
|
||||
}
|
||||
|
||||
/* get empty connection context */
|
||||
int handle = nimble_netif_conn_start_connection(addrn);
|
||||
if (handle == NIMBLE_NETIF_CONN_INVALID) {
|
||||
return NIMBLE_NETIF_NOMEM;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
int nimble_netif_close(int handle)
|
||||
{
|
||||
nimble_netif_conn_t *conn = nimble_netif_conn_get(handle);
|
||||
if (conn == NULL) {
|
||||
return NIMBLE_NETIF_NOTFOUND;
|
||||
}
|
||||
else if (!(conn->state & NIMBLE_NETIF_L2CAP_CONNECTED)) {
|
||||
return NIMBLE_NETIF_NOTCONN;
|
||||
}
|
||||
|
||||
int res = ble_gap_terminate(ble_l2cap_get_conn_handle(conn->coc),
|
||||
BLE_ERR_REM_USER_CONN_TERM);
|
||||
assert(res == 0);
|
||||
(void)res;
|
||||
|
||||
return NIMBLE_NETIF_OK;
|
||||
}
|
||||
|
||||
int nimble_netif_accept(const uint8_t *ad, size_t ad_len,
|
||||
const struct ble_gap_adv_params *adv_params)
|
||||
{
|
||||
assert(ad);
|
||||
assert(adv_params);
|
||||
|
||||
int handle;
|
||||
int res;
|
||||
(void)res;
|
||||
|
||||
/* allocate a connection context for incoming connections */
|
||||
handle = nimble_netif_conn_start_adv();
|
||||
if (handle < 0) {
|
||||
return handle;
|
||||
}
|
||||
|
||||
/* set advertisement data */
|
||||
res = ble_gap_adv_set_data(ad, (int)ad_len);
|
||||
assert(res == 0);
|
||||
/* remember context and start advertising */
|
||||
res = ble_gap_adv_start(nimble_riot_own_addr_type, NULL, BLE_HS_FOREVER,
|
||||
adv_params, _on_gap_slave_evt, (void *)handle);
|
||||
assert(res == 0);
|
||||
|
||||
return NIMBLE_NETIF_OK;
|
||||
}
|
||||
|
||||
int nimble_netif_accept_stop(void)
|
||||
{
|
||||
int handle = nimble_netif_conn_get_adv();
|
||||
if (handle == NIMBLE_NETIF_CONN_INVALID) {
|
||||
return NIMBLE_NETIF_NOTADV;
|
||||
}
|
||||
|
||||
int res = ble_gap_adv_stop();
|
||||
assert(res == 0);
|
||||
(void)res;
|
||||
nimble_netif_conn_free(handle);
|
||||
|
||||
return NIMBLE_NETIF_OK;
|
||||
}
|
||||
|
||||
int nimble_netif_update(int handle,
|
||||
const struct ble_gap_upd_params *conn_params)
|
||||
{
|
||||
nimble_netif_conn_t *conn = nimble_netif_conn_get(handle);
|
||||
if (conn == NULL) {
|
||||
return NIMBLE_NETIF_NOTCONN;
|
||||
}
|
||||
|
||||
int res = ble_gap_update_params(conn->gaphandle, conn_params);
|
||||
if (res != 0) {
|
||||
return NIMBLE_NETIF_DEVERR;
|
||||
}
|
||||
|
||||
return NIMBLE_NETIF_OK;
|
||||
}
|
||||
202
pkg/nimble/netif/nimble_netif_conn.c
Normal file
202
pkg/nimble/netif/nimble_netif_conn.c
Normal file
@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2019 Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup pkg_nimble_netif_conn
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Connection context handling for NimBLE netif
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "nimble_netif_conn.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
#define CONN_CNT (MYNEWT_VAL_BLE_MAX_CONNECTIONS)
|
||||
|
||||
static mutex_t _lock = MUTEX_INIT;
|
||||
static nimble_netif_conn_t _conn[CONN_CNT];
|
||||
|
||||
static int _find_by_state(uint16_t filter)
|
||||
{
|
||||
for (unsigned i = 0; i < CONN_CNT; i++) {
|
||||
if (_conn[i].state & filter) {
|
||||
return (int)i;
|
||||
}
|
||||
}
|
||||
return NIMBLE_NETIF_CONN_INVALID;
|
||||
}
|
||||
|
||||
void nimble_netif_conn_init(void)
|
||||
{
|
||||
DEBUG("conn_init\n");
|
||||
memset(_conn, 0, sizeof(_conn));
|
||||
for (unsigned i = 0; i < CONN_CNT; i++) {
|
||||
_conn[i].state = NIMBLE_NETIF_UNUSED;
|
||||
}
|
||||
}
|
||||
|
||||
nimble_netif_conn_t *nimble_netif_conn_get(int handle)
|
||||
{
|
||||
if ((handle < 0) || (handle >= CONN_CNT)) {
|
||||
return NULL;
|
||||
}
|
||||
return &_conn[handle];
|
||||
}
|
||||
|
||||
int nimble_netif_conn_get_adv(void)
|
||||
{
|
||||
int handle;
|
||||
DEBUG("nimble_netif_conn_get_adv\n");
|
||||
mutex_lock(&_lock);
|
||||
handle = _find_by_state(NIMBLE_NETIF_ADV);
|
||||
mutex_unlock(&_lock);
|
||||
return handle;
|
||||
}
|
||||
|
||||
int nimble_netif_conn_get_connecting(void)
|
||||
{
|
||||
int handle;
|
||||
DEBUG("nimble_netif_conn_get_connecting\n");
|
||||
mutex_lock(&_lock);
|
||||
handle = _find_by_state(NIMBLE_NETIF_CONNECTING);
|
||||
mutex_unlock(&_lock);
|
||||
DEBUG("nimble_netif_conn_get_connecting - handle %i\n", handle);
|
||||
return handle;
|
||||
}
|
||||
|
||||
int nimble_netif_conn_get_by_addr(const uint8_t *addr)
|
||||
{
|
||||
assert(addr);
|
||||
int handle = NIMBLE_NETIF_CONN_INVALID;
|
||||
|
||||
DEBUG("nimble_netif_conn_get_by_addr %02x\n", (int)addr[5]);
|
||||
mutex_lock(&_lock);
|
||||
for (unsigned i = 0; i < CONN_CNT; i++) {
|
||||
if ((_conn[i].state & NIMBLE_NETIF_L2CAP_CONNECTED) &&
|
||||
memcmp(_conn[i].addr, addr, BLE_ADDR_LEN) == 0) {
|
||||
handle = (int)i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&_lock);
|
||||
DEBUG("nimble_netif_conn_get_by_addr - found: %i\n", handle);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
int nimble_netif_conn_get_by_gaphandle(uint16_t gaphandle)
|
||||
{
|
||||
int handle = NIMBLE_NETIF_CONN_INVALID;
|
||||
|
||||
DEBUG("nimble_netif_conn_get_by_gaphandle %i\n", (int)gaphandle);
|
||||
mutex_lock(&_lock);
|
||||
for (unsigned i = 0; i < CONN_CNT; i++) {
|
||||
if (_conn[i].gaphandle == gaphandle) {
|
||||
handle = (int)i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&_lock);
|
||||
DEBUG("nimble_netif_conn_get_by_gaphandle - found %i\n", handle);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
int nimble_netif_conn_start_connection(const uint8_t *addr)
|
||||
{
|
||||
int handle;
|
||||
|
||||
DEBUG("nimble_netif_conn_start_connection, addr %02x\n", (int)addr[5]);
|
||||
mutex_lock(&_lock);
|
||||
handle = _find_by_state(NIMBLE_NETIF_UNUSED);
|
||||
if (handle != NIMBLE_NETIF_CONN_INVALID) {
|
||||
_conn[handle].state = NIMBLE_NETIF_CONNECTING;
|
||||
memcpy(_conn[handle].addr, addr, BLE_ADDR_LEN);
|
||||
}
|
||||
|
||||
mutex_unlock(&_lock);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
int nimble_netif_conn_start_adv(void)
|
||||
{
|
||||
int handle;
|
||||
|
||||
DEBUG("nimble_netif_conn_start_adv\n");
|
||||
mutex_lock(&_lock);
|
||||
handle = _find_by_state(NIMBLE_NETIF_ADV);
|
||||
if (handle != NIMBLE_NETIF_CONN_INVALID) {
|
||||
handle = NIMBLE_NETIF_BUSY;
|
||||
}
|
||||
else {
|
||||
handle = _find_by_state(NIMBLE_NETIF_UNUSED);
|
||||
if (handle != NIMBLE_NETIF_CONN_INVALID) {
|
||||
_conn[handle].state = NIMBLE_NETIF_ADV;
|
||||
}
|
||||
else {
|
||||
handle = NIMBLE_NETIF_NOMEM;
|
||||
}
|
||||
|
||||
}
|
||||
mutex_unlock(&_lock);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void nimble_netif_conn_free(int handle)
|
||||
{
|
||||
assert((handle >= 0) && (handle < CONN_CNT));
|
||||
|
||||
DEBUG("nimble_netif_conn_free, handle %i\n", handle);
|
||||
mutex_lock(&_lock);
|
||||
memset(&_conn[handle], 0, sizeof(nimble_netif_conn_t));
|
||||
_conn[handle].state = NIMBLE_NETIF_UNUSED;
|
||||
mutex_unlock(&_lock);
|
||||
}
|
||||
|
||||
void nimble_netif_conn_foreach(uint16_t filter,
|
||||
nimble_netif_conn_iter_t cb, void *arg)
|
||||
{
|
||||
assert(cb);
|
||||
|
||||
DEBUG("nimble_netif_conn_foreach 0x%04x\n", (int)filter);
|
||||
mutex_lock(&_lock);
|
||||
for (unsigned i = 0; i < CONN_CNT; i++) {
|
||||
if (_conn[i].state & filter) {
|
||||
int res = cb(&_conn[i], (int)i, arg);
|
||||
if (res != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_unlock(&_lock);
|
||||
}
|
||||
|
||||
unsigned nimble_netif_conn_count(uint16_t filter)
|
||||
{
|
||||
unsigned cnt = 0;
|
||||
|
||||
DEBUG("nimble_netif_conn_count, filter 0x%04x\n", (int)filter);
|
||||
mutex_lock(&_lock);
|
||||
for (unsigned i = 0; i < CONN_CNT; i++) {
|
||||
if (_conn[i].state & filter) {
|
||||
++cnt;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&_lock);
|
||||
|
||||
return cnt;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user