关于Netlink IPC方式的介绍,请参见http://blog.chinaunix.net/space.php?uid=14753126&do=blog&id=2978566
本文通过一个编程实例来更深入地了解netlink。
功能描述:
1. 本实例包含2个部分:内核模块和用户程序
2.用户程序通过netlink socket建立与kernel module连接,并向kernel module发送一条信息。
3.内核在接收到用户的信息后,向用户程序发送一条确认信息。

说明:对于不知如何编译内核模块以及用户程序的童鞋请google

内核模块代码(test_netlink_kmodule.c):
  1. #include <linux/kernel.h>
  2. #include <linux/module.h>
  3. #include <linux/types.h>
  4. #include <linux/sched.h>
  5. #include <net/sock.h>
  6. #include <linux/netlink.h>

  7. #define NETLINK_TEST 17
  8. struct {
  9.     __u32 pid;
  10. }user_process;

  11. static struct sock *netlinkfd = NULL;

  12. int send_to_user(char *info) //发送到用户空间
  13. {
  14.     int size;
  15.     struct sk_buff *skb;
  16.     unsigned char *old_tail;
  17.     struct nlmsghdr *nlh; //报文头

  18.     int retval;

  19.     size = NLMSG_SPACE(strlen(info)); //报文大小
  20.     skb = alloc_skb(size, GFP_ATOMIC); //分配一个新的套接字缓存,使用GFP_ATOMIC标志进程不>会被置为睡眠

  21.     //初始化一个netlink消息首部
  22.     nlh = nlmsg_put(skb, 0, 0, 0, NLMSG_SPACE(strlen(info))-sizeof(struct nlmsghdr), 0); 
  23.     old_tail = skb->tail;
  24.     memcpy(NLMSG_DATA(nlh), info, strlen(info)); //填充数据区
  25.     nlh->nlmsg_len = skb->tail - old_tail; //设置消息长度

  26.     //设置控制字段
  27.     NETLINK_CB(skb).pid = 0;
  28.     NETLINK_CB(skb).dst_group = 0;

  29.     printk(KERN_DEBUG "[kernel space] skb->data:%s\n", (char *)NLMSG_DATA((struct nlmsghdr *)skb->data));

  30.     //发送数据
  31.     retval = netlink_unicast(netlinkfd, skb, user_process.pid, MSG_DONTWAIT);
  32.     printk(KERN_DEBUG "[kernel space] netlink_unicast return: %d\n", retval);
  33.     return 0;
  34. }

  35. void kernel_receive(struct sk_buff *__skb) //内核从用户空间接收数据
  36. {
  37.     struct sk_buff *skb;
  38.     struct nlmsghdr *nlh = NULL;

  39.     char *data = "This is eric's test message from kernel";

  40.     printk(KERN_DEBUG "[kernel space] begin kernel_receive\n");
  41.     skb = skb_get(__skb);

  42.     if(skb->len >= sizeof(struct nlmsghdr)){
  43.         nlh = (struct nlmsghdr *)skb->data;
  44.         if((nlh->nlmsg_len >= sizeof(struct nlmsghdr))
  45.             && (__skb->len >= nlh->nlmsg_len)){
  46.             user_process.pid = nlh->nlmsg_pid;
  47.             printk(KERN_DEBUG "[kernel space] data receive from user are:%s\n", (char *)NLMSG_DATA(nlh));
  48.             printk(KERN_DEBUG "[kernel space] user_pid:%d\n", user_process.pid);
  49.             send_to_user(data);
  50.         }
  51.     }else{
  52.         printk(KERN_DEBUG "[kernel space] data receive from user are:%s\n",(char *)NLMSG_DATA(nlmsg_hdr(__skb)));
  53.         send_to_user(data);
  54.     }

  55.     kfree_skb(skb);
  56. }

  57. int __init test_netlink_init(void)
  58. {

  59.     netlinkfd = netlink_kernel_create(&init_net, NETLINK_TEST, 0, kernel_receive, NULL, THIS_MODULE);
  60.     if(!netlinkfd){
  61.         printk(KERN_ERR "can not create a netlink socket\n");
  62.         return -1;
  63.     }
  64.     return 0;
  65. }

  66. void __exit test_netlink_exit(void)
  67. {
  68.     sock_release(netlinkfd->sk_socket);
  69.     printk(KERN_DEBUG "test_netlink_exit!!\n");
  70. }

  71. module_init(test_netlink_init);
  72. module_exit(test_netlink_exit);
  73. MODULE_LICENSE("GPL");
  74. MODULE_AUTHOR("eric.hu");
