一些嵌入式主板集成了RTL8111网卡,出于成本原因没有加EEPROM,这样其MAC地址就无法固定,可能是随机数或全0,不利于使用。当然也可以利用脚本给它设置个MAC地址,但有时不记得修改,就有可能存在相同MAC地址。这里给出一种固定MAC地址方法。
最近在使用NaoPi R4SE时遇到开机后 8111网卡的MAC为 00:00:00:00:00:00,导致无法使用。如果使用脚本命令:ifconfig enp1s0 hw ether 00:0C:29:6A:F7:72 ,也能分配MAC地址,这是临时的。要想永久固定MAC地址,我想到了一种办法,修改r8169驱动程序,让r8169驱动程序从文件中读取MAC地址,文件的MAC地址是系统第一次加载r8169驱动时随机生成,生成文件后,以后每次启动时就读此MAC文件,这样基本上不存在MAC地址相同现象。这种方法也等同于为RTL8111加了EEPROM芯片。
我使用linux内核是 4.19.206的,从 r8169.c 里找到 函数:rtl_init_one,在此函数前增加:
#include <linux/fs.h>
#include <linux/random.h>
static int get_mac_addr(int bus,int devfn)
{
struct file *fp;
loff_t pos = 0;
char filename[100]={0};
int mac ;
get_random_bytes(&mac,sizeof(int));
sprintf(filename,"/etc/.rtl8111-%02x-%02x.mac",bus,devfn);
fp = filp_open(filename, O_RDONLY, 0644);
if (unlikely(IS_ERR(fp))) {
fp = filp_open(filename, O_RDWR | O_CREAT, 0644);
if (unlikely(IS_ERR(fp))) {
return mac;
}
kernel_write(fp, &mac, sizeof(int), &pos);
filp_close(fp,NULL);
return mac;
}
kernel_read(fp, &mac, sizeof(int), &(pos));
filp_close(fp, NULL);
return mac;
}
MAC地址文件保存在/etc目录下,如果有多张RTL8111网卡,会根据bus、devfn来区分网卡,分别使用不同的MAC地址文件。函数 get_mac_addr 的使用:
static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data;
struct rtl8169_private *tp;
struct net_device *dev;
int chipset, region, i;
int jumbo_max, rc;
int mac=get_mac_addr(pdev->bus->number,pdev->devfn);
dev = devm_alloc_etherdev(&pdev->dev, sizeof (*tp));
if (!dev)
return -ENOMEM;
在函数rtl_init_one 后面这样修改:
/* Get MAC address */
switch (tp->mac_version) {
u8 mac_addr[ETH_ALEN] __aligned(4);
case RTL_GIGA_MAC_VER_35 ... RTL_GIGA_MAC_VER_38:
case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51:
*(u32 *)&mac_addr[0] = rtl_eri_read(tp, 0xe0, ERIAR_EXGMAC);
*(u16 *)&mac_addr[4] = rtl_eri_read(tp, 0xe4, ERIAR_EXGMAC);
if (is_valid_ether_addr(mac_addr))
rtl_rar_set(tp, mac_addr);
else
{
mac_addr[0]=0x00;
mac_addr[1]=0x2D;
mac_addr[2]=mac&0xFF;
mac_addr[3]=(mac>>8)&0xFF;
mac_addr[4]=(mac>>16)&0xFF;
mac_addr[5]=(mac>>24)&0xFF;
rtl_rar_set(tp, mac_addr);
}
break;
default:
break;
}
for (i = 0; i < ETH_ALEN; i++)
dev->dev_addr[i] = RTL_R8(tp, MAC0 + i);
我这里固定了MAC前两个字节为:00:2D,可以根据自己修改,后面4个字节随机生成。系统启动过程:
可以看出已经成功为8111分配了MAC地址。