50.Linux-分析ifconfig到内核的调用过程,实现内核启机自动设MAC地址(原)
- 内核版本: Linux version 3.10.14
1.由于每次开发板开机的网卡eth0的物理地址都是随机的.
然后在网上找到可以通过命令行实现设置mac物理地址:
ifconfig eth0 down
ifconfig eth0 hw ether 1234567890ab
ifconfig eth0 up
- 然后带着好奇,想看看命令行ifconfig是如何与内核交互的,想试试如何直接通过内核自动设置MAC.
2.分析介绍
因为ifconfig是命令,代码位于busybox,不过我们在内核的documentation目录下找到了ifconfig介绍,代码介绍文件位于:
- documentation\networking\Ifenslave.c
2.1 如下图所示,对应ifconfig eth0 down和ifconfig eth0 up的函数就是:
比如,当我们敲ifconfig eth0 down时,实则就是调用:
set_if_down("eth0", master_flags.ifr_flags);
该文件除了上图外,还有以下常用函数:
set_if_addr(); //设置地址(包括IP,掩码,广播,目的地)
set_master_hwaddr(); //设置mac物理地址
- 接下来我们以eth0为例,来跟踪ifconfig up/down和ifconfig eth0 hw ether如何调用内核的
3.分析set_if_up()函数
3.1 分析set_if_up()
set_if_up()函数将会调用set_if_flags("eth0", flags | IFF_UP), 向添加ifname(eth0) 开启标志位
3.2 分析set_if_up()->set_if_flags("eth0", flags | IFF_UP)
该函数如下所示:
static int set_if_flags(char *ifname, short flags)
{
struct ifreq ifr;
int res = ;
ifr.ifr_flags = flags;
strncpy(ifr.ifr_name, ifname, IFNAMSIZ); //ifr.ifr_name="eth0" res = ioctl(skfd, SIOCSIFFLAGS, &ifr); //通过ioctl()向内核socket传递命令SIOCSIFFLAGS和ifr变量
if (res < ) {
saved_errno = errno;
v_print("Interface '%s': Error: SIOCSIFFLAGS failed: %s\n",
ifname, strerror(saved_errno));
} else {
v_print("Interface '%s': flags set to %04X.\n", ifname, flags);
}
return res;
}
3.3 寻找SIOCSIFFLAGS宏,看看内核那里在实现它
找到位于net\core\Dev_ioctl.c的dev_ioctl()函数
该函数重要部分代码如下:
int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
{
struct ifreq ifr;
int ret;
char *colon;
//… … switch (cmd) {
//… … case SIOCSIFFLAGS: //设置标志,比如ifconfig up/down
case SIOCSIFMETRIC:
case SIOCSIFMTU: //设置MUT长度
case SIOCSIFHWADDR: //设置mac物理地址
//… … dev_load(net, ifr.ifr_name); //通过ifr.ifr_name(eth0)名字来加载网卡
rtnl_lock(); //对net_device进行加锁,避免与运行冲突
ret = dev_ifsioc(net, &ifr, cmd); //最终调用该函数 rtnl_unlock();
return ret;
//… …
}
从上面可以看出,我们设置mac物理地址时的流程也会运行到这里,最终他们都会调用dev_ifsioc(net, &ifr, cmd)函数
4. 后面的就很简单了,最终ifconfig eth0 up调用内核过程为:
set_if_up()-> set_if_flags("eth0", flags | IFF_UP)-> dev_ifsioc(net, &ifr, cmd)-> dev_change_flags(dev, ifr->ifr_flags)-> __dev_change_flags(dev, flags);
4.1然后在__dev_change_flags(dev, flags)函数中,通过判断flag的IFF_UP位上的值是否相反,来实现是调用__dev_close()还是__dev_open()来开关eth0
如下图所示:
4.2然后__dev_open()则将会调用网卡驱动的net_device_ops结构体下的成员函数实现打开
__dev_open(dev):
dev->netdev_ops->ndo_validate_addr(dev); //测试dev->dev_addr(hw addr)是否有效,一般都是调用eth_validate_addr()函数,需要注意hw_addr[0]的最低位不能为1
dev->netdev_ops->ndo_open(dev); //调用open()函数实现ifconfig up
4.3同样__dev_close()会调用下面的成员函数实现关闭:
dev->netdev_ops->ndo_stop(dev); //调用stop ()函数实现ifconfig down
4.4寻找net_device_ops结构体的成员函数位于哪里
上面讲的dev 变量是struct net_device类型,而struct net_device在内核中表示我们的一个网卡驱动设备,注册该变量的文件都处于内核drivers/net目录下,通过register_netdev() 内核函数来注册.
我们以我们板卡的dm9000网卡为例,该文件位于drivers/net/Ethernet/davicom/dm9000.c,然后便可以找到它的ndo_open ():
5.而对于ifconfig eth0 hw ether 设置网卡流程如下所示:
set_master_hwaddr(master_ifname,&(slave_hwaddr.ifr_hwaddr))-> ioctl (skfd, SIOCSIFHWADDR, &ifr) -> dev_ifsioc(net, &ifr, cmd)-> dev_set_mac_address(dev, &ifr->ifr_hwaddr) -> //设置网卡MAC地址 dev->netdev_ops->ndo_set_mac_address(dev, &ifr->ifr_hwaddr);
//最终调用net_device的ops成员函数实现设置
6.实现内核开机自动设置固定MAC地址
流程分析完后,接下来我们便来实现它.
6.1以我们板卡的dm9000网卡为例
我们找到register_netdev()位置,位于drivers/net/Ethernet/davicom/dm9000.c的dm9000_probe函数里:
6.2 然后在register_netdev()函数下面添加代码:
struct sockaddr hwaddr; //用来存储MAC地址的结构体 rtnl_lock();
ret =dev_close(jz_ndev); //首先需要关闭网卡,以防万一
rtnl_unlock(); hwaddr.sa_family = ndev->type; hwaddr.sa_data[]=0x12; //注意,data[0]最低位不能为1,也就是首位不能为奇数
hwaddr.sa_data[]=0x34;
hwaddr.sa_data[]=0x56;
hwaddr.sa_data[]=0x78;
hwaddr.sa_data[]=0x90;
hwaddr.sa_data[]=0xab; rtnl_lock();
ret = dev_set_mac_address(jz_ndev,&hwaddr); //调用我们分析到的函数,来设置mac地址
rtnl_unlock();
6.3 编译-试验
启动后输入ifconfig,即可看到内核已经帮我设置好了:
- 总结: 其实实现的代码很简单,但是需要去分析才能把东西消化为自己的.
50.Linux-分析ifconfig到内核的调用过程,实现内核启机自动设MAC地址(原)的更多相关文章
- PHP获取网卡的MAC地址原码;目前支持WIN/LINUX系统 获取机器网卡的物理(MAC)地址
声明转换于其它博客当中的. <?php /** 获取网卡的MAC地址原码:目前支持WIN/LINUX系统 获取机器网卡的物理(MAC)地址 **/ class GetMacAddr{ var $ ...
- 在Linux下,在网络没有配置好前,怎样查看网卡的MAC地址?
在Linux下,在网络没有配置好前,怎样查看网卡的MAC地址? 使用 dmesg 与 grep 命令来实际,例如以下: [root@localhost ~]# dmesg | grep eth e10 ...
- Linux 获取本机IP、MAC地址用法大全
getifaddrs()和struct ifaddrs的使用,获取本机IP ifaddrs结构体定义如下: struct ifaddrs { struct ifaddrs *ifa_next; /* ...
- 获取网卡的MAC地址原码;目前支持WIN/LINUX系统 获取机器网卡的物理(MAC)地址(服务器端)
<?php class GetMacAddr{ var $return_array = array(); // 返回带有MAC地址的字串数组 var $mac_addr; function Ge ...
- linux自动获得mac地址,修改网络配置
1.修改网络配置,自动获得mac地址 删除 /etc/udev/rules.d/70-persistent-net.rules 文件 删除 /etc/sysconfig/network-scripts ...
- 20135239 益西拉姆 linux内核分析 跟踪分析Linux内核的启动过程
回顾 1.中断上下文的切换——保存现场&恢复现场 本节主要课程内容 Linux内核源代码简介 1.打开内核源代码页面 arch/目录:支持不同CPU的源代码:其中的X86是重点 init/目录 ...
- Dubbo 源码分析 - 服务调用过程
注: 本系列文章已捐赠给 Dubbo 社区,你也可以在 Dubbo 官方文档中阅读本系列文章. 1. 简介 在前面的文章中,我们分析了 Dubbo SPI.服务导出与引入.以及集群容错方面的代码.经过 ...
- linux/Centos下查看和修改网卡Mac地址(ifconfig命令)
本文转载自http://www.169it.com/article/14360294838474691537.html linux/Centos下查看网卡Mac地址,输入命令: #ifconfig - ...
- Linux/CentOS下修改MAC地址
Linux/CentOS下修改MAC地址 摘自:https://blog.csdn.net/qq_33233768/article/details/64906265 2017年03月22日 11:06 ...
随机推荐
- web测试实践——day01
一.任务进展情况 主要是找寻网站的bug,分析bug的严重程度.同时找了本专业的同学进行博客园系统的使用. 二.存在的问题 由于上线的网站做的比较完善,导致找寻bug比较困难. 三.解决方法 对此我们 ...
- windows运维如何批量远程桌面
作用:windows下批量管理远程桌面, http://www.appmazing.com/ 官方站点 http://www.appmazing.com/files/RDO_Setup.exe wi ...
- 升讯威微信营销系统开发实践:微信接口的 .NET 封装
GitHub:https://github.com/iccb1013/Sheng.WeixinConstruction因为个人精力时间有限,不会再对现有代码进行更新维护,不过微信接口比较稳定,经测试至 ...
- 安卓开发学习笔记(二):如何用Android Stuidio在res资源下创建xml视图文件
笔者在看了相关的教程之后发现教程当中的资源已经过时了.当我们在创建了一个新的空白的工程之后,会发现其文件夹下面的分文件夹目录和官方的教程文件结构完全不同,因此会引起很多误解.笔者使用的是最新版的And ...
- 获取安卓应用APK包名的方法
应用商店按照符合Android标准的原则进行设计,使用包名(Package Name)作为应用的唯一标识.即:包名必须唯一,一个包名代表一个应用,不允许两个应用使用同样的包名.包名主要用于系统识别应用 ...
- JDK设计模式之—动态代理
代理模式的特点 代理模式是常用的java设计模式,它的特征是代理类与委托类有同样的接口.代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类. 代理类的对象并不是真正实现服务,而是通过调用委 ...
- [Swift]LeetCode344. 反转字符串 | Reverse String
Write a function that takes a string as input and returns the string reversed. Example 1: Input: &qu ...
- 初步学习大数据——设置虚拟机固定ip地址
1.打开本机的网络连接 2.右键以太网,打开属性. 3.右键VMnet8,打开属性.最多不能超过255,最少不能小于0. 0~255之间. 4.找到你要设置固定IP地址的虚拟机 ,选择上方的编辑 ...
- 【spring】ApplicationListener传递参数到页面(解决静态+动态资源路径+静态文件的缓存控制)
一.相对路径还是绝对路径的问题 前端页面加载资源或者请求的时候到底是使用相对路径还是绝对路径,想必大家都很清楚,用的是当然是相对路径,因为这样增加了项目的灵活性,不需要经常的改动.那既然是相对路径就需 ...
- vue+cordova构建跨平台应用集成并使用Cordova plugin
安装 //安装 vue-cil npm install --global vue-cli //安装cordova npm i cordova -g cordova 新建项目 //新建cordova 项 ...