Added RADIUS configuration options to Wi-SUN

Added support for external RADIUS server configuration to Wi-SUN Border Router.
Added configuration functions and .json configuration options for:
- external RADIUS server IPv6 address
- RADIUS shared secret.
- RADIUS client retry trickle timer configuration. This can be used to set how fast
the RADIUS client retries Access-Request messages to RADIUS server in case reply
from server is not received.
pull/13573/head
Mika Leppänen 2020-09-08 14:27:08 +03:00
parent 7f60090ddb
commit 23c13d74ec
4 changed files with 406 additions and 9 deletions

View File

@ -50,6 +50,18 @@ typedef struct ws_br_route_info {
uint8_t parent[8];
} ws_br_route_info_t;
/**
* \brief Struct ws_br_radius_timing_t is RADIUS timing configuration structure.
*/
typedef struct ws_br_radius_timing {
/** RADIUS retry trickle timer Imin; in 100ms units; range 1-1200; default 20 (2 seconds) */
uint16_t radius_retry_imin;
/** RADIUS retry trickle timer Imax; in 100ms units; range 1-1200; default 30 (3 seconds) */
uint16_t radius_retry_imax;
/** RADIUS retry trickle count; default 3 */
uint8_t radius_retry_count;
} ws_br_radius_timing_t;
/** Wi-SUN Border Router class
*
* Class can be used to start, stop and configure Wi-SUN Border Router.
@ -60,7 +72,7 @@ public:
/** Create WisunBorderRouter
*
* */
WisunBorderRouter() { }
WisunBorderRouter();
/**
* \brief Start Wi-SUN Border Router
@ -209,9 +221,106 @@ public:
* */
int routing_table_get(ws_br_route_info_t *table_ptr, uint16_t table_len);
private:
int8_t _mesh_if_id = -1;
/**
* \brief Set Wi-SUN RADIUS server IPv6 address.
*
* Function sets external RADIUS server IPv6 address to Border Router. Setting the address enables
* external RADIUS server interface on Border Router. To disable external RADIUS server interface,
* call the function with address set to NULL. The RADIUS shared secret must be set before address
* is set using set_radius_shared_secret() call.
*
* \param address Pointer to IPv6 address string or NULL to disable RADIUS. Address string format is e.g. 2001:1234::1 and it is NUL terminated.
* \return MESH_ERROR_NONE on success.
* \return MESH_ERROR_UNKNOWN in case of failure.
* */
mesh_error_t set_radius_server_ipv6_address(const char *address);
/**
* \brief Get Wi-SUN RADIUS server IPv6 address.
*
* Function gets external RADIUS server IPv6 address from Border Router.
*
* \param address Pointer to buffer where to write IPv6 address string. Must have space at least for 39 characters and NUL terminator.
* \return MESH_ERROR_NONE on success.
* \return error value in case of failure, e.g. if address has not been set to Border Router.
* */
mesh_error_t get_radius_server_ipv6_address(char *address);
/**
* \brief Set Wi-SUN RADIUS shared secret.
*
* Function sets RADIUS shared secret to Border Router. Shared secret may be an ASCII string. Check
* the format and length constraints for the shared secret from the documentation of RADIUS server you
* are connecting to.
*
* \param shared_secret_len The length of the shared secret in bytes.
* \param shared_secret Pointer to shared secret. Can be 8-bit ASCII string or byte array. Is not NUL terminated.
* \return MESH_ERROR_NONE on success.
* \return error value in case of failure.
* */
mesh_error_t set_radius_shared_secret(uint16_t shared_secret_len, const uint8_t *shared_secret);
/**
* \brief Get Wi-SUN RADIUS shared secret.
*
* Function gets RADIUS shared secret from Border Router.
*
* \param shared_secret_len On function call, is the size of the shared secret write buffer in bytes, on return is the shared secret length in bytes.
* \param shared_secret Pointer to buffer where to write shared secret or NULL. At maximum, bytes set by the length parameter are written. If NULL only buffer length is returned.
* \return MESH_ERROR_NONE on success.
* \return error value in case of failure.
* */
mesh_error_t get_radius_shared_secret(uint16_t *shared_secret_len, uint8_t *shared_secret);
/**
* \brief Set Wi-SUN RADIUS timing parameters.
*
* Function sets RADIUS timing parameters to Border Router. For RADIUS retry trickle timer default
* settings are that the first retry is done between 1 to 3 seconds after the initial attempt and
* all retries are done in maximum in 9 seconds.
*
* \param timing Timing parameters.
* \return MESH_ERROR_NONE on success.
* \return error value in case of failure.
* */
mesh_error_t set_radius_timing(ws_br_radius_timing_t *timing);
/**
* \brief Get Wi-SUN RADIUS timing parameters.
*
* Function gets RADIUS timing parameters from Border Router.
*
* \param timing Timing parameters.
* \return MESH_ERROR_NONE on success.
* \return error value in case of failure.
* */
mesh_error_t get_radius_timing(ws_br_radius_timing_t *timing);
/**
* \brief Validate Wi-SUN RADIUS timing parameters.
*
* Function validates RADIUS timing parameters on Border Router.
*
* \param timing Timing parameters.
* \return MESH_ERROR_NONE on success.
* \return error value in case of failure.
* */
mesh_error_t validate_radius_timing(ws_br_radius_timing_t *timing);
private:
mesh_error_t configure();
mesh_error_t apply_configuration(int8_t mesh_if_id);
mesh_error_t set_bbr_radius_address(void);
mesh_error_t set_bbr_radius_shared_secret(void);
mesh_error_t set_bbr_radius_timing(void);
char _radius_ipv6_addr[40];
ws_br_radius_timing_t _radius_timing;
char *_shared_secret = NULL;
uint16_t _shared_secret_len = 0;
int8_t _mesh_if_id = -1;
bool _radius_ipv6_addr_set = false;
bool _configured = false;
bool _radius_timing_set = false;
};
#endif

