1
6
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
34
35
41
42
43
44
46
47
48
49
50
51
52
53
54
55
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
83
84
85
86
89
90
91
92
93
94
95
96
97
100
101
102
103
106
107
111
114
115
121
122
123
124
125
126
135
136
137
138
142
143
146
147
151
152
158
159
160
161
162
163
164
168
169
173
174
175
176
177
178
179
183
184
185
186
187
188
189
190
191
194
195
196
197
198
199
200
201
202
205
206
207
208
209
210
211
212
213
214
215
227
228
229
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
262
263
264
265
266
267
268
269
270
271
272
273
274
277
278
279
280
281
282
283
284
285
286
287
288
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
309
310
311
312
313
314
315
320
321
322
323
324
325
326
330
331
334
335
338
339
340
341
342
343
347
348
349
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
383
384
385
386
387
388
389
390
391
392
399
400
401
402
403
407
408
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
428
429
430
/* ... */
#include <string.h>
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#include "esp_rom_efuse.h"
#include "esp_mac.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"7 includes
#if CONFIG_ESP_MAC_UNIVERSAL_MAC_ADDRESSES_FOUR
#define MAC_ADDR_UNIVERSE_BT_OFFSET 2
#else
#define MAC_ADDR_UNIVERSE_BT_OFFSET 1
#endif
#if SOC_IEEE802154_SUPPORTED
#define ESP_MAC_ADDRESS_LEN 8
#else
#define ESP_MAC_ADDRESS_LEN 6
#endif
static const char *TAG = "system_api";
typedef enum {
STATE_INIT = 0,
STATE_SET = (1 << 0),
}{ ... } state_t;
typedef struct {
esp_mac_type_t type: 4;
state_t state: 4;
uint8_t len;
uint8_t mac[ESP_MAC_ADDRESS_LEN];
}{ ... } mac_t;
static mac_t s_mac_table[] = {
#if SOC_WIFI_SUPPORTED
{ESP_MAC_WIFI_STA, STATE_INIT, 6, {0}},
{ESP_MAC_WIFI_SOFTAP, STATE_INIT, 6, {0}},/* ... */
#endif
#ifdef CONFIG_ESP_MAC_ADDR_UNIVERSE_BT
{ESP_MAC_BT, STATE_INIT, 6, {0}},
#endif
{ESP_MAC_ETH, STATE_INIT, 6, {0}},
#ifdef SOC_IEEE802154_SUPPORTED
{ESP_MAC_IEEE802154, STATE_INIT, ESP_MAC_ADDRESS_LEN, {0}},
{ESP_MAC_EFUSE_EXT, STATE_INIT, 2, {0}},/* ... */
#endif
{ESP_MAC_BASE, STATE_INIT, 6, {0}},
{ESP_MAC_EFUSE_FACTORY, STATE_INIT, 6, {0}},
{ESP_MAC_EFUSE_CUSTOM, STATE_INIT, 6, {0}},
}{...};
#define ITEMS_IN_MAC_TABLE (sizeof(s_mac_table) / sizeof(mac_t))
static esp_err_t generate_mac(uint8_t *mac, uint8_t *base_mac_addr, esp_mac_type_t type);
static esp_err_t get_efuse_factory_mac(uint8_t *mac);
static esp_err_t get_efuse_mac_custom(uint8_t *mac);
#if SOC_IEEE802154_SUPPORTED
static esp_err_t get_efuse_mac_ext(uint8_t *mac);
#endif
static int get_idx(esp_mac_type_t type)
{
for (int idx = 0; idx < ITEMS_IN_MAC_TABLE; idx++) {
if (s_mac_table[idx].type == type) {
return idx;
}{...}
}{...}
ESP_LOGE(TAG, "%d mac type is incorrect (not found)", type);
return -1;
}{ ... }
static esp_err_t get_mac_addr_from_mac_table(uint8_t *mac, int idx, bool silent)
{
if (idx == -1) {
return ESP_ERR_NOT_SUPPORTED;
}{...}
if (!(s_mac_table[idx].state & STATE_SET)) {
esp_mac_type_t type = s_mac_table[idx].type;
if (ESP_MAC_BASE <= type && type <= ESP_MAC_EFUSE_EXT) {
esp_err_t err = ESP_OK;
if (type == ESP_MAC_EFUSE_FACTORY
#ifndef CONFIG_ESP_MAC_USE_CUSTOM_MAC_AS_BASE_MAC
|| type == ESP_MAC_BASE
#endif
) {
err = get_efuse_factory_mac(s_mac_table[idx].mac);
}{...} else if (type == ESP_MAC_EFUSE_CUSTOM
#ifdef CONFIG_ESP_MAC_USE_CUSTOM_MAC_AS_BASE_MAC
|| type == ESP_MAC_BASE
#endif
) {
err = get_efuse_mac_custom(s_mac_table[idx].mac);
}{...}
#if SOC_IEEE802154_SUPPORTED
else if (type == ESP_MAC_EFUSE_EXT) {
err = get_efuse_mac_ext(s_mac_table[idx].mac);
}{...}
#endif/* ... */
if (err != ESP_OK) {
return err;
}{...}
s_mac_table[idx].state = STATE_SET;
}{...} else {
if (!silent) {
ESP_LOGE(TAG, "MAC address (type %d) is not set in mac table", type);
}{...}
return ESP_ERR_INVALID_MAC;
}{...}
}{...}
memcpy(mac, s_mac_table[idx].mac, s_mac_table[idx].len);
return ESP_OK;
}{ ... }
size_t esp_mac_addr_len_get(esp_mac_type_t type)
{
for (int idx = 0; idx < ITEMS_IN_MAC_TABLE; idx++) {
if (s_mac_table[idx].type == type) {
return s_mac_table[idx].len;
}{...}
}{...}
return 0;
}{ ... }
esp_err_t esp_iface_mac_addr_set(const uint8_t *mac, esp_mac_type_t type)
{
if (mac == NULL) {
ESP_LOGE(TAG, "mac address param is NULL");
return ESP_ERR_INVALID_ARG;
}{...}
int idx = get_idx(type);
if (idx == -1) {
return ESP_ERR_NOT_SUPPORTED;
}{...}
if (type == ESP_MAC_EFUSE_FACTORY || type == ESP_MAC_EFUSE_CUSTOM) {
ESP_LOGE(TAG, "EFUSE MAC can not be set using this API");
return ESP_ERR_INVALID_ARG;
}{...}
if (type == ESP_MAC_BASE) {
if (mac[0] & 0x01) {
ESP_LOGE(TAG, "Base MAC must be a unicast MAC");
return ESP_ERR_INVALID_ARG;
}{...}
}{...}
memcpy(s_mac_table[idx].mac, mac, s_mac_table[idx].len);
s_mac_table[idx].state = STATE_SET;
return ESP_OK;
}{ ... }
esp_err_t esp_base_mac_addr_set(const uint8_t *mac)
{
return esp_iface_mac_addr_set(mac, ESP_MAC_BASE);
}{ ... }
esp_err_t esp_base_mac_addr_get(uint8_t *mac)
{
return esp_read_mac(mac, ESP_MAC_BASE);
}{ ... }
#if SOC_IEEE802154_SUPPORTED
static esp_err_t get_efuse_mac_ext(uint8_t *mac)
{
esp_err_t err = esp_efuse_read_field_blob(ESP_EFUSE_MAC_EXT, mac, 16);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Reading MAC_EXT failed, error=%d", err);
return err;
}{...}
return ESP_OK;
}{...}
static esp_err_t insert_mac_ext_into_mac(uint8_t *mac)
{
uint8_t mac_tmp[3];
memcpy(mac_tmp, &mac[3], 3);
esp_err_t err = get_efuse_mac_ext(&mac[3]);
if (err != ESP_OK) {
return err;
}{...}
memcpy(&mac[5], mac_tmp, 3);
return err;
}{...}
/* ... */#endif
esp_err_t esp_efuse_mac_get_custom(uint8_t *mac)
{
esp_err_t err = get_efuse_mac_custom(mac);
if (err != ESP_OK) {
return err;
}{...}
#if SOC_IEEE802154_SUPPORTED
return insert_mac_ext_into_mac(mac);
#else
return ESP_OK;
#endif
}{ ... }
static esp_err_t get_efuse_mac_custom(uint8_t *mac)
{
#if !CONFIG_IDF_TARGET_ESP32
size_t size_bits = esp_efuse_get_field_size(ESP_EFUSE_USER_DATA_MAC_CUSTOM);
assert((size_bits % 8) == 0);
esp_err_t err = esp_efuse_read_field_blob(ESP_EFUSE_USER_DATA_MAC_CUSTOM, mac, size_bits);
if (err != ESP_OK) {
return err;
}{...}
size_t size = size_bits / 8;
if (mac[0] == 0 && memcmp(mac, &mac[1], size - 1) == 0) {
ESP_LOGE(TAG, "eFuse MAC_CUSTOM is empty");
return ESP_ERR_INVALID_MAC;
}{...}
#else/* ... */
uint8_t version;
esp_efuse_read_field_blob(ESP_EFUSE_MAC_CUSTOM_VER, &version, 8);
if (version != 1) {
if (version == 0) {
ESP_LOGD(TAG, "No base MAC address in eFuse (version=0)");
}{...} else if (version != 1) {
ESP_LOGE(TAG, "Base MAC address version error, version = %d", version);
}{...}
return ESP_ERR_INVALID_VERSION;
}{...}
uint8_t efuse_crc;
esp_efuse_read_field_blob(ESP_EFUSE_MAC_CUSTOM, mac, 48);
esp_efuse_read_field_blob(ESP_EFUSE_MAC_CUSTOM_CRC, &efuse_crc, 8);
uint8_t calc_crc = esp_rom_efuse_mac_address_crc8(mac, 6);
if (efuse_crc != calc_crc) {
ESP_LOGE(TAG, "Base MAC address from BLK3 of EFUSE CRC error, efuse_crc = 0x%02x; calc_crc = 0x%02x", efuse_crc, calc_crc);
#ifdef CONFIG_ESP_MAC_IGNORE_MAC_CRC_ERROR
ESP_LOGW(TAG, "Ignore MAC CRC error");
#else
return ESP_ERR_INVALID_CRC;
#endif
}{...}
/* ... */#endif
return ESP_OK;
}{ ... }
esp_err_t esp_efuse_mac_get_default(uint8_t *mac)
{
esp_err_t err = get_efuse_factory_mac(mac);
if (err != ESP_OK) {
return err;
}{...}
#if SOC_IEEE802154_SUPPORTED
return insert_mac_ext_into_mac(mac);
#else
return ESP_OK;
#endif
}{ ... }
static esp_err_t get_efuse_factory_mac(uint8_t *mac)
{
size_t size_bits = esp_efuse_get_field_size(ESP_EFUSE_MAC_FACTORY);
assert((size_bits % 8) == 0);
esp_err_t err = esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, mac, size_bits);
if (err != ESP_OK) {
return err;
}{...}
#ifdef CONFIG_IDF_TARGET_ESP32
uint8_t efuse_crc;
esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY_CRC, &efuse_crc, 8);
uint8_t calc_crc = esp_rom_efuse_mac_address_crc8(mac, 6);
if (efuse_crc != calc_crc) {
uint32_t mac_high = ((uint32_t)mac[0] << 8) | mac[1];
uint32_t mac_low = ((uint32_t)mac[2] << 24) | ((uint32_t)mac[3] << 16) | ((uint32_t)mac[4] << 8) | mac[5];
if (((mac_high & 0xFFFF) == 0x18fe) && (mac_low >= 0x346a85c7) && (mac_low <= 0x346a85f8)) {
return ESP_OK;
}{...} else {
ESP_LOGE(TAG, "Base MAC address from BLK0 of EFUSE CRC error, efuse_crc = 0x%02x; calc_crc = 0x%02x", efuse_crc, calc_crc);
#ifdef CONFIG_ESP_MAC_IGNORE_MAC_CRC_ERROR
ESP_LOGW(TAG, "Ignore MAC CRC error");
#else
return ESP_ERR_INVALID_CRC;
#endif
}{...}
}{...}
#endif/* ... */
return ESP_OK;
}{ ... }
esp_err_t esp_derive_local_mac(uint8_t *local_mac, const uint8_t *universal_mac)
{
if (local_mac == NULL || universal_mac == NULL) {
ESP_LOGE(TAG, "mac address param is NULL");
return ESP_ERR_INVALID_ARG;
}{...}
memcpy(local_mac, universal_mac, 6);
const unsigned UL_BIT = 0x2;
local_mac[0] |= UL_BIT;
if (local_mac[0] == universal_mac[0]) {
local_mac[0] ^= 0x4;
}{...}
return ESP_OK;
}{ ... }
esp_err_t esp_read_mac(uint8_t *mac, esp_mac_type_t type)
{
if (mac == NULL) {
ESP_LOGE(TAG, "mac address param is NULL");
return ESP_ERR_INVALID_ARG;
}{...}
int idx = get_idx(type);
if (idx == -1) {
return ESP_ERR_NOT_SUPPORTED;
}{...}
if (get_mac_addr_from_mac_table(mac, idx, true) == ESP_OK) {
return ESP_OK;
}{...}
uint8_t base_mac_addr[ESP_MAC_ADDRESS_LEN];
esp_err_t err = get_mac_addr_from_mac_table(base_mac_addr, get_idx(ESP_MAC_BASE), false);
if (err) {
ESP_LOGE(TAG, "Error reading BASE MAC address");
return ESP_FAIL;
}{...}
err = generate_mac(mac, base_mac_addr, type);
if (err) {
ESP_LOGE(TAG, "MAC address generation error");
return err;
}{...}
s_mac_table[idx].state = STATE_SET;
memcpy(s_mac_table[idx].mac, mac, s_mac_table[idx].len);
return err;
}{ ... }
static esp_err_t generate_mac(uint8_t *mac, uint8_t *base_mac_addr, esp_mac_type_t type)
{
switch (type) {
#if SOC_WIFI_SUPPORTED
case ESP_MAC_WIFI_STA:
memcpy(mac, base_mac_addr, 6);
break;...
case ESP_MAC_WIFI_SOFTAP:
#if CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP
memcpy(mac, base_mac_addr, 6);
#ifdef CONFIG_IDF_TARGET_ESP32S2
uint8_t mac_begin[6] = { 0x7c, 0xdf, 0xa1, 0x00, 0x30, 0x00 };
uint8_t mac_end[6] = { 0x7c, 0xdf, 0xa1, 0x00, 0x5f, 0xff };
if (memcmp(mac, mac_begin, 6) >= 0 && memcmp(mac_end, mac, 6) >= 0 ) {
mac[3] += 0x02;
mac[4] += 0xd0;
}{...} else {
mac[5] += 1;
}{...}
/* ... */#else
mac[5] += 1;
#endif /* ... */
#else
esp_derive_local_mac(mac, base_mac_addr);
#endif
break;/* ... */
#endif
#if CONFIG_ESP_MAC_ADDR_UNIVERSE_BT
case ESP_MAC_BT:
memcpy(mac, base_mac_addr, 6);
#if SOC_WIFI_SUPPORTED
mac[5] += MAC_ADDR_UNIVERSE_BT_OFFSET;/* ... */
#endif
break;/* ... */
#endif
case ESP_MAC_ETH:
#if CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH
memcpy(mac, base_mac_addr, 6);
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_MAC_ADDR_UNIVERSE_BT
mac[5] += 3;
#endif /* ... */
#else
base_mac_addr[5] += 1;
esp_derive_local_mac(mac, base_mac_addr);/* ... */
#endif
break;
#if SOC_IEEE802154_SUPPORTED...
case ESP_MAC_IEEE802154:
memcpy(mac, base_mac_addr, 3);
esp_read_mac(&mac[3], ESP_MAC_EFUSE_EXT);
memcpy(&mac[5], &base_mac_addr[3], 3);
break;/* ... */
#endif
default:
ESP_LOGE(TAG, "unsupported mac type");
return ESP_ERR_NOT_SUPPORTED;...
}{...}
return ESP_OK;
}{ ... }