linux icotl函数解析

来源:互联网 发布:詹姆斯2016为止总数据 编辑:程序博客网 时间:2024/05/16 16:18

ioctl函数:

       网络程序(一般是服务器程序)中ioctl常用于在程序启动时获得主机上所有接口的信息: 接口的地址、接口是否支持广播、是否支持多播等等。

#include <unistd.h>   or #include <sys/ioctl.h>

int ioctl(int fd, int request, …/*void *arg */);

       返回:成功返回0,出错返回-1

   

下表列出了网络相关ioctl 请求的request 参数以及arg 地址必须指向的数据类型:

 

类别

Request

说明

数据类型

SIOCATMARK

SIOCSPGRP

SIOCGPGRP

是否位于带外标记

设置套接口的进程ID 或进程组ID

获取套接口的进程ID 或进程组ID

int

int

int

 

 

 

 

FIONBIN

FIOASYNC

FIONREAD

FIOSETOWN

FIOGETOWN

 

设置/ 清除非阻塞I/O 标志

设置/ 清除信号驱动异步I/O 标志

获取接收缓存区中的字节数

设置文件的进程ID 或进程组ID

获取文件的进程ID 或进程组ID

int

int

int

int

int

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SIOCGIFCONF

SIOCSIFADDR

SIOCGIFADDR

SIOCSIFFLAGS

SIOCGIFFLAGS

SIOCSIFDSTADDR

SIOCGIFDSTADDR

SIOCGIFBRDADDR

SIOCSIFBRDADDR

SIOCGIFNETMASK

SIOCSIFNETMASK

SIOCGIFMETRIC

SIOCSIFMETRIC

SIOCGIFMTU

SIOCxxx

获取所有接口的清单

设置接口地址

获取接口地址

设置接口标志

获取接口标志

设置点到点地址

获取点到点地址

获取广播地址

设置广播地址

获取子网掩码

设置子网掩码

获取接口的测度

设置接口的测度

获取接口MTU

(还有很多取决于系统的实现)

struct ifconf

struct ifreq

struct ifreq

struct ifreq

struct ifreq

struct ifreq

struct ifreq

struct ifreq

struct ifreq

struct ifreq

struct ifreq

struct ifreq

struct ifreq

struct ifreq

 

ARP

SIOCSARP

SIOCGARP

SIOCDARP

创建/ 修改ARP 表项

获取ARP 表项

删除ARP 表项

struct arpreq

struct arpreq

struct arpreq

SIOCADDRT

SIOCDELRT

增加路径

删除路径

struct rtentry

struct rtentry

I_xxx

 

 

 

