ioctl函数
本函数影响由fd参数引用的一个打开的文件。
#include
intioctl( int fd, int request, .../* void *arg */ );
返回0:成功-1:出错
第三个参数总是一个指针,但指针的类型依赖于request参数。
我们可以把和网络相关的请求划分为6类:
套接口操作
文件操作
接口操作
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结构。
ifc_len
Ifc_buf
1024
--------------------->缓存
假设内核返回2个ifreq结构,ioctl返回时通过同一个ifconf结构缓冲区填入了那2个ifreq结构,ifconf结构的ifc_len成员也被更新,以反映存放在缓冲区中的信息量
一般来讲ioctl在用户程序中的调用是:
ioctl(int fd,int command, (char*)argstruct)
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之外的新的定义,例如,WaveLAN无线网络卡会保