本函数影响由
fd
参数引用的一个打开的文件。
#include<unistd.h>
int ioctl( int fd, int request, .../* void *arg */ );
返回
0
:成功
-1
:
出错
第三个参数总是一个指针,但指针的类型依赖于
request
参数。
我们可以把和网络相关的请求划分为
6
类:
套接口操作
文件操作
接口操作
ARP
高速缓存操作
路由表操作
流系统
下表列出了网络相关
ioctl
请求的
request
参
数以及
arg
地址必须指向的数据类型:
类别 |
Request |
说明 |
数据类型 |
套 接 口 |
SIOCATMARK SIOCSPGRP SIOCGPGRP |
是否位于带外标记 设置套接口的进程 获取套接口的进程 |
int int int |
文 件
|
FIONBIN FIOASYNC FIONREAD FIOSETOWN FIOGETOWN
|
设置 设置 获取接收缓存区中的字节数 设置文件的进程 获取文件的进程 |
int int int int int |
接 口
|
SIOCGIFCONF SIOCSIFADDR SIOCGIFADDR SIOCSIFFLAGS SIOCGIFFLAGS SIOCSIFDSTADDR SIOCGIFDSTADDR SIOCGIFBRDADDR SIOCSIFBRDADDR SIOCGIFNETMASK SIOCSIFNETMASK SIOCGIFMETRIC SIOCSIFMETRIC SIOCGIFMTU SIOCxxx |
获取所有接口的清单 设置接口地址 获取接口地址 设置接口标志 获取接口标志 设置点到点地址 获取点到点地址 获取广播地址 设置广播地址 获取子网掩码 设置子网掩码 获取接口的测度 设置接口的测度 获取接口 (还有很多取决于系统的实现) |
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 |
创建 获取 删除 |
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 |
|
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
同样可
以做到。