rk3288以太网的mac地址调试笔记学习笔记原创

请给我倒杯茶 请给我倒杯茶     2022-10-04     346

关键词:

平台信息:
内核:linux3.1.0
系统:android/android6.0
平台:RK3288

作者:庄泽彬(欢迎转载,请注明作者)

邮箱:2760715357@qq.com

说明:提供以太网mac地址烧录以及读写的方式

一、功能演示以及说明:

1.1在安卓的文件系统生成如下的设备节点:/sys/kernel/pax_ethernet/mac用于烧录以及读取以太网的mac地址。使用adb命令进行以太网mac地址的烧写以及读写。本质上在使用echo "aa:aa:aa:aa:aa:aa" > /sys/kernel/pax_ethernet/mac这个命令的时候会调用kernel的底层驱动往我们存放的mac地址的分区写入以太网的mac地址。我们的需求是在烧录了以太网的mac地址之后,设备就一直使用我们烧录的mac给网卡设备,不在使用随机数生成mac地址。实现的思路大致如下:在使用adb命令往/sys/kernel/pax_ethernet/mac这个设备节点写入合法的mac地址之后,在重启之后uboot启动的时候会从这烧录mac地址的分区读取烧录mac地址,如果烧录的mac地址合法,就会通过cmdline的机制传递给kernel,kernel的以太网往驱动会解析uboot发送的cmdline,将传递的字符串解析之后,如果合法在赋值给网卡,我在kernel的驱动还做了判断,如果uboot传递的mac地址出错或者读取有异常,kernel会在一次从分区中获取mac地址。好吧,讲了这么多,我们还是看代码是如何实现的吧。

二、uboot读取以太网的mac地址以及传递mac地址给kernel的相关代码片段如下:

2.1这部分代码是我封装的用于读取分区中以太网mac地址的读和写的接口

 1 int sp_get_mac(char *value, int len){
 2 
 3     unsigned blocks,offset_blocks;
 4     const disk_partition_t* ptn = get_disk_partition("sp");
 5 
 6     /* strcpy(value,"0123456789"); */
 7     /* return 0; */
 8 
 9     offset_blocks = DIV_ROUND_UP(SP_MAC_OFFSET, RK_BLK_SIZE);
10     /* blocks = DIV_ROUND_UP(len, RK_BLK_SIZE); */
11 
12     if (ptn) {
13         return rkloader_CopyFlash2Memory(value,ptn->start+offset_blocks,1);
14     }
15 
16     return -1;
17 }
18 
19 int sp_set_mac(char *value, int len){
20 
21     unsigned blocks,offset_blocks;
22     const disk_partition_t* ptn = get_disk_partition("sp");
23 
24     offset_blocks = DIV_ROUND_UP(SP_MAC_OFFSET, RK_BLK_SIZE);
25     blocks = DIV_ROUND_UP(len, RK_BLK_SIZE);
26 
27     if (ptn) {
28         StorageEraseBlock(ptn->start+offset_blocks, blocks, 1);
29         return rkloader_CopyMemory2Flash(value,ptn->start+offset_blocks,blocks);
30     }
31 
32     return -1;
33 }

2.2uboot传递给kernel的相关代码片段:

 1     //读取sp分区的mac地址
 2     memset(tbuf,0,sizeof(tbuf));
 3     ret = sp_get_mac(tbuf,64);
 4     if(ret!=0){
 5         tbuf[0]=0;
 6     }else{
 7         if((tbuf[0]==0xff)&&(tbuf[1]==0xff)&&(tbuf[2]==0xff)&&\
 8             (tbuf[3]==0xff)&&(tbuf[4]==0xff)&&(tbuf[5]==0xff)){
 9             tbuf[0]=0;
10         }else if((tbuf[0]==0x00)&&(tbuf[1]==0x00)&&(tbuf[2]==0x00)&&\
11                     (tbuf[3]==0x00)&&(tbuf[4]==0x00)&&(tbuf[5]==0x00)){
12             tbuf[0]=0;
13         }else{
14             unsigned char tmp[32];
15             memset(tmp,0,32);
16 
17             sprintf(tmp,"%02x:%02x:%02x:%02x:%02x:%02x",tbuf[0],tbuf[1],tbuf[2],tbuf[3],tbuf[4],tbuf[5]);
18             printf("[%s:%d]mac:%s\r\n",__func__,__LINE__,tmp);
19             snprintf(command_line, len,
20                     "%s eth_mac=%s", command_line, tmp);
21         }
22     }
23     tbuf[63]=0;