View File

@ -200,6 +200,30 @@
"own-certificate-key-len": {
"help": "Own certificate's key length; optional for PEM format, must be defined for DER format",
"value": null
},
"radius-server-ipv6-address": {
"help": "RADIUS Server IPv6 address in string format (e.g. \"2001:1234::1\")",
"value": null
},
"radius-shared-secret": {
"help": "RADIUS shared secret; ASCII string (e.g. \"radiuspassword\") or sequence of bytes (e.g. 0x01, 0x02, 0x03, 0x04, 0x05)",
"value": null
},
"radius-shared-secret-len": {
"help": "RADIUS shared secret length; If length is not defined, strlen() is used to determine RADIUS shared secret length",
"value": null
},
"radius-retry-imin": {
"help": "RADIUS retry trickle timer Imin; in 100ms units; range 1-1200; default 20 (2 seconds)",
"value": 20
},
"radius-retry-imax": {
"help": "RADIUS retry trickle timer Imax; in 100ms units; range 1-1200; default 30 (3 seconds)",
"value": 30
},
"radius-retry-count": {
"help": "RADIUS retry trickle count; default 3",
"value": 3
}
},
"target_overrides": {

View File

@ -19,6 +19,7 @@
#include "WisunBorderRouter.h"
#include "MeshInterfaceNanostack.h"
#include "net_interface.h"
#include "ip6string.h"
extern "C" {
#include "ws_bbr_api.h"
@ -26,6 +27,13 @@ extern "C" {
#define TRACE_GROUP "WSBR"
WisunBorderRouter::WisunBorderRouter()
{
// Apply mbed configuration to Wi-SUN BBR
configure();
}
mesh_error_t WisunBorderRouter::start(NetworkInterface *mesh_if, NetworkInterface *backbone_if)
{
if (mesh_if == NULL || backbone_if == NULL) {
@ -53,6 +61,8 @@ mesh_error_t WisunBorderRouter::start(NetworkInterface *mesh_if, NetworkInterfac
return MESH_ERROR_UNKNOWN;
}
apply_configuration(mesh_if_id);
int ret = ws_bbr_start(mesh_if_id, backbone_if_id);
if (ret < 0) {
return MESH_ERROR_UNKNOWN;
@ -76,6 +86,8 @@ mesh_error_t WisunBorderRouter::start(NetworkInterface *mesh_if, OnboardNetworkS
return MESH_ERROR_UNKNOWN;
}
apply_configuration(mesh_if_id);
int ret = ws_bbr_start(mesh_if_id, backbone_if_id);
if (ret < 0) {
return MESH_ERROR_UNKNOWN;
@ -95,6 +107,77 @@ void WisunBorderRouter::stop()
_mesh_if_id = -1;
}
mesh_error_t WisunBorderRouter::configure()
{
#if defined(MBED_CONF_MBED_MESH_API_RADIUS_SHARED_SECRET) || defined(MBED_CONF_MBED_MESH_API_RADIUS_SERVER_IPV6_ADDRESS)
mesh_error_t status;
#endif
if (_configured) {
// Already configured
return MESH_ERROR_NONE;
}
_configured = true;
#ifdef MBED_CONF_MBED_MESH_API_RADIUS_SHARED_SECRET
const char radius_shared_secret[] = {MBED_CONF_MBED_MESH_API_RADIUS_SHARED_SECRET};
#ifdef MBED_CONF_MBED_MESH_API_RADIUS_SHARED_SECRET_LEN
const uint16_t radius_shared_secret_len = MBED_CONF_MBED_MESH_API_RADIUS_SHARED_SECRET_LEN;
#else
uint16_t radius_shared_secret_len = strlen(radius_shared_secret);
#endif
status = set_radius_shared_secret(radius_shared_secret_len, (uint8_t *) radius_shared_secret);
if (status != MESH_ERROR_NONE) {
tr_error("Failed to set RADIUS shared secret!");
}
#endif
#ifdef MBED_CONF_MBED_MESH_API_RADIUS_SERVER_IPV6_ADDRESS
const char radius_server_ipv6_addr[] = {MBED_CONF_MBED_MESH_API_RADIUS_SERVER_IPV6_ADDRESS};
status = set_radius_server_ipv6_address(radius_server_ipv6_addr);
if (status != MESH_ERROR_NONE) {
tr_error("Failed to set RADIUS server IPv6 address!");
}
#if defined(MBED_CONF_MBED_MESH_API_RADIUS_RETRY_IMIN) || defined(MBED_CONF_MBED_MESH_API_RADIUS_RETRY_IMAX) || defined(MBED_CONF_MBED_MESH_API_RADIUS_RETRY_COUNT)
ws_br_radius_timing_t timing {
.radius_retry_imin = MBED_CONF_MBED_MESH_API_RADIUS_RETRY_IMIN,
.radius_retry_imax = MBED_CONF_MBED_MESH_API_RADIUS_RETRY_IMAX,
.radius_retry_count = MBED_CONF_MBED_MESH_API_RADIUS_RETRY_COUNT
};
status = set_radius_timing(&timing);
if (status != MESH_ERROR_NONE) {
tr_error("Failed to set RADIUS timing parameters!");
}
#endif
#endif
return MESH_ERROR_NONE;
}
mesh_error_t WisunBorderRouter::apply_configuration(int8_t mesh_if_id)
{
configure();
mesh_error_t status = set_bbr_radius_address();
if (status != MESH_ERROR_NONE) {
tr_error("Failed to apply RADIUS server IPv6 address!");
}
status = set_bbr_radius_shared_secret();
if (status != MESH_ERROR_NONE) {
tr_error("Failed to apply RADIUS server IPv6 address!");
}
status = set_bbr_radius_timing();
if (status != MESH_ERROR_NONE) {
tr_error("Failed to apply RADIUS timing parameters!");
}
return MESH_ERROR_NONE;
}
mesh_error_t WisunBorderRouter::set_rpl_parameters(uint8_t dio_interval_min, uint8_t dio_interval_doublings, uint8_t dio_redundancy_constant)
{
int status = ws_bbr_rpl_parameters_set(_mesh_if_id, dio_interval_min, dio_interval_doublings, dio_redundancy_constant);
@ -188,3 +271,184 @@ int WisunBorderRouter::routing_table_get(ws_br_route_info_t *table_ptr, uint16_t
return ws_bbr_routing_table_get(_mesh_if_id, (bbr_route_info_t *)table_ptr, table_len);
}
mesh_error_t WisunBorderRouter::set_radius_server_ipv6_address(const char *address)
{
if (address) {
uint8_t ipv6_addr[16];
if (!stoip6(address, strlen(address), ipv6_addr)) {
return MESH_ERROR_PARAM;
}
// Stored address (returned by get) is in the format given by user of the interface
strcpy(_radius_ipv6_addr, address);
_radius_ipv6_addr_set = true;
} else {
_radius_ipv6_addr_set = false;
}
return set_bbr_radius_address();
}
mesh_error_t WisunBorderRouter::get_radius_server_ipv6_address(char *address)
{
if (!_radius_ipv6_addr_set) {
return MESH_ERROR_UNKNOWN;
}
strcpy(address, _radius_ipv6_addr);
return MESH_ERROR_NONE;
}
mesh_error_t WisunBorderRouter::set_bbr_radius_address(void)
{
int status;
if (_radius_ipv6_addr_set) {
uint8_t ipv6_addr[16];
if (!stoip6(_radius_ipv6_addr, strlen(_radius_ipv6_addr), ipv6_addr)) {
return MESH_ERROR_PARAM;
}
status = ws_bbr_radius_address_set(_mesh_if_id, ipv6_addr);
} else {
status = ws_bbr_radius_address_set(_mesh_if_id, NULL);
}
if (status != 0) {
return MESH_ERROR_UNKNOWN;
}
return MESH_ERROR_NONE;
}
mesh_error_t WisunBorderRouter::set_radius_shared_secret(uint16_t shared_secret_len, const uint8_t *shared_secret)
{
if (shared_secret_len == 0 || !shared_secret) {
return MESH_ERROR_PARAM;
}
if (_shared_secret != NULL) {
delete[] _shared_secret;
}
_shared_secret = new (std::nothrow) char[shared_secret_len];
if (_shared_secret == NULL) {
return MESH_ERROR_MEMORY;
}
memcpy(_shared_secret, shared_secret, shared_secret_len);
_shared_secret_len = shared_secret_len;
int status = ws_bbr_radius_shared_secret_set(_mesh_if_id, shared_secret_len, shared_secret);
if (status != 0) {
return MESH_ERROR_UNKNOWN;
}
return set_bbr_radius_shared_secret();
}
mesh_error_t WisunBorderRouter::set_bbr_radius_shared_secret(void)
{
if (_shared_secret_len == 0 || _shared_secret == NULL) {
return MESH_ERROR_UNKNOWN;
}
int status = ws_bbr_radius_shared_secret_set(_mesh_if_id, _shared_secret_len, (uint8_t *) _shared_secret);
if (status != 0) {
return MESH_ERROR_UNKNOWN;
}
return MESH_ERROR_NONE;
}
mesh_error_t WisunBorderRouter::get_radius_shared_secret(uint16_t *shared_secret_len, uint8_t *shared_secret)
{
if (shared_secret_len == NULL) {
return MESH_ERROR_PARAM;
}
int status = ws_bbr_radius_shared_secret_get(_mesh_if_id, shared_secret_len, shared_secret);
if (status != 0) {
return MESH_ERROR_UNKNOWN;
}
return MESH_ERROR_NONE;
}
mesh_error_t WisunBorderRouter::set_radius_timing(ws_br_radius_timing_t *timing)
{
if (timing == NULL) {
return MESH_ERROR_PARAM;
}
if (validate_radius_timing(timing) != MESH_ERROR_NONE) {
return MESH_ERROR_PARAM;
}
_radius_timing = *timing;
_radius_timing_set = true;
return set_bbr_radius_timing();
}
mesh_error_t WisunBorderRouter::set_bbr_radius_timing(void)
{
if (!_radius_timing_set) {
return MESH_ERROR_NONE;
}
bbr_radius_timing_t bbr_timing = {
.radius_retry_imin = _radius_timing.radius_retry_imin,
.radius_retry_imax = _radius_timing.radius_retry_imax,
.radius_retry_count = _radius_timing.radius_retry_count
};
int status = ws_bbr_radius_timing_set(_mesh_if_id, &bbr_timing);
if (status != 0) {
return MESH_ERROR_UNKNOWN;
}
return MESH_ERROR_NONE;
}
mesh_error_t WisunBorderRouter::get_radius_timing(ws_br_radius_timing_t *timing)
{
if (timing == NULL) {
return MESH_ERROR_PARAM;
}
if (_radius_timing_set) {
*timing = _radius_timing;
return MESH_ERROR_NONE;
}
bbr_radius_timing_t bbr_timing;
int status = ws_bbr_radius_timing_get(_mesh_if_id, &bbr_timing);
if (status != 0) {
return MESH_ERROR_UNKNOWN;
}
timing->radius_retry_imin = bbr_timing.radius_retry_imin;
timing->radius_retry_imax = bbr_timing.radius_retry_imax;
timing->radius_retry_count = bbr_timing.radius_retry_count;
return MESH_ERROR_NONE;
}
mesh_error_t WisunBorderRouter::validate_radius_timing(ws_br_radius_timing_t *timing)
{
if (timing == NULL) {
return MESH_ERROR_PARAM;
}
bbr_radius_timing_t bbr_timing = {
.radius_retry_imin = timing->radius_retry_imin,
.radius_retry_imax = timing->radius_retry_imax,
.radius_retry_count = timing->radius_retry_count
};
int status = ws_bbr_radius_timing_validate(_mesh_if_id, &bbr_timing);
if (status != 0) {
return MESH_ERROR_UNKNOWN;
}
return MESH_ERROR_NONE;
}

View File

@ -71,7 +71,7 @@ nsapi_error_t WisunInterface::do_initialize()
nsapi_error_t WisunInterface::configure()
{
int status;
mesh_error_t status;
if (_configured) {
// Already configured
@ -82,7 +82,7 @@ nsapi_error_t WisunInterface::configure()
#ifdef MBED_CONF_MBED_MESH_API_WISUN_NETWORK_NAME
char network_name[] = {MBED_CONF_MBED_MESH_API_WISUN_NETWORK_NAME};
status = set_network_name((char *) &network_name);
if (status < 0) {
if (status != MESH_ERROR_NONE) {
tr_error("Failed to set network name!");
return NSAPI_ERROR_PARAMETER;
}
@ -92,7 +92,7 @@ nsapi_error_t WisunInterface::configure()
status = set_network_regulatory_domain(MBED_CONF_MBED_MESH_API_WISUN_REGULATORY_DOMAIN,
MBED_CONF_MBED_MESH_API_WISUN_OPERATING_CLASS,
MBED_CONF_MBED_MESH_API_WISUN_OPERATING_MODE);
if (status < 0) {
if (status != MESH_ERROR_NONE) {
tr_error("Failed to set regulatory domain!");
return NSAPI_ERROR_PARAMETER;
}
@ -102,7 +102,7 @@ nsapi_error_t WisunInterface::configure()
status = set_unicast_channel_function(static_cast<mesh_channel_function_t>(MBED_CONF_MBED_MESH_API_WISUN_UC_CHANNEL_FUNCTION),
MBED_CONF_MBED_MESH_API_WISUN_UC_FIXED_CHANNEL,
MBED_CONF_MBED_MESH_API_WISUN_UC_DWELL_INTERVAL);
if (status < 0) {
if (status != MESH_ERROR_NONE) {
tr_error("Failed to set unicast channel function configuration");
return NSAPI_ERROR_PARAMETER;
}
@ -113,7 +113,7 @@ nsapi_error_t WisunInterface::configure()
MBED_CONF_MBED_MESH_API_WISUN_BC_FIXED_CHANNEL,
MBED_CONF_MBED_MESH_API_WISUN_BC_DWELL_INTERVAL,
MBED_CONF_MBED_MESH_API_WISUN_BC_INTERVAL);
if (status < 0) {
if (status != MESH_ERROR_NONE) {
tr_error("Failed to set broadcast channel function configuration");
return NSAPI_ERROR_PARAMETER;
}
@ -121,7 +121,7 @@ nsapi_error_t WisunInterface::configure()
#ifdef MBED_CONF_MBED_MESH_API_WISUN_NETWORK_SIZE
status = set_network_size(MBED_CONF_MBED_MESH_API_WISUN_NETWORK_SIZE);
if (status < 0) {
if (status != MESH_ERROR_NONE) {
tr_error("Failed to set network size");
return NSAPI_ERROR_PARAMETER;
}