平台信息:
内核: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地址的读和写的接口

 int sp_get_mac(char *value, int len){

     unsigned blocks,offset_blocks;
const disk_partition_t* ptn = get_disk_partition("sp"); /* strcpy(value,"0123456789"); */
/* return 0; */ offset_blocks = DIV_ROUND_UP(SP_MAC_OFFSET, RK_BLK_SIZE);
/* blocks = DIV_ROUND_UP(len, RK_BLK_SIZE); */ if (ptn) {
return rkloader_CopyFlash2Memory(value,ptn->start+offset_blocks,);
} return -;
} int sp_set_mac(char *value, int len){ unsigned blocks,offset_blocks;
const disk_partition_t* ptn = get_disk_partition("sp"); offset_blocks = DIV_ROUND_UP(SP_MAC_OFFSET, RK_BLK_SIZE);
blocks = DIV_ROUND_UP(len, RK_BLK_SIZE); if (ptn) {
StorageEraseBlock(ptn->start+offset_blocks, blocks, );
return rkloader_CopyMemory2Flash(value,ptn->start+offset_blocks,blocks);
} return -;
}

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

     //读取sp分区的mac地址
memset(tbuf,,sizeof(tbuf));
ret = sp_get_mac(tbuf,);
if(ret!=){
tbuf[]=;
}else{
if((tbuf[]==0xff)&&(tbuf[]==0xff)&&(tbuf[]==0xff)&&\
(tbuf[]==0xff)&&(tbuf[]==0xff)&&(tbuf[]==0xff)){
tbuf[]=;
}else if((tbuf[]==0x00)&&(tbuf[]==0x00)&&(tbuf[]==0x00)&&\
(tbuf[]==0x00)&&(tbuf[]==0x00)&&(tbuf[]==0x00)){
tbuf[]=;
}else{
unsigned char tmp[];
memset(tmp,,); sprintf(tmp,"%02x:%02x:%02x:%02x:%02x:%02x",tbuf[],tbuf[],tbuf[],tbuf[],tbuf[],tbuf[]);
printf("[%s:%d]mac:%s\r\n",__func__,__LINE__,tmp);
snprintf(command_line, len,
"%s eth_mac=%s", command_line, tmp);
}
}
tbuf[]=;

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

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

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

