Linux2.6.27内核 netlink socket实现内核和用户的通信

snowboy00 2011-07-23

终于搞定了自己需要的这种通信机制:由内核态向用户态反馈信息;

先看代码,内核的:

  1. #include <linux/init.h>      
  2. #include <linux/module.h>      
  3. #include <linux/timer.h>    
  4. #include <linux/time.h>     
  5. #include <linux/types.h>   
  6. #include <net/sock.h>   
  7. #include <net/netlink.h> //it include linux/netlink.h   
  8.   
  9. #define NETLINK_TEST 17   
  10. #define MAX_MSGSIZE 1024   
  11.   
  12. struct sock *nl_sk = NULL;  
  13.   
  14. // Get string's length   
  15. int stringlength(char *s)  
  16. {  
  17.     int slen = 0;  
  18.   
  19.     for(; *s; s++){  
  20.         slen++;  
  21.     }  
  22.   
  23.     return slen;  
  24. }  
  25.   
  26. // Send message by netlink   
  27. void sendnlmsg(char *message)    
  28. {  
  29.     struct sk_buff *skb;  
  30.     struct nlmsghdr *nlh;  
  31.     int len = NLMSG_SPACE(MAX_MSGSIZE);  
  32.     int slen = 0;  
  33.       
  34.     if(!message || !nl_sk){  
  35.         return;  
  36.     }  
  37.   
  38.     // Allocate a new sk_buffer   
  39.     skb = alloc_skb(len, GFP_KERNEL);  
  40.     if(!skb){  
  41.         printk(KERN_ERR "my_net_link: alloc_skb Error./n");  
  42.         return;  
  43.     }  
  44.   
  45.     slen = stringlength(message);  
  46.   
  47.     //Initialize the header of netlink message   
  48.     nlh = nlmsg_put(skb, 0, 0, 0, MAX_MSGSIZE, 0);  
  49.   
  50.     NETLINK_CB(skb).pid = 0; // from kernel   
  51.     NETLINK_CB(skb).dst_group = 1; // multi cast   
  52.   
  53.     message[slen] = '/0';  
  54.     memcpy(NLMSG_DATA(nlh), message, slen+1);  
  55.     printk("my_net_link: send message '%s'./n", (char *)NLMSG_DATA(nlh));  
  56.   
  57.     //send message by multi cast   
  58.     netlink_broadcast(nl_sk, skb, 0, 1, GFP_KERNEL);   
  59.     return;  
  60. }  
  61.   
  62. // Initialize netlink   
  63. int netlink_init(void)  
  64. {  
  65.     int i = 10;  
  66.     struct completion cmpl;  
  67.   
  68.     nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST, 1,   
  69.                                   NULL, NULL, THIS_MODULE);  
  70.   
  71.     if(!nl_sk){  
  72.         printk(KERN_ERR "my_net_link: create netlink socket error./n");  
  73.         return 1;  
  74.     }  
  75.   
  76.     printk("my_net_link: create netlink socket ok./n");  
  77.     while(i--){  
  78.         init_completion(&cmpl);  
  79.         wait_for_completion_timeout(&cmpl, 3 * HZ);  
  80.         sendnlmsg("I am from kernel!");  
  81.           
  82.     }  
  83.   
  84.     return 0;  
  85. }  
  86.   
  87. static void netlink_exit(void)     
  88. {     
  89.     if(nl_sk != NULL){  
  90.         sock_release(nl_sk->sk_socket);  
  91.     }  
  92.   
  93.     printk("my_net_link: self module exited/n");     
  94. }  
  95.   
  96. module_init(netlink_init);     
  97. module_exit(netlink_exit);     
  98.   
  99. MODULE_AUTHOR("donglp");     
  100. MODULE_LICENSE("GPL");   

用户的:

  1. #include <sys/stat.h>   
  2. #include <unistd.h>   
  3. #include <stdio.h>   
  4. #include <stdlib.h>   
  5. #include <sys/socket.h>   
  6. #include <sys/types.h>   
  7. #include <string.h>   
  8. #include <asm/types.h>   
  9. #include <linux/netlink.h>   
  10. #include <linux/socket.h>   
  11. #include <errno.h>   
  12.   
  13. #define NETLINK_TEST 17   
  14. #define MAX_PAYLOAD 1024  // maximum payload size   
  15.   
  16.   
  17. int main(int argc, char* argv[])  
  18. {  
  19.     struct sockaddr_nl src_addr, dest_addr;  
  20.     struct nlmsghdr *nlh = NULL;  
  21.     struct iovec iov;  
  22.     struct msghdr msg;  
  23.     int sock_fd, retval;  
  24.       
  25.     // Create a socket   
  26.     sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_TEST);  
  27.     if(sock_fd == -1){  
  28.         printf("error getting socket: %s", strerror(errno));  
  29.         return -1;  
  30.     }  
  31.       
  32.     // To prepare binding   
  33.     memset(&src_addr, 0, sizeof(src_addr));  
  34.     src_addr.nl_family = PF_NETLINK;   
  35.     src_addr.nl_pid = getpid();  // self pid    
  36.     src_addr.nl_groups = 1; // multi cast   
  37.   
  38.     retval = bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));  
  39.     if(retval < 0){  
  40.         printf("bind failed: %s", strerror(errno));  
  41.         close(sock_fd);  
  42.         return -1;  
  43.     }  
  44.       
  45.     // To prepare recvmsg   
  46.     nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));  
  47.     if(!nlh){  
  48.         printf("malloc nlmsghdr error!/n");  
  49.         close(sock_fd);  
  50.         return -1;  
  51.     }  
  52.   
  53.     memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));  
  54.     iov.iov_base = (void *)nlh;  
  55.     iov.iov_len = NLMSG_SPACE(MAX_PAYLOAD);  
  56.   
  57.     memset(&msg, 0, sizeof(msg));  
  58.     memset(&dest_addr, 0, sizeof(dest_addr));  
  59.     msg.msg_name = (void *)&dest_addr;  
  60.     msg.msg_namelen = sizeof(dest_addr);  
  61.     msg.msg_iov = &iov;  
  62.     msg.msg_iovlen = 1;  
  63.   
  64.     // Read message from kernel   
  65.     while(1){  
  66.         recvmsg(sock_fd, &msg, 0);  
  67.         printf("Received message: %s/n", NLMSG_DATA(nlh));  
  68.     }  
  69.   
  70.     close(sock_fd);  
  71.   
  72.     return 0;  
  73. }  

Makefile文件:

  1. obj-m := self.o  
  2. KERNELBUILD := /lib/modules/`uname -r`/build  
  3. default:  
  4.     @echo "  BUILD kmod"  
  5.     @make -C $(KERNELBUILD) M=$(shell pwd) modules  
  6.     gcc -o u u.c  
  7. clean:  
  8.     @echo "  CLEAN kmod"  
  9.     @rm -rf *.o  
  10.     @rm -rf .depend .*.cmd *.ko *.mod.c .tmp_versions *.symvers .*.d  

编译方法:直接make

如何看效果:

必须先运行insmod self.ko 

然后在另外一个终端运行./u 

就能看到效果,关注dmesg信息和./u显示出来的信息。

相关推荐