Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2150586
  • 博文数量: 438
  • 博客积分: 3871
  • 博客等级: 中校
  • 技术积分: 6075
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-10 00:11
个人简介

邮箱: wangcong02345@163.com

文章分类

全部博文(438)

文章存档

2017年(15)

2016年(119)

2015年(91)

2014年(62)

2013年(56)

2012年(79)

2011年(16)

分类: LINUX

2015-12-23 17:42:18

一.内核层的改动
1.1 头文件中加入NETLINK的命令
  1. include/linux/netlink.h
  2. #define NETLINK_TEST 26
注意:这个必须得在头文件中申请,直接在.c文件中定义,上层在调用时会提示找不到
这个得再看一下内核代码,查一下原因
1.2 hello.c中
  1. #include <linux/init.h>
  2. #include <linux/module.h>
  3. #include <linux/workqueue.h>
  4. #include <linux/device.h>
  5. #include <linux/errno.h>
  6. #include <linux/workqueue.h>
  7. #include <linux/dma-mapping.h>
  8. #include <linux/platform_device.h>
  9. #include <linux/interrupt.h>
  10. #include <linux/irqreturn.h>
  11. #include <linux/types.h>
  12. #include <linux/delay.h>
  13. #include <linux/clk.h>
  14. #include <linux/err.h>
  15. #include <linux/io.h>
  16. #include <linux/spinlock.h>
  17. #include <linux/sched.h>
  18. #include <linux/kthread.h>
  19. #include <linux/wait.h>

  20. #include <linux/netlink.h>
  21. #include <net/netlink.h>
  22. #include <net/net_namespace.h>
  23. #include <linux/skbuff.h>

  24. #define MAX_MSGSIZE 1024
  25. //#define NETLINK_TEST 26

  26. //static wait_queue_head_t mythread_wq;
  27. struct task_struct *wait_thread_task;

  28. static DEFINE_MUTEX(netlink_rx_mutex);

  29. struct sock *nl_sk = NULL;
  30. int pid;

  31. void nl_data_recv(struct sk_buff *__skb)
  32. {
  33.     struct sk_buff *skb;
  34.     struct nlmsghdr *nlh;
  35.     char str[100];

  36.     printk(KERN_NOTICE "cong: %s:%s[%d]: in func \n", __FILE__,__FUNCTION__, __LINE__);
  37.     mutex_lock(&netlink_rx_mutex);
  38.     skb = skb_get (__skb);

  39.     if(skb->len >= NLMSG_SPACE(0))
  40.     {
  41.         nlh = nlmsg_hdr(skb);

  42.         memcpy(str, NLMSG_DATA(nlh), sizeof(str));
  43.         printk("cong:%s:%s:%d, str=%s\n",__FILE__,__FUNCTION__, __LINE__,str);

  44.         // H stands for Hello message.
  45.         if(str[0] == 'P')
  46.         {
  47.             pid = nlh->nlmsg_pid;
  48.             //sendnlmsg("Hello reply.");
  49.         }
  50.         // E stands for Exit message
  51.         else if(str[0] == 'E')
  52.         {
  53.             pid = 0;
  54.         }
  55.         kfree_skb(skb);
  56.     }
  57.     mutex_unlock(&netlink_rx_mutex);
  58. }

  59. //向用户空间发送消息的接口
  60. void nl_data_send(char *message,int dst_pid)
  61. {
  62.     struct sk_buff *skb;
  63.     struct nlmsghdr *nlh;
  64.     int len = NLMSG_SPACE(MAX_MSGSIZE);
  65.     int slen = 0;

  66.     if(!message || !nl_sk){
  67.         return;
  68.     }

  69.     // 为新的 sk_buffer申请空间
  70.     skb = alloc_skb(len, GFP_KERNEL);
  71.     if(!skb){
  72.         printk("cong:%s:%s:%d, alloc_skb error\n",__FILE__,__FUNCTION__, __LINE__);
  73.         return;
  74.     }

  75.     slen = strlen(message)+1;

  76.     //用nlmsg_put()来设置netlink消息头部
  77.     nlh = nlmsg_put(skb, 0, 0, 0, MAX_MSGSIZE, 0);

  78.     // 设置Netlink的控制块
  79.     NETLINK_CB(skb).pid = 0; // 消息发送者的id标识,如果是内核发的则置0
  80.     NETLINK_CB(skb).dst_group = 0; //如果目的组为内核或某一进程,该字段也置0

  81.     message[slen] = '\0';
  82.     memcpy(NLMSG_DATA(nlh), message, slen+1);

  83.     printk("cong:%s:%s:%d, next send dst_pid=%d\n",__FILE__,__FUNCTION__, __LINE__, dst_pid);
  84.     //通过netlink_unicast()将消息发送用户空间由dst_pid所指定了进程号的进程
  85.     netlink_unicast(nl_sk, skb, dst_pid, 0);
  86.     printk("cong:%s:%s:%d, send ok\n",__FILE__,__FUNCTION__, __LINE__);
  87.     return;
  88. }

  89. static int my_wait_thread(void* data)
  90. {
  91.     //char* buf = "hello,world\n";
  92.     while(1)
  93.     {
  94.         printk("cong:%s:%s:%d, in thread, pid=%d\n",__FILE__,__FUNCTION__, __LINE__, pid);
  95.         //发送者的进程ID我们已经将其存储在了netlink消息头部里的nlmsg_pid字段里,所以这里可以拿来用。
  96.         if(pid != 0)
  97.             nl_data_send("I see you", pid);
  98.         msleep(1000);
  99.     }
  100.     return 0;
  101. }


  102. static int __init hello_init(void)
  103. {
  104.     int rc;
  105.     printk(KERN_ALERT "my first driver\n");

  106.     //extern struct sock *netlink_kernel_create(struct net *net, int unit,unsigned int groups,
  107.     // void (*input)(struct sk_buff *skb), struct mutex *cb_mutex, struct module *module);
  108.     //1. create a netlink
  109.     nl_sk= netlink_kernel_create(&init_net, NETLINK_1408_TRIGGER_TEST, 0,nl_data_recv, NULL, THIS_MODULE);
  110.     if(!nl_sk)
  111.     {
  112.         printk(KERN_NOTICE "cong: %s:%s[%d]: can't create netlink socket ", __FILE__,__FUNCTION__, __LINE__);
  113.         rc = -1;
  114.         goto fail;
  115.     }

  116.     wait_thread_task = kthread_create(my_wait_thread, NULL, "my_wait_thread");
  117.     if (IS_ERR(wait_thread_task)) {
  118.         return PTR_ERR(wait_thread_task);
  119.     }
  120.     wake_up_process(wait_thread_task);
  121.     return 0;
  122. fail:
  123.     return rc;
  124. }

  125. static void __exit hello_exit(void)
  126. {
  127.     printk(KERN_ALERT "goodbye my first dirver\n");
  128.     return ;
  129. }

  130. module_init(hello_init);
  131. module_exit(hello_exit);
  132. MODULE_LICENSE("GPL");

