內核態與用戶態通信 之 sockopt


轉自:http://blog.csdn.net/jk110333/article/details/8642261
 
用戶態與內核態交互通信的方法不止一種,sockopt是比較方便的一個,寫法也簡單.
缺點就是使用 copy_from_user()/copy_to_user()完成內核和用戶的通信, 效率其實不高, 多用在傳遞控制 選項 信息,不適合做大量的數據傳輸
 
用戶態函數:
發送:int setsockopt ( int sockfd, int proto, int cmd, void *data, int datelen);
接收:int getsockopt(int sockfd, int proto, int cmd, void *data, int datalen)
第一個參數是socket描述符;
第二個參數proto是sock協議,IP RAW的就用SOL_SOCKET/SOL_IP等,TCP/UDP socket的可用SOL_SOCKET/SOL_IP/SOL_TCP/SOL_UDP等,即高層的socket是都可以使用低層socket的命令字 的,IPPROTO_IP;
第三個參數cmd是操作命令字,由自己定義;
第四個參數是數據緩沖區起始位置指針,set操作時是將緩沖區數據寫入內核,get的時候是將內核中的數 據讀入該緩沖區;
第五個參數數據長度
 
內核態函數
注冊:nf_register_sockopt(struct nf_sockopt_ops *sockops)
解除:nf_unregister_sockopt(struct nf_sockopt_ops *sockops)
setsockopt():在內核調用kernel_setsockopt函數
 
結構體 nf_sockopt_ops test_sockops

static struct nf_sockopt_ops nso = { 
       .pf  = PF_INET,       // 協議族  
      .set_optmin = 常數,    // 定義最小set命令字  
       .set_optmax = 常數+N,  // 定義最大set命令字 
       .set  = recv_msg,   // 定義set處理函數 
       .get_optmin = 常數,    // 定義最小get命令字 
       .get_optmax = 常數+N,  // 定義最大get命令字 
       .get  = send_msg,   // 定義set處理函數 
};

其中命令字不能和內核已有的重復,宜大不宜小。命令字很重要,是用來做標識符的。而且用戶態和內核態要定義的相同,
    #define SOCKET_OPS_BASE          128 
    #define SOCKET_OPS_SET       (SOCKET_OPS_BASE) 
    #define SOCKET_OPS_GET      (SOCKET_OPS_BASE)  
    #define SOCKET_OPS_MAX       (SOCKET_OPS_BASE + 1)  

set/get處理函數是直接由用戶空間的 set/getsockopt函數調用的。 setsockopt函數向內核寫數據,用getsockopt向內核讀數據。
另外set和get的處理函數的參數應該是這樣的
int recv_msg(struct sock *sk, int cmd, void __user *user, unsigned int len)
int send_msg(struct sock *sk, int cmd, void __user *user, unsigned int *len)
 
附:

int kernel_setsockopt(struct socket *sock, int level, int optname,
char *optval, unsigned int optlen)
{
mm_segment_t oldfs = get_fs();
char __user *uoptval;
int err;

uoptval = (char __user __force *) optval;

set_fs(KERNEL_DS);
if (level == SOL_SOCKET)
err = sock_setsockopt(sock, level, optname, uoptval, optlen);
else
err = sock->ops->setsockopt(sock, level, optname, uoptval,
optlen);
set_fs(oldfs);
return err;
}

如果用戶態level == SOL_SOCKET時,那么直接調用socket層統一的接口:sock_setsockopt,在socket層處理了,就像我之前說的那樣,無論哪種協議,都在一個函數里面處理。
如果level不是SOL_SOCKET(也就是level是SOL_TCP/SOL_UDP,IPPROTO_IP),那么調用各自協議棧初始化時指向的setsockopt函數,11行的:sock->ops->setsockopt,


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM