前言
①假设有许多开发板,连接到了同一个路由器中,而路由器的dhcpd是根据MAC地址来分配一个固定的IP地址,那么就需要为每一个开发板设定一个不同的MAC地址从而获取不同的IP地址。

②MAC地址是需要购买的(参考点1),在产品出厂之前,都需要给板子一个MAC地址(如果有对应的设备,例如网卡,Wifi)。且这个MAC地址在出厂后,我们并不期望被更改。

下面简述了嵌入式产品中如何保证IP地址不被更改的、以及开发过程或者生产过程如何更改MAC地址。

不被更改的方法
嵌入式中对于期望不被更改的数据,一般都是存放在无法被直接擦除或者修改的存储设备中,例如nand、eMMC、EEPROM、带保护的Nor Flash、甚至是直接写在程序中。这里说的无法被直接修改是相对内存而言的,并不是无法被修改。例如nand在修改之前,一般是需要去保护、擦除。

具体的,对于嵌入式产品而言,一般都是使用u-boot来作为bootloader,u-boot将需要的一些参数放在环境变量中,例如MAC地址就是从环境变量ethaddr中获取的。因此要保证MAC地址能够不被直接修改,那么可以将u-boot中的环境变量放在一个带有保护措施的存储器中,在需要改写的时候去除保护,改写完成后再进行保护。

u-boot启动后,在板极硬件初始化的过程中,会去初始化网卡,并获取MAC地址,这有两种情况:

在初始化的过程中会去读取MAC地址相关的环境变量
也有可能是从网卡芯片中的内置EEPROM获取MAC地址(例如SMC911x,就会有一个EEPROM存储MAC地址,上电后,会将此IP地址加载到用户可以访问的寄存器中)
调用的路径如下,具体详细的关于u-boot中eth driver的说明参考u-boot中的文档doc/drivers.net.eth:

board_init()
eth_initialize()
board_eth_init() / cpu_eth_init()
driver_register()
initialize eth_device
eth_register()
从环境变量ethaddr获取MAC地址的实例
具体到瑞萨的Cortex-A15芯片而言,如果使用的是SoC自带的ether,那么在board_eth_init中会从环境变量中读取ethaddr环境变量,来获取MAC地址。代码文件sh-net.c。

int board_eth_init(bd_t *bis)
{
int ret = -ENODEV;
u32 val;
unsigned char enetaddr[6];

#ifdef CONFIG_SH_ETHER
ret = sh_eth_initialize(bis);
if (!eth_getenv_enetaddr("ethaddr", enetaddr))
return ret;

/* Set Mac address */
val = enetaddr[0] << 24 | enetaddr[1] << 16 |
enetaddr[2] << 8 | enetaddr[3];
writel(val, 0xEE7003C0);

val = enetaddr[4] << 8 | enetaddr[5];
writel(val, 0xEE7003C8);
#endif

return ret;
}
在sh_eth_initialize(瑞萨的一款Cortex-A15 SoC自带的eth)中,会去读取ethaddr环境变量:

int sh_eth_initialize(bd_t *bd)
{
int ret = 0;
struct sh_eth_dev *eth = NULL;
struct eth_device *dev = NULL;

eth = (struct sh_eth_dev *)malloc(sizeof(struct sh_eth_dev));
if (!eth) {
printf(SHETHER_NAME ": %s: malloc failed\n", __func__);
ret = -ENOMEM;
goto err;
}

dev = (struct eth_device *)malloc(sizeof(struct eth_device));
if (!dev) {
printf(SHETHER_NAME ": %s: malloc failed\n", __func__);
ret = -ENOMEM;
goto err;
}
memset(dev, 0, sizeof(struct eth_device));
memset(eth, 0, sizeof(struct sh_eth_dev));

eth->port = CONFIG_SH_ETHER_USE_PORT;
eth->port_info[eth->port].phy_addr = CONFIG_SH_ETHER_PHY_ADDR;

dev->priv = (void *)eth;
dev->iobase = 0;
dev->init = sh_eth_init;
......

sprintf(dev->name, SHETHER_NAME);

/* Register Device to EtherNet subsystem */
eth_register(dev);

bb_miiphy_buses[0].priv = eth;
miiphy_register(dev->name, bb_miiphy_read, bb_miiphy_write);

if (!eth_getenv_enetaddr("ethaddr", dev->enetaddr))
puts("Please set MAC address\n");

return ret;

.....

}
在倒数几行中,使用eth_getenv_ethaddr函数从环境变量ethaddr中获取并设置MAC地址,如果环境变量中不存在此环境变量,那么就会要求你先设置一个。如果设置成功了,那么以后都会从这个环境变量中获取。

从网卡芯片中的EEPROM中获取MAC地址
对于SMC911x(这里使用smc911x与smsc911x,不作区分,一个是实际的名字,一个是代码中使用的名字)芯片而言,在其上电后,会从EEPROM中将MAC地址加载到用户可以访问的MAC地址寄存器中,参考下面的图Figure1:MAC Address Reg中的框图中的Description描述。如果SMC911x没有设置过MAC地址,那么出厂的默认MAC都是FF。

