标签:goto pos mask span cas ota style 方式 dmi
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 = 0; /* * Fetch the caller‘s info block into kernel space */ //从用户空间拷贝配置 if (copy_from_user(&ifr, arg, sizeof(struct ifreq))) goto out; ifr.ifr_name[IFNAMSIZ - 1] = 0; /* save original address for comparison */ //存储原地址 memcpy(&sin_orig, sin, sizeof(*sin)); //如果配置了别名,则将别名后缀去掉,后续恢复 colon = strchr(ifr.ifr_name, ‘:‘); if (colon) *colon = 0; //加载驱动 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, 0, 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 = 0; //关闭网络设备,则删除ip if (!(ifr.ifr_flags & IFF_UP)) inet_del_ifa(in_dev, ifap, 1); 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) < 0) 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 = 0; //地址相同 if (ifa->ifa_local == sin->sin_addr.s_addr) break; //地址不同,则删除原地址 inet_del_ifa(in_dev, ifap, 0); ifa->ifa_broadcast = 0; ifa->ifa_scope = 0; } //设置地址 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 < 31) ifa->ifa_broadcast = ifa->ifa_address | ~ifa->ifa_mask; } else { //设置掩码 ifa->ifa_prefixlen = 32; ifa->ifa_mask = inet_make_mask(32); } //设置生命周期 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 = 0; //删除重新设置 if (ifa->ifa_broadcast != sin->sin_addr.s_addr) { inet_del_ifa(in_dev, ifap, 0); ifa->ifa_broadcast = sin->sin_addr.s_addr; inet_insert_ifa(ifa); } break; //设置点对点目的地址 case SIOCSIFDSTADDR: /* Set the destination address */ ret = 0; //相同 if (ifa->ifa_address == sin->sin_addr.s_addr) break; ret = -EINVAL; //校验地址 if (inet_abc_len(sin->sin_addr.s_addr) < 0) break; ret = 0; //删除重置地址 inet_del_ifa(in_dev, ifap, 0); 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, 0)) break; ret = 0; if (ifa->ifa_mask != sin->sin_addr.s_addr) { //设置掩码 __be32 old_mask = ifa->ifa_mask; inet_del_ifa(in_dev, ifap, 0); 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 < 31) && (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 : 0; goto out; }
标签:goto pos mask span cas ota style 方式 dmi
原文地址:http://www.cnblogs.com/wanpengcoder/p/7396169.html