u_char mac_addr_str[] = {};
u_char mac_addr[] = {};
static int __init get_mac_addr(char *str)
{
strncpy(mac_addr_str,str,);
printk(KERN_ERR"[%s:%d] mac_addr_str = %s",__func__,__LINE__,mac_addr_str);
return ;
} //解析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 ;
break;
case 'b':
case 'B':
return ;
break;
case 'c':
case 'C':
return ;
break;
case 'd':
case 'D':
return ;
break;
case 'e':
case 'E':
return ;
break;
case 'f':
case 'F':
return ;
break;
default:
return ;
}
}
void str2byte(u_char *str, u_char *byte)
{
int i=, j=;
u_char num, n;
u_char temp[] = {}; for(i=; i<; i++){
if(str[i] == ':'){
continue;
}else{
temp[j] = str[i];
j++;
}
}
temp[j]='\0';
i=;
while(*(temp+i)!='\0')
{
if(*(temp+i)>='' && *(temp+i) <= ''){
if(i% == ){ //żÊýΪʮλ
num = (*(temp+i)-'') * ;
}else{
num = num + (*(temp+i)-'');
}
i++;
}else if((*(temp+i)>='a' && *(temp+i) <= 'f') || (*(temp+i)>='A' && *(temp+i) <= 'F')){
n = char2num(*(temp+i));
if(n == ){
memset(byte, , );
break;
}
if(i% == ){ //żÊýΪʮλ
num = n * ;
}else{
num = num + n;
}
i++;
}else{
memset(byte, , );
break;
}
if(i% == ){
*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 ;
} static ssize_t block_mac_show( char *buf)
{
char mac_buf[] = {}; read_block_info(BLOCK_NAME, mac_buf, , 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[],mac_addr[],mac_addr[],mac_addr[],mac_addr[],mac_addr[]);
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,,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[],block_mac_buf[],block_mac_buf[],block_mac_buf[],block_mac_buf[],block_mac_buf[]); 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的方法如下。

 +
+static ssize_t sys_mac_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ char temp_mac_buf[];
+
+ memset(temp_mac_buf,,sizeof(temp_mac_buf));
+ read_block_info(BLOCK_NAME, temp_mac_buf, , MAC_ADDR_OFFSET);
+ 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[]);
+
+ return sprintf(buf, "%pM\n", temp_mac_buf);
+}
+
+static ssize_t sys_mac_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ u_char mac_addr[] = {};
+
+ printk(KERN_ERR"[%s:%d]%02x:%02x:%02x:%02x:%02x:%02x\r\n",__func__,__LINE__,buf[],buf[],buf[],buf[],buf[],buf[]);
+ if (buf != NULL && strlen(buf)){
+ //memcpy(mac_str, buf, strlen(buf));
+ //<D7>ַ<FB><B4><AE><B5><C4>ת<BB><BB>
+ str2byte(buf, mac_addr);
+ 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[]);
+ write_block_info(BLOCK_NAME, mac_addr, , MAC_ADDR_OFFSET);
+ }
+
+ return count;
+}
+
+static struct kobj_attribute mac_attribute =
+ __ATTR(mac, , sys_mac_show, sys_mac_store);
+
+
+static struct attribute *attrs[] = {
+ &mac_attribute.attr,
+ NULL, /* need to NULL terminate the list of attributes */
+};
+static struct attribute_group attr_group = {
+ .attrs = attrs,
+};
+
+static struct kobject *ethernet_kobj;
+ + ethernet_kobj = kobject_create_and_add("pax_ethernet", kernel_kobj);
+ if (!ethernet_kobj)
+ return -ENOMEM;
+
+ /* Create the files associated with this kobject */
+ ret = sysfs_create_group(ethernet_kobj, &attr_group);
+ if (ret)
+ kobject_put(ethernet_kobj);
+

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

 int write_block_info(const char *name, char *data, int length, loff_t offset)
{
struct file *fp;
mm_segment_t fs; AUTHINFO_DEBUG("%s start, data: %s, length: %d \n",__func__, data, length); fp = filp_open(name, O_RDWR | O_CREAT, );
if (IS_ERR(fp)) {
AUTHINFO_ERROR("create file error");
return -;
} fs = get_fs();
set_fs(KERNEL_DS); vfs_write(fp, data, length, &offset); filp_close(fp, NULL);
set_fs(fs); AUTHINFO_DEBUG("%s end",__func__); return ;
}
EXPORT_SYMBOL(write_block_info); int read_block_info(const char *name, char *buf, int length, loff_t offset)
{
struct file *fp;
mm_segment_t fs; AUTHINFO_DEBUG("%s start",__func__);
fp = filp_open(name, O_RDWR | O_CREAT, );
if (IS_ERR(fp)) {
AUTHINFO_ERROR("create file error");
return -;
} fs = get_fs();
set_fs(KERNEL_DS); vfs_read(fp, buf, length, &offset); filp_close(fp, NULL);
set_fs(fs); AUTHINFO_DEBUG("%s end %d %s",__func__,length,buf); return ;
}
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. Laravel(4.2)-->whereHas/ whereDoesntHave

    在开发过程中,有时间需要用 wherehas 联合查询 出想要的结果,但是有的时候想搜索出不在关联表中出现的数据 whereDoesntHave(例:搜索出开卡的用户和没有开卡的用户)if($is_o ...

  2. Oracle の ty_str_split + MySQL の proc_split

    oracle实现字符串分割 功能描述:用指定分隔符切割输入的字符串,返回一维数组,每个数组元素为一个子串. ); CREATE OR REPLACE FUNCTION fn_split (p_str ...

  3. Python 迭代器&生成器,装饰器,递归,算法基础:二分查找、二维数组转换,正则表达式,作业:计算器开发

    本节大纲 迭代器&生成器 装饰器  基本装饰器 多参数装饰器 递归 算法基础:二分查找.二维数组转换 正则表达式 常用模块学习 作业:计算器开发 实现加减乘除及拓号优先级解析 用户输入 1 - ...

  4. zoj 2947 Abbreviation

    Abbreviation Time Limit: 2 Seconds      Memory Limit: 65536 KB When a Little White meets another Lit ...

  5. devstack脚本安装Openstack总结(转载)

    1:vmware 基本设置 我采用的vmware workstation 8.0的版本,其他版本应该都是没问题.我是把虚拟机放在NAT的网络. 虚拟机就单块网卡就可以. 如果你希望可以在dashboa ...

  6. [luoguP1198][JSOI2008] 最大数(线段树 || 单调栈)

    题目传送门 1.线段树 线段树可以搞. 不过慢的要死1300+ms #include <cstdio> #include <iostream> using namespace ...

  7. 事件和委托:第 5 页 委托、事件与Observer设计模式

    原文发布时间为:2008-11-01 -- 来源于本人的百度文章 [由搬家工具导入] 委托、事件与Observer设计模式 范例说明 上面的例子已不足以再进行下面的讲解了,我们来看一个新的范例,因为之 ...

  8. Codeforces 659A Round House【水题,细节】

    题目链接: http://codeforces.com/contest/659/problem/A 题意: 一个圈,按逆时针编号,给定起点,方向和步数,问终点在几号? 分析: 很简单的模拟...注意答 ...

  9. React学习及实例开发(一)——开始

    本文基于React v16.4.1 初学react,有理解不对的地方,欢迎批评指正^_^ 一.构建一个新项目 1.命令行运行如下命令,构建一个新的react项目 npm install -g crea ...

  10. Prime Ring Problem---hdu1016(dfs)

    http://acm.hdu.edu.cn/showproblem.php?pid=1016 这就是一道简单的dfs  但是是我自己想起来的   必须要记录一下 #include<stdio.h ...