netlink 通信广播demo

最近在做工程时,用到了内核间通信,需要把内核部分得到发送至用户空间。下面给出demo例子:

分为内核部分和用户空间部分:

首先在内核部分增加一个netlink消息类型

#define NETLINK_URL			23


创建内核的netlink socket

 
  1. static struct sock *nlfd;

  2.  
  3.  
  4. struct netlink_kernel_cfg cfg = {

  5. .groups = 1, //组播标识,当前只有1个组

  6. .input = netlink_receive,//接收回调函数

    扫描二维码关注公众号,回复: 11149348 查看本文章
  7. };

  8.  
  9. nlfd = netlink_kernel_create(net, NETLINK_URL, &cfg);

  10. if (nlfd == NULL) {

  11. printk(KERN_INFO "netlink kernel create failed\n");

  12. return -ENOMEM;

  13. }


向用户空间广播报文

 
  1. int send_urlinfo_to_usrspace(struct sk_buff *skb, char *url)

  2. {

  3. struct sk_buff *info;

  4. struct nlmsghdr *nlh;

  5. struct packet_info *data;

  6. int ret;

  7.  
  8. if(unlikely(nlfd== NULL))

  9. return 0;

  10.  
  11. if (!netlink_has_listeners(nlfd, 1))

  12. return 0;

  13.  
  14. info = alloc_skb(NLMSG_SPACE(PACKET_INFO_PAYLOAD),GFP_ATOMIC);

  15. if(info == NULL)

  16. return;

  17.  
  18. skb_put(info, NLMSG_SPACE(PACKET_INFO_PAYLOAD));

  19.  
  20. nlh = (struct nlmsghdr *)info->data;

  21. nlh->nlmsg_len = NLMSG_SPACE(PACKET_INFO_PAYLOAD);

  22. nlh->nlmsg_pid = 0;

  23. nlh->nlmsg_flags = 0;

  24. data = NLMSG_DATA(nlh);

  25. memset(data, 0, sizeof(struct packet_info));

  26. strncpy(data->url, url, sizeof(data->url));

  27.  
  28. fill_mac_and_ip(skb, info);

  29.  
  30. ret = netlink_broadcast(nlfd, info, 0, 1, GFP_ATOMIC);

  31.  
  32. debug("send_urlinfo_to_usrspace, ret = %d, %d, %s\n", ret, info->len, url);

  33.  
  34. return ret;

  35. }


接收用户空间的报文

 
  1. static void netlink_receive(struct sk_buff *skb)

  2. {

  3. int ret;

  4. mutex_lock(&receive_mutex);

  5. ret = netlink_rcv_skb(skb, &user_rcv_msg);

  6. mutex_unlock(&receive_mutex);

  7. }

 
  1. static int user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)

  2. {

  3. struct packet_info *data;

  4. int err, len;

  5.  
  6. nlh = nlmsg_hdr(skb);

  7. len = skb->len;

  8.  
  9. data = nlmsg_data(nlh);

  10.  
  11. switch (nlh->nlmsg_type)

  12. {

  13. case ADD_URL:

  14. if (nlmsg_len(nlh) < sizeof(struct packet_info))

  15. return -EINVAL;

  16. err = process_usr_info(data->url, strlen(data->url), data->blacklist);

  17. break;

  18. default:

  19. printk(KERN_INFO "recv type error = %d\n", nlh->nlmsg_type);

  20. err = -EINVAL;

  21. break;

  22. }

  23.  
  24. return err;

  25. }


用户空间代码:

创建netlink socket,并绑定

 
  1. if((nlsock = socket(PF_NETLINK, SOCK_RAW, NETLINK_URL)) < 0) {

  2. printf( "Unable to create apmon socket: %s\n", strerror(errno));

  3. return -1;

  4. }

  5.  
  6. memset(&addr, 0, sizeof(addr));

  7. addr.nl_family = AF_NETLINK;

  8. addr.nl_pid = 0;

  9. addr.nl_groups = 1;

  10. if (bind(nlsock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {

  11. perror("bind");

  12. }


接收部分,报文缓存在pbf中

 
  1. static int netlink_recv(void *pbf, int maxlen)

  2. {

  3. struct sockaddr_nl dest_addr;

  4. struct iovec iov;

  5. struct msghdr hdr;

  6.  
  7. memset(pbf, 0, sizeof(struct nlmsghdr) + sizeof(struct packet_info));

  8. memset(&dest_addr, 0, sizeof(dest_addr));

  9. memset(&iov, 0, sizeof(iov));

  10. memset(&hdr, 0, sizeof(hdr));

  11.  
  12. iov.iov_base = pbf;

  13. iov.iov_len = maxlen;

  14. hdr.msg_name = (void *)&dest_addr;

  15. hdr.msg_namelen = sizeof(dest_addr);

  16. hdr.msg_iov = &iov;

  17. hdr.msg_iovlen = 1;

  18.  
  19. return recvmsg(nlsock, &hdr, 0);

  20. }


发送报文至内核

 
  1. struct nlmsghdr nlh = {0};

  2. struct sockaddr_nl snl;

  3. memset (&snl, 0, sizeof snl);

  4. snl.nl_family = AF_NETLINK;

  5.  
  6. struct req req_ = {0};

  7.  
  8. req_.nlh.nlmsg_len = sizeof(struct req);

  9. req_.nlh.nlmsg_type = 0x11;

  10. req_.nlh.nlmsg_flags = NLM_F_REQUEST;

  11. req_.nlh.nlmsg_pid = 0;

  12. req_.nlh.nlmsg_seq = 0;

  13.  
  14. req_.info.blacklist = 0;

  15. strcpy(req_.info.url, r->info.url);

  16.  
  17. ret = sendto(nlsock, (void*)&req_, sizeof(struct req), 0 , (struct sockaddr *) &snl, sizeof snl);

  18. if (ret < 0)

  19. perror("sendto");

  20. else printf("send len %d\n", ret);

原创文章 11 获赞 10 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_14874791/article/details/81940340
今日推荐