Cannot change MAC address dynamically?

Continuing the discussion from FreeRTOS_IPInit function Variable MAC Address:

Hi I’d like the forum to revisit this topic. I’m having a terrible issue just trying to dynamically update my device’s MAC address. I’m building a real device that will have a valid mac address but for now I’m using dummy addresses that do work.

If I change the mac address using the defines, then all is well. But if I change it dynamically then ping replies never succeed. Although arp cache shows the device with the new mac address.

Has anyone solved this? Really stuck here.

One issue is that when you change the MAC address of your device, you need to make sure that the software driver knows about that change and updates its internal copies of that.

The driver may just be seeing the packets with the “wrong” MAC address in them and discarding them.

It might be that the MAC address is cached on the computer you are pinging from so when you ping after changing the MAC address the machine you are pinging from is still sending the packets to the old MAC address. If you are pinging from windows you can do an ‘arp -a’ to print the arp cache - look for the client there with the old mac address. If it’s there with the old MAC you can delete the entry or just flush the ARP cache with `arp -d *'.

Hello Giselle, although there are two great answers already, which might solve your problem, a third suggestion.

Most EMAC peripherals maintain a list of valid MAC-addresses.

When you call IPInit(), the MAC-address will be copied to a variable:

#define ipLOCAL_MAC_ADDRESS           ( xDefaultPartUDPPacketHeader.ucBytes )

And a function like xNetworkInterfaceInitialise() will copy that MAC-address to the EMAC, e.g. here:

    xETH.Init.MACAddr = ( uint8_t * ) FreeRTOS_GetMACAddress();

and later in stm32fxx_hal_eth.c:

    /* Initialize MAC address in ethernet MAC */
    ETH_MACAddressConfig( heth, ETH_MAC_ADDRESS0, heth->Init.MACAddr );

Note that this is a hardware filter. It allows the reception of a certain set of MAC-addresses.
The reception of broadcast and multicast packets is often enabled with special configuration bits.

Now when you call:

void FreeRTOS_UpdateMACAddress( const uint8_t ucMACAddress[ ipMAC_ADDRESS_LENGTH_BYTES ] )
{
    /* Copy the MAC address at the start of the default packet header fragment. */
    ( void ) memcpy( ipLOCAL_MAC_ADDRESS, ucMACAddress, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
}
/*-----------------------------------------------------------*/

all you’re updating is a local variable which will be used for outgoing packets. The hardware will still listen to the old MAC-addresses.

What you’ll have to do is copy the new MAC-address to the hardware.

Matt is right: often the old MAC-address is still cached in the OS.

A FreeRTOS+TCP device will send a gratuitous ARP packet about every 20 seconds (see arpGRATUITOUS_ARP_PERIOD). This packet will inform the devices on the LAN about the (MAC and IP) addresses. When you run WireShark you should see the change in ARP address(!)

What type (brand) of hardware are you using? For STM32xx you might want to call:

    /* xETH is declared static in NetworkInterface. */
    ETH_MACAddressConfig( &( xETH ), ETH_MAC_ADDRESS0, ucNewMAC );