Ubuntu下netlink套接字测试实例

mac2025-12-16  9

此项目在Linux ubuntu 4.4.0-21-generic实际环境中正常运行。

1.sender.c用户态netlink程序

#include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <string.h> #include <linux/netlink.h> #include <stdint.h> #include <unistd.h> #include <errno.h> #define NETLINK_TEST 30 #define MSG_LEN 125 #define MAX_PLOAD 125 typedef struct _user_msg_info { struct nlmsghdr hdr; char msg[MSG_LEN]; } user_msg_info; int main(int argc, char **argv) { int skfd; int ret; user_msg_info u_info; socklen_t len; struct nlmsghdr *nlh = NULL; struct sockaddr_nl saddr, daddr; char *umsg = "hello netlink!!"; /* 创建NETLINK socket */ skfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST); if(skfd == -1) { perror("create socket error\n"); return -1; } memset(&saddr, 0, sizeof(saddr)); saddr.nl_family = AF_NETLINK; //AF_NETLINK saddr.nl_pid = 100; //端口号(port ID) saddr.nl_groups = 0; if(bind(skfd, (struct sockaddr *)&saddr, sizeof(saddr)) != 0) { perror("bind() error\n"); close(skfd); return -1; } memset(&daddr, 0, sizeof(daddr)); daddr.nl_family = AF_NETLINK; daddr.nl_pid = 0; // to kernel daddr.nl_groups = 0; nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PLOAD)); memset(nlh, 0, sizeof(struct nlmsghdr)); nlh->nlmsg_len = NLMSG_SPACE(MAX_PLOAD); nlh->nlmsg_flags = 0; nlh->nlmsg_type = 0; nlh->nlmsg_seq = 0; nlh->nlmsg_pid = saddr.nl_pid; //self port memcpy(NLMSG_DATA(nlh), umsg, strlen(umsg)); ret = sendto(skfd, nlh, nlh->nlmsg_len, 0, (struct sockaddr *)&daddr, sizeof(struct sockaddr_nl)); if(!ret) { perror("sendto error\n"); close(skfd); exit(-1); } printf("send kernel:%s\n", umsg); memset(&u_info, 0, sizeof(u_info)); len = sizeof(struct sockaddr_nl); ret = recvfrom(skfd, &u_info, sizeof(user_msg_info), 0, (struct sockaddr *)&daddr, &len); if(!ret) { perror("recv form kernel error\n"); close(skfd); exit(-1); } printf("from kernel:%s\n", u_info.msg); close(skfd); free((void *)nlh); return 0; }

2.netlink_test.c内核态netlink程序

#include <linux/init.h> #include <linux/module.h> #include <linux/types.h> #include <net/sock.h> #include <linux/netlink.h> #define NETLINK_TEST 30 #define MSG_LEN 125 #define USER_PORT 100 MODULE_LICENSE("GPL"); MODULE_AUTHOR("zhangwj"); MODULE_DESCRIPTION("netlink example"); struct sock *nlsk = NULL; extern struct net init_net; int send_usrmsg(char *pbuf, uint16_t len) { struct sk_buff *nl_skb; struct nlmsghdr *nlh; int ret; /* 创建sk_buff 空间 */ nl_skb = nlmsg_new(len, GFP_ATOMIC); if(!nl_skb) { printk("netlink alloc failure\n"); return -1; } /* 设置netlink消息头部 */ nlh = nlmsg_put(nl_skb, 0, 0, NETLINK_TEST, len, 0); if(nlh == NULL) { printk("nlmsg_put failaure \n"); nlmsg_free(nl_skb); return -1; } /* 拷贝数据发送 */ memcpy(nlmsg_data(nlh), pbuf, len); ret = netlink_unicast(nlsk, nl_skb, USER_PORT, MSG_DONTWAIT); return ret; } static void netlink_rcv_msg(struct sk_buff *skb) { struct nlmsghdr *nlh = NULL; char *umsg = NULL; char *kmsg = "hello users!!!"; if(skb->len >= nlmsg_total_size(0)) { nlh = nlmsg_hdr(skb); umsg = NLMSG_DATA(nlh); if(umsg) { printk("kernel recv from user: %s\n", umsg); send_usrmsg(kmsg, strlen(kmsg)); } } } struct netlink_kernel_cfg cfg = { .input = netlink_rcv_msg, /* set recv callback */ }; int test_netlink_init(void) { /* create netlink socket */ nlsk = (struct sock *)netlink_kernel_create(&init_net, NETLINK_TEST, &cfg); if(nlsk == NULL) { printk("netlink_kernel_create error !\n"); return -1; } printk("test_netlink_init\n"); return 0; } void test_netlink_exit(void) { if (nlsk){ netlink_kernel_release(nlsk); /* release ..*/ nlsk = NULL; } printk("test_netlink_exit!\n"); } module_init(test_netlink_init); module_exit(test_netlink_exit);

3.内核态程序编译Makefile文件

MODULE_NAME :=netlink_test obj-m :=$(MODULE_NAME).o KERNELDIR = /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) all: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules clean: $(MAKE) -C $(KERNELDIR) M=$(PWD) clean

4.编译和运行测试

上传到服务器的工程目录各文件:

make目录:

此时netlink_test.ko即我们测试实验的内核模块。

编译sender.c文件:

 加载内核模块($sudo insmod netlink_test.ko):

运行用户态程序sender:

可以看到已经接收到了来自内核的信息了。

最后查看内核态接收的信息(dmesg):

最新回复(0)