当前位置:   article > 正文

RK3288以太网的mac地址调试笔记【学习笔记】【原创】

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

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

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

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

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

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

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

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

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

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

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

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

觉得不错,就给我点小支持吧,蟹蟹

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/498201
推荐阅读
相关标签
  

闽ICP备14008679号