Merely adding a protocol stack and networking API to your software doesn't make you TCP/IP ready. You'll also need to assign your product a MAC address.

Any book on TCP/IP will tell you that each network-connected device has a globally unique hardware address. But where, exactly, do these addresses come from? And why is it that the authors of books on TCP/IP never bother to answer this or any other practical implementation question?

Plenty of good books are available about TCP/IP and I have no desire to rehash the material covered there. Rather, I hope to supplement the discussion found in those books with the practical information embedded developers need most. I begin by tackling some of the oft-ignored practicalities in and around embedded networking.

Hidden assumptions

Before we go on, I want to make sure you have a solid picture in your head. That picture is the one in Figure 1, which shows how the TCP/UDP/IP stack fits in between your application code and the network interface. What I want you to understand from this figure is the black box nature of the stack. From the application programmer's point of view, a TCP/UDP/IP stack is nothing but an API to be called. In other words, data is sent and received over the network via a set of well-defined function calls. Typically, the so-called "sockets" API is used.

Figure 1 also shows the black box nature of the network interface. In an ideal world, the device driver interface would remove the stack developer from any knowledge of the actual interface type. In such a case, the same stack could communicate unchanged over an Ethernet network or via a serial or modem link, through the same set of device driver calls. In practice, however, this is difficult to achieve.

Figure 1. Protocol stack in context

You'll see as we go along that the implementation of the lowest layers of the TCP/UDP/IP stack is inextricably linked with the device driver and particulars of the hardware below. This is one of those practical realities rarely dealt with in books.

If you read Christopher Leidigh's recent article in Embedded Systems Programming ("Configuring TCP/IP Hosts," April 2000), you're probably aware that simply adding a protocol stack and network interface to your software doesn't make your system TCP/IP-ready. Among other things, each system requires an IP address to communicate over the network. Leidigh's article did a great job of showing us how to bootstrap a system, determining the IP address in the process. But did you notice the way he assumed (like everyone else) that your system already had a unique hardware address?

"Upon receipt [of the broadcast packet], a RARP server will look up the client's hardware address in its tables [and return the IP address allocated to the client]".

Where does the "client's hardware address" (also called the MAC address1) come from? Unlike the IP address, this is not something you can request from a local server. In fact, the RARP server referred to in the above quote can only respond to your system by using the hardware address it sent within the IP address request. The hardware address must be built into your system at manufacturing time.

This leads, of course, to two questions. One is: what value should you use for the hardware address? The other is: how do you have that value "built into your system"? I'll answer the second, and easier, question first. Every system on a physical network like Ethernet includes a peripheral called a network controller. This chip is the processor's interface to the physical communications medium. As part of its initialization, the network controller must be fed a unique hardware address. In the case of Ethernet, the hardware address is a 48-bit value. In all but the rarest of circumstances, the hardware address will reside in an on-board non-volatile memory device.

Since the hardware address is unique for each board that rolls off the assembly line, it's typically not placed in the same ROM as the firmware. That way, identical copies of the firmware can be mass produced at a lower average cost per chip, while the unique hardware address can be placed in a very small EEPROM (along with other board-specific parameters, if any) when the board is assembled. The contents of this EEPROM might be determined by the board's serial number and created as part of the manufacturing process.2

Now onto the remaining question.

OUI, Oui!

Okay, so you know what the hardware address is and what to do with it once you've got it. But where does this globally unique 48-bit identifier come from? Clearly 248 is an incredibly large number of unique addresses, but no set of numbers is itself large enough to guarantee global uniqueness on its own. In the case of Ethernet, the upper three bytes of the 48-bit MAC address are carefully controlled by the IEEE. The scheme for guaranteeing uniqueness of the lower three bytes is individually up to the companies that make Ethernet-capable devices. All of us must work together with the IEEE to guarantee global uniqueness of our MAC addresses.

Every company that wants to produce Ethernet-capable products must first register with the IEEE ( You start by filling out some paperwork and sending them a check. In return, your organization becomes the proud owner of a 24-bit Organizationally Unique Identifier (OUI) and the 16,777,216 unique hardware addresses it is capable of identifying.3]

What I've found usually works best for internal management of the lower 24 bits of the address is to break those bits into two fields. For example, you might break up your approximately 16.8 million unique addresses into 256 blocks of 65,536 addresses. That way, you could allocate the blocks one at a time to particular manufacturing groups, on an as-needed basis. The lowest 16 bits of the MAC address could then match up with the lowest 16 bits of the device's serial number for ease of manufacturing. Following this scheme, the 255th board manufactured within block two would be given the MAC address <OUI>:02:00:FF, where <OUI> is the three-byte hexadecimal value assigned to your company by the IEEE.


[1] MAC is short for media access control. [back]

[2] It should be clear that there is nothing to preclude your storing the hardware address in any nonvolatile memory device, including the ROM or Flash that contains the firmware. This is a decision, however, that should be made with manufacturing concerns, and costs, in mind. [back]

[3] I was shocked to learn recently that Cisco owns 60 such sets, for a grand total of over 1 billion addresses! [back]

This column was published in the June 2000 issue of Embedded Systems Programming. If you wish to cite the article in your own work, you may find the following MLA-style information helpful:

Barr, Michael. "MAC Daddy," Embedded Systems Programming, June 2000 , pp. 41-46.