MAC 地址配置
以太网驱动可以将初始化期间的大部分 MAC 地址处理工作交给 net_eth_mac_config 和 net_eth_mac_load()。该结构通常存放在驱动配置中,并使用 NET_ETH_MAC_DT_CONFIG_INIT 或 NET_ETH_MAC_DT_INST_CONFIG_INIT 初始化,这些宏会将 devicetree 属性转换为以下行为之一:
NET_ETH_MAC_STATIC:使用完整的local-mac-address属性。NET_ETH_MAC_RANDOM:生成随机的本地管理 MAC 地址,可选地使用zephyr,mac-address-prefix中提供的字节作为前几个八位组。NET_ETH_MAC_NVMEM:从"mac-address"NVMEM 单元读取剩余字节,同样可以选择以zephyr,mac-address-prefix作为前缀。NET_ETH_MAC_DEFAULT:回退到驱动的默认逻辑(例如存储在外设寄存器中的出厂编程 MAC 地址)。
驱动集成
将 net_eth_mac_config 结构嵌入驱动的配置中,并在驱动的数据中嵌入一个静态缓冲区:
struct my_eth_config {
struct net_eth_mac_config mac_cfg;
/* more config fields */
};
struct my_eth_data {
uint8_t mac_addr[NET_ETH_ADDR_LEN];
/* more data fields */
};
static const struct my_eth_config my_eth_config_0 = {
.mac_cfg = NET_ETH_MAC_DT_INST_CONFIG_INIT(0),
};
static struct my_eth_data my_eth_data_0;
初始化时,先调用 net_eth_mac_load(),然后再向网络接口注册地址。该辅助函数会复制静态提供的字节、填充剩余的八位组并执行必要的校验。未提供配置时,驱动仍可回退到 SoC 专用的存储。
static int my_eth_init(const struct device *dev)
{
const struct my_eth_config *cfg = dev->config;
struct my_eth_data *data = dev->data;
int ret;
ret = net_eth_mac_load(&cfg->mac_cfg, data->mac_addr);
if (ret == -ENODATA) {
ret = my_eth_hw_read_mac(dev, data->mac_addr);
}
return ret;
}
static void my_eth_iface_init(struct net_if *iface)
{
const struct device *dev = net_if_get_device(iface);
struct my_eth_data *data = dev->data;
net_if_set_link_addr(iface, data->mac_addr, sizeof(data->mac_addr), NET_LINK_ETHERNET);
}
Devicetree 示例
以下示例展示如何为 ð0 之类的以太网控制器节点选择 MAC 地址配置。
静态 MAC 地址
ð0 {
local-mac-address = [00 11 22 33 44 55];
};
带前缀的随机 MAC 地址
ð0 {
zephyr,mac-address-prefix = [00 04 25];
zephyr,random-mac-address;
};
由 NVMEM 提供并带前缀的 MAC 地址
借助 NVMEM API,可以从非易失性存储器(通常是 EEPROM)中获取 MAC 地址。
ð0 {
zephyr,mac-address-prefix = [00 12 34];
nvmem-cells = <&macaddr_cell>;
nvmem-cell-names = "mac-address";
};
&eeprom0 {
nvmem-layout {
compatible = "fixed-layout";
#address-cells = <1>;
#size-cells = <1>;
macaddr_cell: cell@0 {
reg = <0x0 0x6>;
#nvmem-cell-cells = <0>;
};
};
};
当不存在任何与 MAC 相关的属性时,net_eth_mac_load() 返回 -ENODATA,此时驱动应使用其现有机制(例如读取硬件寄存器或使用构建时常量)。
在运行时更改 MAC 地址
需要动态设置 MAC 地址(例如采用从管理接口获取的地址)的应用,必须使用 CONFIG_NET_MGMT 启用网络管理 API,并将 net_mgmt 与 NET_REQUEST_ETHERNET_SET_MAC_ADDRESS 配合使用。该请求内部会调用驱动的 ethernet_api.set_config() 实现。
static int app_set_mac_address(const struct device *dev)
{
struct net_if *iface = net_if_lookup_by_dev(dev);
struct ethernet_req_params params = {
.mac_address = { { 0x02, 0x00, 0x5E, 0x01, 0x02, 0x03 } },
};
/* Make sure the iface is down */
return net_mgmt(NET_REQUEST_ETHERNET_SET_MAC_ADDRESS, iface,
¶ms, sizeof(params));
}