netlink(三)-用户态发起会话

200阅读 0评论2023-08-04 zpf1218
分类:LINUX

用户态程序


点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <sys/socket.h>
  4. #include <string.h>
  5. #include <linux/netlink.h>
  6. #include <stdint.h>
  7. #include <unistd.h>
  8. #include <fcntl.h>
  9. #include <errno.h>


  10. #define NETLINK_TEST 30
  11. #define MSG_LEN 100
  12. #define MAX_PLOAD 100
  13. #define USER_PORT 66
  14. typedef struct _user_msg_info
  15. {
  16.     struct nlmsghdr hdr;
  17.     char msg[MSG_LEN];
  18. } user_msg_info;

  19. int main(int argc,char **argv)
  20. {
  21.     int sockfd;
  22.     struct sockaddr_nl saddr, daddr;
  23.     struct nlmsghdr *nlh;
  24.     user_msg_info u_info;
  25.     char *msg = "hello kernel, I am user process!";
  26.     socklen_t len;

  27.     //创建socket SOCK_RAW|SOCK_NONBLOCK
  28.     sockfd = socket(AF_NETLINK,SOCK_RAW, NETLINK_TEST);
  29.  
  30.     //初始化目的地址
  31.     memset(&daddr, 0, sizeof(daddr));
  32.     daddr.nl_family = AF_NETLINK;
  33.     daddr.nl_pid = 0; // to kernel
  34.     daddr.nl_groups = 0;
  35.     
  36.     //初始化消息头
  37.     nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PLOAD));
  38.     memset(nlh, 0, sizeof(struct nlmsghdr));
  39.     nlh->nlmsg_len = NLMSG_SPACE(MAX_PLOAD);
  40.     nlh->nlmsg_flags = 0;
  41.     nlh->nlmsg_type = 0;
  42.     nlh->nlmsg_seq = 0;
  43.     //nlh->nlmsg_pid = USER_PORT; //self port
  44.     nlh->nlmsg_pid = getpid();//我们希望得到内核回应,所以得告诉内核我们ID号

  45.     //设置消息内容
  46.     memcpy(NLMSG_DATA(nlh),msg,strlen(msg));

  47.     do
  48.     {
  49.         //发送消息
  50.         int ret = sendto(sockfd,nlh,nlh->nlmsg_len,0,(struct sockaddr *)&daddr,sizeof(struct sockaddr_nl));
  51.         if(ret < 0){
  52.             printf("sendto error, errno:%d \n", errno);
  53.             break;
  54.         }
  55.         printf("send to kernel :%s ret:%d nlmsg_len:%d \n",msg,ret, nlh->nlmsg_len);
  56.         
  57.         memset(&u_info, 0, sizeof(u_info));
  58.         len = sizeof(struct sockaddr_nl);
  59.         //接收消息
  60.         ret = recvfrom(sockfd,&u_info,sizeof(user_msg_info),0,(struct sockaddr *)&daddr,&len);
  61.         if(ret < 0){
  62.             printf("recvfrom error, errno:%d \n",errno);
  63.             break;
  64.         }
  65.         
  66.         printf("recv from kernel:%s ret:%d\n",u_info.msg,ret);
  67.     }while(0);
  68.     
  69.     free(nlh);
  70.     close(sockfd);
  71.     return 0;
  72. }

编译命令:

Gcc -o netlink_user netlink_user.c



内核态程序


点击(此处)折叠或打开

  1. #include <linux/init.h>
  2. #include <linux/module.h>
  3. #include <linux/types.h>
  4. #include <net/sock.h>
  5. #include <linux/netlink.h>

  6. #define NETLINK_TEST 30
  7. #define MSG_LEN 100
  8. #define USER_PORT 66

  9. struct sock *nlsk;

  10. extern struct net init_net;

  11. int send_usrmsg(char *pbuf, uint16_t len, int pid)
  12. {
  13.     struct sk_buff *nl_skb;
  14.     struct nlmsghdr *nlh; //消息头部

  15.     int ret;
  16.     //创建sk_buff
  17.     nl_skb = nlmsg_new(len, GFP_ATOMIC);
  18.     if(!nl_skb)
  19.     {
  20.         printk("netlink alloc failure\n");
  21.         return -1;
  22.     }
  23.     
  24.     /* 设置netlink消息头部 */
  25.     nlh = nlmsg_put(nl_skb, 0, 0, NETLINK_TEST, len, 0);
  26.     if(nlh == NULL)
  27.     {
  28.         printk("nlmsg_put failaure \n");
  29.         nlmsg_free(nl_skb);
  30.         return -1;
  31.     }
  32.  
  33.     /* 拷贝数据发送 */
  34.     memcpy(nlmsg_data(nlh), pbuf, len);
  35. ret = netlink_unicast(nlsk, nl_skb, pid, 0); //阻塞模式
  36.     //ret = netlink_unicast(nlsk, nl_skb, USER_PORT, MSG_DONTWAIT);
  37.     return ret;
  38. }

  39. static void netlink_rcv_msg(struct sk_buff *skb)
  40. {
  41.     struct nlmsghdr *nlh;
  42.     char *umsg = NULL;
  43.     char *kmsg = "hello users";
  44.     //从skb中获取data字段,并转换成nlh进行读取
  45.     nlh = nlmsg_hdr(skb);
  46.     //读取nlh后面的数据部分
  47.     umsg = NLMSG_DATA(nlh);
  48.     if(umsg){
  49.         printk("kernel recv from user: %s\n", umsg);
  50.         printk("port id :%d\n",NETLINK_CB(skb).portid);
  51.         send_usrmsg(kmsg, strlen(kmsg), nlh->nlmsg_pid); //给用户态发消息
  52.     }
  53.     
  54. }
  55. struct netlink_kernel_cfg cfg = {
  56.     .input = netlink_rcv_msg,
  57. };

  58. static int __init test_netlink_init(void)
  59. {
  60.     nlsk = (struct sock *)netlink_kernel_create(&init_net,NETLINK_TEST,&cfg);
  61.     return 0;
  62. }

  63. static void __exit test_netlink_exit(void)
  64. {
  65.      // 注销netlink协议
  66.     if(nlsk)
  67.     {
  68.         netlink_kernel_release(nlsk);
  69.         nlsk = NULL;
  70.     }
  71.     printk("exit......\n");
  72. }
  73. MODULE_LICENSE("GPL");
  74. module_init(test_netlink_init);
  75. module_exit(test_netlink_exit);

makefile 文件:

obj-m:=netlink_kernel.o     

                                  

CURRENT_PATH:=$(shell pwd)   

LINUX_KERNEL:=$(shell uname -r) 

LINUX_KERNEL_PATH:=/usr/src/kernels/$(LINUX_KERNEL) 

#linux-headers-                    

all:

       make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules

clean:

       make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean



上一篇:netlink(二)-API
下一篇:netlink(四)-内核态发起会话