netlink example

参考文章

netlink详解

应用层程序

// netlink_user.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <linux/netlink.h>
#include <errno.h>

struct bgscan {
    int sock;
};

void bgsacn_deinit(struct bgscan *bgscan)
{
    if (!bgscan)
        return;
    if (bgscan->sock >= 0)
        close(bgscan->sock);
    free(bgscan);
}

struct bgscan * bgscan_init(void)
{
    struct bgscan *bgscan;
    struct sockaddr_nl local;

    bgscan = (struct bgscan*)calloc(1, sizeof(*bgscan));
    if (bgscan == NULL)
        return NULL;

    bgscan->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_USERSOCK);
    if (bgscan->sock < 0) {
        printf("%s: Failed to open netlink socket: %s\n", __func__, strerror(errno));
        bgsacn_deinit(bgscan);
        return NULL;
    }

    memset(&local, 0, sizeof(local));
    local.nl_family = AF_NETLINK;
    local.nl_groups = 1;
    if (bind(bgscan->sock, (struct sockaddr *) &local, sizeof(local)) < 0) {
        printf("%s: Failed to bind netlink socket: %s\n", __func__, strerror(errno));
        bgsacn_deinit(bgscan);
        return NULL;
    }

    return bgscan;
}

static void bgscan_netlink_receive(struct bgscan *bgscan)
{
    if (!bgscan)
        return;

    char buf[2048];
    int left;
    struct sockaddr_nl from;
    socklen_t fromlen;
    struct nlmsghdr *h;

    fromlen = sizeof(from);
    left = recvfrom(bgscan->sock, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr *) &from, &fromlen);
    if (left < 0) {
        if (errno != EINTR && errno != EAGAIN)
            printf("%s failed: %s", __func__, strerror(errno));
        return;
    }

    h = (struct nlmsghdr *) buf;
    printf("%s received: %s\n", __func__, NLMSG_DATA(h));
}

int main(int argc, char* argv[])
{
    struct bgscan* bgscan = bgscan_init();
    while (1) {
        bgscan_netlink_receive(bgscan);
        sleep(1);
    }
    bgsacn_deinit(bgscan);
}

内核测试程序

netlink_kernel.c

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

#define NETLINK_BGSCAN 25
#define MAX_PAYLOAD 1024

struct sock *bgscan_nl_sock = NULL;

static void bgscan_netlink_receive(struct sk_buff *__skb)
{
    struct sk_buff *skb;
    struct nlmsghdr *nlh;
    u32 pid;
    int rc;
    int len = NLMSG_SPACE(1200);
    char str[100];

    printk("net_link: data is ready to read.\n");
    skb = skb_get(__skb);

    if (skb->len >= NLMSG_SPACE(0)) {
        nlh = nlmsg_hdr(skb);
        printk("net_link: recv %s.\n", (char *)NLMSG_DATA(nlh));
        memcpy(str, NLMSG_DATA(nlh), sizeof(str));
        pid = nlh->nlmsg_pid; /*pid of sending process */
        printk("net_link: pid is %d\n", pid);
        kfree_skb(skb);
    }
    return;
}

static void send(void)
{
    struct sk_buff *skb = NULL;
    struct nlmsghdr *nlh;

    skb = alloc_skb(NLMSG_SPACE(MAX_PAYLOAD), GFP_ATOMIC);
    if (NULL == skb) {
        return;
    }

    skb_put(skb, NLMSG_SPACE(MAX_PAYLOAD));
    nlh = (struct nlmsghdr *)skb->data;
    nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
    nlh->nlmsg_pid = 0;  /* from kernel */
    nlh->nlmsg_flags = 0;

    memcpy(NLMSG_DATA(nlh), "hello", strlen("hello") + 1);
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
    NETLINK_CB(skb).pid = 0;  /* from kernel */
#else
    NETLINK_CB(skb).portid = 0;  /* from kernel */
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
    NETLINK_CB(skb).dst_pid = 0;  /* multicast */
#endif
    /* dest group 1<<0 */
    NETLINK_CB(skb).dst_group = 1;
    printk("called %s\n", __func__);
    netlink_broadcast(bgscan_nl_sock, skb, 0, 1, GFP_KERNEL);
}

static int netlink_init(void)
{
    if (bgscan_nl_sock == NULL) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION (3,10,0)
        struct netlink_kernel_cfg cfg;
        memset(&cfg, 0, sizeof(cfg));
        cfg.groups = 1;
        cfg.input = bgscan_netlink_receive;
        bgscan_nl_sock = (struct sock *)netlink_kernel_create(&init_net, NETLINK_USERSOCK, &cfg);

#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
        struct netlink_kernel_cfg cfg = {
            .groups = 1,
            .input  = bgscan_netlink_receive,
        };

        bgscan_nl_sock = (struct sock *)netlink_kernel_create(&init_net, NETLINK_USERSOCK, &cfg);

#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
        struct netlink_kernel_cfg cfg = {
            .groups = 1,
            .input  = bgscan_netlink_receive,
        };

        bgscan_nl_sock = (struct sock *)netlink_kernel_create(&init_net, NETLINK_USERSOCK, THIS_MODULE, &cfg);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION (2,6,24)
        bgscan_nl_sock = (struct sock *)netlink_kernel_create(&init_net, NETLINK_USERSOCK,
                         1, bgscan_netlink_receive, NULL, THIS_MODULE);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION (2,6,22)
        bgscan_nl_sock = (struct sock *)netlink_kernel_create(NETLINK_USERSOCK,
                         1, bgscan_netlink_receive, (struct mutex *) NULL, THIS_MODULE);
#else
        bgscan_nl_sock = (struct sock *)netlink_kernel_create(NETLINK_USERSOCK,
                         1, bgscan_netlink_receive, THIS_MODULE);
#endif
        if (bgscan_nl_sock == NULL) {
            printk(KERN_ERR "%s, netlink_kernel_create failed\n", __func__);
            return -ENODEV;
        }
    }
    send();
    return 0;
}

static void netlink_exit(void)
{
    send();
    if (bgscan_nl_sock != NULL) {
        sock_release(bgscan_nl_sock->sk_socket);
    }
    printk("%s\n", __func__);
}

module_init(netlink_init);
module_exit(netlink_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Yy");

内核Makefile

ifeq ($(KERNELRELEASE),)
    KERNELDIR ?= /home/Yy/kernels/ #注意,这里替换为你的内核的路径
    PWD := $(shell pwd)

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

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

clean:
    rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

.PHONY: modules modules_install clean

else
    obj-m := netlink_kernel.o
endif
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值