参考文章
应用层程序
// 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