netlink 学习笔记 3.8.13内核

网上有很多netlink的教程,但多针对2.6.*的内核,3.8.13内核的netlink API做了很多改动,但总体上差不多

学习netlink除了看别人的教程,感觉要写出个能跑的程序还得自己去读内核代码,就比如netlink_kernel_create这个函数,各版本间有很大不同,如2.6.18和2.6.34都不同,教程上的代码只能作参考

下面主要写一下3.8.13内核相比2.6.*内核在使用netlink上的不同,其他的请参考教程链接。

PS:代码是在虚拟机里写的,不知道怎么拷出来,所以下面的代码是重新手写的,并不完整

PPS:经过这次学习也发现,学内核编程真得在虚拟机里面学,不然时间都花在开关机上面了,另外最好是字符模式,减少开机时间

1. 创建内核sock代码

struct netlink_kernel_cfg cfg = {
    .input = nl_data_ready,//该函数原型可参考内核代码,其他参数默认即可,可参考内核中的调用
};
nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST, &cfg);// init_net是内核定义的变量,貌似是不建议使用的,测试足够了

2. 内核端发送消息

  参考链接里的代码有使用nl_data_ready内接收的skb来发送消息的,测试中发现这个skb不能用来发送(内核直接崩掉),猜测是因为有些变量设置的值不适合发送。

  我曾怀疑过是因为不能使用接收的skb来发送,就重新申请了一个skb,然后将接收的skb拷过来,修改参数(portid)发送,仍然崩溃。

  教程里的代码在nlmsg_put还设置了skb的一些参数,比如pid什么的,3.8.13内核中不需要设置,默认即可

struct sk_buf *skb;
struct nlmsghdr *nlh;
 
// 创建skb
skb = nlmsg_new(MAX_PAYLOAD, GFP_ATOMIC);
if(!skb)
{
    printk(KERN_ERR"FAILED TO ALLOC SKB\n");
    return;    
}
// 看了下内核的代码,下面的函数不是直观上的put到什么列表里,而是针对nlh的做些初始化工作
nlh = nlmsg_put(skb, 0, 0, 0, MAX_PAYLOAD, 0);
memcpy(NLMSG_DATA(nlh), "AA", sizeof("AA"));
<br>// 最后一个参数其实没什么用,因为内核会检测nl_sk是否为内核sock,是的话不会使用该参数
if(netlink_unicast(nl_sk, skb, pid, MSG_DONTWAIT) < 0)
{
    printk(KERN_ERR"FAILED TO send SKB\n");
    return;    
}

3. 释放skb

  发送的skb不需要内核模块去释放,也不能释放,否则会崩溃,因为不能保证netlink_unicast返回不能保证用户层已经接受到消息。内核会处理skb的释放,所以不会出现内存泄露问题


I'm developing a kernel module which send messages to user space via netlink.

To create a message (message to send): skb_out = nlmsg_new(msg_size,0);.

After sending the first message and before sending the second one, I tried to free the skb_out withnlmsg_free(skb_out) but this function cause a kernel crash.

  • How to fix this crash ?

or

  • Are there any other alternative to fre the skb_out after the send of the message?

here after the source code:

 skb_out = nlmsg_new(msg_size,0);
    if(!skb_out)
    {
        printk(KERN_ERR "Failed to allocate new skb\n");
        return;
    }

    nlh=nlmsg_put(skb_out,0,0,NLMSG_DONE,msg_size,0);
    NETLINK_CB(skb_out).dst_group = 0; /* not in mcast group */
    strncpy(nlmsg_data(nlh),msg,msg_size);
    res=nlmsg_unicast(nl_sk,skb_out,pid);
    if(res<0)
    {
        printk(KERN_INFO "Error while sending bak to user\n");
    }

    nlmsg_free(skb_out);

上述代码中关于 nlmsg_unicast函数说明

You're not allowed to free the skb after you've sent it. nlmsg_unicast() will take care of that.

The reason is fairly simple: once you send the message it can be queued in the netlink socket for a while before anyone reads it. Just because nlmsg_unicast() returned it doesn't mean that the other side of the socket already got the message. If you free it before it's received you end up with a freed message in the queue, which causes the crash when the kernel tries to deliver it.

Simply allocate a new skb for every message.

所以上述代码中 nlmsg_free(skb_out);这一行代码注释掉·

你可能感兴趣的:(netlink 学习笔记 3.8.13内核)