diff --git a/UNITTESTS/stubs/NetworkInterface_stub.cpp b/UNITTESTS/stubs/NetworkInterface_stub.cpp index f039a848ca..020a551ba9 100644 --- a/UNITTESTS/stubs/NetworkInterface_stub.cpp +++ b/UNITTESTS/stubs/NetworkInterface_stub.cpp @@ -26,6 +26,11 @@ const char *NetworkInterface::get_mac_address() return 0; } +nsapi_error_t NetworkInterface::set_mac_address(uint8_t *mac_addr, nsapi_size_t addr_len) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + nsapi_error_t NetworkInterface::get_ip_address(SocketAddress *) { return NSAPI_ERROR_UNSUPPORTED; diff --git a/connectivity/nanostack/include/nanostack-interface/Nanostack.h b/connectivity/nanostack/include/nanostack-interface/Nanostack.h index c322ef75a5..53894a1f10 100644 --- a/connectivity/nanostack/include/nanostack-interface/Nanostack.h +++ b/connectivity/nanostack/include/nanostack-interface/Nanostack.h @@ -41,6 +41,7 @@ public: /* Implement OnboardNetworkStack method */ nsapi_error_t add_ethernet_interface(EMAC &emac, bool default_if, OnboardNetworkStack::Interface **interface_out) override; + nsapi_error_t add_ethernet_interface(EMAC &emac, bool default_if, OnboardNetworkStack::Interface **interface_out, const uint8_t *mac_addr) override; /* Local variant with stronger typing and manual address specification */ nsapi_error_t add_ethernet_interface(EMAC &emac, bool default_if, Nanostack::EthernetInterface **interface_out, const uint8_t *mac_addr = NULL); @@ -74,7 +75,7 @@ protected: * @param interface_name Network interface name * @return NSAPI_ERROR_OK on success, negative error code on failure. */ - virtual nsapi_error_t gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version, const char *interface_name); + virtual nsapi_error_t gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version, const char *interface_name) override; /** Translate a hostname to an IP address (asynchronous) using network interface name. * @@ -98,7 +99,7 @@ protected: * a positive unique id that represents the hostname translation operation * and can be passed to cancel. */ - virtual nsapi_value_or_error_t gethostbyname_async(const char *name, hostbyname_cb_t callback, nsapi_version_t version, const char *interface_name); + virtual nsapi_value_or_error_t gethostbyname_async(const char *name, hostbyname_cb_t callback, nsapi_version_t version, const char *interface_name) override; /** Get a domain name server from a list of servers to query * @@ -107,9 +108,10 @@ protected: * * @param index Index of the DNS server, starts from zero * @param address Destination for the host address + * @param interface_name Network interface name * @return 0 on success, negative error code on failure */ - virtual nsapi_error_t get_dns_server(int index, SocketAddress *address, const char *interface_name); + virtual nsapi_error_t get_dns_server(int index, SocketAddress *address, const char *interface_name) override; /** Opens a socket * diff --git a/connectivity/nanostack/mbed-mesh-api/mbed-mesh-api/MeshInterfaceNanostack.h b/connectivity/nanostack/mbed-mesh-api/mbed-mesh-api/MeshInterfaceNanostack.h index 8b8691aa19..cbe956d0eb 100644 --- a/connectivity/nanostack/mbed-mesh-api/mbed-mesh-api/MeshInterfaceNanostack.h +++ b/connectivity/nanostack/mbed-mesh-api/mbed-mesh-api/MeshInterfaceNanostack.h @@ -26,19 +26,13 @@ class Nanostack::Interface : public OnboardNetworkStack::Interface, private mbed::NonCopyable { public: nsapi_error_t get_ip_address(SocketAddress *address) final; - char *get_mac_address(char *buf, nsapi_size_t buflen) final; + char *get_mac_address(char *buf, nsapi_size_t buflen) override; + nsapi_error_t set_mac_address(uint8_t *buf, nsapi_size_t buflen); nsapi_error_t get_netmask(SocketAddress *address) final; nsapi_error_t get_gateway(SocketAddress *address) override; void attach(mbed::Callback status_cb) final; nsapi_connection_status_t get_connection_status() const final; - - void get_mac_address(uint8_t *buf) const - { - NanostackMACPhy *phy = interface_phy.nanostack_mac_phy(); - if (phy) { - phy->get_mac_address(buf); - } - } + virtual void get_mac_address(uint8_t *buf) const; /** * \brief Callback from C-layer @@ -109,6 +103,9 @@ public: */ const char *get_mac_address() override; + /** @copydoc NetworkInterface::set_mac_address */ + nsapi_error_t set_mac_address(uint8_t *mac_addr, nsapi_size_t addr_len) override; + /** Register callback for status reporting * * The specified status callback function will be called on status changes diff --git a/connectivity/nanostack/mbed-mesh-api/mbed-mesh-api/NanostackEthernetInterface.h b/connectivity/nanostack/mbed-mesh-api/mbed-mesh-api/NanostackEthernetInterface.h index 4d0ffefe9f..38e9df6202 100644 --- a/connectivity/nanostack/mbed-mesh-api/mbed-mesh-api/NanostackEthernetInterface.h +++ b/connectivity/nanostack/mbed-mesh-api/mbed-mesh-api/NanostackEthernetInterface.h @@ -28,8 +28,10 @@ public: nsapi_ip_stack_t stack = DEFAULT_STACK, bool blocking = true) override; nsapi_error_t bringdown() override; + void get_mac_address(uint8_t *buf); + char *get_mac_address(char *buf, nsapi_size_t buflen) override; - char *get_interface_name(char *buf); + char *get_interface_name(char *buf) override; private: friend class Nanostack; friend class NanostackEthernetInterface; diff --git a/connectivity/nanostack/mbed-mesh-api/mbed-mesh-api/NanostackPPPInterface.h b/connectivity/nanostack/mbed-mesh-api/mbed-mesh-api/NanostackPPPInterface.h index 75876f6f1b..1297c2f9e9 100644 --- a/connectivity/nanostack/mbed-mesh-api/mbed-mesh-api/NanostackPPPInterface.h +++ b/connectivity/nanostack/mbed-mesh-api/mbed-mesh-api/NanostackPPPInterface.h @@ -32,7 +32,7 @@ public: typedef mbed::Callback link_state_cb_t; void set_link_state_changed_callback(link_state_cb_t link_state_cb); - char *get_interface_name(char *buf); + char *get_interface_name(char *buf) override; private: friend class Nanostack; PPPInterface(NanostackPPPPhy &phy) : Interface(phy) {} diff --git a/connectivity/nanostack/mbed-mesh-api/source/MeshInterfaceNanostack.cpp b/connectivity/nanostack/mbed-mesh-api/source/MeshInterfaceNanostack.cpp index 43718d7f72..fb90a7a9fb 100644 --- a/connectivity/nanostack/mbed-mesh-api/source/MeshInterfaceNanostack.cpp +++ b/connectivity/nanostack/mbed-mesh-api/source/MeshInterfaceNanostack.cpp @@ -48,6 +48,27 @@ char *Nanostack::Interface::get_mac_address(char *buf, nsapi_size_t buflen) } } +nsapi_error_t Nanostack::Interface::set_mac_address(uint8_t *buf, nsapi_size_t buflen) +{ + if (buflen != 8) { + /* Provided MAC is too short */ + return NSAPI_ERROR_PARAMETER; + } + + if (_device_id >= 0) { + /* device is already registered, can't set MAC address anymore */ + return NSAPI_ERROR_BUSY; + } + + NanostackMACPhy *phy = interface_phy.nanostack_mac_phy(); + if (phy) { + phy->set_mac_address(buf); + return NSAPI_ERROR_OK; + } + + return NSAPI_ERROR_UNSUPPORTED; +} + nsapi_error_t Nanostack::Interface::get_netmask(SocketAddress *address) { return NSAPI_ERROR_UNSUPPORTED; @@ -63,6 +84,14 @@ nsapi_connection_status_t Nanostack::Interface::get_connection_status() const return _connect_status; } +void Nanostack::Interface::get_mac_address(uint8_t *buf) const +{ + NanostackMACPhy *phy = interface_phy.nanostack_mac_phy(); + if (phy) { + phy->get_mac_address(buf); + } +} + void Nanostack::Interface::attach( mbed::Callback status_cb) { @@ -197,6 +226,11 @@ const char *InterfaceNanostack::get_mac_address() return NULL; } +nsapi_error_t InterfaceNanostack::set_mac_address(uint8_t *mac_addr, nsapi_size_t addr_len) +{ + return _interface->set_mac_address(mac_addr, addr_len); +} + nsapi_connection_status_t InterfaceNanostack::get_connection_status() const { if (_interface) { diff --git a/connectivity/nanostack/mbed-mesh-api/source/NanostackEMACInterface.cpp b/connectivity/nanostack/mbed-mesh-api/source/NanostackEMACInterface.cpp index 8d677a4b56..b9c243c4f6 100644 --- a/connectivity/nanostack/mbed-mesh-api/source/NanostackEMACInterface.cpp +++ b/connectivity/nanostack/mbed-mesh-api/source/NanostackEMACInterface.cpp @@ -222,7 +222,14 @@ nsapi_error_t Nanostack::add_ethernet_interface(EMAC &emac, bool default_if, Nan *interface_out = interface; return NSAPI_ERROR_OK; +} +nsapi_error_t Nanostack::add_ethernet_interface(EMAC &emac, bool default_if, OnboardNetworkStack::Interface **interface_out, const uint8_t *mac_addr) +{ + Nanostack::EthernetInterface *interface; + nsapi_error_t err = add_ethernet_interface(emac, default_if, &interface, mac_addr); + *interface_out = interface; + return err; } nsapi_error_t Nanostack::add_ethernet_interface(EMAC &emac, bool default_if, OnboardNetworkStack::Interface **interface_out) @@ -231,4 +238,4 @@ nsapi_error_t Nanostack::add_ethernet_interface(EMAC &emac, bool default_if, Onb nsapi_error_t err = add_ethernet_interface(emac, default_if, &interface); *interface_out = interface; return err; -} +} \ No newline at end of file diff --git a/connectivity/nanostack/mbed-mesh-api/source/NanostackEthernetInterface.cpp b/connectivity/nanostack/mbed-mesh-api/source/NanostackEthernetInterface.cpp index 189671d00d..6b05ff2f2b 100644 --- a/connectivity/nanostack/mbed-mesh-api/source/NanostackEthernetInterface.cpp +++ b/connectivity/nanostack/mbed-mesh-api/source/NanostackEthernetInterface.cpp @@ -132,3 +132,26 @@ char *Nanostack::EthernetInterface::get_interface_name(char *buf) sprintf(buf, "ETH%d", interface_id); return buf; }; + +void Nanostack::EthernetInterface::get_mac_address(uint8_t *buf) +{ + if (!buf) { + return; + } + + get_phy().get_mac_address(buf); +} + +char *Nanostack::EthernetInterface::get_mac_address(char *buf, nsapi_size_t buflen) +{ + uint8_t mac_buf[NSAPI_MAC_BYTES] = {0}; + + if (!buf || buflen < NSAPI_MAC_SIZE) { + return NULL; + } + + get_phy().get_mac_address(mac_buf); + + snprintf(buf, buflen, "%02x:%02x:%02x:%02x:%02x:%02x", mac_buf[0], mac_buf[1], mac_buf[2], mac_buf[3], mac_buf[4], mac_buf[5]); + return buf; +} diff --git a/connectivity/netsocket/include/netsocket/EMACInterface.h b/connectivity/netsocket/include/netsocket/EMACInterface.h index 8979b0942e..8cf47cb703 100644 --- a/connectivity/netsocket/include/netsocket/EMACInterface.h +++ b/connectivity/netsocket/include/netsocket/EMACInterface.h @@ -86,6 +86,9 @@ public: /** @copydoc NetworkInterface::get_mac_address */ const char *get_mac_address() override; + /** @copydoc NetworkInterface::set_mac_address */ + nsapi_error_t set_mac_address(uint8_t *mac_addr, nsapi_size_t addr_len) override; + /** @copydoc NetworkInterface::get_ip_address */ nsapi_error_t get_ip_address(SocketAddress *address) override; @@ -143,10 +146,12 @@ protected: OnboardNetworkStack::Interface *_interface = nullptr; bool _dhcp = true; bool _blocking = true; + bool _hw_mac_addr_set = false; char _mac_address[NSAPI_MAC_SIZE]; char _ip_address[NSAPI_IPv6_SIZE] {}; char _netmask[NSAPI_IPv4_SIZE] {}; char _gateway[NSAPI_IPv4_SIZE] {}; + uint8_t _hw_mac_addr[NSAPI_MAC_BYTES] {}; mbed::Callback _connection_status_cb; }; diff --git a/connectivity/netsocket/include/netsocket/NetworkInterface.h b/connectivity/netsocket/include/netsocket/NetworkInterface.h index ef7748ff93..25d9f546eb 100644 --- a/connectivity/netsocket/include/netsocket/NetworkInterface.h +++ b/connectivity/netsocket/include/netsocket/NetworkInterface.h @@ -101,6 +101,31 @@ public: */ virtual const char *get_mac_address(); + /** Set the MAC address to the interface. + * + * Set the provided MAC address on the network interface. The address must + * be unique globally. The address must be set before calling the interface + * connect() method. + * + * Not all interfaces are supporting MAC address set and an error is not returned + * for this method call. Verify the changed MAC address by checking packet + * captures from the used network interface. + * + * 6-byte EUI-48 MAC addresses are used for Ethernet while Mesh interface is + * using 8-byte EUI-64 address. + * + * More information about obtaining MAC address can be found from: + * https://standards.ieee.org/products-services/regauth/index.html + * + * @param mac_addr Buffer containing the MAC address in hexadecimal format. + * @param addr_len Length of provided buffer in bytes (6 or 8) + * @retval NSAPI_ERROR_OK on success + * @retval NSAPI_ERROR_UNSUPPORTED if this feature is not supported + * @retval NSAPI_ERROR_PARAMETER if address is not valid + * @retval NSAPI_ERROR_BUSY if address can't be set. + */ + virtual nsapi_error_t set_mac_address(uint8_t *mac_addr, nsapi_size_t addr_len); + /** Get the local IP address * * @param address SocketAddress representation of the local IP address diff --git a/connectivity/netsocket/include/netsocket/OnboardNetworkStack.h b/connectivity/netsocket/include/netsocket/OnboardNetworkStack.h index 0a4e67c6ea..8c48c7b75f 100644 --- a/connectivity/netsocket/include/netsocket/OnboardNetworkStack.h +++ b/connectivity/netsocket/include/netsocket/OnboardNetworkStack.h @@ -162,6 +162,11 @@ public: */ virtual nsapi_error_t add_ethernet_interface(EMAC &emac, bool default_if, Interface **interface_out) = 0; + virtual nsapi_error_t add_ethernet_interface(EMAC &emac, bool default_if, Interface **interface_out, const uint8_t *mac_addr) + { + return NSAPI_ERROR_UNSUPPORTED; + } + virtual nsapi_error_t add_l3ip_interface(L3IP &l3ip, bool default_if, Interface **interface_out) { return NSAPI_ERROR_OK; diff --git a/connectivity/netsocket/source/EMACInterface.cpp b/connectivity/netsocket/source/EMACInterface.cpp index fba8fa5888..6474b6a570 100644 --- a/connectivity/netsocket/source/EMACInterface.cpp +++ b/connectivity/netsocket/source/EMACInterface.cpp @@ -16,9 +16,12 @@ */ #include "netsocket/EMACInterface.h" +#include "mbed-trace/mbed_trace.h" using namespace mbed; +#define TRACE_GROUP "EMACi" + /* Interface implementation */ EMACInterface::EMACInterface(EMAC &emac, OnboardNetworkStack &stack) : _emac(emac), @@ -49,7 +52,19 @@ nsapi_error_t EMACInterface::set_dhcp(bool dhcp) nsapi_error_t EMACInterface::connect() { if (!_interface) { - nsapi_error_t err = _stack.add_ethernet_interface(_emac, true, &_interface); + nsapi_error_t err = NSAPI_ERROR_UNSUPPORTED; + + if (_hw_mac_addr_set) { + err = _stack.add_ethernet_interface(_emac, true, &_interface, _hw_mac_addr); + if (err == NSAPI_ERROR_UNSUPPORTED) { + tr_error("Failed to set user MAC address"); + } + } + + if (err == NSAPI_ERROR_UNSUPPORTED) { + err = _stack.add_ethernet_interface(_emac, true, &_interface); + } + if (err != NSAPI_ERROR_OK) { _interface = NULL; return err; @@ -81,6 +96,23 @@ const char *EMACInterface::get_mac_address() return nullptr; } +nsapi_error_t EMACInterface::set_mac_address(uint8_t *mac_addr, nsapi_size_t addr_len) +{ + if (!mac_addr || addr_len != NSAPI_MAC_BYTES) { + return NSAPI_ERROR_PARAMETER; + } + + if (_interface) { + // can't set MAC address once initialized + return NSAPI_ERROR_BUSY; + } + + memcpy(_hw_mac_addr, mac_addr, addr_len); + _hw_mac_addr_set = true; + + return NSAPI_ERROR_OK; +} + nsapi_error_t EMACInterface::get_ip_address(SocketAddress *address) { if (_interface && _interface->get_ip_address(address) == NSAPI_ERROR_OK) { diff --git a/connectivity/netsocket/source/NetworkInterface.cpp b/connectivity/netsocket/source/NetworkInterface.cpp index 6e0ecd8a57..3dcd4b33fe 100644 --- a/connectivity/netsocket/source/NetworkInterface.cpp +++ b/connectivity/netsocket/source/NetworkInterface.cpp @@ -33,6 +33,11 @@ const char *NetworkInterface::get_mac_address() return 0; } +nsapi_error_t NetworkInterface::set_mac_address(uint8_t *mac_addr, nsapi_size_t addr_len) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + nsapi_error_t NetworkInterface::get_ip_address(SocketAddress *) { return NSAPI_ERROR_UNSUPPORTED; diff --git a/connectivity/netsocket/tests/TESTS/network/emac/emac_TestNetworkStack.cpp b/connectivity/netsocket/tests/TESTS/network/emac/emac_TestNetworkStack.cpp index ca1449014f..6f8afc4cdd 100644 --- a/connectivity/netsocket/tests/TESTS/network/emac/emac_TestNetworkStack.cpp +++ b/connectivity/netsocket/tests/TESTS/network/emac/emac_TestNetworkStack.cpp @@ -155,6 +155,11 @@ char *EmacTestNetworkStack::Interface::get_mac_address(char *buf, nsapi_size_t b return NULL; } +nsapi_error_t EmacTestNetworkStack::Interface::set_mac_address(uint8_t *buf, nsapi_size_t buflen) +{ + return NSAPI_STATUS_ERROR_UNSUPPORTED; +} + nsapi_error_t EmacTestNetworkStack::Interface::get_ip_address(SocketAddress *address) { return NSAPI_ERROR_OK; diff --git a/connectivity/netsocket/tests/TESTS/network/emac/emac_TestNetworkStack.h b/connectivity/netsocket/tests/TESTS/network/emac/emac_TestNetworkStack.h index 3b66dcbde2..95eba068a4 100644 --- a/connectivity/netsocket/tests/TESTS/network/emac/emac_TestNetworkStack.h +++ b/connectivity/netsocket/tests/TESTS/network/emac/emac_TestNetworkStack.h @@ -86,6 +86,17 @@ public: */ virtual char *get_mac_address(char *buf, nsapi_size_t buflen); + /** Set MAC address on the network interface + * + * @param mac_addr Buffer containing the MAC address in hexadecimal format. + * @param addr_len Length of provided buffer in bytes (6 or 8) + * @retval NSAPI_ERROR_OK on success + * @retval NSAPI_ERROR_UNSUPPORTED if this feature is not supported + * @retval NSAPI_ERROR_PARAMETER if address is not valid + * @retval NSAPI_ERROR_BUSY if address can't be set. + */ + virtual nsapi_error_t set_mac_address(uint8_t *mac_addr, nsapi_size_t addr_len); + /** Copies IP address of the network interface to user supplied buffer * * @param buf buffer to which IP address will be copied as "W:X:Y:Z" diff --git a/connectivity/netsocket/tests/UNITTESTS/netsocket/NetworkInterface/test_NetworkInterface.cpp b/connectivity/netsocket/tests/UNITTESTS/netsocket/NetworkInterface/test_NetworkInterface.cpp index 6552487e80..1a928c36ee 100644 --- a/connectivity/netsocket/tests/UNITTESTS/netsocket/NetworkInterface/test_NetworkInterface.cpp +++ b/connectivity/netsocket/tests/UNITTESTS/netsocket/NetworkInterface/test_NetworkInterface.cpp @@ -75,6 +75,12 @@ TEST_F(TestNetworkInterface, get_mac_address) EXPECT_EQ(iface->get_mac_address(), n); } +TEST_F(TestNetworkInterface, set_mac_address) +{ + uint8_t mac_buf[8]; + EXPECT_EQ(iface->set_mac_address(mac_buf, 8), NSAPI_ERROR_UNSUPPORTED); +} + TEST_F(TestNetworkInterface, get_ip_address) { SocketAddress addr; diff --git a/targets/TARGET_WICED/TOOLCHAIN_ARMC6/TARGET_WIO_EMW3166/libwiced_drivers.ar b/targets/TARGET_WICED/TOOLCHAIN_ARMC6/TARGET_WIO_EMW3166/libwiced_drivers.ar index 953b7d0490..e382daecc6 100644 Binary files a/targets/TARGET_WICED/TOOLCHAIN_ARMC6/TARGET_WIO_EMW3166/libwiced_drivers.ar and b/targets/TARGET_WICED/TOOLCHAIN_ARMC6/TARGET_WIO_EMW3166/libwiced_drivers.ar differ