一、ioctl函數原型及作用
#include<unistd.h>
int ioctl( int fd, int request, ... );
作用:操作檔案描述符,用于設定硬體裝置的一些配置資訊,比如:序列槽的波特率,AD轉換的精度,音頻裝置的采樣率等
二、我們可以把和網絡相關的請求劃分為六類:
1> 套接口操作
2> 檔案操作
3> 接口操作
4> ARP高速緩存操作
5> 路由表操作
6> 流系統
三、列出了網絡相關ioctl 請求request 參數以及arg 位址必須指向的資料類型:
四:ioctl函數使用
1>套接口操作:
明确用于套接口操作的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 操作。
2>檔案操作
以下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 等效。
3> 接口配置:
得到系統中所有接口由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無線網絡卡會保