为这个调用拥有与网络相关的代码,所以文件描述符号fd就是socket()系统调用所返回的,command参数可以是/usr/include/linux/sockios.h头文件中的任何一个,这些个命令根据它可以解决的问题所涉及的方面被分为多种的类型.

  改变路由表(SIOCADDRT, SIOCDELRT)  

  读取或更新ARP/RARP缓存(SIOCDARP, SIOCSRARP

  一般的和网络有关的函数(SIOCGIFNAME, SIOCSIFADDR等等)

 

Goodies目录中包含了很多展示ioctl用法的示例程序,看这些程序的时候,注意根据ioctl的命令类型来使用具体的调用参数结构,比如:和路由表相关的IOCTLRTENTRY结构,rtentry结构是被定义在/usr/include/linux/route.h文件中的,和ARP相关的ioctl调用到的arpreq结构被定义在/usr/include/linux/if_arp.h文件之中。网络接口相关的ioctl命令最具有代表性的特征的是都以SG开头,其实就是设置或得到数据,getifinfo.c程序用这些命令去读取IP地址信息,硬件地址信息,广播地址信息和与网络接口相关的标志。对于这些ioctl,第三个参数是一个ifreq结构体,这个结构体被定义在/usr/include/linux/if.h头文件中。

       根据常规约定,一个用户程序调用一个特定的ioctl命令如下:

ioctl(sockid, SIOCDEVPRIVATE, (char *) &ifr);

这里ifr是一个ifreq结构体变量,它用一个和这个设备联系的接口名称来填充ifrifr NAME域,比如前述的无线网卡接口名称为eth1

       ifreq结构体:

/* Interface request structure used for socket ioctl's.  All interface
 ioctl's must have parameter definitions which begin with ifr_name.
 The remainder may be interface specific.  */

struct ifreq
 {
# define IFHWADDRLEN 6
# define IFNAMSIZ IF_NAMESIZE
   union
     {
char ifrn_name[IFNAMSIZ]; /* Interface name, e.g. "en0".  */
     } ifr_ifrn;

   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;
 };
# define ifr_name ifr_ifrn.ifrn_name /* interface name */
# define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */
# define ifr_addr ifr_ifru.ifru_addr /* address */
# define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */
# define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */
# define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */
# define ifr_flags ifr_ifru.ifru_flags /* flags */
# define ifr_metric ifr_ifru.ifru_ivalue /* metric */
# define ifr_mtu ifr_ifru.ifru_mtu /* mtu */
# define ifr_map ifr_ifru.ifru_map /* device map */
# define ifr_slave ifr_ifru.ifru_slave /* slave device */
# define ifr_data ifr_ifru.ifru_data /* for use by interface */
# define ifr_ifindex ifr_ifru.ifru_ivalue    /* interface index      */
# define ifr_bandwidth ifr_ifru.ifru_ivalue /* link bandwidth */
# define ifr_qlen ifr_ifru.ifru_ivalue /* queue length */
# define ifr_newname ifr_ifru.ifru_newname /* New name */
# define _IOT_ifreq _IOT(_IOTS(char),IFNAMSIZ,_IOTS(char),16,0,0)
# define _IOT_ifreq_short _IOT(_IOTS(char),IFNAMSIZ,_IOTS(short),1,0,0)
# define _IOT_ifreq_int _IOT(_IOTS(char),IFNAMSIZ,_IOTS(int),1,0,0)

 

******************************************************************************************************************************************

linux系统ioctl使用示例
These were writed and collected by kf701,
you can use and modify them but NO WARRANTY.
Contact with me : kf_701@21cn.com
程序1:检测接口的inet_addr, netmask, broad_addr
程序2:检查接口的物理连接是否正常
程序3:测试物理连接
程序4:调节音量

***************************程序1****************************************
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <net/if.h>

static void usage()
{
   printf("usage : ipconfig interface /n");
   exit(0);
}

int main(int argc,char **argv)
{
   struct sockaddr_in *addr;
   struct ifreq ifr;
   char *name,*address;
   int sockfd;

   if(argc != 2)  usage();
    else  name = argv[1];

   sockfd = socket(AF_INET,SOCK_DGRAM,0);
   strncpy(ifr.ifr_name,name,IFNAMSIZ-1);

   if(ioctl(sockfd,SIOCGIFADDR,&ifr) == -1)
      perror("ioctl error"),exit(1);

   addr = (struct sockaddr_in *)&(ifr.ifr_addr);
   address = inet_ntoa(addr->sin_addr);
   printf("inet addr: %s ",address);

   if(ioctl(sockfd,SIOCGIFBRDADDR,&ifr) == -1)
      perror("ioctl error"),exit(1);

   addr = (struct sockaddr_in *)&ifr.ifr_broadaddr;
   address = inet_ntoa(addr->sin_addr);
   printf("broad addr: %s ",address);

   if(ioctl(sockfd,SIOCGIFNETMASK,&ifr) == -1)
      perror("ioctl error"),exit(1);
   addr = (struct sockaddr_in *)&ifr.ifr_addr;
   address = inet_ntoa(addr->sin_addr);
   printf("inet mask: %s ",address);

   printf("/n");
   exit(0);
}

******************************** 程序2*****************************************************
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <stdlib.h>
#include <unistd.h>
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned char u8;
#include <linux/ethtool.h>
#include <linux/sockios.h>

int detect_mii(int skfd, char *ifname)
{
   struct ifreq ifr;
   u16 *data, mii_val;
   unsigned phy_id;

   /* Get the vitals from the interface. */
   strncpy(ifr.ifr_name, ifname, IFNAMSIZ);

   if (ioctl(skfd, SIOCGMIIPHY, &ifr) < 0)
      {
         fprintf(stderr, "SIOCGMIIPHY on %s failed: %s/n", ifname, strerror(errno));
         (void) close(skfd);
         return 2;
      }

   data = (u16 *)(&ifr.ifr_data);
   phy_id = data[0];
   data[1] = 1;

   if (ioctl(skfd, SIOCGMIIREG, &ifr) < 0)
     {
        fprintf(stderr, "SIOCGMIIREG on %s failed: %s/n", ifr.ifr_name, strerror(errno));
        return 2;
     }

   mii_val = data[3];
   return(((mii_val & 0x0016) == 0x0004) ? 0 : 1);
}

int detect_ethtool(int skfd, char *ifname)
{
   struct ifreq ifr;
   struct ethtool_value edata;
   memset(&ifr, 0, sizeof(ifr));
   edata.cmd = ETHTOOL_GLINK;

   strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)-1);
   ifr.ifr_data = (char *) &edata;

   if (ioctl(skfd, SIOCETHTOOL, &ifr) == -1)
     {
        printf("ETHTOOL_GLINK failed: %s/n", strerror(errno));
        return 2;
     }

   return (edata.data ? 0 : 1);
}

