现在的位置: 首页 > 综合 > 正文

最复杂的函数—-ioctl()

2012年02月12日 ⁄ 综合 ⁄ 共 5395字 ⁄ 字号 评论关闭

本函数影响由
fd
参数引用的一个打开的文件。

 

#include<unistd.h>

int ioctl( 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
成员也被更新,以反映存放在缓冲区中的信息量。


口操作:

SIOCGIFCONF
请求为每个已配置的接口返回其名字以及一个套接口地址结构。我们接着可以发出多个接
口类其他请求以设置或获取每个接口的其他特征。这些请求的获取(

get
)版本(
SIOCGxxx

通常由

netstat
程序发出,设置(
set

版本(

SIGOCSxxx
)通常由
ifconfig

序发出。任何用户都可以获取接口信息,设置接口信息却要求有超级用户权限。

 

这些请求汲取或返回一个一个
ifreq
结构中的信息,而这个结构的地址则作为
ioctl

用的第三个参数制定。接口总是以其名标志,在

ifreq
结构的
ifr_name

员中指定,如

le0

lo0

ppp0
等。

这些请求中有许多使用套接口地址结构在应用进程和内核之间指定或返回具体接口的
IP

址或地址掩码。对于

IPV4
,这个地址或掩码放在一个网际套接口地址结构的
sin_addr

员中;对于

IPV6
,它是一个
IPV6
套接
口地址结构的

sin6_addr
成员。

 

SIOCGIFADDR

 


ifr_addr

员中返回单播地址。

SIOCSIFADDR
:用
ifr_addr
成员设
置接口地址,这个接口的初始化函数也被调用。

 

SIOCGIFFLAGS


ifr_flags
成员中返回接口标志。这些接口标志的名字格式为
IFF_XXX,

<net/if.h>

文件中定义。举例来说,这些标志指示接口是否处于

UP
即在工状态
(IFF_UP),

否为一个点到点接口(

IFF_POINTOPOINT

,

否支持广播(

IFF_BROADCAST

,

等。

SIOCSIFFLAGS


ifr_flags
成员设置接口标志。

SIOCGIFDSTADDR


ifr_dstaddr
成员中返回点到点地址。

SIOCSIFDSTADDR: 



ifr_dstaddr
成员中设置点到点地址

SIOCGIFBRDADDR: 



ifr_broadaddr
成员中返回广播地址。应
用进程必须首先获取接口标志,然后发出正确的请求;对于广播接口为

SIOCGIFBRDADDR

对于点到点接口为

SIOCGIFDSTADDR

SIOCSIFBRDADDR


ifr_broadaddr
成员设置广播地址。

SIOCGIFNETMASK


ifr_addr
成员中返回子网掩码。

SIOCSIFNETMASK


ifr_addr
成员中设置子网掩码。

SIOCGIFMETRIC


ifr_metric
成员返回接口测度。接口测度由内核为每个接口维护,不过使用他的是路由守护
进程

routed
。接口测度被
routed

到跳数上。

SIOCSIFMETRIC


ifr_metric
成员设置接口的路由测度。

 

 

 

ARP


速缓存操作

ARP

诉缓存也通过

ioctl
函数操纵。使用路由域套接口的系统往往改用路由套接口访问

ARP

速缓存。这些请求使用如下的

arpreq
结构,定义在
<net/if_arp.h>

 

struct arpreq {

   
struct
sockaddr     
arp_pa;

   
struct
sockaddr     
arp_ha;

 
  

int                 
arp_flags;

};

 

#define
ATF_INUSE     
0x01  
//entry in use

#define ATF_COM        

0x02  
//completed entry


hardware
addr valid


#define ATF_PERM      

0x04  
// permanent entry

#define ATF_PUBL

0x08  
// published entry (respond for other host )

 

Ioctl

第三个必须指向某个

arpreq
结构,操纵
ARP

速缓存的

ioctl
请求有以下三个:

 

SIOCSARP:          


把一个新的表项加入
ARP
告诉缓存中区,或者修改其中
已经存在的一个表项,其中

arp_pa
是一个含有
IP

址的网际套接口地址结构,

arp_ha
则是一个通用套接口地址结构,他的
sa_family


AF_unspec,sa_data
中含有硬件地址(例如
6

接的以太网地址)。

ATF_PERM

ATF_PUBL

两个标志也可以由应用进程指定。另外两个标志(

ATF_INUSE

ATF_COM

则由内核设置。

SIOCDARP

       



ARP
告诉缓存中删除一个表项。调用者指定要删除表
项的网际地址。

SIOCGARP

       



ARP
高速缓存中获取一个表项。调用者指定网际地
址,相应的硬件地址(例外以太网地址)随标志一起返回。

 

只有超级用户才能增加或删除表项。
这三个请求通常由

arp
程序发出。

注意
ioctl

有办法列出

ARP
高速缓存中的所有表项。当指定
-a

志执行

arp
命令时,大多

数版本的
arp

序通过读取内核的内存

( /dev/kmem )
获得
ARP

速缓存的当前内容。

 

路由
表操作

 

有些系统提供
2

用于操纵路由表的

ioctl
请求。这
2
个请
求要求

ioctl
的第三个参数是指向

某个
rtentry

构的一个指针,该结构定义在

<net/route.h>
头文件中。这些请求通常由
route

程序发出。只有超级用户才能发出这
些请求。

SIOCADDRT

往路由表中增加一个表项

SIOCDELRT

从路由表中删除一个表项

Ioctl

有办法列出路由表中的所有表项。这个操作通常由

netstat
程序在指定
-r

志自行四

完成。
netstat

序通过读取内核的内存

 


/dev/kmem

获得整个路由表。用

sysctl
同样可

以做到。

抱歉!评论已关闭.