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. 【Asp.Net Core】ASP.NET Core 2.0 + EF6 + Linux +MySql混搭

    好消息!特好消息!同时使用ASP.NET Core 2.0和.NET Framework类库还能运行在linux上的方法来啦! 是的,你没有看错!ASP.NET Core 2.0,.NET Frame ...

  2. Codeforces Round #524 Div. 2 翻车记

    A:签到.room里有一个用for写的,hack了一发1e8 1,结果用了大概600+ms跑过去了.惨绝人寰. #include<iostream> #include<cstdio& ...

  3. [JSOI2010]部落划分 最小生成树

    一道最小生成树经典题 由于是最靠近的两个部落尽可能远,如果我们先处理出任意两个居住点之间的距离并将其当做边,那么我们可以发现,因为在一个部落里面的边是不用计入答案的,所以应该要尽量把小边放在一个部落里 ...

  4. 【BZOJ2648】SJY摆棋子(KD-Tree)

    [BZOJ2648]SJY摆棋子(KD-Tree) 题面 BZOJ Description 这天,SJY显得无聊.在家自己玩.在一个棋盘上,有N个黑色棋子.他每次要么放到棋盘上一个黑色棋子,要么放上一 ...

  5. POJ1474:Video Surveillance——题解

    http://poj.org/problem?id=1474 题目大意:给按照顺时针序的多边形顶点,问其是否有内核. —————————————————————————————— (和上道题目一模一样 ...

  6. BZOJ1046 [HAOI2007]上升序列 【LIS + 字典序最小】

    1046: [HAOI2007]上升序列 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 5410  Solved: 1877 [Submit][St ...

  7. 洛谷 P2258 子矩阵 解题报告

    P2258 子矩阵 题目描述 给出如下定义: 子矩阵:从一个矩阵当中选取某些行和某些列交叉位置所组成的新矩阵(保持行与列的相对顺序)被称为原矩阵的一个子矩阵. 例如,下面左图中选取第 2 . 4行和第 ...

  8. js判断设备类型

    1. 判断微信 function is_weixin() { var ua = window.navigator.userAgent.toLowerCase(); if (ua.match(/Micr ...

  9. (ex)BSGS题表

    学了一下BSGS大概知道他是什么了,但是并没有做什么难题,所以也就会个板子.普通的BSGS,我还是比较理解的,然而exBSGS我却只理解个大概,也许还会个板子......(这个东西好像都会有一群恶心的 ...

  10. BZOJ1898: [Zjoi2005]Swamp 沼泽鳄鱼(矩阵乘法)

    1898: [Zjoi2005]Swamp 沼泽鳄鱼 题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1898 Description 潘塔 ...