内核网卡参数设置:devinet_ioctl()

4180阅读 0评论2013-08-17 slp195
分类:LINUX

devinet_ioctl() 根据用户空间提供的ifreq参数和cmd操作对网卡进行设置或参数的获取
cmd:大体分为两种,即set和get
p.s. 有意思的是,用户空间的ifreq指针指向的参数需要拷贝到内存空间中,让后函数才能对参数进行解读和分析。
        copy_from_user(&ifr, arg, sizeof(struct ifreq)

点击(此处)折叠或打开

  1. struct ifreq {
  2.     char ifr_name[IFNAMSIZ];
  3.     union
  4.     {
  5.         struct sockaddr ifru_addr;
  6.         struct sockaddr ifru_dstaddr;
  7.         struct sockaddr ifru_broadaddr;
  8.         struct sockaddr ifru_netmask;
  9.         struct sockaddr ifru_hwaddr;
  10.         short int ifru_flags;
  11.         int ifru_ivalue;
  12.         int ifru_mtu;
  13.         struct ifmap ifru_map;
  14.         char ifru_slave[IFNAMSIZ]; /* Just fits the size */
  15.         char ifru_newname[IFNAMSIZ];
  16.         __caddr_t ifru_data;
  17.     } ifr_ifru;
  18. };

  19. int devinet_ioctl(unsigned int cmd, void *arg)
  20. {
  21.     struct ifreq ifr;
  22.     struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
  23.     struct in_device *in_dev;
  24.     struct in_ifaddr **ifap = NULL;
  25.     struct in_ifaddr *ifa = NULL;
  26.     struct net_device *dev;
  27.     char *colon;
  28.     int ret = 0;

  29.     /*
  30.      *    Fetch the caller's info block into kernel space
  31.      */

  32.     if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
  33.         return -EFAULT;
  34.     ifr.ifr_name[IFNAMSIZ-1] = 0;

  35.     colon = strchr(ifr.ifr_name, ':');
  36.     if (colon)
  37.         *colon = 0;

  38. #ifdef CONFIG_KMOD
  39.     dev_load(ifr.ifr_name);
  40. #endif

  41.     switch(cmd) {        //根據cmd對參數進行檢查
  42.     case SIOCGIFADDR:    /* Get interface address */
  43.     case SIOCGIFBRDADDR:    /* Get the broadcast address */
  44.     case SIOCGIFDSTADDR:    /* Get the destination address */
  45.     case SIOCGIFNETMASK:    /* Get the netmask for the interface */
  46.         /* Note that this ioctls will not sleep,
  47.          so that we do not impose a lock.
  48.          One day we will be forced to put shlock here (I mean SMP)
  49.          */
  50.         memset(sin, 0, sizeof(*sin));
  51.         sin->sin_family = AF_INET;
  52.         break;

  53.     case SIOCSIFFLAGS:
  54.         if (!capable(CAP_NET_ADMIN))
  55.             return -EACCES;
  56.         break;
  57.     case SIOCSIFADDR:    /* Set interface address (and family) */
  58.     case SIOCSIFBRDADDR:    /* Set the broadcast address */
  59.     case SIOCSIFDSTADDR:    /* Set the destination address */
  60.     case SIOCSIFNETMASK:     /* Set the netmask for the interface */
  61.         if (!capable(CAP_NET_ADMIN))
  62.             return -EACCES;
  63.         if (sin->sin_family != AF_INET)
  64.             return -EINVAL;
  65.         break;
  66.     default:
  67.         return -EINVAL;
  68.     }
  69.     //
  70.     dev_probe_lock();
  71.     rtnl_lock();
  72.     //獲取設備名對應的設備的數據結構(描述一個設備)
  73.     if ((dev = __dev_get_by_name(ifr.ifr_name)) == NULL) {
  74.         ret = -ENODEV;
  75.         goto done;
  76.     }

  77.     if (colon)
  78.         *colon = ':';

  79.     if ((in_dev=__in_dev_get(dev)) != NULL) {                //查找對應的設備名
  80.         for (ifap=&in_dev->ifa_list; (ifa=*ifap) != NULL; ifap=&ifa->ifa_next)
  81.             if (strcmp(ifr.ifr_name, ifa->ifa_label) == 0)
  82.                 break;
  83.     }

  84.     if (ifa == NULL && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS) {
  85.         ret = -EADDRNOTAVAIL;
  86.         goto done;
  87.     }

  88.     switch(cmd) {                                            //在對應的設備上進行操作
  89.         case SIOCGIFADDR:    /* Get interface address */        //獲取IP
  90.             sin->sin_addr.s_addr = ifa->ifa_local;
  91.             goto rarok;

  92.         case SIOCGIFBRDADDR:    /* Get the broadcast address */
  93.             sin->sin_addr.s_addr = ifa->ifa_broadcast;
  94.             goto rarok;

  95.         case SIOCGIFDSTADDR:    /* Get the destination address */
  96.             sin->sin_addr.s_addr = ifa->ifa_address;
  97.             goto rarok;

  98.         case SIOCGIFNETMASK:    /* Get the netmask for the interface */
  99.             sin->sin_addr.s_addr = ifa->ifa_mask;
  100.             goto rarok;

  101.         case SIOCSIFFLAGS:
  102.             if (colon) {
  103.                 if (ifa == NULL) {
  104.                     ret = -EADDRNOTAVAIL;
  105.                     break;
  106.                 }
  107.                 if (!(ifr.ifr_flags&IFF_UP))
  108.                     inet_del_ifa(in_dev, ifap, 1);
  109.                 break;
  110.             }
  111.             ret = dev_change_flags(dev, ifr.ifr_flags);
  112.             break;
  113.     
  114.         case SIOCSIFADDR:    /* Set interface address (and family) */
  115.             if (inet_abc_len(sin->sin_addr.s_addr) < 0) {
  116.                 ret = -EINVAL;
  117.                 break;
  118.             }

  119.             if (!ifa) {
  120.                 if ((ifa = inet_alloc_ifa()) == NULL) {
  121.                     ret = -ENOBUFS;
  122.                     break;
  123.                 }
  124.                 if (colon)
  125.                     memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
  126.                 else
  127.                     memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
  128.             } else {
  129.                 ret = 0;
  130.                 if (ifa->ifa_local == sin->sin_addr.s_addr)
  131.                     break;
  132.                 inet_del_ifa(in_dev, ifap, 0);
  133.                 ifa->ifa_broadcast = 0;
  134.                 ifa->ifa_anycast = 0;
  135.             }

  136.             ifa->ifa_address =
  137.             ifa->ifa_local = sin->sin_addr.s_addr;            //設置IP

  138.             if (!(dev->flags&IFF_POINTOPOINT)) {
  139.                 ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
  140.                 ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
  141.                 if ((dev->flags&IFF_BROADCAST) && ifa->ifa_prefixlen < 31)
  142.                     ifa->ifa_broadcast = ifa->ifa_address|~ifa->ifa_mask;
  143.             } else {
  144.                 ifa->ifa_prefixlen = 32;
  145.                 ifa->ifa_mask = inet_make_mask(32);
  146.             }
  147.             ret = inet_set_ifa(dev, ifa);
  148.             break;

  149.         case SIOCSIFBRDADDR:    /* Set the broadcast address */
  150.             if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
  151.                 inet_del_ifa(in_dev, ifap, 0);
  152.                 ifa->ifa_broadcast = sin->sin_addr.s_addr;
  153.                 inet_insert_ifa(ifa);
  154.             }
  155.             break;
  156.     
  157.         case SIOCSIFDSTADDR:    /* Set the destination address */
  158.             if (ifa->ifa_address != sin->sin_addr.s_addr) {
  159.                 if (inet_abc_len(sin->sin_addr.s_addr) < 0) {
  160.                     ret = -EINVAL;
  161.                     break;
  162.                 }
  163.                 inet_del_ifa(in_dev, ifap, 0);
  164.                 ifa->ifa_address = sin->sin_addr.s_addr;
  165.                 inet_insert_ifa(ifa);
  166.             }
  167.             break;

  168.         case SIOCSIFNETMASK:     /* Set the netmask for the interface */

  169.             /*
  170.              *    The mask we set must be legal.
  171.              */
  172.             if (bad_mask(sin->sin_addr.s_addr, 0)) {
  173.                 ret = -EINVAL;
  174.                 break;
  175.             }

  176.             if (ifa->ifa_mask != sin->sin_addr.s_addr) {
  177.                 inet_del_ifa(in_dev, ifap, 0);
  178.                 ifa->ifa_mask = sin->sin_addr.s_addr;
  179.                 ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
  180.                 inet_insert_ifa(ifa);
  181.             }
  182.             break;
  183.     }
  184. done:
  185.     rtnl_unlock();
  186.     dev_probe_unlock();
  187.     return ret;

  188. rarok:
  189.     rtnl_unlock();
  190.     dev_probe_unlock();
  191.     if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
  192.         return -EFAULT;
  193.     return 0;
  194. }



上一篇:Hadoop在数据分析的几个例子
下一篇:linux内核中,tcp连接三次握手过程中的,tcp协议栈中的函数调用关系