linux内核编程之netlink

来源:互联网 发布:usb hub 知乎 编辑:程序博客网 时间:2024/04/30 07:31

【版权声明:转载请保留出处:blog.csdn.net/gentleliu。邮箱:shallnew*163.com】


上一节说到proc文件系统,这是用户态和内核态通信的一种方法,本节将要说到另外一种通信的方法,该方法相比于其他的内核和用户通信有时在于:
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
原创粉丝点击