对于SMC911x(smc911x.c代码文件点击此处, smsc911x的datasheet下载点击此处),u-boot在启动后,smc911x的initialze中会到硬件中获取MAC地址,如果MAC地址全部为FF,那么就会从环境变量中获取,然后在smc911x_init中将此MAC值设置到芯片的MAC地址存储寄存器中,芯片会自动将这个MAC地址写入到EEPROM中,用于下一次的使用。

详细而言,网络控制器芯片SMC911X,使用两个寄存器来保存MAC地址值,这两个寄存器32Bit的,每一个寄存器保存6字节MAC地址的3Byte。需要注意的是这个寄存器是可读可写的:

Figure1:MAC Address Reg

对应的代码实现在drivers/net/smc911x.c中,设置MAC地址的函数为:

static void smc911x_handle_mac_address(struct eth_device *dev)
{
unsigned long addrh, addrl;
uchar *m = dev->enetaddr;

addrl = m[0] | (m[1] << 8) | (m[2] << 16) | (m[3] << 24);
addrh = m[4] | (m[5] << 8);
smc911x_set_mac_csr(dev, ADDRL, addrl);
smc911x_set_mac_csr(dev, ADDRH, addrh);

printf(DRIVERNAME ": MAC %pM\n", m);
}
其中第8-9行,就是设置数据书册中的提到的MAC地址高低寄存器。

不可被覆盖
如果在设置了ethaddr之后,又去设置ethaddr环境变量,那么会出现错误,提示不能重写ethaddr,这样就完成了基本的不可重写的保护:

set ethaddr 2e:09:0a:00:6e:1f
[ 28.372] ## Error: Can't overwrite "ethaddr"
[ 28.373] ## Error inserting "ethaddr" variable, errno=1

更改的方法
MAC地址可以配置的地方有以下2个:

u-boot中
Linux启动后
u-boot中更改MAC地址
共有两种方法:

destroy所有的环境变量:不需要重新编译u-boot,但是如果env写死在代码中,那么就无能为力了
在板极配置头文件(include/configs/xxx.h)中定义CONFIG_ENV_OVERWRITE 后重新编译u-boot:需要重新编译u-boot
销毁env区域来更改
对于第一种方法,因为不同的板子,存放u-boot环境变量的位置也不一样,有可能是nand flash、eMMC、SD Card也有可能是SPI Norflash,因此命令各不相同,但是显然步骤几乎都是一样的:

保存现在的所有env,以免万一哪些项需要的是无法恢复:可以使用pri来查看所有的env

擦除u-boot env区域:使用不同flash的擦除命令来完成
设置default env值:可以使用env default -a
设置MAC地址:setenv ethaddr XX:YY:...
将env存储到env layout区域::saveenv
重新编译u-boot来更改
如果是代码中直接写死了ethaddr环境变量的值,那么就只能重新编译了:

#define CONFIG_EXTRA_ENV_SETTINGS \
"baudrate=460800\0" \
"bootm_low=0x40e00000\0" \
"bootm_size=0x100000\0" \
"ethact=smc911x-2\0" \
"ethaddr=2e:09:0a:00:6e:1e\0"
如果代码中没有写死,那么可以在配置文件中添加下面一行来让ethaddr可以被更改:

#define CONFIG_ENV_OVERWRITE 1
linux下更改MAC地址

当系统启动到OS后,要更改MAC地址既可以直接使用命令来更改,也可以在sysV-init脚本中配置。

①对于命令行,可以直接使用busybox中的ifconfig来完成:

busybox ifconfig eth0 hw ether 12:34:56:78:90:af
但是这个更改无法永久性的更改,重启后就又恢复回到原值了,因为ifconfig命令中根本就不会去更改硬件寄存器,或者环境变量,ifconfig中设置hw部分的代码如下:

#if ENABLE_FEATURE_IFCONFIG_HW
} else { /* A_CAST_HOST_COPY_IN_ETHER */
/* This is the "hw" arg case. */
smalluint hw_class = index_in_substrings("ether\0"
IF_FEATURE_HWIB("infiniband\0"), *argv) + 1;
if (!hw_class || !*++argv)
bb_show_usage();
host = *argv;
if (hw_class == 1 ? in_ether(host, &sa) : in_ib(host, &sa))
bb_error_msg_and_die("invalid hw-addr %s", host);
p = (char *) &sa;
}
#endif
②对于使用更改SysV-Init或者systemd等的更改,google中可以找到许多的答案。但是这种方法也无法永久性的更改,因为同样也没有操作硬件。

参考
1. 14.2.14. Where Can I Get a Valid MAC Address from?

如果文章有格式问题,请移步:http://www.hexiongjun.com/?p=228

