Merge pull request #13936 from artokin/mac_address_set_get_mbed_os_master

Network interface MAC address set/get
pull/13568/head
Martin Kojtal 2020-12-09 05:55:49 +00:00 committed by GitHub
commit e5e315eb80
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 180 additions and 16 deletions

View File

@ -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;

View File

@ -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
*

View File

@ -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
@ -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

View File

@ -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;

View File

@ -32,7 +32,7 @@ public:
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) {}

View File

@ -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<void(nsapi_event_t, intptr_t)> 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) {

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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<void(nsapi_event_t, intptr_t)> _connection_status_cb;
};

View File

@ -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

View File

@ -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;

View File

@ -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) {

View File

@ -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;

View File

@ -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;

View File

@ -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"

View File

@ -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;