ioctl 函数html
本函数影响由fd 参数引用的一个打开的文件。linux
#include<unistd.h>ios
int ioctl( int fd, int request, .../* void *arg */ );编程
返回0 :成功 -1 :出错缓存
第三个参数老是一个指针,但指针的类型依赖于request 参数。网络
咱们能够把和网络相关的请求划分为6 类:异步
套接口操做socket
文件操做函数
接口操做测试
ARP 高速缓存操做
路由表操做
流系统
下表列出了网络相关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 |
|
|
套接口操做:
明确用于套接口操做的ioctl 请求有三个, 它们都要求ioctl 的第三个参数是指向某个整数的一个指针。
SIOCATMARK: 若是本套接口的的度指针当前位于带外标记,那就经过由第三个参数指向的整数返回一个非0 值;不然返回一个0 值。POSIX 以函数sockatmark 替换本请求。
SIOCGPGRP : 经过第三个参数指向的整数返回本套接口的进程ID 或进程组ID ,该ID 指定针对本套接口的SIGIO 或SIGURG 信号的接收进程。本请求和fcntl 的F_GETOWN 命令等效,POSIX 标准化的是fcntl 函数。
SIOCSPGRP : 把本套接口的进程ID 或者进程组ID 设置成第三个参数指向的整数,该ID 指定针对本套接口的SIGIO 或SIGURG 信号的接收进程,本请求和fcntl 的F_SETOWN 命令等效,POSIX 标准化的是fcntl 操做。
文件操做:
如下5 个请求都要求ioctl 的第三个参数指向一个整数。
FIONBIO : 根据ioctl 的第三个参数指向一个0 或非0 值分别清除或设置本套接口的非阻塞标志。本请求和O_NONBLOCK 文件状态标志等效,而该标志经过fcntl 的F_SETFL 命令清除或设置。
FIOASYNC : 根据iocl 的第三个参数指向一个0 值或非0 值分别清除或设置针对本套接口的信号驱动异步I/O 标志,它决定是否收取针对本套接口的异步I/O 信号(SIGIO )。本请求和O_ASYNC 文件状态标志等效,而该标志能够经过fcntl 的F_SETFL 命令清除或设置。
FIONREAD : 经过由ioctl 的第三个参数指向的整数返回当前在本套接口接收缓冲区中的字节数。本特性一样适用于文件,管道和终端。
FIOSETOWN : 对于套接口和SIOCSPGRP 等效。
FIOGETOWN : 对于套接口和SIOCGPGRP 等效。
接口配置:
获得系统中全部接口由SIOCGIFCONF 请求完成,该请求使用ifconf 结构,ifconf 又使用ifreq
结构,以下所示:
Struct ifconf{
int ifc_len; // 缓冲区的大小
union{
caddr_t ifcu_buf; // input from user->kernel
struct ifreq *ifcu_req; // return of structures returned
}ifc_ifcu;
};
#define ifc_buf ifc_ifcu.ifcu_buf //buffer address
#define ifc_req ifc_ifcu.ifcu_req //array of structures returned
#define IFNAMSIZ 16
struct ifreq{
char ifr_name[IFNAMSIZ]; // interface name, e.g., “le0”
union{
struct sockaddr ifru_addr;
struct sockaddr ifru_dstaddr;
struct sockaddr ifru_broadaddr;
short ifru_flags;
int ifru_metric;
caddr_t ifru_data;
}ifr_ifru;
};
#define ifr_addr ifr_ifru.ifru_addr // address
#define ifr_dstaddr ifr_ifru.ifru_dstaddr // otner end of p-to-p link
#define ifr_broadaddr ifr_ifru.ifru_broadaddr // broadcast address
#define ifr_flags ifr_ifru.ifru_flags // flags
#define ifr_metric ifr_ifru.ifru_metric // metric
#define ifr_data ifr_ifru.ifru_data // for use by interface
再调用ioctl 前咱们必须先分撇一个缓冲区和一个ifconf 结构,而后才初始化后者。以下图
展现了一个ifconf 结构的初始化结构,其中缓冲区的大小为1024 ,ioctl 的第三个参数指向
这样一个ifconf 结构。
1024
---------------------> 缓存
假设内核返回2 个ifreq 结构,ioctl 返回时经过同一个ifconf 结构缓冲区填入了那2 个ifreq 结构,ifconf 结构的ifc_len 成员也被更新,以反映存放在缓冲区中的信息量
ioctl调用与网络编程有关(本文只讨论这一点),文件描述符fd其实是由socket()系统调用返回的。参数command的取值由/usr/include/linux/sockios.h 所规定。这些command的因为功能的不一样,可分为如下几个小类:
• 改变路由表 (例如 SIOCADDRT, SIOCDELRT),
• 读/更新 ARP/RARP 缓存(如:SIOCDARP, SIOCSRARP),
• 通常的与网络接口有关的(例如 SIOCGIFNAME, SIOCSIFADDR 等等)
在 Gooodies目录下有不少样例程序展现了如何使用ioctl。当你看这些程序时,注意参数argstruct是与参数command相关的。例如,与 路由表相关的ioctl使用rtentry这种结构,rtentry定义在/usr/include/linux/route.h(参见例子 adddefault.c)。与ARP有关的ioctl调用使用arpreq结构,arpreq定义在/usr/include/linux /if_arp.h(参见例子arpread.c)
与网络接口有关的ioctl调用使用的command参数一般看起来像SIOCxIFyyyy的形式,这里x要 么是S(设定set,写write),要么是G(获得get,读read)。在getifinfo.c程序中就使用了这种形式的command参数来读 IP地址,硬件地址,广播地址和获得与网络接口有关的一些标志(flag)。在这些ioctl调用中,第三个参数是ifreq结构,它在/usr /include/linux/if.h中定义。在某些状况下, ioctrl调用可能会使用到在sockios.h以外的新的定义。
实例:
程序1:检测接口的 .net_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]; 内容来自ltesting.net
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, SIOCG
MIIPHY, &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, 领测软件测试网http://www.ltesting.net 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) { ltesting.net 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]); } *************************************程序4********************************************************* #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <sys/soundcard.h> #include <stdio.h> #include <unistd.h> #include <math.h> #include <string.h> #include <stdlib.h> #define BASE_VALUE 257 int main(int argc,char *argv[]) { int mixer_fd=0; char *names[SOUND_MIXER_NRDEVICES]=SOUND_DEVICE_LABELS; int value,i; printf("\nusage:%s dev_no.[0..24] value[0..100]\n\n",argv[0]); printf("eg. %s 0 100\n",argv[0]); printf(" will change the volume to MAX volume.\n\n"); printf("The dev_no. are as below:\n"); for (i=0;i<SOUND_MIXER_NRDEVICES;i++){ if (i%3==0) printf("\n"); printf("%s:%d\t\t",names[i],i); } printf("\n\n"); if (argc<3) exit(1); if ((mixer_fd = open("/dev/mixer",O_RDWR))){ printf("Mixer opened successfully,working...\n"); value=BASE_VALUE*atoi(argv[2]); if (ioctl(mixer_fd,MIXER_WRITE(atoi(argv[1])),&value)==0) printf("successfully....."); else printf("unsuccessfully....."); printf("done.\n"); }else printf("can't open /dev/mixer error....\n"); ltesting.net exit(0); }