用户空间程序代码:user_sent.c
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <sys/socket.h>
  4. #include <string.h>
  5. #include <linux/netlink.h>

  6. #define NETLINK_TEST 17
  7. #define MSG_LEN 100

  8. struct msg_to_kernel
  9. {
  10.     struct nlmsghdr hdr;
  11.     char data[MSG_LEN];
  12. };
  13. struct u_packet_info
  14. {
  15.     struct nlmsghdr hdr;
  16.     char msg[MSG_LEN];
  17. };

  18. int main(int argc, char* argv[]) 
  19. {
  20.     char *data = "This message is from eric's space";
  21.     //初始化
  22.     struct sockaddr_nl local;
  23.     struct sockaddr_nl kpeer;
  24.     int skfd, ret, kpeerlen = sizeof(struct sockaddr_nl);
  25.     struct nlmsghdr *message;
  26.     struct u_packet_info info;
  27.     char *retval;
  28.     message = (struct nlmsghdr *)malloc(1);

  29.     skfd = socket(PF_NETLINK, SOCK_RAW, NETLINK_TEST);
  30.     if(skfd < 0){
  31.         printf("can not create a netlink socket\n");
  32.         return -1;
  33.     }
  34.     memset(&local, 0, sizeof(local));
  35.     local.nl_family = AF_NETLINK;
  36.     local.nl_pid = getpid();
  37.     local.nl_groups = 0;
  38.     if(bind(skfd, (struct sockaddr *)&local, sizeof(local)) != 0){
  39.         printf("bind() error\n");
  40.         return -1;
  41.     }
  42.     memset(&kpeer, 0, sizeof(kpeer));
  43.     kpeer.nl_family = AF_NETLINK;
  44.     kpeer.nl_pid = 0;
  45.     kpeer.nl_groups = 0;

  46.     memset(message, '\0', sizeof(struct nlmsghdr));
  47.     message->nlmsg_len = NLMSG_SPACE(strlen(data));
  48.     message->nlmsg_flags = 0;
  49.     message->nlmsg_type = 0;
  50.     message->nlmsg_seq = 0;
  51.     message->nlmsg_pid = local.nl_pid;

  52.     retval = memcpy(NLMSG_DATA(message), data, strlen(data));

  53.     printf("message sendto kernel are:%s, len:%d\n", (char *)NLMSG_DATA(message), message->nlmsg_len);
  54.     ret = sendto(skfd, message, message->nlmsg_len, 0,(struct sockaddr *)&kpeer, sizeof(kpeer));
  55.     if(!ret){
  56.         perror("send pid:");
  57.         exit(-1);
  58.     }

  59.     //接受内核态确认信息
  60.     ret = recvfrom(skfd, &info, sizeof(struct u_packet_info),0, (struct sockaddr*)&kpeer, &kpeerlen);
  61.     if(!ret){
  62.         perror("recv form kerner:");
  63.         exit(-1);
  64.     }

  65.     printf("message receive from kernel:%s\n",(char *)info.msg);
  66.     //内核和用户进行通信

  67.     close(skfd);
  68.     return 0;
  69. }
运行用户程序,输出结果如下:
  1. [root@FriendlyARM netlink]# ./user_sent
  2. message sendto kernel are:This message is from eric'space, len:52
  3. message receive from kernel:This is eric's test message from kernel
Logo

更多推荐