【版权声明:转载请保留出处:blog.csdn.net/gentleliu。邮箱:shallnew*163.com】
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; #else void 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; }