Convert MAC address to string

Is there a standard function that will take the MAC address as passed as the last parameter to FreeRTOS_IPInit() and convert it into a string in the form xx:xx:xx:xx:xx:xx?

-Andy.

That is a good question. I always write a printf, but why not make a function of it?

Can you propose a proper function name? Something with ntop?

( Once I was so tired of converting IPv4/6 addresses in logging that I added 2 new formats: %xip and %pip. When using printf-stdarg.c, the formats will translate to the proper ASCII expressions. This may result in for instance 192.168.2.10 (%xip) or fe80::7007 (%pip) )

There is one problem for the implementation, MISRA doesn’t like the use of snprintf(). The function FreeRTOS_inet_ntoa() and FreeRTOS_inet_ntop6() show an attempt to live without snprintf().

In terms of function names I would think either FreeRTOS_mac_... or FreeRTOS_EUI48_... would work as the prefix.

How many functions would we want?

String in the form xx:xx:xx:xx:xx:xx to uint64_t and back again?

Pointer to ucMACAddress[ ipMAC_ADDRESS_LENGTH_BYTES ] to uint64_t?

-Andy.

I’d not recommend abusing uint64_t with the open question of endianness.
A MAC address consists of 6 byte. I’d prefer the byte order starting with OUID.

Hartmut wrote:

I’d not recommend abusing uint64_t with the open question of endianness.

Good point.

As you know, tithin the library, the MAC address is always stored and transferred as:

    uint8_t ucBytes[ ipMAC_ADDRESS_LENGTH_BYTES ]

The term “MAC” address is obsolete, so I also think of FreeRTOS_EUI48_pton and FreeRTOS_EUI48_ntop.
The letters “p” and “n” stand for “presentation” ( “printable” ) and “numeric”.

( IPv4 addresses are stored as uint32_t numbers because that results in more efficient code for comparing and assigning )

This is one of the few places where I’d consider using something like sscanf() to parse the string, since MAC addresses tend to be formatted very rigidly:

char str[] = "00:0d:3f:cd:02:5f";
uint8_t mac_addr[6];
if (sscanf(str, "%x:%x:%x:%x:%x:%x",
           &mac_addr[0],
           &mac_addr[1],
           &mac_addr[2],
           &mac_addr[3],
           &mac_addr[4],
           &mac_addr[5]) < 6)
{
    fprintf(stderr, "could not parse %s\n", str);
}

I still haven’t got around to implementing this (too many other higher priority tasks).

To be generic (and to keep everyone happy) it is potentially going to need more intelligence. The IEEE 802 standard defines the format for printing EUI-48 addresses as xx-xx-xx-xx-xx-xx. The use of xx:xx:xx:xx:xx:xx is common (but not in the standard as far as I can see) and Cisco (amongst others) use the form xxxx.xxxx.xxxx.

Hopefully I will get back to this next week!

-Andy.

I implemented a version of ntop without using printf() :

void FreeRTOS_EUI48_ntop( const uint8_t *pucSource, char * pcTarget, char cTen, char cSeparator )
{
    size_t uxIndex;
    size_t uxNibble;
    size_t uxTarget = 0U;

    for( uxIndex = 0U; uxIndex < ipMAC_ADDRESS_LENGTH_BYTES; uxIndex++ )
    {
        uint8_t ucByte = pucSource[ uxIndex ];
        for( uxNibble = 0; uxNibble < 2U; uxNibble++ )
        {
            uint8_t ucNibble;
            char cResult;
            if( uxNibble == 0U )
            {
                ucNibble = ucByte >> 4;
            }
            else
            {
                ucNibble = ucByte & 0x0FU;
            }
            if( ucNibble < 0x09U )
            {
                cResult = '0';
                cResult = cResult + ucNibble;
            }
            else
            {
                cResult = cTen;    /* Either 'a' or 'A' */
                cResult = cResult + ( ucNibble - 10U );
            }
            pcTarget[ uxTarget++ ] = cResult;
        }
        if( uxIndex == ( ipMAC_ADDRESS_LENGTH_BYTES - 1U ) )
        {
            pcTarget[ uxTarget++ ] = 0;
        }
        else
        {
            pcTarget[ uxTarget++ ] = cSeparator;
        }
    }
}
/*-----------------------------------------------------------*/

The parameter cSeparator can have a value like either ‘:’ or ‘-’.

Hello Hein!
That is a good solution. Thank you for that! :slight_smile:

You wrote:

Correct me if I am wrong but should that not be a <= instead of a <?

Aniruddha, you are absolutely right:

-    if( ucNibble < 0x09U )
+    if( ucNibble <= 0x09U )

In a meanwhile I implemented both functions, and created a PR for both IPv4/IPv6:

IPv6/multi: Adding EUI48_pton and EUI48_ntop for MAC address conversion.
IPv4/single: Adding EUI48_pton and EUI48_ntop for MAC address conversion.

I know that a much shorter version is possible when printf() and scanf() are used. However, these functions are not allowed by the MISRA rules.