二.上层测试程序
2.1 netlinktest.c
  1. #include <unistd.h>
  2. #include <sys/stat.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. //next defined must match kernel: include/linux/netlink.h
  12. #define NETLINK_1408_TRIGGER_TEST 27

  13. #define MAX_PAYLOAD 1024 /*消息最大负载为1024字节*/
  14. static int create_and_sendmsg(struct nlmsghdr * nlh, struct msghdr msg)
  15. {
  16.     struct sockaddr_nl dest_addr;
  17.     
  18.     struct iovec iov;
  19.     int sock_fd=-1;
  20.     if(-1 == (sock_fd=socket(PF_NETLINK, SOCK_RAW,NETLINK_1408_TRIGGER_TEST)) )//创建套接字
  21.     {
  22.         perror("can't create netlink socket!");
  23.         return -1;
  24.     }

  25.     memset(&dest_addr, 0, sizeof(dest_addr));
  26.     dest_addr.nl_family = AF_NETLINK;
  27.     dest_addr.nl_pid = 0; /*我们的消息是发给内核的*/
  28.     dest_addr.nl_groups = 0; /*在本示例中不存在使用该值的情况*/

  29.     printf("next bind\n");
  30.     //将套接字和Netlink地址结构体进行绑定
  31.     if(-1 == bind(sock_fd, (struct sockaddr*)&dest_addr, sizeof(dest_addr))){
  32.         perror("can't bind sockfd with sockaddr_nl!");
  33.         return -1;
  34.     }

  35.     printf("%d: next malloc\n", __LINE__);
  36.     

  37.     printf("%d: next memset\n", __LINE__);
  38.     memset(nlh,0,MAX_PAYLOAD);
  39.     /* 填充Netlink消息头部 */
  40.     nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
  41.     nlh->nlmsg_pid = getpid();//我们希望得到内核回应,所以得告诉内核我们ID号
  42.     nlh->nlmsg_type = NLMSG_NOOP; //指明我们的Netlink是消息负载是一条空消息
  43.     nlh->nlmsg_flags = 0;

  44.     printf("%d: next strcpy\n", __LINE__);
  45.     /*设置Netlink的消息内容,来自我们命令行输入的第一个参数*/
  46.     //strcpy(NLMSG_DATA(nlh), argv[1]);
  47.     strcpy(NLMSG_DATA(nlh), "P");

  48.     printf("%d: next memset\n", __LINE__);
  49.     /*这个是模板,暂时不用纠结为什么要这样用。有时间详细讲解socket时再说*/
  50.     memset(&iov, 0, sizeof(iov));
  51.     iov.iov_base = (void *)nlh;
  52.     iov.iov_len = nlh->nlmsg_len;
  53.     memset(&msg, 0, sizeof(msg));
  54.     msg.msg_iov = &iov;
  55.     msg.msg_iovlen = 1;

  56.     printf("next sendmsg\n");
  57.     sendmsg(sock_fd, &msg, 0); //通过Netlink socket向内核发送消息
  58.     return sock_fd;
  59. }

  60. int main(int argc, char* argv[])
  61. {
  62.     //struct sockaddr_nl dest_addr;
  63.     struct nlmsghdr *nlh = NULL;
  64.     struct iovec iov;
  65.     int sock_fd=-1;
  66.     struct msghdr msg;
  67.     fd_set rset;
  68.     int maxfdp1, ret, stdineof;
  69.     if(NULL == (nlh=(struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD)))){
  70.         perror("alloc mem failed!");
  71.         return 1;
  72.     }
  73.     
  74.     sock_fd = create_and_sendmsg(nlh, msg);
  75.     if(sock_fd < 0)
  76.     {
  77.         printf("create_and_sendmsg error %d\n", sock_fd);
  78.         return NULL;
  79.     }
  80.     
  81.     /*这个是模板,暂时不用纠结为什么要这样用。有时间详细讲解socket时再说*/
  82.     memset(&iov, 0, sizeof(iov));
  83.     iov.iov_base = (void *)nlh;
  84.     iov.iov_len = nlh->nlmsg_len;
  85.     memset(&msg, 0, sizeof(msg));
  86.     msg.msg_iov = &iov;
  87.     msg.msg_iovlen = 1;
  88. #if 0   
  89.     FD_ZERO(&rset);
  90.     while(1)
  91.     {
  92.         FD_SET(sock_fd, &rset);
  93.         //maxfdp1 = max(fileno(fp), sock_fd)+1;
  94.         maxfdp1 = sock_fd+1;
  95.         //SLOGD("fd=%d,sockfd=%d,maxfdp1=%d",fileno(fp), sockfd, maxfdp1);
  96.         ret = select(maxfdp1, &rset, NULL, NULL, NULL);
  97.         if(ret <= 0)
  98.             continue;
  99.         if(FD_ISSET(sock_fd, &rset))
  100.         {
  101.             //接收内核消息的消息
  102.             printf("waiting message from kernel!\n");
  103.             memset((char*)NLMSG_DATA(nlh),0,1024);
  104.             //printf("next recvmsg\n");
  105.             recvmsg(sock_fd, &msg, 0);
  106.             printf("Got response: %s\n",NLMSG_DATA(nlh));
  107.         }
  108.     }
  109. #endif
  110. #if 1
  111.     while(1)
  112.     {
  113.         //接收内核消息的消息
  114.         printf("waiting message from kernel!,nlh=0x%x\n", nlh);
  115.         
  116.         memset((char*)NLMSG_DATA(nlh),0,1024);
  117.         recvmsg(sock_fd,&msg,0);
  118.         printf("Got response: %s\n",NLMSG_DATA(nlh));
  119.     }
  120. #endif
  121.     /* 关闭netlink套接字 */
  122.     close(sock_fd);
  123.     free(nlh);
  124.     return 0;
  125. }
2.2 Android.mk
  LOCAL_PATH:= $(call my-dir)
  1. include $(CLEAR_VARS)

  2. LOCAL_SRC_FILES:= netlinktest.c

  3. LOCAL_SHARED_LIBRARIES := \
  4.     libutils liblog libcutils

  5. # for asprinf
  6. LOCAL_CFLAGS := -D_GNU_SOURCE

  7. LOCAL_C_INCLUDES := $(KERNEL_HEADERS)

  8. LOCAL_MODULE:=netlinktest
  9. include $(BUILD_EXECUTABLE)

三.源码下载
 hello.rar (内核层)
 test_netlinktest.rar (应用层)

四. 参考文章:
netlink socket编程实例
http://blog.chinaunix.net/uid-14753126-id-2983915.html
阅读(1933) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~