int main(int argc, char **argv)
{
   int skfd = -1;
   char *ifname;
   int retval;

   if( argv[1] )  ifname = argv[1];
     else  ifname = "eth0";

   /* Open a socket. */
   if (( skfd = socket( AF_INET, SOCK_DGRAM, 0 ) ) < 0 )
      {
         printf("socket error/n");
         exit(-1);
      }

   retval = detect_ethtool(skfd, ifname);
   if (retval == 2)
     retval = detect_mii(skfd, ifname);

   close(skfd);
 
   if (retval == 2)
     printf("Could not determine status/n");
   if (retval == 1)
     printf("Link down/n");
   if (retval == 0)
     printf("Link up/n");

   return retval;
}

*******************************程序3*****************************************************
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <net/if.h>
#include <linux/sockios.h>
#include <sys/ioctl.h>

#define LINKTEST_GLINK 0x0000000a

struct linktest_value {
        unsigned int    cmd;
        unsigned int    data;
};

static void usage(const char * pname)
{
   fprintf(stderr, "usage: %s <device>/n", pname);
   fprintf(stderr, "returns: /n");
   fprintf(stderr, "/t 0: link detected/n");
   fprintf(stderr, "/t%d: %s/n", ENODEV, strerror(ENODEV));
   fprintf(stderr, "/t%d: %s/n", ENONET, strerror(ENONET));
   fprintf(stderr, "/t%d: %s/n", EOPNOTSUPP, strerror(EOPNOTSUPP));
   exit(EXIT_FAILURE);
}

static int linktest(const char * devname)
{
   struct ifreq ifr;
   struct linktest_value edata;
   int fd;

   /* setup our control structures. */
   memset(&ifr, 0, sizeof(ifr));
   strcpy(ifr.ifr_name, devname);

   /* open control socket. */
   fd=socket(AF_INET, SOCK_DGRAM, 0);
   if(fd < 0 )
     return -ECOMM;

   errno=0;
   edata.cmd = LINKTEST_GLINK;
   ifr.ifr_data = (caddr_t)&edata;

   if(!ioctl(fd, SIOCETHTOOL, &ifr))
      {
        if(edata.data)
          {
            fprintf(stdout, "link detected on %s/n", devname);
            return 0;
          } else
             {
               errno=ENONET;
              }
     }

   perror("linktest");
   return errno;
}

int main(int argc, char *argv[])
{
   if(argc != 2)
      {
         usage(argv[0]);
      }
   return linktest(argv[1]);
}