devinet_ioctl
Kernel: 4.12.6
deinet_ioctl:获取或者设置接口的地址,掩码,标记等信息;
注意,使用SIOCSIFFLAGS关闭设备,如果使用了别名,则删除对应ip,如果其为主ip,并且从ip未设置提升主ip,则所有从ip也会删除;
int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
{
struct ifreq ifr;
struct sockaddr_in sin_orig;
struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
struct in_device *in_dev;
struct in_ifaddr **ifap = NULL;
struct in_ifaddr *ifa = NULL;
struct net_device *dev;
char *colon;
int ret = -EFAULT;
int tryaddrmatch = ; /*
* Fetch the caller's info block into kernel space
*/ //从用户空间拷贝配置
if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
goto out;
ifr.ifr_name[IFNAMSIZ - ] = ; /* save original address for comparison */
//存储原地址
memcpy(&sin_orig, sin, sizeof(*sin)); //如果配置了别名,则将别名后缀去掉,后续恢复
colon = strchr(ifr.ifr_name, ':');
if (colon)
*colon = ; //加载驱动
dev_load(net, ifr.ifr_name); //参数检查
switch (cmd) {
//获取接口地址,广播地址,目的地址,子网掩码
case SIOCGIFADDR: /* Get interface address */
case SIOCGIFBRDADDR: /* Get the broadcast address */
case SIOCGIFDSTADDR: /* Get the destination address */
case SIOCGIFNETMASK: /* Get the netmask for the interface */
/* Note that these ioctls will not sleep,
so that we do not impose a lock.
One day we will be forced to put shlock here (I mean SMP)
*/
//记录原地址协议族是否为AF_INET
tryaddrmatch = (sin_orig.sin_family == AF_INET); //设置协议族为AF_INET
memset(sin, , sizeof(*sin));
sin->sin_family = AF_INET;
break; //设置接口flag
case SIOCSIFFLAGS:
ret = -EPERM; //检查权限,不足则退出
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
goto out;
break; //设置接口地址,广播地址,目的地址,子网掩码
case SIOCSIFADDR: /* Set interface address (and family) */
case SIOCSIFBRDADDR: /* Set the broadcast address */
case SIOCSIFDSTADDR: /* Set the destination address */
case SIOCSIFNETMASK: /* Set the netmask for the interface */ //检查权限,不足则退出 ret = -EPERM;
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
goto out; //检查协议族,不是AF_INET则退出
ret = -EINVAL;
if (sin->sin_family != AF_INET)
goto out;
break; //其他情况参数非法
default:
ret = -EINVAL;
goto out;
} rtnl_lock(); //根据名称查找设备
ret = -ENODEV;
dev = __dev_get_by_name(net, ifr.ifr_name); //未找到退出
if (!dev)
goto done; //恢复别名分隔符
if (colon)
*colon = ':'; //获取in_device结构
in_dev = __in_dev_get_rtnl(dev); //若存在
if (in_dev) { //如果为AF_INET,则根据ip和标签查找ifa
if (tryaddrmatch) {
/* Matthias Andree */
/* compare label and address (4.4BSD style) */
/* note: we only do this for a limited set of ioctls
and only if the original address family was AF_INET.
This is checked above. */
for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
ifap = &ifa->ifa_next) {
if (!strcmp(ifr.ifr_name, ifa->ifa_label) &&
sin_orig.sin_addr.s_addr ==
ifa->ifa_local) {
break; /* found */
}
}
}
/* we didn't get a match, maybe the application is
4.3BSD-style and passed in junk so we fall back to
comparing just the label */
//如果没找到,则之查找标签
if (!ifa) {
for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
ifap = &ifa->ifa_next)
if (!strcmp(ifr.ifr_name, ifa->ifa_label))
break;
}
} //若ifa不存在,设置地址和设置标志以外的命令不合法
ret = -EADDRNOTAVAIL;
if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
goto done; switch (cmd) {
//获取ip地址
case SIOCGIFADDR: /* Get interface address */
sin->sin_addr.s_addr = ifa->ifa_local;
goto rarok;
//获取广播地址
case SIOCGIFBRDADDR: /* Get the broadcast address */
sin->sin_addr.s_addr = ifa->ifa_broadcast;
goto rarok;
//获取点对点目的地址
case SIOCGIFDSTADDR: /* Get the destination address */
sin->sin_addr.s_addr = ifa->ifa_address;
goto rarok;
//获取子网掩码
case SIOCGIFNETMASK: /* Get the netmask for the interface */
sin->sin_addr.s_addr = ifa->ifa_mask;
goto rarok;
//设置flags
case SIOCSIFFLAGS:
//别名
if (colon) {
ret = -EADDRNOTAVAIL;
if (!ifa)
break;
ret = ; //关闭网络设备,则删除ip
if (!(ifr.ifr_flags & IFF_UP))
inet_del_ifa(in_dev, ifap, );
break;
} //修改标记
ret = dev_change_flags(dev, ifr.ifr_flags);
break;
//设置地址
case SIOCSIFADDR: /* Set interface address (and family) */
ret = -EINVAL;
//检查掩码长度
if (inet_abc_len(sin->sin_addr.s_addr) < )
break; //地址不存在
if (!ifa) {
ret = -ENOBUFS;
ifa = inet_alloc_ifa();
if (!ifa)
break;
INIT_HLIST_NODE(&ifa->hash); //拷贝名称
if (colon)
memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
else
memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
} else {
ret = ;
//地址相同
if (ifa->ifa_local == sin->sin_addr.s_addr)
break; //地址不同,则删除原地址
inet_del_ifa(in_dev, ifap, );
ifa->ifa_broadcast = ;
ifa->ifa_scope = ;
} //设置地址
ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr; //如果不是点对点
if (!(dev->flags & IFF_POINTOPOINT)) { //设置掩码
ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen); //设置广播地址
if ((dev->flags & IFF_BROADCAST) &&
ifa->ifa_prefixlen < )
ifa->ifa_broadcast = ifa->ifa_address |
~ifa->ifa_mask;
} else {
//设置掩码
ifa->ifa_prefixlen = ;
ifa->ifa_mask = inet_make_mask();
} //设置生命周期
set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME); //添加ip地址
ret = inet_set_ifa(dev, ifa);
break;
//设置广播地址
case SIOCSIFBRDADDR: /* Set the broadcast address */
ret = ; //删除重新设置
if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
inet_del_ifa(in_dev, ifap, );
ifa->ifa_broadcast = sin->sin_addr.s_addr;
inet_insert_ifa(ifa);
}
break;
//设置点对点目的地址
case SIOCSIFDSTADDR: /* Set the destination address */
ret = ;
//相同
if (ifa->ifa_address == sin->sin_addr.s_addr)
break;
ret = -EINVAL; //校验地址
if (inet_abc_len(sin->sin_addr.s_addr) < )
break;
ret = ; //删除重置地址
inet_del_ifa(in_dev, ifap, );
ifa->ifa_address = sin->sin_addr.s_addr;
inet_insert_ifa(ifa);
break;
//设置掩码
case SIOCSIFNETMASK: /* Set the netmask for the interface */ /*
* The mask we set must be legal.
*/ //检查掩码
ret = -EINVAL;
if (bad_mask(sin->sin_addr.s_addr, ))
break;
ret = ;
if (ifa->ifa_mask != sin->sin_addr.s_addr) {
//设置掩码
__be32 old_mask = ifa->ifa_mask;
inet_del_ifa(in_dev, ifap, );
ifa->ifa_mask = sin->sin_addr.s_addr;
ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask); /* See if current broadcast address matches
* with current netmask, then recalculate
* the broadcast address. Otherwise it's a
* funny address, so don't touch it since
* the user seems to know what (s)he's doing...
*/
//如果之前广播地址与掩码匹配,
//则重新按照此方式计算广播地址
if ((dev->flags & IFF_BROADCAST) &&
(ifa->ifa_prefixlen < ) &&
(ifa->ifa_broadcast ==
(ifa->ifa_local|~old_mask))) {
ifa->ifa_broadcast = (ifa->ifa_local |
~sin->sin_addr.s_addr);
}
//重新设置ip
inet_insert_ifa(ifa);
}
break;
}
done:
rtnl_unlock();
out:
return ret;
rarok:
rtnl_unlock(); //拷贝到用户空间
ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : ;
goto out;
}
devinet_ioctl的更多相关文章
- Linux就这个范儿 第13章 打通任督二脉
Linux就这个范儿 第13章 打通任督二脉 0111010110……你有没有想过,数据从看得见或看不见的线缆上飞来飞去,是怎么实现的呢?数据传输业务的未来又在哪里?在前面两章中我们学习了Linux网 ...
- DDNS 的工作原理及其在 Linux 上的实现--转
http://www.ibm.com/developerworks/cn/linux/1305_wanghz_ddns/index.html DDNS (Dynamic DNS) 扩展了 DNS 将客 ...
- Linux协议栈代码阅读笔记(二)网络接口的配置
Linux协议栈代码阅读笔记(二)网络接口的配置 (基于linux-2.6.11) (一)用户态通过C库函数ioctl进行网络接口的配置 例如,知名的ifconfig程序,就是通过C库函数sys_io ...
- 深入理解linux网络技术内幕读书笔记(三)--用户空间与内核的接口
Table of Contents 1 概论 1.1 procfs (/proc 文件系统) 1.1.1 编程接口 1.2 sysctl (/proc/sys目录) 1.2.1 编程接口 1.3 sy ...
- 【linux】linux内核移植错误记录
欢迎转载,转载时请保留作者信息,谢谢. 邮箱:tangzhongp@163.com 博客园地址:http://www.cnblogs.com/embedded-tzp Csdn博客地址:http ...
- 网口up不起来问题排查
最近处理一个问题,发现有的网口up不起来. ethtool eth6 Settings for eth6: Supported ports: [ FIBRE ] Support ...
- [置顶] Linux协议栈代码阅读笔记(二)网络接口的配置
Linux协议栈代码阅读笔记(二)网络接口的配置 (基于linux-2.6.11) (一)用户态通过C库函数ioctl进行网络接口的配置 例如,知名的ifconfig程序,就是通过C库函数sys_io ...
- IP编址
IP地址 /include/linux/inetdevice.h,定义IPV4专用的网络设备相关的结构.宏等 /net/ipv4/devinet.c.支持IPV4特性的设备操作接口 数据组织 net_ ...
- 以太网驱动的流程浅析(一)-Ifconfig主要流程【原创】
以太网驱动的流程浅析(一)-Ifconfig主要流程 Author:张昺华 Email:920052390@qq.com Time:2019年3月23日星期六 此文也在我的个人公众号以及<Lin ...
随机推荐
- 2011 Multi-University Training Contest 4 - Host by SDU
A.Color the Simple Cycle(polya计数+字符串匹配) 此题的难点在于确定置换的个数,由a[i+k]=a[i], e[i+k]=e[i]联想到KMP. 于是把原串和原串扩大两倍 ...
- Java入门之:对象和类
Java对象和类 Java作为一种面向对象语言,支持以下基本概念: 多态 继承 封装 抽象 类 对象 实例 方法 重载 本节我们重点研究对象和类的概念: 对象: 对象是类的一个实例,有状态和行为.例如 ...
- Linux相关——记一些ubuntu相关快捷键&操作(持续更新)
(有一些是windows通用的...放上来凑字数...) 1, ctrl + alt + t.调出终端,这个没什么好解释的. 2, win + s.可以快速查看打开的窗口,并进行切换 3,win + ...
- 【BZOJ4894】天赋(矩阵树定理)
[BZOJ4894]天赋(矩阵树定理) 题面 BZOJ Description 小明有许多潜在的天赋,他希望学习这些天赋来变得更强.正如许多游戏中一样,小明也有n种潜在的天赋,但有 一些天赋必须是要有 ...
- [Leetcode] Maximum depth of binary tree二叉树的最大深度
Given a binary tree, find its maximum depth. The maximum depth is the number of nodes along the long ...
- 洛谷 P1653 猴子 解题报告
P1653 猴子 题目描述 有N只猴子,第一只尾巴挂在树上,剩下的N-1只,要么被其他的猴子抓住,要么抓住了其他的猴子,要么两者均有.当然一只猴子最多抓两只另外的猴子.现在给出这N只猴子抓与被抓的信息 ...
- POJ.1061 青蛙的约会 (拓展欧几里得)
POJ.1061 青蛙的约会 (拓展欧几里得) 题意分析 我们设两只小青蛙每只都跳了X次,由于他们相遇,可以得出他们同余,则有: 代码总览 #include <iostream> #inc ...
- 项目管理---git----快速使用git笔记(五)------本地项目代码提交到远程仓库---新建项目
上一篇我们已经知道了怎么从远程仓库获取项目文件代码. 项目管理---git----快速使用git笔记(四)------远程项目代码的首次获取 git还有一种使用场景是 我本来在电脑里就有一个项目,现在 ...
- Spring中事务传播行为类型
Spring在TransactionDefinition接口中规定了7种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播: 事务传播行为类型 说明 PROPAGATION ...
- Mac将应用拖入Finder工具栏
在Finder的工具栏上放一下应用,方便打开对应的文件,可以 Command + 鼠标拖动应用,将应用拖入Finder工具栏中. 本人的Finder工具栏上添加了vscode这个应用