2.3实验结果如下,具体的代码大家就自己看吧。uboot阶段以及成果读取并且通过cmdline发送mac的地址.

 

三、kernel的以太网驱动解析cmdline并赋值给以太网的网卡设备。

3.1kernel解析cmdline的相关代码片段如下:查看下面的图片kernel已经成果的获取uboot传递的mac地址

u_char mac_addr_str[18] = {0};
u_char mac_addr[7] = {0};
static int __init get_mac_addr(char *str)                                                                                                                   
{                                                                                                                                                           
    strncpy(mac_addr_str,str,17);                                                                                                                           
    printk(KERN_ERR"[%s:%d] mac_addr_str = %s",__func__,__LINE__,mac_addr_str);                                                                             
    return 0;                                                                                                                                               
}                                                                                                                                                           
                                                                                                                                                            
//解析cmdline
__setup("eth_mac=",get_mac_addr);                                                                                                                           
                                                                                                                                                            
module_init(stmmac_init);                                                                                                                                   
module_exit(stmmac_exit);       

 

 

3.2kernel层将传递的mac地址赋值给设备.

u_char char2num(u_char ch)
{   
    switch(ch){
        case 'a':
        case 'A':
            return 10;
            break;
        case 'b':
        case 'B':
            return 11;
            break;
        case 'c':
        case 'C':
            return 12;
            break;
        case 'd':
        case 'D':
            return 13;
            break;
        case 'e':
        case 'E':
            return 14;
            break;
        case 'f':
        case 'F':
            return 15;
            break;
        default:
            return 0;
    }
}
void str2byte(u_char *str, u_char *byte)
{
    int i=0, j=0;
    u_char num, n;
    u_char temp[20] = {0};

    for(i=0; i<17; i++){
        if(str[i] == ':'){
            continue;
        }else{
            temp[j] = str[i];
            j++;
        }
    }
    temp[j]='\0';
    i=0;
    while(*(temp+i)!='\0')
    {
        if(*(temp+i)>='0' && *(temp+i) <= '9'){
            if(i%2 == 0){ //żÊýΪʮλ
                num = (*(temp+i)-'0') * 16;
            }else{
                num = num + (*(temp+i)-'0');
            }
            i++;
        }else if((*(temp+i)>='a' && *(temp+i) <= 'f') || (*(temp+i)>='A' && *(temp+i) <= 'F')){
            n = char2num(*(temp+i));
            if(n == 0){
                memset(byte, 0, 6);
                break;
            }
            if(i%2 == 0){ //żÊýΪʮλ
                num = n * 16;
            }else{
                num = num + n;
            }
            i++;
        }else{
            memset(byte, 0, 6);
            break;
        }
        if(i%2 == 0){
            *byte++ = num;
        }

    }
}
static ssize_t block_mac_store(const char *buf, size_t count)
{

    if (buf != NULL && strlen(buf))
    {
        write_block_info(BLOCK_NAME, buf, strlen(buf), MAC_ADDR_OFFSET);
    }

    return 0;
}

static ssize_t block_mac_show( char *buf)
{
    char mac_buf[18] = {0};

    read_block_info(BLOCK_NAME, mac_buf, 17, MAC_ADDR_OFFSET);
    printk(KERN_ERR"[%s:%d] mac: %pM\r\n",__func__,__LINE__,mac_buf);
    return sprintf(buf, "%s", mac_buf);
}


    //这部分的代码就是赋值将获取的mac地址赋值给网卡设备的主要地方.
