Linux中与内核通信的Netlink机制
2014年09月20日 14:37:42 Linux ⁄ 共 5625字 暂无评论 ⁄ 被围观 1,774次

netlink_k.c为内核的空间的程序,netlink_u.c为用户的空间的程序。程序源代码附在后面:

   先运行内核代码netlink_k.ko,也就是在执行完makefile文件后,会生成一个netlink_k.ko文件,可以使用下面的命令进行安装,insmod netlink_k.ko,使用lsmod查看,当安装成功后,然后,执行./netlink用户空间程序,可以在另一个终端下执行dmesg命令,查看内核通信的情况。这里netlink程序向内核空间发送一个hello you!内核返回给一个I am from kernel!在这里使用了一个定时器,也就是每3秒中发送一次I am from kernel!只有内核把10个字符串全部发送完毕后,用户空间的sendmsg()才会返回,也就是在用户空间的netlink才会输出内核空间发送过来的数据,这里只有一个简单的程序,并没有什么实际的意义,因为,正如前面所说的一般情况下不会在回调函数中处理太多的东西,以免sendmsg()函数返回不及时。

 

netlink_k.c:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/timer.h>
#include <linux/time.h>
#include <linux/types.h>
#include <net/sock.h>
#include <net/netlink.h>

#define NETLINK_TEST 25
#define MAX_MSGSIZE 1024
int stringlength(char *s);
void sendnlmsg(char * message);
int pid;
int err;
struct sock *nl_sk = NULL;
int flag = 0;

void sendnlmsg(char *message)
{
   struct sk_buff *skb_1;
   struct nlmsghdr *nlh;
   int len = NLMSG_SPACE(MAX_MSGSIZE);
   int slen = 0;
   if(!message || !nl_sk)
   {
       return ;
   }
   skb_1 = alloc_skb(len,GFP_KERNEL);
   if(!skb_1)
   {
       printk(KERN_ERR "my_net_link:alloc_skb_1 error\n");
   }
   slen = stringlength(message);
   nlh = nlmsg_put(skb_1,0,0,0,MAX_MSGSIZE,0);

   NETLINK_CB(skb_1).pid = 0;
   NETLINK_CB(skb_1).dst_group = 0;

    message[slen]= '\0';
   memcpy(NLMSG_DATA(nlh),message,slen+1);
   printk("my_net_link:send message '%s'.\n",(char *)NLMSG_DATA(nlh));

   netlink_unicast(nl_sk,skb_1,pid,MSG_DONTWAIT);

}

int stringlength(char *s)
{
   int slen = 0;
   for(; *s; s++){
       slen++;
   }

   return slen;
}

void nl_data_ready(struct sk_buff *__skb)
{
    struct sk_buff *skb;
    struct nlmsghdr *nlh;
    char str[100];
   struct completion cmpl;
   int i=10;
    skb = skb_get (__skb);
    if(skb->len >= NLMSG_SPACE(0))
    {
        nlh = nlmsg_hdr(skb);

        memcpy(str, NLMSG_DATA(nlh), sizeof(str));
          printk("Message received:%s\n",str) ;
            pid = nlh->nlmsg_pid;
   while(i--)
   {
       init_completion(&cmpl);
    wait_for_completion_timeout(&cmpl,3 * HZ);
       sendnlmsg("I am from kernel!");
   }
       flag = 1;
        kfree_skb(skb);
   }

}

// Initialize netlink

int netlink_init(void)
{
   nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST, 1,
                                nl_data_ready, NULL, THIS_MODULE);

   if(!nl_sk){
       printk(KERN_ERR "my_net_link: create netlink socket error.\n");
       return 1;
   }

   printk("my_net_link_3: create netlink socket ok.\n");
   return 0;
}

static void netlink_exit(void)
{
   if(nl_sk != NULL){
       sock_release(nl_sk->sk_socket);
   }

   printk("my_net_link: self module exited\n");
}

module_init(netlink_init);
module_exit(netlink_exit);

MODULE_AUTHOR("frankzfz");
MODULE_LICENSE("GPL");

 