转载请注明出处。作者:TonyHo hexiongjun.com

————————————————
版权声明:本文为CSDN博主「TonyHo」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/sy373466062/article/details/49021485

u-boot与linux下网卡MAC地址的更改相关推荐

  1. Linux下修改MAC地址总结

    偶尔会用到这个知识点,久了不用又会记不住,所以记之,方便以后查询. Linux下修改MAC地址 方法一: 1.关闭网卡设备 ifconfig eth0 down 2.修改MAC地址 ifconfig ...

  2. 网关屏蔽mac地址,linux下修改mac地址方法

    局域网里有一台机器,同一网段内的机器,只有部分能够ping通,也无法ping通网关,现象很奇怪,尝试过修改IP,重启网络服务,都无法解决问题. 最后怀疑是不是网关将该机器mac地址给屏蔽掉了,因此修改 ...

  3. Linux调整网卡MAC地址(指令)

    Linux调整网卡MAC地址(指令) 有的时候需要使用欺骗的方法为电脑设置新的mac,比如存在上网网卡限制,或者想要隐藏自己的真实mac地址.这里列举三种修改mac的方法,适用于Debian系的Lin ...

  4. linux 命令行修改mac,Linux下修改MAC地址

    Linux下修改MAC地址 Author: Jaylin Zhou Date: 10/17/2009 使用ifconfig命令 标准形式: # ifconfig device_name hw ethe ...

  5. linux设置mac地址命令,[转载]Linux下修改MAC地址

    转自http://blogold.chinaunix.net/u3/94284/showart_2430693.html Linux下修改MAC地址 方法一: 1.关闭网卡设备 ifconfig et ...

  6. linux服务器远程修改mac地址,linux下修改MAC地址问题解决方法

    linux下修改MAC地址问题解决方法 作者:佚名 来源:网络整理 2013-4-17 在linux中,修改MAC地址 # ifdown eth0 # ifconfig eth0 hw ether 1 ...

  7. Linux服务器绑定mac地址,linux下绑定mac地址

    我还是分两种发行版来介绍绑定mac的方法.RedHat和Debian. RedHat(这是网友的一篇文章) linux的发布版本我选择了Redhat9.0,为什么?没有为什么,就因为他安装so eas ...

  8. linux电脑mac地址修改不了怎么办,linux下修改MAC地址问题解决方法

    在linux中,修改MAC地址 # ifdown eth0 # ifconfig eth0 hw ether 12:34:56:78:90:12 (修改的MAC地址跟原来的地址不同) # ifup e ...

  9. Linux 下查看mac地址

    linux 最常用的查看mac地址的方式 有很多种,下面给出4种方式,其中前两种在配置ip之后,后面两种可以在操作系统未设置IP地址之前. 1.ifconfig 这是最常用的方式 2.CentOS系统 ...

  10. linux得到网卡mac地址,获取 linux 网卡MAC地址(包含编程方法)

    网卡在计算机专业词汇里面被叫做 network interface 如果检索资料可以用这个词汇 常用的几种办法 ip link show cat /sys/class/net//address 使用 ...

最新文章

  1. php源码安全加密之PHP混淆算法.
  2. 5G时代下,边缘计算产品的未来展望
  3. Linux服务器-使用mysql
  4. Feather包实现数据框快速读写,你值得拥有
  5. 如何缩小码农和高手的差距
  6. 学习 SpringCloud 五大组件后的总结 一
  7. python—缺失数据的处理
  8. HTTP协议发展历史
  9. u盘启动盘 联想服务器TS250 Win Server 2016 下 安装Linux(ubuntu-18.04.1-desktop-amd64)双系统 各种问题总结(2018-11-13)
  10. 谷歌浏览器为什么要禁用Flash插件?深夜有感而发
  11. selenium 确实是好东西,使用selenium-server 加快执行速度,对速度有很大提升,同时可以拆分服务,进行集群部署。
  12. RSA系列第2篇:RSA 加密解密
  13. 安卓开发之Intent使用介绍(显式Intent和隐式Intent)
  14. mars3d中时间的转换
  15. mount qemu qcow2、img
  16. Linux下服务器开发的必要准备
  17. 离散型随机变量-Discrete Random Variables
  18. Python nose测试大法
  19. 同事喜欢、领导器重的是哪类人?
  20. proteus教程——使能端口控制8255

热门文章

  1. IDC与云计算有什么区别
  2. Python实现《都挺好》社交网络分析
  3. 计算机专业学习自然辩证法,深度学习 自然辩证法
  4. 【工具封装】不用 for 循环, 教你如何向MySQL数据库批量插入数据
  5. 标准误 Standard error 简单解释
  6. Office阻止激活silverlight控件的解决方法
  7. SqlServer毫秒/秒转时分秒
  8. 达梦数据库基础知识(七)如何管理表
  9. PS图层蒙版应用——图片抠字
  10. 设计模式---原型模式