Skip to content
5 changes: 5 additions & 0 deletions UNITTESTS/stubs/NetworkInterface_stub.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class Nanostack : public OnboardNetworkStack, private mbed::NonCopyable<Nanostac

/* 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);
Expand Down Expand Up @@ -74,7 +75,7 @@ class Nanostack : public OnboardNetworkStack, private mbed::NonCopyable<Nanostac
* @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.
*
Expand All @@ -98,7 +99,7 @@ class Nanostack : public OnboardNetworkStack, private mbed::NonCopyable<Nanostac
* 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
*
Expand All @@ -107,9 +108,10 @@ class Nanostack : public OnboardNetworkStack, private mbed::NonCopyable<Nanostac
*
* @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
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,13 @@
class Nanostack::Interface : public OnboardNetworkStack::Interface, private mbed::NonCopyable<Nanostack::Interface> {
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<void(nsapi_event_t, intptr_t)> 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
Expand Down Expand Up @@ -109,6 +103,9 @@ class InterfaceNanostack : public virtual NetworkInterface {
*/
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ class Nanostack::EthernetInterface final : public Nanostack::Interface {
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class Nanostack::PPPInterface final : public Nanostack::Interface {
typedef mbed::Callback<void (uint8_t up, int8_t device_id)> 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) {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<void(nsapi_event_t, intptr_t)> status_cb)
{
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
5 changes: 5 additions & 0 deletions connectivity/netsocket/include/netsocket/EMACInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ class EMACInterface : public virtual NetworkInterface {
/** @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;

Expand Down Expand Up @@ -143,10 +146,12 @@ class EMACInterface : public virtual NetworkInterface {
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<void(nsapi_event_t, intptr_t)> _connection_status_cb;
};

Expand Down
25 changes: 25 additions & 0 deletions connectivity/netsocket/include/netsocket/NetworkInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,31 @@ class NetworkInterface: public DNS {
*/
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@ class OnboardNetworkStack : public NetworkStack {
*/
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;
Expand Down
34 changes: 33 additions & 1 deletion connectivity/netsocket/source/EMACInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down
5 changes: 5 additions & 0 deletions connectivity/netsocket/source/NetworkInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,17 @@ class EmacTestNetworkStack : public OnboardNetworkStack, private mbed::NonCopyab
*/
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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Binary file not shown.