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的更多相关文章

  1. Linux就这个范儿 第13章 打通任督二脉

    Linux就这个范儿 第13章 打通任督二脉 0111010110……你有没有想过,数据从看得见或看不见的线缆上飞来飞去,是怎么实现的呢?数据传输业务的未来又在哪里?在前面两章中我们学习了Linux网 ...

  2. DDNS 的工作原理及其在 Linux 上的实现--转

    http://www.ibm.com/developerworks/cn/linux/1305_wanghz_ddns/index.html DDNS (Dynamic DNS) 扩展了 DNS 将客 ...

  3. Linux协议栈代码阅读笔记(二)网络接口的配置

    Linux协议栈代码阅读笔记(二)网络接口的配置 (基于linux-2.6.11) (一)用户态通过C库函数ioctl进行网络接口的配置 例如,知名的ifconfig程序,就是通过C库函数sys_io ...

  4. 深入理解linux网络技术内幕读书笔记(三)--用户空间与内核的接口

    Table of Contents 1 概论 1.1 procfs (/proc 文件系统) 1.1.1 编程接口 1.2 sysctl (/proc/sys目录) 1.2.1 编程接口 1.3 sy ...

  5. 【linux】linux内核移植错误记录

       欢迎转载,转载时请保留作者信息,谢谢. 邮箱:tangzhongp@163.com 博客园地址:http://www.cnblogs.com/embedded-tzp Csdn博客地址:http ...

  6. 网口up不起来问题排查

    最近处理一个问题,发现有的网口up不起来.       ethtool eth6   Settings for eth6:   Supported ports: [ FIBRE ]   Support ...

  7. [置顶] Linux协议栈代码阅读笔记(二)网络接口的配置

    Linux协议栈代码阅读笔记(二)网络接口的配置 (基于linux-2.6.11) (一)用户态通过C库函数ioctl进行网络接口的配置 例如,知名的ifconfig程序,就是通过C库函数sys_io ...

  8. IP编址

    IP地址 /include/linux/inetdevice.h,定义IPV4专用的网络设备相关的结构.宏等 /net/ipv4/devinet.c.支持IPV4特性的设备操作接口 数据组织 net_ ...

  9. 以太网驱动的流程浅析(一)-Ifconfig主要流程【原创】

    以太网驱动的流程浅析(一)-Ifconfig主要流程 Author:张昺华 Email:920052390@qq.com Time:2019年3月23日星期六 此文也在我的个人公众号以及<Lin ...

随机推荐

  1. AndroidStudio3.0 注解报错Annotation processors must be explicitly declared now. The following dependencies on the compile classpath are found to contain annotation processor.

    把Androidstudio2.2的项目放到3.0里面去了,然后开始报错了. 体验最新版AndroidStudio3.0 Canary 8的时候,发现之前项目的butter knife报错,用到注解的 ...

  2. [C/C++] C/C++错题集

    1. 解析: A:在GCC下输出:0    在VC6.0下输出:1 B:在GCC下输出:段错误 (核心已转储)    在VC6.0下输出:已停止工作,出现了一个问题,导致程序停止正常工作. C:正常 ...

  3. Delphi 模式窗体返回值ModalResult的使用方法及注意事项

    1.基础知识简介: ModalResult是指一个模式窗体(form.showmodal)的返回值,一般用于相应窗体上按钮的ModalResult属性: 显示完窗体(关闭)后,会返回此属性预设的值做为 ...

  4. 如何在存储过程中执行set命令  我来答

    1.EXEC使用EXEC命令两种用种执行存储程另种执行态批处理所讲都第二种用 面先使用EXEC演示例,代码1DECLARE @TableName VARCHAR(50),@Sql NVARCHAR ( ...

  5. bzoj3502[PA2012]Tanie Linie(最大k区间和)

    题意:给定一个长为n的数列,要求选出最多k个不相交的区间(可以不选),使得选中的数字之和最大.(1<=k<=n<=1000000)分析:首先我们通过预处理对问题做一些简化.原序列中的 ...

  6. Elasticsearch Query DSL备忘(1)(Constant score query和Bool Query)

    Query DSL (Domain Specific Language),基于json的查询方式 1.Constant score query,常量分值查询,目的就是返回指定的score,一般都结合f ...

  7. 史上最简单的 MySQL 教程(十五)「列属性 之 自动增长」

    自动增长 自动增长:auto_increment,当对应的字段,不给值,或者是默认值,或者是null的时候,就会自动的被系统触发,系统会从当前字段中取已有的最大值再进行+1操作,得到新的字段值. 自增 ...

  8. BZOJ4200 & 洛谷2304 & UOJ132:[NOI2015]小园丁与老司机——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4200 https://www.luogu.org/problemnew/show/P2304 ht ...

  9. [Leetcode] gas station 气站

    There are N gas stations along a circular route, where the amount of gas at station i isgas[i]. You ...

  10. 【链表】【UVA11988】Broken Keyboard

    传送门 明明是道黄题我竟然来写博客……我真的是什么数据结构也不会写了 Description 你在输入文章的时候,键盘上的Home键和End键出了问题,会不定时的按下.你却不知道此问题,而是专心致志地 ...