1. 简介
前篇博文(linux内核编程一:模块的装载和卸载)中我们已经知道了自定义内核模块的装载和卸载。由于linux内核本身非常强大,编写自定义的内核模块往往是为了实现我们独特的功能或需求,这经常涉及到内核态与用户态之间通信。Linux本身提供丰富的系统调用(如ioctl、open)来实现用户态与内核态交互,此文基于getsockopt系统调用,介绍一种简单的用户态与内核态通信方法:增加sockopt命令字。
2. Socket选项
我们知道,系统调用getsockopt/ setsockopt可以操作socket文件描述符(FD)的相关选项,常用的有:
SO_BROADCAST----Set or get 描述符广播标志。Set socket文件描述符SO_BROADCAST可以使FD能发送广播报文;
SO_OOBINLINE ---- 使FD发送的带外数据直接放置在报文中(默认情况下是通过MSG_OOB标识接收到另外一个缓冲区中);
SO_RCVBUF ----- set or get FD的接收缓存区长度,如在卫星通信中,可能需要将缓存区长度扩大已接收超大报文;
其实这些选项就相对于命令字,内核根据命令字对FD的内核结构进行相关操作。内核通过以下数据结构区分不同命令字的不同处理方法,并用全局链表串联起来:
static LIST_HEAD(nf_sockopts);
struct nf_sockopt_ops {
structlist_head list; -------------链表,用于串联不同的命令字
u_int8_tpf; ------------ 协议类型,如PF_INET、PF_INET6等
/*Non-inclusive ranges: use 0/0/NULL to never get called. */
intset_optmin; ------------set操作命令字最小值
intset_optmax; ----------- set操作命令字最大值
int(*set)(struct sock *sk, int optval, void __user *user, unsigned int len); ------set操作回调指针
#ifdef CONFIG_COMPAT
int(*compat_set)(struct sock *sk, int optval,
void__user *user, unsigned int len);
#endif
intget_optmin; ------------g