netlink_u.c:

#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/socket.h>
#include <errno.h>

#define NETLINK_TEST 25
#define MAX_PAYLOAD 1024 // maximum payload size

int main(int argc, char* argv[])
{
   int state;
   struct sockaddr_nl src_addr, dest_addr;
   struct nlmsghdr *nlh = NULL;
   struct iovec iov;
   struct msghdr msg;
   int sock_fd, retval;
   int state_smg = 0;
   // Create a socket

   sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);
   if(sock_fd == -1){
       printf("error getting socket: %s", strerror(errno));
       return -1;
   }

   // To prepare binding

   memset(&msg,0,sizeof(msg));
   memset(&src_addr, 0, sizeof(src_addr));
   src_addr.nl_family = AF_NETLINK;
   src_addr.nl_pid = getpid(); // self pid

   src_addr.nl_groups = 0; // multi cast
   retval = bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));
   if(retval < 0){
       printf("bind failed: %s", strerror(errno));
       close(sock_fd);
       return -1;
   }

   // To prepare recvmsg

   nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
   if(!nlh){
       printf("malloc nlmsghdr error!\n");
       close(sock_fd);
       return -1;
   }

   memset(&dest_addr,0,sizeof(dest_addr));
   dest_addr.nl_family = AF_NETLINK;
   dest_addr.nl_pid = 0;
   dest_addr.nl_groups = 0;

   nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
   nlh->nlmsg_pid = getpid();
   nlh->nlmsg_flags = 0;
   strcpy(NLMSG_DATA(nlh),"Hello you!");

   iov.iov_base = (void *)nlh;
  iov.iov_len = NLMSG_SPACE(MAX_PAYLOAD);
   // iov.iov_len = nlh->nlmsg_len;

   memset(&msg, 0, sizeof(msg));
 
   msg.msg_name = (void *)&dest_addr;
   msg.msg_namelen = sizeof(dest_addr);
   msg.msg_iov = &iov;
   msg.msg_iovlen = 1;

   printf("state_smg\n");
   state_smg = sendmsg(sock_fd,&msg,0);

   if(state_smg == -1)
   {
       printf("get error sendmsg = %s\n",strerror(errno));
   }

   memset(nlh,0,NLMSG_SPACE(MAX_PAYLOAD));
   printf("waiting received!\n");
   // Read message from kernel

   while(1){
       printf("In while recvmsg\n");
       state = recvmsg(sock_fd, &msg, 0);
       if(state<0)
       {
           printf("state<1");
       }
       printf("In while\n");
       printf("Received message: %s\n",(char *) NLMSG_DATA(nlh));
   }

   close(sock_fd);

   return 0;
}

 

makefile:

obj-m := netlink_k.o
KERNELBUILD := /lib/modules/`uname -r`/build
default:
@echo "BUILE Kmod"
@make -C $(KERNELBUILD) M=$(shell pwd) modules
gcc -o netlink_u netlink_u.c
clean:
@echo " CLEAN kmod"
@rm -rf *.o
@rm -rf .depend .*.cmd *.ko *.mod.c .tmp_versions *.symvers .*.d

 

下面是使用dmesg命令输出的信息:

[873791.498039] my_net_link_3: create netlink socket ok.

[873810.263676] Message received:Hello

[873813.260848] my_net_link_4:send message 'I am from kernel!'.

[873816.260821] my_net_link_4:send message 'I am from kernel!'.

[873819.260860] my_net_link_4:send message 'I am from kernel!'.

[873822.260762] my_net_link_4:send message 'I am from kernel!'.

[873825.260883] my_net_link_4:send message 'I am from kernel!'.

[873828.260669] my_net_link_4:send message 'I am from kernel!'.

[873831.260714] my_net_link_4:send message 'I am from kernel!'.

[873834.260683] my_net_link_4:send message 'I am from kernel!'.

[873837.260666] my_net_link_4:send message 'I am from kernel!'.

[873840.260632] my_net_link_4:send message 'I am from kernel!'.

给我留言

留言无头像?