diff --git a/TESTS/network/emac/emac_TestNetworkStack.cpp b/TESTS/network/emac/emac_TestNetworkStack.cpp index ca1449014f..6f8afc4cdd 100644 --- a/TESTS/network/emac/emac_TestNetworkStack.cpp +++ b/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/TESTS/network/emac/emac_TestNetworkStack.h b/TESTS/network/emac/emac_TestNetworkStack.h index 1403313669..841e906f6e 100644 --- a/TESTS/network/emac/emac_TestNetworkStack.h +++ b/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/UNITTESTS/features/netsocket/NetworkInterface/test_NetworkInterface.cpp b/UNITTESTS/features/netsocket/NetworkInterface/test_NetworkInterface.cpp index b89e503617..535faa4a33 100644 --- a/UNITTESTS/features/netsocket/NetworkInterface/test_NetworkInterface.cpp +++ b/UNITTESTS/features/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/UNITTESTS/stubs/NetworkInterface_stub.cpp b/UNITTESTS/stubs/NetworkInterface_stub.cpp index 16521ac052..dfab019eeb 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/features/nanostack/mbed-mesh-api/mbed-mesh-api/MeshInterfaceNanostack.h b/features/nanostack/mbed-mesh-api/mbed-mesh-api/MeshInterfaceNanostack.h index 51d4ca1431..6863e4c0af 100644 --- a/features/nanostack/mbed-mesh-api/mbed-mesh-api/MeshInterfaceNanostack.h +++ b/features/nanostack/mbed-mesh-api/mbed-mesh-api/MeshInterfaceNanostack.h @@ -29,6 +29,7 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.15", "String-based APIs are deprecated") virtual char *get_ip_address(char *buf, nsapi_size_t buflen); virtual char *get_mac_address(char *buf, nsapi_size_t buflen); + virtual nsapi_error_t set_mac_address(uint8_t *buf, nsapi_size_t buflen); virtual nsapi_error_t get_netmask(SocketAddress *address); MBED_DEPRECATED_SINCE("mbed-os-5.15", "String-based APIs are deprecated") virtual char *get_netmask(char *buf, nsapi_size_t buflen); @@ -37,14 +38,7 @@ public: virtual char *get_gateway(char *buf, nsapi_size_t buflen); virtual void attach(mbed::Callback status_cb); virtual nsapi_connection_status_t get_connection_status() const; - - 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 @@ -118,6 +112,9 @@ public: */ virtual const char *get_mac_address(); + /** @copydoc NetworkInterface::set_mac_address */ + virtual nsapi_error_t set_mac_address(uint8_t *mac_addr, nsapi_size_t addr_len); + /** Register callback for status reporting * * The specified status callback function will be called on status changes diff --git a/features/nanostack/mbed-mesh-api/mbed-mesh-api/NanostackEthernetInterface.h b/features/nanostack/mbed-mesh-api/mbed-mesh-api/NanostackEthernetInterface.h index da2c9d4881..31852974b3 100644 --- a/features/nanostack/mbed-mesh-api/mbed-mesh-api/NanostackEthernetInterface.h +++ b/features/nanostack/mbed-mesh-api/mbed-mesh-api/NanostackEthernetInterface.h @@ -28,6 +28,8 @@ public: nsapi_ip_stack_t stack = DEFAULT_STACK, bool blocking = true); virtual nsapi_error_t bringdown(); + virtual void get_mac_address(uint8_t *buf); + virtual char *get_mac_address(char *buf, nsapi_size_t buflen); char *get_interface_name(char *buf); private: diff --git a/features/nanostack/mbed-mesh-api/source/MeshInterfaceNanostack.cpp b/features/nanostack/mbed-mesh-api/source/MeshInterfaceNanostack.cpp index b33b83f84e..f09f2175ef 100644 --- a/features/nanostack/mbed-mesh-api/source/MeshInterfaceNanostack.cpp +++ b/features/nanostack/mbed-mesh-api/source/MeshInterfaceNanostack.cpp @@ -61,6 +61,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; @@ -86,6 +107,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) { @@ -237,6 +266,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/features/nanostack/mbed-mesh-api/source/NanostackEMACInterface.cpp b/features/nanostack/mbed-mesh-api/source/NanostackEMACInterface.cpp index cecb39cabc..dcd85973c6 100644 --- a/features/nanostack/mbed-mesh-api/source/NanostackEMACInterface.cpp +++ b/features/nanostack/mbed-mesh-api/source/NanostackEMACInterface.cpp @@ -209,7 +209,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) @@ -218,4 +225,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/features/nanostack/mbed-mesh-api/source/NanostackEthernetInterface.cpp b/features/nanostack/mbed-mesh-api/source/NanostackEthernetInterface.cpp index 3ad3e3fa39..681f0f62b8 100644 --- a/features/nanostack/mbed-mesh-api/source/NanostackEthernetInterface.cpp +++ b/features/nanostack/mbed-mesh-api/source/NanostackEthernetInterface.cpp @@ -129,3 +129,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/features/nanostack/nanostack-interface/Nanostack.h b/features/nanostack/nanostack-interface/Nanostack.h index a266233f74..bcc4314dc5 100644 --- a/features/nanostack/nanostack-interface/Nanostack.h +++ b/features/nanostack/nanostack-interface/Nanostack.h @@ -41,6 +41,7 @@ public: /* Implement OnboardNetworkStack method */ virtual nsapi_error_t add_ethernet_interface(EMAC &emac, bool default_if, OnboardNetworkStack::Interface **interface_out); + virtual nsapi_error_t add_ethernet_interface(EMAC &emac, bool default_if, OnboardNetworkStack::Interface **interface_out, const uint8_t *mac_addr); /* 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); diff --git a/features/netsocket/EMACInterface.cpp b/features/netsocket/EMACInterface.cpp index 275ac601bf..a212a14522 100644 --- a/features/netsocket/EMACInterface.cpp +++ b/features/netsocket/EMACInterface.cpp @@ -15,9 +15,12 @@ */ #include "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), @@ -25,6 +28,7 @@ EMACInterface::EMACInterface(EMAC &emac, OnboardNetworkStack &stack) : _interface(NULL), _dhcp(true), _blocking(true), + _hw_mac_addr_set(false), _ip_address(), _netmask(), _gateway() @@ -68,7 +72,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; @@ -100,6 +116,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/features/netsocket/EMACInterface.h b/features/netsocket/EMACInterface.h index 1e493ea3a4..4a359f1acf 100644 --- a/features/netsocket/EMACInterface.h +++ b/features/netsocket/EMACInterface.h @@ -99,6 +99,9 @@ public: */ virtual const char *get_mac_address(); + /** @copydoc NetworkInterface::set_mac_address */ + virtual nsapi_error_t set_mac_address(uint8_t *mac_addr, nsapi_size_t addr_len); + /** Get the local IP address * * @return Null-terminated representation of the local IP address @@ -196,10 +199,12 @@ protected: OnboardNetworkStack::Interface *_interface; bool _dhcp; bool _blocking; + bool _hw_mac_addr_set; 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/features/netsocket/NetworkInterface.cpp b/features/netsocket/NetworkInterface.cpp index 37b49747ab..0bbc77b909 100644 --- a/features/netsocket/NetworkInterface.cpp +++ b/features/netsocket/NetworkInterface.cpp @@ -32,6 +32,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/features/netsocket/NetworkInterface.h b/features/netsocket/NetworkInterface.h index a03909d795..bfb86d030d 100644 --- a/features/netsocket/NetworkInterface.h +++ b/features/netsocket/NetworkInterface.h @@ -100,6 +100,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/features/netsocket/OnboardNetworkStack.h b/features/netsocket/OnboardNetworkStack.h index 16f1a79107..53fc4ab9b4 100644 --- a/features/netsocket/OnboardNetworkStack.h +++ b/features/netsocket/OnboardNetworkStack.h @@ -159,6 +159,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/targets/TARGET_WICED/TOOLCHAIN_ARMC6/TARGET_MTB_ADV_WISE_1530/libwiced_drivers.ar b/targets/TARGET_WICED/TOOLCHAIN_ARMC6/TARGET_MTB_ADV_WISE_1530/libwiced_drivers.ar index e4a3bb090e..9d510f4532 100644 Binary files a/targets/TARGET_WICED/TOOLCHAIN_ARMC6/TARGET_MTB_ADV_WISE_1530/libwiced_drivers.ar and b/targets/TARGET_WICED/TOOLCHAIN_ARMC6/TARGET_MTB_ADV_WISE_1530/libwiced_drivers.ar differ diff --git a/targets/TARGET_WICED/TOOLCHAIN_ARMC6/TARGET_MTB_MXCHIP_EMW3166/libwiced_drivers.ar b/targets/TARGET_WICED/TOOLCHAIN_ARMC6/TARGET_MTB_MXCHIP_EMW3166/libwiced_drivers.ar index 9cb667c931..ad1890ccc1 100644 Binary files a/targets/TARGET_WICED/TOOLCHAIN_ARMC6/TARGET_MTB_MXCHIP_EMW3166/libwiced_drivers.ar and b/targets/TARGET_WICED/TOOLCHAIN_ARMC6/TARGET_MTB_MXCHIP_EMW3166/libwiced_drivers.ar differ diff --git a/targets/TARGET_WICED/TOOLCHAIN_ARMC6/TARGET_MTB_USI_WM_BN_BM_22/libwiced_drivers.ar b/targets/TARGET_WICED/TOOLCHAIN_ARMC6/TARGET_MTB_USI_WM_BN_BM_22/libwiced_drivers.ar index 870b702766..9b1bb2ad13 100644 Binary files a/targets/TARGET_WICED/TOOLCHAIN_ARMC6/TARGET_MTB_USI_WM_BN_BM_22/libwiced_drivers.ar and b/targets/TARGET_WICED/TOOLCHAIN_ARMC6/TARGET_MTB_USI_WM_BN_BM_22/libwiced_drivers.ar differ