//cmdline´«µÝµÄmacµØÖ· str2byte(mac_addr_str, mac_addr); printk(KERN_ERR"[%s:%d]%02x:%02x:%02x:%02x:%02x:%02x\r\n",__func__,__LINE__,mac_addr[0],mac_addr[1],mac_addr[2],mac_addr[3],mac_addr[4],mac_addr[5]); if(is_valid_ether_addr(mac_addr)){ priv->dev->dev_addr = mac_addr; printk(KERN_ERR"[%s:%d]\r\n",__func__,__LINE__); } if(!is_valid_ether_addr(priv->dev->dev_addr)){ memset(block_mac_buf,0,sizeof(block_mac_buf)); block_mac_show(block_mac_buf); printk(KERN_ERR"[%s:%d]%02x:%02x:%02x:%02x:%02x:%02x\r\n",__func__,__LINE__,block_mac_buf[0],block_mac_buf[1],block_mac_buf[2],block_mac_buf[3],block_mac_buf[4],block_mac_buf[5]); if(is_valid_ether_addr(block_mac_buf)){ priv->dev->dev_addr = block_mac_buf; printk(KERN_ERR"[%s:%d]\r\n",__func__,__LINE__); } }

 

 四、生成设备/sys/kernel/pax_ethernet/mac的方法如下。

 1 +
 2 +static ssize_t sys_mac_show(struct kobject *kobj, struct kobj_attribute *attr,
 3 +            char *buf)
 4 +{ 
 5 +       char temp_mac_buf[18];
 6 +
 7 +       memset(temp_mac_buf,0,sizeof(temp_mac_buf));
 8 +       read_block_info(BLOCK_NAME, temp_mac_buf, 18, MAC_ADDR_OFFSET);
 9 +       printk(KERN_ERR"[%s:%d]%02x:%02x:%02x:%02x:%02x:%02x\r\n",__func__,__LINE__,temp_mac_buf[0],temp_mac_buf[1],temp_mac_buf[2],temp_mac_buf[3],temp_mac_buf[4],temp_mac_buf[5]);
10 +
11 +    return sprintf(buf, "%pM\n", temp_mac_buf);
12 +}
13 +
14 +static ssize_t sys_mac_store(struct kobject *kobj, struct kobj_attribute *attr,
15 +             const char *buf, size_t count)
16 +{   
17 +       u_char mac_addr[7] = {0};
18 +
19 +       printk(KERN_ERR"[%s:%d]%02x:%02x:%02x:%02x:%02x:%02x\r\n",__func__,__LINE__,buf[0],buf[1],buf[2],buf[3],buf[4],buf[5]);
20 +       if (buf != NULL && strlen(buf)){
21 +               //memcpy(mac_str, buf, strlen(buf));
22 +               //<D7>ַ<FB><B4><AE><B5><C4>ת<BB><BB>
23 +               str2byte(buf, mac_addr);
24 +               printk(KERN_ERR"[%s:%d]%02x:%02x:%02x:%02x:%02x:%02x\r\n",__func__,__LINE__,mac_addr[0],mac_addr[1],mac_addr[2],mac_addr[3],mac_addr[4],mac_addr[5]);
25 +               write_block_info(BLOCK_NAME, mac_addr, 6, MAC_ADDR_OFFSET);
26 +       }
27 +       
28 +    return count;
29 +}
30 +
31 +static struct kobj_attribute mac_attribute =
32 +    __ATTR(mac, 0666, sys_mac_show, sys_mac_store);
33 +
34 +
35 +static struct attribute *attrs[] = {
36 +    &mac_attribute.attr,
37 +    NULL,   /* need to NULL terminate the list of attributes */
38 +};
39 +static struct attribute_group attr_group = {
40 +    .attrs = attrs,
41 +};
42 +
43 +static struct kobject *ethernet_kobj;
44 +
45 
46 
47 +       ethernet_kobj = kobject_create_and_add("pax_ethernet", kernel_kobj);
48 +    if (!ethernet_kobj)
49 +        return -ENOMEM;
50 +    
51 +    /* Create the files associated with this kobject */
52 +    ret = sysfs_create_group(ethernet_kobj, &attr_group);
53 +    if (ret)
54 +        kobject_put(ethernet_kobj);
55 +       

