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. 运行jar

    将Spring Boot 应用打包成jar, java -jar **.jar运行, 如果需要设置运行参数 java -jar **.jar --server.port=9080

  2. 创建udp服务端对象

    DatagramSocket ds = null;//创建服务器对象 ds = new DatagramSocket(10001);//创建对象并指定端口 byte[] bytes = new byt ...

  3. bzoj 3132: 上帝造题的七分钟 (二维树状数组)

    推推公式,最后变成四个东西的前缀和 然后不知道为什么一直wa,数据在本地测是没有错的& 好心的管理员还给了某位p党大神a了的代码,感人肺腑(虽然还是没发现到底我的程序是问题) var f1,f ...

  4. Java.util包简单总结

    Java.util包简单总结 1. util包的框架 常用的集合类主要实现两个“super接口”而来:Collection和Map. 1.1 Collection有两个子接口:List和Set è¿é ...

  5. Android Intent Action 一览表

    String ADD_SHORTCUT_ACTION 动作:在系统中添加一个快捷方式.. "android.intent.action.ADD_SHORTCUT" String A ...

  6. BZOJ3992:[SDOI2015]序列统计——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=3992 https://www.luogu.org/problemnew/show/P3321 小C ...

  7. BZOJ4004:[JLOI2015]装备购买——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4004 https://www.luogu.org/problemnew/show/P3265 脸哥 ...

  8. HDOJ(HDU).2660 Accepted Necklace (DFS)

    HDOJ(HDU).2660 Accepted Necklace (DFS) 点我挑战题目 题意分析 给出一些石头,这些石头都有自身的价值和重量.现在要求从这些石头中选K个石头,求出重量不超过W的这些 ...

  9. c#中文件流的读写

    文件流读入:第一static void Main(string[] args) { //C#文件流写文件,默认追加FileMode.Append string msg = "okffffff ...

  10. Nginx 配置解析

    概述:本篇文章主要对Nginx配置文件中一些常用配置进行了讲解,和如何使用Docker进行安装Nginx.因为该文章是回首在工作闲暇之余整理的,还有待完善,如果有疑义和更好的建议的朋友可以留言给我. ...