您的位置:首页 > 其它

O4 - Netlink学习

2015-10-30 09:30 1026 查看
/*
kernl.c
netlink 内核部分
*/

#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/types.h>
#include <net/sock.h>
#include <net/netlink.h>

#ifndef TEST_NETLINK
#define TEST_NETLINK 25
#endif

#ifndef TEST_GROUP
#define TEST_GROUP 2
#endif

#define TYPE_REQ_KERMSG     1
#define TYPE_REQ_USERPID 2
typedef struct netlink_msg {
    int    type;
    int    opt;
    char    path[4096];
    int    gid;
    int    uid;
}netlink_msg;

struct sock *g_nlsocket = NULL;
static int g_userpid = 0;
static int create_netlink(void);

static int get_userpid(void)
{    
    struct sk_buff *skb = NULL;
    struct nlmsghdr *nlh = NULL;
    netlink_msg message = {
        .type = TYPE_REQ_USERPID,
    };
    int len = NLMSG_SPACE(sizeof(netlink_msg) + sizeof(struct nlmsghdr));
    
    if(!g_nlsocket)
        if (create_netlink()) return -1;

    skb = alloc_skb(len, GFP_KERNEL);
    if(!skb){
        printk(KERN_ERR "ERROR: KERNEL NETLINK - userpid miss.\n");
        return -1;
    }
    nlh = nlmsg_put(skb, 0, 0, 0, len, 0);

    NETLINK_CB(skb).creds.pid = 0;
    NETLINK_CB(skb).portid = 0;
    NETLINK_CB(skb).dst_group = TEST_GROUP;

    memcpy(NLMSG_DATA(nlh), &message, sizeof(netlink_msg));
    netlink_broadcast(g_nlsocket, skb, 0, TEST_GROUP, GFP_KERNEL);
    return 0;
}

int netlink_sendmsg(void *msg, int msglen)
{    
    struct sk_buff *skb = NULL;
    struct nlmsghdr *nlh = NULL;
    int skblen = 0;

    if (g_userpid <= 0) {
        get_userpid();
        mdelay(8); /* sleep 8ms */
    }

    skblen = NLMSG_SPACE(msglen + sizeof(struct nlmsghdr));
    skb = alloc_skb(skblen, GFP_ATOMIC);
    if (!skb){
        printk("ERROR: KERNEL NETLINK - allocate failed.\n");
        return -1;
    }

    nlh = nlmsg_put(skb, 0, 0, 0, skblen, 0);
    NETLINK_CB(skb).creds.pid = 0;
    memcpy(NLMSG_DATA(nlh), msg, msglen);

    if (g_userpid > 0) {
        netlink_unicast(g_nlsocket, skb, g_userpid, MSG_DONTWAIT);
    } else {
        NETLINK_CB(skb).portid = 0;
        NETLINK_CB(skb).dst_group = TEST_GROUP;
        netlink_broadcast(g_nlsocket, skb, 0, TEST_GROUP, GFP_KERNEL);    
    }
    return 0;
}

static int netlink_recvmsg(netlink_msg *msg)
{
    if (IS_ERR_OR_NULL(msg))
        return -1;
    printk("receive message:\ntype: %d\nopt: %d\npath: %s\ngid: %d uid: %d\n",
            msg->type, msg->opt, msg->path, msg->gid, msg->uid);
    return 0;
}

void nl_data_ready (struct sk_buff *__skb)
{
    struct sk_buff *skb = NULL;
    struct nlmsghdr *nlh = NULL;
    netlink_msg *nlmsg = (netlink_msg* )kmalloc(sizeof(netlink_msg), GFP_ATOMIC);
    if (IS_ERR_OR_NULL(nlmsg)) return;
    memset(nlmsg, 0, sizeof(netlink_msg));
    skb = skb_get(__skb);
    if(skb && skb->len >= NLMSG_SPACE(0)) {
        nlh = nlmsg_hdr(skb);
        g_userpid = nlh->nlmsg_pid;
        memcpy(nlmsg, NLMSG_DATA(nlh), nlh->nlmsg_len);
        netlink_recvmsg(nlmsg);
        kfree_skb(skb);
    }
    kfree(nlmsg);
}

static int create_netlink(void)
{
    struct netlink_kernel_cfg cfg = {
        .input = nl_data_ready,
    };
    
    g_nlsocket = netlink_kernel_create(&init_net, TEST_NETLINK, &cfg);
    if (!g_nlsocket) {
        printk("ERROR: KERNEL NETLINK - Cannot create netlink socket.\n");
        return -EIO;
    }

    return 0;
}

static struct task_struct *taskp = NULL;
static int stime = 2;
module_param(stime, int ,S_IRUGO);
static int thread_fun(void *data)
{
    netlink_msg sendmsg;
    int msgcnt = 1;
    while (!kthread_should_stop()) {
        ssleep(stime);
        sendmsg.type = TYPE_REQ_KERMSG;
        sendmsg.opt = msgcnt++;
        snprintf(sendmsg.path, sizeof(sendmsg.path), "%s", "/where/is/the/file");
        sendmsg.gid = 4;
        sendmsg.uid = 5;
        netlink_sendmsg(&sendmsg, sizeof(netlink_msg));        
    }
    return 0;
}

int __init init_netlink(void)
{
    create_netlink();
    taskp = kthread_run(thread_fun, NULL, "%s", "netlink_thread");
    return 0;
}

void __exit exit_netlink(void )
{
    kthread_stop(taskp);
    if (g_nlsocket != NULL)
        sock_release(g_nlsocket->sk_socket);
}

module_init(init_netlink);
module_exit(exit_netlink);
MODULE_LICENSE("GPL");


obj-m := kernl.o
KERNELDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