五、kernel层对分区操作的函数如下:

 1 int write_block_info(const char *name, char *data, int length, loff_t offset)
 2 {
 3     struct file *fp;
 4     mm_segment_t fs;
 5 
 6 
 7     AUTHINFO_DEBUG("%s start, data: %s, length: %d \n",__func__, data, length);
 8 
 9     fp = filp_open(name, O_RDWR | O_CREAT, 0644);
10     if (IS_ERR(fp)) {
11         AUTHINFO_ERROR("create file error");
12         return -1;
13     }
14 
15     fs = get_fs();
16     set_fs(KERNEL_DS);
17 
18     vfs_write(fp, data, length, &offset);
19 
20     filp_close(fp, NULL);
21     set_fs(fs);
22 
23     AUTHINFO_DEBUG("%s end",__func__);
24 
25     return 0;
26 }
27 EXPORT_SYMBOL(write_block_info);
28 
29 int read_block_info(const char *name, char *buf, int length, loff_t offset)
30 {
31     struct file *fp;
32     mm_segment_t fs;
33 
34     AUTHINFO_DEBUG("%s start",__func__);
35     fp = filp_open(name, O_RDWR | O_CREAT, 0644);
36     if (IS_ERR(fp)) {
37         AUTHINFO_ERROR("create file error");
38         return -1;
39     }
40 
41     fs = get_fs();
42     set_fs(KERNEL_DS);
43 
44     vfs_read(fp, buf, length, &offset);
45 
46 
47     filp_close(fp, NULL);
48     set_fs(fs);
49 
50     AUTHINFO_DEBUG("%s end %d %s",__func__,length,buf);
51 
52     return 0;
53 }
54 EXPORT_SYMBOL(read_block_info);

 六、最终的结果.查看一下设置以太网的mac地址成功,可以下班了啊。

 

 

大话存储学习笔记(11章),tcp/ip

TCP/IP协议以太网的出现,给系统的互联带来方便的方式,每个节点安装一块以太网适配器,上层程序只要将发送的数据以及目的MAC地址告诉以太网卡,就可以完成通信过程。但是实际上,以太网不能直接被应用程序用来收发数据... 查看详情

以太网笔记

...可以端口学习需要转发到别的交换机的mac地址。 百兆以太网长度没变但是间隔时间缩小了,缩小倍数从原来的9.6 编程现在的0.96网络层只负责传数据 查看详情

计算机网络学习笔记6-多播(代码片段)

...~239.255.255.254任意一个IP地址都代表一个多播组多播地址向以太网MAC地址的映射即前24位固定为01005e第25位固定 查看详情

mac地址学习笔记

 MAC(MediaAccessControl或者MediumAccessControl)地址,意译为媒体访问控制,或称为物理地址、硬件地址,用来定义网络设备的位置。 在OSI模型中,第三层网络层负责 IP地址第二层数据链路层则负责MAC地址。因此一个主机会... 查看详情

计算机网络学习笔记(代码片段)

...路层数据链路层的功能介质访问控制局域网的数据链路层以太网的MAC层以太网的帧格式广域网的数据链路层PPP协议HDLC的帧类型透明网桥源路由网桥多接口网桥(以太网交换机) 查看详情

笔记本mac地址在哪看

...牙笔记本电脑有三个 MAC地址。它们用于蓝牙、Wi-Fi和以太网连接。MAC地址是电脑网卡的物理地址,每台电脑的电脑网卡都是有这个物理地址的。我们在描述MAC地址时,不能说一台电脑的MAC地址,而应该说一个网卡的MAC地址。一台... 查看详情

