netlink的使用方法
内核空间
与应用程序内核,内核空间也主要完成三件工作:
n 创建netlink 套接字
n 接收处理用户空间发送的数据
n 发送数据至用户空间
API 函数netlink_kernel_create 用于创建一个netlink socket,同时,注册一个回调函数,用于接收处理用户空间的消息:
struct sock * netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len));
参数unit 表示netlink 协议类型,如NL_IMP2,参数input 则为内核模块定义的netlink 消息处理函数,当有消息到达这个netlink socket 时,该input 函数指针就会被引用。函数指针input 的参数sk 实际上就是函数netlink_kernel_create 返回的struct sock 指针,sock 实际是socket 的一个内核表示数据结构,用户态应用创建的socket 在内核中也会有一个struct sock 结构来表示。
static int __init init(void)
{
rwlock_init(&user_proc.lock); /*初始化读写锁*/
/*创建一个netlink socket,协议类型是自定义的ML_IMP2,kernel_reveive 为接受处理函数*/ nlfd = netlink_kernel_create(NL_IMP2, kernel_receive);
if(!nlfd) /*创建失败*/
{
printk("can not create a netlink socket\n");
return -1;
}
return nf_register_hook(&imp2_ops); /*注册一个Netfilter 钩子*/
}
module_init(init);
用户空间向内核发送了两种自定义消息类型:IMP2_U_PID 和IMP2_CLOSE,分别是请求和关闭。kernel_receive 函数分别处理这两种消息:
DECLARE_MUTEX(receive_sem); /*初始化信号量*/
static void kernel_receive(struct sock *sk, int len)
{
do
{
struct sk_buff *skb;
if(down_trylock(&receive_sem)) /*获取信号量*/
return;
/*从接收队列中取得skb,然后进行一些基本的长度的合法性校验*/
while((skb = skb_dequeue(&sk->receive_queue)) != NULL)
{
{
struct nlmsghdr *nlh = NULL;
if(skb->len >= sizeof(struct nlmsghdr))
{/*获取数据中的nlmsghdr 结构的报头*/
nlh = (struct nlmsghdr *)skb->data;
if((nlh->nlmsg_len >= sizeof(struct nlmsghdr))&& (skb->len >= nlh->nlmsg_len))
{ /*长度的全法性校验完成后,处理应用程序自定义消息类型,主要是对用户PID
的保存,即为内核保存“把消息发送给谁”*/
if(nlh->nlmsg_type == IMP2_U_PID) /*请求*/
{
write_lock_bh(&user_proc.pid);