install:
insmod kernl.ko
remove:
rmmod kernl
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions modules.order  Module.symvers .tmp* .ker_*


<pre name="code" class="cpp">/*
usernl.c
netlink 用户态部分
*/#include <sys/stat.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <sys/socket.h>#include <sys/types.h>#include <string.h>#include <asm/types.h>#include <linux/netlink.h>#include <linux/socket.h>#include <sys/select.h>#include
<errno.h>#include <pthread.h>#ifndef TEST_NETLINK#define TEST_NETLINK 25#endif#ifndef TEST_GROUP#define TEST_GROUP 2#endif#define TYPE_ACK_KERMSG 0x01#define TYPE_REQ_DOWN 0x10static int run = 1;typedef struct netlink_msg {int type;int opt;char path[4096];int
gid;int uid;}netlink_msg;int nl_create_bind(int netlinkid, int netlinkgid){int sock_fd, retval, group;struct sockaddr_nl src_addr;/* Create a socket */sock_fd = socket(AF_NETLINK, SOCK_RAW, netlinkid);if(sock_fd == -1){printf("error create socket: %s", strerror(errno));return
-1;}/* bind */memset(&src_addr, 0, sizeof(src_addr));src_addr.nl_family = AF_NETLINK;src_addr.nl_pid = getpid();src_addr.nl_groups = netlinkgid;retval = bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));if(retval < 0){printf("error bind socket:
%s", strerror(errno));close(sock_fd);return -1;}/* 270 is SOL_NETLINK */group = netlinkgid;retval = setsockopt(sock_fd, 270, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group));if (retval < 0) {printf("error setsockopt: %s", strerror(errno));close(sock_fd);return
-1;}return sock_fd;}int nl_sendmsg(int sock_fd, void *msgsend, int msgsize){struct msghdr msg;struct nlmsghdr *nlh = NULL;struct sockaddr_nl dest_addr;struct iovec iov;int state_smg = 0;int payload = NLMSG_SPACE(msgsize + sizeof(struct nlmsghdr));nlh = (struct
nlmsghdr *)malloc(NLMSG_SPACE(payload));if(!nlh){printf("error malloc nlmsghdr: %s", strerror(errno));close(sock_fd);return -1;}memset(&dest_addr, 0, sizeof(dest_addr));dest_addr.nl_family = AF_NETLINK;dest_addr.nl_pid = 0;dest_addr.nl_groups = TEST_GROUP;nlh->nlmsg_len
= NLMSG_SPACE(payload);nlh->nlmsg_pid = getpid();nlh->nlmsg_flags = 0;memcpy(NLMSG_DATA(nlh), msgsend, msgsize);iov.iov_base = (void *)nlh;iov.iov_len = NLMSG_SPACE(payload);memset(&msg, 0, sizeof(msg));msg.msg_name = (void *)&dest_addr;msg.msg_namelen = sizeof(dest_addr);msg.msg_iov
= &iov;msg.msg_iovlen = 1;state_smg = sendmsg(sock_fd, &msg, 0);if(state_smg == -1)printf("get error sendmsg = %s\n",strerror(errno));free(nlh);return state_smg;}typedef void (*recv_cbfun)(struct netlink_msg *);recv_cbfun nl_recvmsg = NULL;void recvmsg_cb(struct
netlink_msg *nlmsg){printf("receive message:\ntype: %d\nopt: %d\npath: %s\ngid: %d uid: %d\n",nlmsg->type, nlmsg->opt, nlmsg->path, nlmsg->gid, nlmsg->uid);if (nlmsg->type == TYPE_REQ_DOWN) run = 0;//nlh->nlmsg_pid = getpid();//sendmsg(sock_fd, &msg, 0);}void
register_recvcb(recv_cbfun cb){nl_recvmsg = cb;}void *recvmsg_thread(void *param){int sock_fd = *(int *)param;struct msghdr msg;struct nlmsghdr *nlh = NULL;struct iovec iov;int payload = NLMSG_SPACE(sizeof(struct netlink_msg) + sizeof(struct nlmsghdr));nlh
= (struct nlmsghdr *)calloc(NLMSG_SPACE(payload), 1);if(!nlh){printf("error malloc nlmsghdr: %s", strerror(errno));return NULL;}iov.iov_base = (void *)nlh;iov.iov_len = NLMSG_SPACE(payload);memset(&msg, 0, sizeof(msg));msg.msg_iov = &iov;msg.msg_iovlen = 1;while
(1) {recvmsg(sock_fd, &msg, 0);struct netlink_msg *nlmsg = (struct netlink_msg *)NLMSG_DATA(nlh);if (nl_recvmsg) (*nl_recvmsg)(nlmsg);if (!run) break;}return NULL;}int main(int argc, char* argv[]){int sock_fd = nl_create_bind(TEST_NETLINK, TEST_GROUP);if (sock_fd
< 0) return -1;struct netlink_msg u2k = {.type = TYPE_ACK_KERMSG,.opt = 1,.path = {"/HELLO/THIS/IS/USERSPACE."},.gid = 2,.uid = 3,};int state_smg = nl_sendmsg(sock_fd, &u2k, sizeof(netlink_msg));if(state_smg == -1)printf("get error sendmsg\n");register_recvcb(recvmsg_cb);pthread_t
pthid;pthread_create(&pthid, NULL, recvmsg_thread, &sock_fd);while (run) {usleep(1000 * 500); /* 200ms */nl_sendmsg(sock_fd, &u2k, sizeof(netlink_msg));}pthread_join(pthid, NULL);close(sock_fd);return 0;}


参考文档:
http://qos.ittc.ku.edu/netlink/netlink.pdf http://1984.lsi.us.es/~pablo/docs/spae.pdf
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: