devinet_ioctl() 根据用户空间提供的ifreq参数和cmd操作对网卡进行设置或参数的获取
cmd:大体分为两种,即set和get
p.s. 有意思的是,用户空间的ifreq指针指向的参数需要拷贝到内存空间中,让后函数才能对参数进行解读和分析。
copy_from_user ( & ifr , arg , sizeof ( struct ifreq )
阅读(117) | 评论(0) | 转发(0) |
<script type=text/javascript charset=utf-8 src="http://static.bshare.cn/b/buttonLite.js#style=-1&uuid=&pophcol=3&lang=zh"></script> <script type=text/javascript charset=utf-8 src="http://static.bshare.cn/b/bshareC0.js"></script>
cmd:大体分为两种,即set和get
p.s. 有意思的是,用户空间的ifreq指针指向的参数需要拷贝到内存空间中,让后函数才能对参数进行解读和分析。
copy_from_user ( & ifr , arg , sizeof ( struct ifreq )
点击(此处)折叠或打开
- struct ifreq {
- char ifr_name[IFNAMSIZ];
- union
- {
- struct sockaddr ifru_addr;
- struct sockaddr ifru_dstaddr;
- struct sockaddr ifru_broadaddr;
- struct sockaddr ifru_netmask;
- struct sockaddr ifru_hwaddr;
- short int ifru_flags;
- int ifru_ivalue;
- int ifru_mtu;
- struct ifmap ifru_map;
- char ifru_slave[IFNAMSIZ]; /* Just fits the size */
- char ifru_newname[IFNAMSIZ];
- __caddr_t ifru_data;
- } ifr_ifru;
- };
-
- int devinet_ioctl(unsigned int cmd, void *arg)
- {
- struct ifreq ifr;
- 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 = 0;
-
- /*
- * Fetch the caller's info block into kernel space
- */
-
- if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
- return -EFAULT;
- ifr.ifr_name[IFNAMSIZ-1] = 0;
-
- colon = strchr(ifr.ifr_name, ':');
- if (colon)
- *colon = 0;
-
- #ifdef CONFIG_KMOD
- dev_load(ifr.ifr_name);
- #endif
-
- switch(cmd) { //根據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 this 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)
- */
- memset(sin, 0, sizeof(*sin));
- sin->sin_family = AF_INET;
- break;
-
- case SIOCSIFFLAGS:
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
- 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 */
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
- if (sin->sin_family != AF_INET)
- return -EINVAL;
- break;
- default:
- return -EINVAL;
- }
- //鎖
- dev_probe_lock();
- rtnl_lock();
- //獲取設備名對應的設備的數據結構(描述一個設備)
- if ((dev = __dev_get_by_name(ifr.ifr_name)) == NULL) {
- ret = -ENODEV;
- goto done;
- }
-
- if (colon)
- *colon = ':';
-
- if ((in_dev=__in_dev_get(dev)) != NULL) { //查找對應的設備名
- for (ifap=&in_dev->ifa_list; (ifa=*ifap) != NULL; ifap=&ifa->ifa_next)
- if (strcmp(ifr.ifr_name, ifa->ifa_label) == 0)
- break;
- }
-
- if (ifa == NULL && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS) {
- ret = -EADDRNOTAVAIL;
- goto done;
- }
-
- switch(cmd) { //在對應的設備上進行操作
- case SIOCGIFADDR: /* Get interface address */ //獲取IP
- 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;
-
- case SIOCSIFFLAGS:
- if (colon) {
- if (ifa == NULL) {
- ret = -EADDRNOTAVAIL;
- break;
- }
- 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) */
- if (inet_abc_len(sin->sin_addr.s_addr) < 0) {
- ret = -EINVAL;
- break;
- }
-
- if (!ifa) {
- if ((ifa = inet_alloc_ifa()) == NULL) {
- ret = -ENOBUFS;
- break;
- }
- 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_anycast = 0;
- }
-
- ifa->ifa_address =
- ifa->ifa_local = sin->sin_addr.s_addr; //設置IP
-
- 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);
- }
- ret = inet_set_ifa(dev, ifa);
- break;
-
- case SIOCSIFBRDADDR: /* Set the broadcast address */
- 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 */
- if (ifa->ifa_address != sin->sin_addr.s_addr) {
- if (inet_abc_len(sin->sin_addr.s_addr) < 0) {
- ret = -EINVAL;
- break;
- }
- 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.
- */
- if (bad_mask(sin->sin_addr.s_addr, 0)) {
- ret = -EINVAL;
- break;
- }
-
- if (ifa->ifa_mask != sin->sin_addr.s_addr) {
- inet_del_ifa(in_dev, ifap, 0);
- ifa->ifa_mask = sin->sin_addr.s_addr;
- ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
- inet_insert_ifa(ifa);
- }
- break;
- }
- done:
- rtnl_unlock();
- dev_probe_unlock();
- return ret;
-
- rarok:
- rtnl_unlock();
- dev_probe_unlock();
- if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
- return -EFAULT;
- return 0;
- }
相关热门文章
给主人留下些什么吧!~~
评论热议