zoukankan      html  css  js  c++  java
  • RK3288以太网的mac地址调试笔记【学习笔记】【原创】

    平台信息:
    内核: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
    ",__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]='';
        i=0;
        while(*(temp+i)!='')
        {
            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
    ",__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 ",__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] ",__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 ",__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] ",__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
    ",__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
    ", 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
    ",__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
    ",__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 
    ",__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地址成功,可以下班了啊。

     

  • 相关阅读:
    ExtJs之表格控件入门
    bootstrap错误警告信息提示
    android采用MVP漫画APP、适配刘海屏、小黄车主界面、录音波浪动画、综合APP等源码
    iOS仿QQ侧滑菜单、登录按钮动画、仿斗鱼直播APP、城市选择器、自动布局等源码
    iOS仿抖音节拍界面、Swift,MVVM架构完整项目、日历demo、滚动切换分类等源码
    接住! 安卓巴士开发者大会花絮第二弹来啦
    iOS漂亮的Toolbar动画、仿美团主页、简易笔记本、流失布局、标签分组等源码
    android仿今日头条App、多种漂亮加载效果、选择器汇总、记事本App、Kotlin开发等源码
    到场率高达96% 这才是高水准技术大会应该有的样子
    iOS动画效果集合、 通过摄像头获取心率、仿淘宝滑动样式、瀑布流、分类切换布局等源码
  • 原文地址:https://www.cnblogs.com/zzb-Dream-90Time/p/8012098.html
Copyright © 2011-2022 走看看