平台信息:
内核: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,);
  14. }
  15.  
  16. return -;
  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, );
  29. return rkloader_CopyMemory2Flash(value,ptn->start+offset_blocks,blocks);
  30. }
  31.  
  32. return -;
  33. }

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

  1. //读取sp分区的mac地址
  2. memset(tbuf,,sizeof(tbuf));
  3. ret = sp_get_mac(tbuf,);
  4. if(ret!=){
  5. tbuf[]=;
  6. }else{
  7. if((tbuf[]==0xff)&&(tbuf[]==0xff)&&(tbuf[]==0xff)&&\
  8. (tbuf[]==0xff)&&(tbuf[]==0xff)&&(tbuf[]==0xff)){
  9. tbuf[]=;
  10. }else if((tbuf[]==0x00)&&(tbuf[]==0x00)&&(tbuf[]==0x00)&&\
  11. (tbuf[]==0x00)&&(tbuf[]==0x00)&&(tbuf[]==0x00)){
  12. tbuf[]=;
  13. }else{
  14. unsigned char tmp[];
  15. memset(tmp,,);
  16.  
  17. sprintf(tmp,"%02x:%02x:%02x:%02x:%02x:%02x",tbuf[],tbuf[],tbuf[],tbuf[],tbuf[],tbuf[]);
  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[]=;

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

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

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

  1. u_char mac_addr_str[] = {};
  2. u_char mac_addr[] = {};
  3. static int __init get_mac_addr(char *str)
  4. {
  5. strncpy(mac_addr_str,str,);
  6. printk(KERN_ERR"[%s:%d] mac_addr_str = %s",__func__,__LINE__,mac_addr_str);
  7. return ;
  8. }
  9.  
  10. //解析cmdline
  11. __setup("eth_mac=",get_mac_addr);
  12.  
  13. module_init(stmmac_init);
  14. module_exit(stmmac_exit);

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

  1. u_char char2num(u_char ch)
  2. {
  3. switch(ch){
  4. case 'a':
  5. case 'A':
  6. return ;
  7. break;
  8. case 'b':
  9. case 'B':
  10. return ;
  11. break;
  12. case 'c':
  13. case 'C':
  14. return ;
  15. break;
  16. case 'd':
  17. case 'D':
  18. return ;
  19. break;
  20. case 'e':
  21. case 'E':
  22. return ;
  23. break;
  24. case 'f':
  25. case 'F':
  26. return ;
  27. break;
  28. default:
  29. return ;
  30. }
  31. }
  32. void str2byte(u_char *str, u_char *byte)
  33. {
  34. int i=, j=;
  35. u_char num, n;
  36. u_char temp[] = {};
  37.  
  38. for(i=; i<; i++){
  39. if(str[i] == ':'){
  40. continue;
  41. }else{
  42. temp[j] = str[i];
  43. j++;
  44. }
  45. }
  46. temp[j]='\0';
  47. i=;
  48. while(*(temp+i)!='\0')
  49. {
  50. if(*(temp+i)>='' && *(temp+i) <= ''){
  51. if(i% == ){ //żÊýΪʮλ
  52. num = (*(temp+i)-'') * ;
  53. }else{
  54. num = num + (*(temp+i)-'');
  55. }
  56. i++;
  57. }else if((*(temp+i)>='a' && *(temp+i) <= 'f') || (*(temp+i)>='A' && *(temp+i) <= 'F')){
  58. n = char2num(*(temp+i));
  59. if(n == ){
  60. memset(byte, , );
  61. break;
  62. }
  63. if(i% == ){ //żÊýΪʮλ
  64. num = n * ;
  65. }else{
  66. num = num + n;
  67. }
  68. i++;
  69. }else{
  70. memset(byte, , );
  71. break;
  72. }
  73. if(i% == ){
  74. *byte++ = num;
  75. }
  76.  
  77. }
  78. }
  79. static ssize_t block_mac_store(const char *buf, size_t count)
  80. {
  81.  
  82. if (buf != NULL && strlen(buf))
  83. {
  84. write_block_info(BLOCK_NAME, buf, strlen(buf), MAC_ADDR_OFFSET);
  85. }
  86.  
  87. return ;
  88. }
  89.  
  90. static ssize_t block_mac_show( char *buf)
  91. {
  92. char mac_buf[] = {};
  93.  
  94. read_block_info(BLOCK_NAME, mac_buf, , MAC_ADDR_OFFSET);
  95. printk(KERN_ERR"[%s:%d] mac: %pM\r\n",__func__,__LINE__,mac_buf);
  96. return sprintf(buf, "%s", mac_buf);
  97. }
  98.  
  99.     //这部分的代码就是赋值将获取的mac地址赋值给网卡设备的主要地方.
  100. //cmdline´«µÝµÄmacµØÖ·
  101. str2byte(mac_addr_str, mac_addr);
  102. printk(KERN_ERR"[%s:%d]%02x:%02x:%02x:%02x:%02x:%02x\r\n",__func__,__LINE__,mac_addr[],mac_addr[],mac_addr[],mac_addr[],mac_addr[],mac_addr[]);
  103. if(is_valid_ether_addr(mac_addr)){
  104. priv->dev->dev_addr = mac_addr;
  105. printk(KERN_ERR"[%s:%d]\r\n",__func__,__LINE__);
  106. }
  107.  
  108. if(!is_valid_ether_addr(priv->dev->dev_addr)){
  109. memset(block_mac_buf,,sizeof(block_mac_buf));
  110. block_mac_show(block_mac_buf);
  111. printk(KERN_ERR"[%s:%d]%02x:%02x:%02x:%02x:%02x:%02x\r\n",__func__,__LINE__,block_mac_buf[],block_mac_buf[],block_mac_buf[],block_mac_buf[],block_mac_buf[],block_mac_buf[]); if(is_valid_ether_addr(block_mac_buf)){
  112. priv->dev->dev_addr = block_mac_buf;
  113. printk(KERN_ERR"[%s:%d]\r\n",__func__,__LINE__);
  114. }
  115. }

四、生成设备/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[];
  6. +
  7. + memset(temp_mac_buf,,sizeof(temp_mac_buf));
  8. + read_block_info(BLOCK_NAME, temp_mac_buf, , MAC_ADDR_OFFSET);
  9. + printk(KERN_ERR"[%s:%d]%02x:%02x:%02x:%02x:%02x:%02x\r\n",__func__,__LINE__,temp_mac_buf[],temp_mac_buf[],temp_mac_buf[],temp_mac_buf[],temp_mac_buf[],temp_mac_buf[]);
  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[] = {};
  18. +
  19. + printk(KERN_ERR"[%s:%d]%02x:%02x:%02x:%02x:%02x:%02x\r\n",__func__,__LINE__,buf[],buf[],buf[],buf[],buf[],buf[]);
  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[],mac_addr[],mac_addr[],mac_addr[],mac_addr[],mac_addr[]);
  25. + write_block_info(BLOCK_NAME, mac_addr, , MAC_ADDR_OFFSET);
  26. + }
  27. +
  28. + return count;
  29. +}
  30. +
  31. +static struct kobj_attribute mac_attribute =
  32. + __ATTR(mac, , 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. + ethernet_kobj = kobject_create_and_add("pax_ethernet", kernel_kobj);
  47. + if (!ethernet_kobj)
  48. + return -ENOMEM;
  49. +
  50. + /* Create the files associated with this kobject */
  51. + ret = sysfs_create_group(ethernet_kobj, &attr_group);
  52. + if (ret)
  53. + kobject_put(ethernet_kobj);
  54. +

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

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

 

RK3288以太网的mac地址调试笔记【学习笔记】【原创】的更多相关文章

  1. jz2440使用openjtag+openocd+eclipse调试【学习笔记】

    平台:jz2440 作者:庄泽彬(欢迎转载,请注明作者) 说明:韦东山二期视频学习笔记 交叉编译工具:arm-linux-gcc (GCC) 3.4.5 eclipse版本:eclipse-cpp-l ...

  2. 【MarkMark学习笔记学习笔记】javascript/js 学习笔记

    1.0, 概述.JavaScript是ECMAScript的实现之一 2.0,在HTML中使用JavaScript. 2.1 3.0,基本概念 3.1,ECMAScript中的一切(变量,函数名,操作 ...

  3. ios/mac/COCOA系列 -- UIALertVIew 学习笔记

    最近在学习ios开发,学习的书籍<ios7 Pragramming cookbook>,做笔记的目的以后方便查看.笔记形式是小例子,将书上的例子书写完整. UIAlertViewClass ...

  4. Android Studio调试方法学习笔记

    (注:本人所用Android Studio的Keymap已设为Eclipse copy) 1.设置断点 只有设置断点,才好定位要调试什么地方,否则找不到要调试的地方,无法调试.(调试过程中也可以增加断 ...

  5. 关于OPC的研究1]c# opc client源码调试和学习笔记

    c# opc client是一个在网上下载的示例程序,调试的时候还是费了一番周折,服务器端程序来自king view6.55,另文介绍. 1.注册dll 程序中有一个名叫OPCDAAuto.dll的文 ...

  6. 地址(Address)——WCF学习笔记(2)

    地址(Address)分为: 统一资源表示(URI). EndpointAddress. 端口共享. 逻辑地址与物理地址. 请求监听与消息分发.

  7. 【10-26】java调试技术学习笔记

    调试工具 jdk自带的工具 jmap jconsole VisualVM jmap jmap -histo:live pid 列出该进程的所有活动实例统计信息 jmap -dump:live,file ...

  8. 《MarkMark学习笔记学习笔记》html学习笔记

    iframe里有一个srcdoc属性,很有用! window.location.href=document.referrer//可以实现返回上一级页面并刷新 HTML5权威指南©®,比较老的书了,有些 ...

  9. Android5.1修改以太网MAC地址(SElinux)【转】

    本文转载自:http://blog.csdn.net/LoongEmbedded/article/details/71477203 最近高通平台Android5.1项目中有个关于设置以太网MAC的需求 ...

随机推荐

  1. 国内UED收录

    腾讯 腾讯CDC http://cdc.tencent.com/ CDC(Customer Research & User Experience Design Center)腾讯用户研究与体验 ...

  2. hihoCoder#1086 Browser Caching

    原题地址 list+map可以轻松搞定,如果不借助STL实现起来还是挺麻烦的 代码: #include <iostream> #include <string> #includ ...

  3. HDU 2767 Proving Equivalences(强连通 Tarjan+缩点)

    Consider the following exercise, found in a generic linear algebra textbook. Let A be an n × n matri ...

  4. react.js 父子组件数据绑定实时通讯

    import React,{Component} from 'react' import ReactDOM from 'react-dom' class ChildCounter extends Co ...

  5. .NET 调用java webservice保存datetime类型数据为空的解决办法

    问题描述:       用C#.NET调用Java开发的WebService时,先在客户端封装的带有int属性的对象,当将该对象传到服务器端时,服务器端可以得到 string类型的属性值,却不能得到i ...

  6. NOI导刊2010提高(06) 黑匣子

    题目描述 Black Box是一种原始的数据库.它可以储存一个整数数组,还有一个特别的变量i.最开始的时候Black Box是空的.而i等于0.这个Black Box要处理一串命令. 命令只有两种: ...

  7. Codevs 1695 Windows2013

    时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold   题目描述 Description 话说adamyi编的Windows 2013超时了(- -!),所以他不得不在自 ...

  8. winServer-常用winrm命令

    学习WinServer必须学习powershell,学习powershell必须掌握远程管理服务器的方法,所以必须学会winrm来远程管理服务器 记录一些常用的winrm命令和错误 常用命令 //在P ...

  9. Nginx配置upstream实现负载均衡及keepalived实现nginx高可用

    (原文链接:http://www.studyshare.cn/blog-front//blog/details/1159/0 ) 一.准备工作 1.准备两个项目,发布到不同的服务器上,此处使用2个虚拟 ...

  10. cds.data:=dsp.data赋值有时会出现AV错误剖析

    cds.data:=dsp.data赋值有时会出现AV错误剖析 如果QUERY没有查询到任何数据,cds.data:=dsp.data赋值会触发AV错误. 大家知道,DATASNAP有许多远程方法就是 ...