netlink的使用方法
skb = alloc_skb(size, GFP_ATOMIC); /*分配一个新的套接字缓存*/
old_tail = skb->tail;
nlh = NLMSG_PUT(skb, 0, 0, IMP2_K_MSG, size-sizeof(*nlh)); /*初始化一个netlink 消息首部*/ packet = NLMSG_DATA(nlh); /*跳过消息首部,指向数据区*/
memset(packet, 0, sizeof(struct packet_info)); /*初始化数据区*/
packet->src = info->src; /*填充待发送的数据*/
packet->dest = info->dest;
nlh->nlmsg_len = skb->tail - old_tail; /*计算skb 两次长度之差,即netlink 的长度总和*/
NETLINK_CB(skb).dst_groups = 0; /*设置控制字段*/
read_lock_bh(&user_proc.lock); /*发送数据*/
ret = netlink_unicast(nlfd, skb, user_proc.pid, MSG_DONTWAIT);
read_unlock_bh(&user_proc.lock);
}
函数初始化netlink 消息首部,填充数据区,然后设置控制字段,这三部份都包含在skb_buff中,最后调用netlink_unicast 函数把数据发送出去。
函数中调用了netlink 的一个重要的宏NLMSG_PUT,它用于初始化netlink 消息首部:
#define NLMSG_PUT(skb, pid, seq, type, len) \
({ if (skb_tailroom(skb) < (int)NLMSG_SPACE(len)) goto nlmsg_failure; \
__nlmsg_put(skb, pid, seq, type, len); })
static __inline__ struct nlmsghdr *
__nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len)
{
struct nlmsghdr *nlh;
int size = NLMSG_LENGTH(len);
nlh = (struct nlmsghdr*)skb_put(skb, NLMSG_ALIGN(size));
nlh->nlmsg_type = type;
nlh->nlmsg_len = size;
nlh->nlmsg_flags = 0;
nlh->nlmsg_pid = pid;
nlh->nlmsg_seq = seq;
return nlh;
}
这个宏一个需要注意的地方是调用了nlmsg_failure 标签,所以在程序中应该定义这个标签。在内核中使用函数sock_release 来释放函数netlink_kernel_create()创建的netlink socket:
void sock_release(struct socket * sock);
程序在退出模块中释放netlink sockets 和netfilter hook:
static void __exit fini(void)
{
if(nlfd)
{
sock_release(nlfd->socket); /*释放netlink socket*/
}
nf_unregister_hook(&imp2_ops); /*撤锁netfilter 钩子*/}
}