笔记本电脑的mac地址怎么查

...标右击电脑的【开始】菜单,单击【网络链接】,选择【以太网】;01查看本机MAC地址点击“开始”→“运行”。02在“运行”界面下输入“cmd”点击 查看详情

学习笔记(13)

...大的输出距离500米3.hub(集线器)工作在物理层,不记忆MAC地址,只是将报文复制出多份从集线器的各个端口转发出去,集线器不隔离冲突域4.数据链路层中的源地址不可能是全1的广播地址,全1的MAC地址是广播报文时加到目标MAC地... 查看详情

安全牛学习笔记mac地址绑定攻击

MAC地址绑定攻击MAC绑定                          管理员误以为MAC绑定是一种安全机制限制可以关联的客户端MA 查看详情

ip地址和子网划分学习笔记之《ip地址基础篇》

一、IP地址和MAC地址1、MAC地址MAC(MediaAccessControl,介质访问控制)地址,或称为物理地址,也叫硬件地址,用来定义网络设备的位置,MAC地址是网卡出厂时设定的,是固定的(但可以通过在设备管理器中或注册表等方式修改,同... 查看详情

千兆以太网读写flash调试笔记

千兆以太网读写flash调试笔记1.版本管理版本号功能介绍开发时间v1.4目前可以通过以太网来连续写入数据,并利用串口可以显示写入的内容2022.7.29v1.7目前可以实现以太网来连续写入任意数据,并在写入后,对数据进行... 查看详情

千兆以太网读写flash调试笔记

千兆以太网读写flash调试笔记1.版本管理版本号功能介绍开发时间v1.4目前可以通过以太网来连续写入数据,并利用串口可以显示写入的内容2022.7.29v1.7目前可以实现以太网来连续写入任意数据,并在写入后,对数据进行... 查看详情

rk3399平台开发系列讲解(内核调试篇)9.28以太网phy调试方法(代码片段)

平台内核版本安卓版本RK3399Linux4.14Android7.1=>返回专栏总目录<=文章目录调试步骤调试步骤阅读对应PHY的技术手册,弄清MDIO的使用条款,clause22orclause45测试PHY的外部供电是否正常,包含系统的电源供电和PHY的... 查看详情

esp32学习笔记(35)——蓝牙mac地址(代码片段)

一、背景一个BLE设备,可以使用两种类型的地址(一个BLE设备可同时具备两种地址):PublicDeviceAddress(公共设备地址)RandomDeviceAddress(随机设备地址)可分为两类:StaticDeviceAddress(静态设... 查看详情

stm32cubemx学习笔记(41)——eth接口+lwip协议栈使用(dhcp)(代码片段)

一、ETH简介STM32F4xx系列控制器内部集成了一个以太网外设,它实际是一个通过DMA控制器进行介质访问控制(MAC),它的功能就是实现MAC层的任务。借助以太网外设,STM32F4xx控制器可以通过ETH外设按照IEEE802.3-2002标准发送... 查看详情

stm32cubemx学习笔记(41)——eth接口+lwip协议栈使用(dhcp)(代码片段)

一、ETH简介STM32F4xx系列控制器内部集成了一个以太网外设,它实际是一个通过DMA控制器进行介质访问控制(MAC),它的功能就是实现MAC层的任务。借助以太网外设,STM32F4xx控制器可以通过ETH外设按照IEEE802.3-2002标准发送... 查看详情

杜鹃沙盒cuckoosandbox学习笔记

...完成学习了部分功能,前来分享点经验  整个工程连接地址:https://github.com/cuckoosandbox/cuckoo0x01调试运行学习代码很关键的就是调试了所以首先奉上点调试小技巧      一个编译器最基本的就是调试了,所以... 查看详情

rk3568开发笔记:入手rk3568开发板的套件介绍底板介绍和外设测试

若该文为原创文章,转载请注明原文出处本文章博客地址:https://hpzwl.blog.csdn.net/article/details/124980037红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、... 查看详情