《linux内核的ioctl函数学习》由会员分享,可在线阅读,更多相关《linux内核的ioctl函数学习(18页珍藏版)》请在金锄头文库上搜索。
1、本函数影响由fd参数引用的一个打开的文件。#include#includeint ioctl( int fd, int request, ./* void *arg */ );返回0:成功 -1:出错第三个参数总是一个指针,但指针的类型依赖于request参数。我们可以把和网络相关的请求划分为6类:套接口操作文件操作接口操作ARP高速缓存操作路由表操作流系统下表列出了网络相关ioctl请求的request参数以及arg地址必须指向的数据类型:类别 Request 说明 数据类型套接口SIOCATMARKSIOCSPGRPSIOCGPGRP是否位于带外标记设置套接口的进程ID或进程组ID获取套接
2、口的进程ID或进程组IDintintint文 件 FIONBINFIOASYNCFIONREADFIOSETOWNFIOGETOWN 设置/清除非阻塞I/O标志设置/清除信号驱动异步I/O标志获取接收缓存区中的字节数设置文件的进程ID或进程组ID获取文件的进intintintintint程ID或进程组ID接口 SIOCGIFCONFSIOCSIFADDRSIOCGIFADDRSIOCSIFFLAGSSIOCGIFFLAGSSIOCSIFDSTADDRSIOCGIFDSTADDRSIOCGIFBRDADDRSIOCSIFBRDADDRSIOCGIFNETMASKSIOCSIFNETMASKSIO
3、CGIFMETRICSIOCSIFMETRICSIOCGIFMTUSIOCxxx获取所有接口的清单设置接口地址获取接口地址设置接口标志获取接口标志设置点到点地址获取点到点地址获取广播地址设置广播地址获取子网掩码设置子网掩码获取接口的测度设置接口的测度获取接口MTU(还有很多取决于系统的实现)struct ifconfstruct ifreqstruct ifreqstruct ifreqstruct ifreqstruct ifreqstruct ifreqstruct ifreqstruct ifreqstruct ifreqstruct ifreqstruct ifreqstruct if
4、reqstruct ifreqARP SIOCSARPSIOCGARPSIOCDARP 创建/修改ARP表项获取ARP表项删除ARP表项struct arpreqstruct arpreqstruct arpreq路由 SIOCADDRTSIOCDELRT 增加路径删除路径 struct rtentrystruct rtentry流 I_xxx 套接口操作:明确用于套接口操作的ioctl请求有三个,它们都要求ioctl的第三个参数是指向某个整数的一个指针。SIOCATMARK: 如果本套接口的的度指针当前位于带外标记,那就通过由第三个参数指向的整数返回一个非0值;否则返回一个0值。POSIX以
5、函数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的
6、第三个参数指向一个0或非0值分别清除或设置本套接口的非阻塞标志。本请求和O_NONBLOCK文件状态标志等效,而该标志通过fcntl的F_SETFL命令清除或设置。FIOASYNC: 根据iocl的第三个参数指向一个0值或非0值分别清除或设置针对本套接口的信号驱动异步I/O标志,它决定是否收取针对本套接口的异步I/O信号(SIGIO) 。本请求和O_ASYNC文件状态标志等效,而该标志可以通过fcntl的F_SETFL命令清除或 设置。FIONREAD: 通过由ioctl的第三个参数指向的整数返回当前在本套接口接收 缓冲区中的字节数。本特性同样适用于文件,管道和终端。FIOSETOWN: 对于
7、套接口和SIOCSPGRP等效。FIOGETOWN: 对于套接口和SIOCGPGRP等效。接口配置:得到系统中所有接口由SIOCGIFCONF请求完成,该请求使用ifconf结构,ifconf 又使用ifreq结构,如下所示:Struct ifconfint ifc_len; / 缓冲区的大小unioncaddr_t ifcu_buf; / input from user-kernelstruct ifreq *ifcu_req; / return of structures returned ifc_ifcu;#define ifc_buf ifc_ifcu.ifcu_buf /buffer
8、 address#define ifc_req ifc_ifcu.ifcu_req /array of structures returned#define IFNAMSIZ 16struct ifreqchar ifr_nameIFNAMSIZ; / interface name, e.g., “le0”unionstruct sockaddr ifru_addr;struct sockaddr ifru_dstaddr;struct sockaddr ifru_broadaddr;short ifru_flags;int ifru_metric;caddr_t ifru_data;ifr_
9、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_ifr
10、u.ifru_data / for use by interface再调用ioctl前我们必须先分撇一个缓冲区和一个ifconf结构,然后才初始化后者。如下图展示了一个ifconf结构的初始化结构,其中缓冲区的大小为1024,ioctl的第三个参数指向这样一个ifconf结构。ifc_lenIfc_buf1024-缓存假设内核返回2个ifreq结构,ioctl 返回时通过同一个ifconf结构缓冲区填入了那2个ifreq结构,ifconf结构的ifc_len 成员 也被更新,以反映存放在 缓冲区中的信息量一般来讲ioctl在用户程序中的调用是:ioctl(int fd,int command,
11、 (char*)argstruct)ioctl调用与网络编程有关(本文只讨论这一点) ,文件描述符fd实际上是由socket()系统调用返回的。参数command的取值由/usr/include/linux/sockios.h所规定。这些command的由于功能的不同,可分为以下几个小类: 改 变路由表 (例如 SIOCADDRT, SIOCDELRT), 读 /更新 ARP/RARP 缓存(如:SIOCDARP, SIOCSRARP), 一般的与网络 接口有关的( 例如 SIOCGIFNAME, SIOCSIFADDR 等等) 在Gooodies 目录下有很多样例程序展示了如何使用ioctl
12、。当你看这些程序时,注意参数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) 。在
13、getifinfo.c程序中就使用了这种形式的command参数来读 IP地址,硬件地址,广播地址和得到与网络接口有关的一些标志(flag) 。在 这些ioctl调用中,第三个参数是ifreq 结构,它在 /usr/include/linux/if.h中定 义。在某些情况下, ioctrl调用可能会使用到在sockios.h之外的新的定义,例如,WaveLAN无线网络卡会保存有关无线网络信号强度的信息,这对用户的程序可 能有用。但用户怎么得到这种信息呢?我 们的第一个本能是在sockios.h中定义新的ioctl命令,例如SIOCGIFWVLNSS(它的英文缩写表 示WaveLAN的信号强度)
14、 。但不幸的是,这种命令不是对所有其他的网络接口(例如:loopback环回接口)有意义,而且不应当允许对于 WAVLAN卡以外的网络接口使用ioctl命令。那么,我们需要的是这样一种机制:它能够定义一种与网络接口相关的ioctl命令。幸运的是,在 Linux操作系统中已经为实现这个目的内建了一种挂钩(hook)机制。当你再次看sockios.h文件时,你将发现每一种设备已经预先定义了 SIOCDEVPRIVATE的ioctl命令。而它的实现将留给开发相应驱动程序的人去完成。通常,一个用户程序使用ioctl (sockid,SIOCDEVPRIVATE,(char*)&ifr)来调用与某种设备
15、(指像WaveLAN那样的特殊设备)相关的 ioctl命令,这里ifr是struct ifreq ifr形式的变量。用户程序应当在ifr.ifr_name中填充与这个设备相关的名字,例如,假设WaveLAN使用的接口号为eth1。一般的,一个 用户程序还需要与内核互相交换ioctl的command参数和结果,这可以通过ifr.ifr_data这个变量来实现,例如,想得到WaveLAN中 表示信号强度的信息时,可以通过返回这个变量来实现。Linux 的源代码已经包括了两种设备de4x5和ewrk3,它们定义并且实现了特定的ioctl 调用。这两个设备的源代码在de4x5.h,de4x5.c,ewrk3.h,ewrk3.c中(在 /usr/src/linux/drivers/net/目录中) 。这两种设备都定义了它们特有的结构(struct ewrk3_ioctl 和 struct de4x5_ioctl)来方便用户程序和设备驱动之间交换信息。每次调用ioctl前,用户程序应当在相应的结构变量中设定合适的初值,并且将 ifr.ifr_data指向该值。在 我们进一步讨论ewrk3和de4x5 的代码前,让我们仔细看看ioctl调用是如何一步步地实现的。所有的和接口相关的ioctl请求 (SIOCxIFyyyy 和 SIOCDEVPRIVATE)将会调用dev_ioctl(