Linux Netlink: 从内核模块发送数据到应用程序示例代码
下面是一个简单的示例代码,演示了如何从内核模块向用户空间应用程序发送数据。
内核模块代码:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netlink.h>
#include <net/sock.h>
#define NETLINK_USER 31
struct sock *netlink_sock = NULL;
static void netlink_recv_msg(struct sk_buff *skb)
{
struct nlmsghdr *nlh;
int pid, len;
void *msg_data;
char *reply = 'Hello from kernel!';
nlh = (struct nlmsghdr *)skb->data;
pid = nlh->nlmsg_pid; /* 发送进程的 pid */
len = nlh->nlmsg_len - NLMSG_HDRLEN;
if (len > 0) {
msg_data = NLMSG_DATA(nlh);
printk(KERN_INFO 'Received data from user: %s\n', (char *)msg_data);
}
/* 发送回复消息给用户 */
struct sk_buff *skb_out;
int msg_size = strlen(reply) + 1;
int res;
skb_out = nlmsg_new(msg_size, 0);
if (!skb_out) {
printk(KERN_ERR 'Failed to allocate new skb\n');
return;
}
nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, msg_size, 0);
NETLINK_CB(skb_out).dst_group = 0;
strncpy(nlmsg_data(nlh), reply, msg_size);
res = nlmsg_unicast(netlink_sock, skb_out, pid);
if (res < 0)
printk(KERN_ERR 'Error sending reply to user\n');
}
static struct netlink_kernel_cfg netlink_cfg = {
.input = netlink_recv_msg,
};
static int __init netlink_init(void)
{
netlink_sock = netlink_kernel_create(&init_net, NETLINK_USER, &netlink_cfg);
if (!netlink_sock) {
printk(KERN_ERR 'Failed to create netlink socket\n');
return -ENOMEM;
}
printk(KERN_INFO 'Netlink socket created\n');
return 0;
}
static void __exit netlink_exit(void)
{
if (netlink_sock)
netlink_kernel_release(netlink_sock);
printk(KERN_INFO 'Netlink socket released\n');
}
module_init(netlink_init);
module_exit(netlink_exit);
MODULE_LICENSE('GPL');
应用程序代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#define NETLINK_USER 31
int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh;
struct iovec iov;
struct msghdr msg;
char *msg_data = 'Hello from user!';
char buf[4096];
sockfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_USER);
if (sockfd < 0) {
perror('socket');
exit(EXIT_FAILURE);
}
memset(&src_addr, 0, sizeof(src_addr));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = getpid();
bind(sockfd, (struct sockaddr *)&src_addr, sizeof(src_addr));
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.nl_family = AF_NETLINK;
dest_addr.nl_pid = 0; /* 发送到内核 */
dest_addr.nl_groups = 0; /* 单播 */
nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(strlen(msg_data) + 1));
nlh->nlmsg_len = NLMSG_SPACE(strlen(msg_data) + 1);
nlh->nlmsg_pid = getpid();
nlh->nlmsg_flags = 0;
strcpy(NLMSG_DATA(nlh), msg_data);
iov.iov_base = (void *)nlh;
iov.iov_len = nlh->nlmsg_len;
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;
sendmsg(sockfd, &msg, 0);
/* 接收来自内核的回复消息 */
memset(buf, 0, sizeof(buf));
recv(sockfd, &buf, sizeof(buf), 0);
printf('Received reply from kernel: %s\n', buf);
close(sockfd);
return 0;
}
运行应用程序,输出应该类似于以下内容:
Received reply from kernel: Hello from kernel!
原文地址: https://www.cveoy.top/t/topic/nu3b 著作权归作者所有。请勿转载和采集!