linux内核编程之netlink
来源:互联网 发布:usb hub 知乎 编辑:程序博客网 时间:2024/04/30 07:31
【版权声明:转载请保留出处:blog.csdn.net/gentleliu。邮箱:shallnew*163.com】
Netlink相对于其他的通信机制具有以下优点:
1.使用Netlink通过自定义一种新的协议并加入协议族即可通过socket API使用Netlink协议完成数据交换,而ioctl和proc文件系统均需要通过程序加入相应的设备或文件。
2.Netlink使用socket缓存队列,是一种异步通信机制,而ioctl是同步通信机制,如果传输的数据量较大,会影响系统性能。
3.Netlink支持多播,属于一个Netlink组的模块和进程都能获得该多播消息。
4.Netlink允许内核发起会话,而ioctl和系统调用只能由用户空间进程发起。
建立netlink会话如下:
1.在内核使用netlink_kernel_create()创建套接字,指明接受函数。
2.在用户态创建套接字,并将进程ID发送至内核空间。
3.内核接受函数收到用户空间进程ID。
4.用户空间与内核空间可以通信。
需要详细描述的内容太多,下面直接给一个例子算了,以后有时间在细说,
下面是内核部分代码:
#include <linux/init.h>#include <linux/module.h>#include <linux/version.h> //LINUX_VERSION_CODE#include <net/sock.h> //struct sock *#include <linux/netlink.h> //netlink_kernel_create()#include <linux/sched.h>#include "netlink_k.h"static struct sock *nlfd;static int pid;int netlink_deliver(uint16_t type, void *data, unsigned short dlen){ int ret, len; char *old_tail; struct sk_buff *skb = NULL; struct nlmsghdr *nlh = NULL; if (0 == pid) { return 0; } len = NLMSG_SPACE(dlen + sizeof(unsigned short)); skb = alloc_skb(len, GFP_ATOMIC); if (NULL == skb) { printk(KERN_ALERT"alloc skb failed!\n"); goto nlmsg_failure; } old_tail = (char *)skb->tail; nlh = NLMSG_PUT(skb, 0, 0, type, len - sizeof(*nlh)); memcpy((char *)NLMSG_DATA(nlh), &dlen, sizeof(unsigned short)); memcpy((char *)NLMSG_DATA(nlh) + sizeof(unsigned short), data, dlen); nlh->nlmsg_len = (char *)skb->tail - (char *)old_tail; NETLINK_CB(skb).dst_group = 0; printk(KERN_ALERT"Send: data: %s, dlen = %d, nlh->nlmsg_len: %d\n", (char*)data, (int)dlen, nlh->nlmsg_len); ret = netlink_unicast(nlfd, skb, pid, MSG_DONTWAIT); return ret;nlmsg_failure: if(skb) kfree_skb(skb); return -1;}#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)void nlsock_receive_process(struct sock *sk, int len){ struct sk_buff *skb = NULL; struct nlmsghdr *nlh = NULL; char info[] = "Haha, welcome to Kernel!"; unsigned char data[MAX_PACKET]; unsigned short dlen; while ((skb = skb_dequeue(&sk->sk_receive_queue))) { nlh = (struct nlmsghdr *)skb->data;#elsevoid nlsock_receive_process(struct sk_buff *skb){ struct nlmsghdr *nlh = NULL; char info[] = "Haha, welcome to Kernel!"; unsigned char *data = NULL; unsigned short dlen; nlh = nlmsg_hdr(skb);#endif printk(KERN_ALERT"===%s===\n", __func__); pid = nlh->nlmsg_pid; memcpy(&dlen, (char *)NLMSG_DATA(nlh), sizeof(unsigned short)); printk(KERN_ALERT"dlen: %d\n", dlen); data = (char *)NLMSG_DATA(nlh) + sizeof(unsigned short); //sln_dump_pkt(NLMSG_DATA(nlh), 100); printk(KERN_ALERT"Receive netlink data: %s, nlh->nlmsg_len = %d\n", data, nlh->nlmsg_len); netlink_deliver(NL_FRAMEIO, info, strlen(info));#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) }#endif}static int __init nlk_init(void){#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) nlfd = netlink_kernel_create(NL_FRAMEIO, 0, nlsock_receive_process, THIS_MODULE);#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,5) struct netlink_kernel_cfg cfg = { .input = nlsock_receive_process, }; nlfd = netlink_kernel_create(&init_net, NL_FRAMEIO, THIS_MODULE, &cfg);#else nlfd = netlink_kernel_create(&init_net, NL_FRAMEIO, 0, nlsock_receive_process, NULL, THIS_MODULE);#endif printk(KERN_ALERT"===%s===\n", __func__); if (NULL == nlfd) { printk(KERN_ALERT"Can't create netlink sock!\n"); return -1; } return 0;}static void __exit nlk_exit(void){ printk(KERN_ALERT"===%s===\n", __func__); if (NULL != nlfd) { netlink_kernel_release(nlfd); nlfd = NULL; }}module_init(nlk_init);module_exit(nlk_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("sln");
下面是用户态部分代码:
#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <sys/socket.h>#include <sys/types.h>#include <string.h>#include <errno.h>#include <pthread.h>#include <linux/netlink.h>#include <linux/socket.h>#include "netlink_u.h"struct sockaddr_nl local_addr, dest_addr;int sockfd;int bcm_netlink_init(void){ sockfd = socket(PF_NETLINK, SOCK_RAW, NL_FRAMEIO); if (sockfd < 0) { fprintf(stderr, "sockfd: %s\n", strerror(errno)); return -1; } memset(&local_addr, 0, sizeof(local_addr)); local_addr.nl_family = AF_NETLINK; local_addr.nl_pid = getpid(); /* self pid */ local_addr.nl_groups = 0; /* not in mcast groups */ if (bind(sockfd, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) { fprintf(stderr, "bind: %s\n", strerror(errno)); close(sockfd); return -1; } memset(&dest_addr, 0, sizeof(dest_addr)); dest_addr.nl_family = AF_NETLINK; dest_addr.nl_pid = 0; /* To Linux Kernel */ dest_addr.nl_groups = 0; /* unicast */ return 0;}int bcm_netlink_send(char *data, unsigned short dlen){ int len; struct iovec iov; struct msghdr msg; struct nlmsghdr *nlh = NULL; nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(dlen + sizeof(unsigned short))); if (NULL == nlh) { printf("malloc failed!\n"); return -1; } /* Fill the netlink message header */ memset(nlh, 0, sizeof(struct nlmsghdr));// nlh->nlmsg_len = NLMSG_SPACE(MAX_PACKET); nlh->nlmsg_len = NLMSG_SPACE(dlen + sizeof(unsigned short)); nlh->nlmsg_pid = getpid(); /* self pid */ nlh->nlmsg_flags = 0; /* Fill in the netlink message payload */ memcpy(NLMSG_DATA(nlh), &dlen, sizeof(unsigned short)); memcpy((char *)NLMSG_DATA(nlh) + sizeof(unsigned short), data, dlen); /* * if not two line below, send will failure. Very IMPORTANT ! */ memset(&iov, 0, sizeof(struct iovec)); memset(&msg, 0, sizeof(struct msghdr)); iov.iov_base = (void *)nlh; iov.iov_len = nlh->nlmsg_len; msg.msg_name = (void *)&dest_addr; msg.msg_namelen = sizeof(dest_addr); msg.msg_iov = &iov; msg.msg_iovlen = 1; while ((len = sendmsg(sockfd, &msg, 0)) < 0) { if (errno == EINTR) { continue; } fprintf(stderr, "sendmsg: %s, len = %d\n", strerror(errno), len); return -1; } fprintf(stderr, "senddata: %s, sizeof(struct nlmsghdr) = %d, mydatalen: %d, sendlen = %d\n", data, (int)sizeof(struct nlmsghdr), (int)dlen, len); return 0;}int bcm_netlink_recv(){ struct sockaddr_nl peer_addr; struct nlmsghdr *nlh = NULL; struct iovec iov; int recvlen; struct msghdr msg; char *data = NULL; unsigned short dlen; nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(dlen + sizeof(unsigned short))); if (NULL == nlh) { printf("malloc failed!\n"); return -1; } /* Fill the netlink message header */ memset(nlh, 0, sizeof(struct nlmsghdr)); nlh->nlmsg_len = NLMSG_SPACE(MAX_PACKET); nlh->nlmsg_pid = getpid(); /* self pid */ nlh->nlmsg_flags = 0; /* * if not two line below ,send will failure. Very IMPORTANT! */ memset(&iov, 0, sizeof(struct iovec)); memset(&msg, 0, sizeof(struct msghdr)); iov.iov_base = (void *)nlh; iov.iov_len = nlh->nlmsg_len; msg.msg_name = (void *)&peer_addr; msg.msg_namelen = sizeof(peer_addr); msg.msg_iov = &iov; msg.msg_iovlen = 1; /* A loop to read message from kernel */ for (;;) { memset(nlh, 0, nlh->nlmsg_len); if ((recvlen = recvmsg(sockfd, &msg, 0)) < 0) { fprintf(stderr, "recvmsg: %s\n", strerror(errno)); continue; } memcpy(&dlen, (char *)NLMSG_DATA(nlh), sizeof(unsigned short)); data = (char *)NLMSG_DATA(nlh) + sizeof(unsigned short); fprintf(stdout, "Received message payload: %s, recvlen: %d, dlen: %d\n", data, recvlen, dlen); }}int main(int argc, char* argv[]){ int ret; pthread_t pid; char sendbuf[MAX_PACKET] = "info from user!"; ret = bcm_netlink_init(); if (ret < 0) { goto err; } if (pthread_create(&pid, NULL, (void *)bcm_netlink_recv, NULL) < 0) { fprintf(stderr, "Create receive thread failed!\n"); goto err; } for (;;) { sleep(1); bcm_netlink_send(sendbuf, strlen(sendbuf)); }// pthread_join(pid, NULL);err: if (sockfd > 0) { close(sockfd); } return 0;}
2 0
- linux内核编程之netlink
- Linux-内核通信之netlink机制-详解
- Linux-内核通信之netlink机制-详解
- linux 内核与用户空间通信之netlink使用方法[转]
- linux 内核与用户空间通信之netlink使用方法
- linux 内核与用户空间通信之netlink使用方法
- Linux内核空间与用户空间通信之netlink
- linux 内核与用户空间通信之netlink使用方法
- linux 内核与用户空间通信之netlink使用方法
- linux 内核与用户空间通信之netlink使用方法
- linux 内核与用户空间通信之netlink使用方法
- linux 内核与用户空间通信之netlink使用方法
- linux 用户态和内核通信之Netlink
- linux用户态和内核态通信之netlink机制
- linux 内核和用户空间通信之netlink使用方法
- linux 内核与用户空间通信之netlink使用方法
- Linux 内核与用户空间通信之 netlink 使用方法
- linux 内核与用户空间通信之netlink使用方法
- [回溯&&剪枝]Sticks UVA307
- linux输入子系统之按键驱动
- python 总结
- 随机数
- 电脑怎么上youtube 国内怎么看YOUTUBE视频
- linux内核编程之netlink
- 青草悠悠
- ZOJ-2212
- 纯C语言:谈心会议安排源码
- QT事件处理 (一)之 重载事件处理器
- javascript内部原理篇[javascript实现继承]
- C常识
- win8.1 64bit下IIS8.5无法连接Access数据库的解决方案
- 纯C语言:贪心部分背包问题源码