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. React 16.x & Hooks

    React 16.x & Hooks Hooks https://reactjs.org/docs/hooks-intro.html https://reactjs.org/docs/hook ...

  2. Matlab 函数ndims简介,flipdim简介

    ndims是matlab中求一个数组维数的函数. 调用格式: n=ndims(A) 将A的维数返回给变量n.n>=2 n=ndims(A)与n=length(size(A))是等价的 MATLA ...

  3. Go语言【第七篇】:Go函数

    Go语言函数 函数是基本的代码块,用于执行某个任务.Go语言最少有个main()函数,可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务.函数声明告诉了编译器函数的名称,返回类型和参数.Go ...

  4. Java.util包简单总结

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

  5. Java异常捕捉

    相信你在处理异常的时候不是每次都把它 throws 掉就完事了,很多时候异常是需要我们自己来 catch 并针对所抛出的 Exception 做一些后续的处理工作. 直接上代码,先贴下面测试需要调用的 ...

  6. UVA.12096 The SetStack Computer ( 好题 栈 STL混合应用)

    UVA.12096 The SetStack Computer ( 好题 栈 STL混合应用) 题意分析 绝对的好题. 先说做完此题的收获: 1.对数据结构又有了宏观的上的认识; 2.熟悉了常用STL ...

  7. HDOJ.1800 Flying to the Mars(贪心+map)

    Flying to the Mars 点我挑战题目 题意分析 有n个人,每个人都有一定的等级,高等级的人可以教低等级的人骑扫帚,并且他们可以共用一个扫帚,问至少需要几个扫帚. 这道题与最少拦截系统有异 ...

  8. 20181015 考试记录&数论

    题目传送门 W神爷的题解 数论 小 M 的算式 [问题描述] 小 M 在做数学作业的时候遇到了一个有趣的问题:有一个长度为 n 的数字 串 S,小 M 需要在数字之间填入若干个“+”和恰好一个“=”, ...

  9. git安装配置和使用

    ## 安装git服务器 ## 安装git sudo apt-get install git ## 建立git用户 sudo adduser git ## 修改git用户 * 设置不能登录 vim /e ...

  10. 【转载】Innodb共享表空间VS独立表空间

    http://www.mysqlsupport.cn/innodb%E5%85%B1%E4%BA%AB%E8%A1%A8%E7%A9%BA%E9%97%B4vs%E7%8B%AC%E7%AB%8B%E ...