Guide ยท Manufacturing & provisioning
How to allocate MAC addresses to devices during manufacturing
From owning an IEEE block to a programmed, verified unit: how manufacturers assign a unique MAC address to every network interface they ship, and the decisions that keep two units from ever sharing one.
Every Ethernet, Wi-Fi or Bluetooth interface a device ships with needs a MAC address that is unique across every device anyone will ever make. On a production line that means a system for handing out addresses one range at a time, never reusing one, and proving after programming that the address in the part matches the address you assigned. This guide is the vendor-neutral version of that process. For a walkthrough of how the allocation tool here does each step, see how to provision MAC addresses and serial numbers for a device run.
1. Where the addresses come from
You have three practical sources, and most products use more than one:
| Source | What you get | When it fits |
|---|---|---|
| Your own IEEE block (MA-L, MA-M, MA-S) | A prefix that is yours, and the responsibility to allocate within it | The MAC should carry your identity, or volume is high enough that per-unit chip cost matters |
| Pre-programmed MAC EEPROM / ID chip | The silicon vendor's OUI, one globally unique address per chip, loaded at their factory | Low to moderate volume, no need for the address to identify you |
| MAC embedded in the SoC / PHY | The chip vendor's OUI and a per-part address, already in the part | Wi-Fi and consumer designs built around an SoC that ships with one |
The rest of this guide is about the first case, because it is the only one where allocation is your problem to solve. If you are deciding whether you need a block at all, the block capacity calculator works the address maths against your projected volume.
2. MA-L, MA-M and MA-S
IEEE issues assignments in three sizes. The name tells you how many address bits are yours:
| Assignment | Prefix length | EUI-48 addresses | Also known as |
|---|---|---|---|
| MA-L | 24 bits | 224 = 16,777,216 | The classic OUI |
| MA-M | 28 bits | 220 = 1,048,576 | - |
| MA-S | 36 bits | 212 = 4,096 | OUI-36; carries an associated IAB-style range |
An MA-M or MA-S holder shares the first 24 bits with other organizations, so a vendor lookup has to match the full assigned prefix, not just the OUI. See how MAC addresses are structured for the bit layout. Pick the size from lifetime unit count times interfaces per unit, plus margin for scrap and reserved-but-unused ranges: an MA-S is 4,096 addresses and is genuinely easy to exhaust.
macadress.com does not issue or register IEEE assignments and does not verify that you hold one. You register a block you already control, and the tool computes addresses inside the range you assert.
3. Dividing the block between products and factories
Decide the partition before the first unit is built. The goal is that every point which can hand out an address draws from a range no other point can touch:
- Per product line. A router and a separate access point built from the same block get their own sub-ranges, so their sequences and exports never interleave. In the tool this is one portfolio per line.
- Per factory. If two sites build in parallel, give each a distinct sub-range so an outage or a bookkeeping mistake at one cannot produce an address the other already used. See MAC address pool management for multiple factories.
- Reserve headroom. Leave a gap after each sub-range so a line can grow without renumbering.
4. Sequential vs random allocation
Sequential is the default and almost always right: addresses are handed out in order from the low end of a range, so utilisation is obvious, gaps are visible, and an export is a contiguous block. Random allocation within the range is sometimes asked for so that unit counts are not inferable from a captured MAC. It costs you the easy "how much is left" read and needs a collision check on every draw. Unless a specific threat model requires it, allocate sequentially and, if disclosure is the worry, start the range at a non-zero offset.
5. Atomic reservation and concurrency
The failure that produces duplicate MAC addresses is two runs reserving the same range because each read "next free address" before either wrote its result. The fix is that a batch reservation is a single atomic operation: it takes a contiguous MAC range and a matching serial-number range together and advances the pointer once, so two batches started seconds apart on two lines get adjacent ranges, never the same one. Ask this of whatever system you use, spreadsheet-based or not: can two people generate a batch at the same instant and be guaranteed non-overlapping output.
6. Preventing duplicates over the life of the block
Duplicate prevention is not only about concurrency. It also means:
- An address that was allocated but the unit scrapped is not silently returned to the pool. It stays spent unless someone explicitly decides to reuse that exact range.
- A range that a factory did not use is marked released as a deliberate, opt-in starting point for a later run, not auto-recycled.
- Every address ever handed out stays on record, including ones that turned out unused, so any later "was this shipped" question has an answer.
7. Failed, scrapped and partial batches
Real runs do not consume exactly what was reserved:
| Situation | Handling |
|---|---|
| Run of 10,000 reserved, 8,000 good units shipped | Split the batch at 8,000. Mark the first part shipped (now permanent). Release the remaining 2,000 as an explicit starting point for next time. |
| Units fail final test after programming | Their addresses are spent. Do not reissue them. Record the serials as scrapped in your own tracking; the identifiers stay allocated. |
| Whole batch generated then cancelled before build | Release it. Nothing was consumed, and the record of the range having existed is kept. |
| Batch released by mistake | Reactivate it, as long as nothing else has since drawn on that range. |
8. Writing the address into the device
Where the address lives depends on the design:
- EEPROM (a dedicated I2C/SPI part, or a region of a config EEPROM): rewritable, simple to program on the line, simple to correct.
- Flash (a manufacturing data partition, U-Boot environment, a Yocto or Android mfg step): rewritable, but tied to your firmware layout.
- OTP / eFuse (one-time-programmable fuses in the SoC): permanent, tamper-evident, and unforgiving. A wrong value burned here scraps the unit, so verification before the burn matters more, not less.
The programming station consumes a file that maps each unit to its address. Keep that file as the record of what was actually sent to the programmer, separate from what was reserved.
9. Verify after programming
Programming can fail silently: a bad I2C write, a mispositioned part, an off-by-one in the station script. Read the address back from the unit after programming and compare it to the allocated value before the unit passes final test. macadress.com does not do this step for you; it is a line operation. What the tool gives you is the authoritative allocated value to check against, per serial number, in the export.
10. Mapping serial numbers to MAC addresses
Every unit gets both, reserved together, so the serial-to-MAC mapping is fixed at batch generation and never drifts. The export is that mapping. If a unit has more than one interface, see assigning multiple MAC addresses to one device for how to lay the addresses out per unit. For the serial format itself, see how to generate serial numbers for manufactured products.
11. The production CSV
An export row carries the MAC address, the serial number, the device category, the portfolio, the block label, and the batch status. A minimal mapping the programming station can read looks like this:
serial_number,mac_address,device_category,portfolio,block_label,status
GW-26370000007,00:1B:44:11:00:00,router,Gateway line,ACME MA-L,generated
GW-26370000015,00:1B:44:11:00:01,router,Gateway line,ACME MA-L,generated
GW-26370000023,00:1B:44:11:00:02,router,Gateway line,ACME MA-L,generated
The allocation spreadsheet template adds the columns a factory usually wants next to that mapping: interface type, firmware version, programming status, shipment status.
Reference: IEEE Registration Authority for assignment types and how to apply. When you hold a block, the Scale plan runs the allocation, or start with the step-by-step guide.
More guides