diff --git a/features/nanostack/mbed-mesh-api/mbed-mesh-api/WisunBorderRouter.h b/features/nanostack/mbed-mesh-api/mbed-mesh-api/WisunBorderRouter.h index 1005480410e..eca0c3050e7 100644 --- a/features/nanostack/mbed-mesh-api/mbed-mesh-api/WisunBorderRouter.h +++ b/features/nanostack/mbed-mesh-api/mbed-mesh-api/WisunBorderRouter.h @@ -60,7 +60,7 @@ class WisunBorderRouter { /** Create WisunBorderRouter * * */ - WisunBorderRouter() { } + WisunBorderRouter(); /** * \brief Start Wi-SUN Border Router @@ -209,9 +209,65 @@ class WisunBorderRouter { * */ int routing_table_get(ws_br_route_info_t *table_ptr, uint16_t table_len); + /** + * \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); + private: + mesh_error_t configure(); + mesh_error_t apply_configuration(int8_t mesh_if_id); + mesh_error_t set_bbr_radius_address(void); + char _radius_ipv6_addr[40]; int8_t _mesh_if_id = -1; - + bool _radius_ipv6_addr_set = false; + bool _configured = false; }; #endif diff --git a/features/nanostack/mbed-mesh-api/mbed_lib.json b/features/nanostack/mbed-mesh-api/mbed_lib.json index d26fa4452ba..7d14d858333 100644 --- a/features/nanostack/mbed-mesh-api/mbed_lib.json +++ b/features/nanostack/mbed-mesh-api/mbed_lib.json @@ -195,6 +195,18 @@ "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 } }, "target_overrides": { diff --git a/features/nanostack/mbed-mesh-api/source/WisunBorderRouter.cpp b/features/nanostack/mbed-mesh-api/source/WisunBorderRouter.cpp index 969dbe72f6a..a681b8109a4 100644 --- a/features/nanostack/mbed-mesh-api/source/WisunBorderRouter.cpp +++ b/features/nanostack/mbed-mesh-api/source/WisunBorderRouter.cpp @@ -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,55 @@ 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!"); + return status; + } +#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!"); + return status; + } +#endif + + return MESH_ERROR_NONE; +} + +mesh_error_t WisunBorderRouter::apply_configuration(int8_t mesh_if_id) +{ + mesh_error_t status = set_bbr_radius_address(); + if (status != MESH_ERROR_NONE) { + tr_error("Failed to apply RADIUS server IPv6 address!"); + return MESH_ERROR_PARAM; + } + 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 +249,78 @@ 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; + } + + int status = ws_bbr_radius_shared_secret_set(_mesh_if_id, shared_secret_len, 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; +} diff --git a/features/nanostack/mbed-mesh-api/source/WisunInterface.cpp b/features/nanostack/mbed-mesh-api/source/WisunInterface.cpp index 0cdf79dbd24..36687a82961 100644 --- a/features/nanostack/mbed-mesh-api/source/WisunInterface.cpp +++ b/features/nanostack/mbed-mesh-api/source/WisunInterface.cpp @@ -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(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; }