我引用了 Yd Ahhrk 的以下来源
Multicast from kernel to user space via Netlink in C
模块是正确的 insmod,lsmod|less 可以看到它在那里,但是当尝试运行用户空间应用程序时,我有错误:
seotsockopt < 0
在用户空间应用程序中,它正在执行组错误:
if (setsockopt(sock, 270, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group)) < 0) {
printf("seotsockopt < 0\n");
return -1;
}
虽然我用谷歌搜索其他来源,但看起来像 setsockopt 和 NETLINK_ADD_MEMBERSHIP 做完全正确的事情,除了 Yd Ahhrk 在 3.13 测试它, 我在 3.10 测试它,我不知道如何避免错误并使其工作。
编辑:
以下是我的代码: xyz内核.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netlink.h>
#include <net/netlink.h>
#include <net/net_namespace.h>
/* Protocol family, consistent in both kernel prog and user prog. */
#define MYPROTO NETLINK_USERSOCK
/* Multicast group, consistent in both kernel prog and user prog. */
#define MYGRP 1
static struct sock *nl_sk = NULL;
static void send_to_user(void)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
char *msg = "Hello from kernel";
int msg_size = strlen(msg) + 1;
int res;
pr_info("Creating skb.\n");
skb = nlmsg_new(NLMSG_ALIGN(msg_size + 1), GFP_KERNEL);
if (!skb) {
pr_err("Allocation failure.\n");
return;
}
nlh = nlmsg_put(skb, 0, 1, NLMSG_DONE, msg_size + 1, 0);
strcpy(nlmsg_data(nlh), msg);
pr_info("Sending skb.\n");
res = nlmsg_multicast(nl_sk, skb, 0, MYGRP, GFP_KERNEL);
if (res < 0)
pr_info("nlmsg_multicast() error: %d\n", res);
else
pr_info("Success.\n");
}
static int __init marskernel_init(void)
{
pr_info("Inserting marskernel module.\n");
nl_sk = netlink_kernel_create(&init_net, MYPROTO, NULL);
if (!nl_sk) {
pr_err("Error creating socket.\n");
return -10;
}
send_to_user();
netlink_kernel_release(nl_sk);
return 0;
}
static void __exit marskernel_exit(void)
{
pr_info("Exiting marskernel module.\n");
}
module_init(marskernel_init);
module_exit(marskernel_exit);
MODULE_LICENSE("GPL");
和client.cpp
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <unistd.h>
/* Protocol family, consistent in both kernel prog and user prog. */
#define MYPROTO NETLINK_USERSOCK
/* Multicast group, consistent in both kernel prog and user prog. */
#define MYMGRP 1
int open_netlink(void)
{
int sock;
struct sockaddr_nl addr;
int group = MYMGRP;
sock = socket(AF_NETLINK, SOCK_RAW, MYPROTO);
if (sock < 0) {
printf("sock < 0.\n");
return sock;
}
memset((void *) &addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid();
/* This doesn't work for some reason. See the setsockopt() below. */
/* addr.nl_groups = MYMGRP; */
if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
printf("bind < 0.\n");
return -1;
}
/*
* 270 is SOL_NETLINK. See
* http://lxr.free-electrons.com/source/include/linux/socket.h?v=4.1#L314
* and
* https://stackoverflow.com/questions/17732044/
*/
/*
if (setsockopt(sock, 270, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group)) < 0) {
printf("setsockopt < 0\n");
return -1;
}
*/
return sock;
}
void read_event(int sock)
{
struct sockaddr_nl nladdr;
struct msghdr msg;
struct iovec iov;
char buffer[65536];
int ret;
iov.iov_base = (void *) buffer;
iov.iov_len = sizeof(buffer);
msg.msg_name = (void *) &(nladdr);
msg.msg_namelen = sizeof(nladdr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
printf("Ok, listening.\n");
ret = recvmsg(sock, &msg, 0);
if (ret < 0)
printf("ret < 0.\n");
else
printf("Received message payload: %s\n", NLMSG_DATA((struct nlmsghdr *) &buffer));
}
int main(int argc, char *argv[])
{
int nls;
nls = open_netlink();
if (nls < 0)
return nls;
while (1)
read_event(nls);
return 0;
}
当我标记两者时
/* addr.nl_groups = MYMGRP; */
和
/*
if (setsockopt(sock, 270, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group)) < 0) {
printf("setsockopt < 0\n");
return -1;
}
*/
不会遇到运行时错误,但自 MYGRP 1 以来就没有意义 不再使用,但如果我取消标记 addr.nl_groups = MYMGRP 然后绑定(bind)会出错,未标记setsockopt然后setsockopt 会出错.....我不知道如何处理这种情况!!
最佳答案
我有一个类似的问题,我想我可能一直在处理相同或相似的例子。在没有看到您的所有代码的情况下,我可以告诉您的数量不多。不过,我可以传递一些我为使多播工作所做的事情。
- 在内核和用户空间代码中将您的组定义为 1。
- 完全删除 setsockopt()。
没有看到您的其余代码,我无法提供更多说明。
祝你好运
这是我使用的代码。它应该一路帮助你。但是,出于安全原因,我的内核模块没有退出功能。
内核代码
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netlink.h>
#include <net/netlink.h>
#include <net/sock.h>
#include <net/net_namespace.h>
#include <linux/skbuff.h>
#define MY_GROUP 1
struct sock* socket;
struct sk_buff* socket_buff;
char *log;
void nl_data_ready(struct sock *sk, int len)
{
nlmsg_free(socket_buff);
}
static void send_to_user(char *message)
{
struct nlmsghdr *nlsk_mh;
char* msg = message;
int res;
socket_buff = nlmsg_new(256, GFP_KERNEL);
nlsk_mh = nlmsg_put(socket_buff, 0, 0, NLMSG_DONE, strlen(msg), 0);
NETLINK_CB(socket_buff).pid = 0; // kernel pid
NETLINK_CB(socket_buff).dst_group = MY_GROUP;
strcpy(nlmsg_data(nlsk_mh), msg);
res = nlmsg_multicast(socket, socket_buff, 0, MY_GROUP, GFP_KERNEL);
if(res < 0)
{
printk("Multicast not sent: res < 0\n");
return 0;
}
else
{
printk("Multicast Sent\n");
}
}
void netlink_test(char *buf)
{
socket = netlink_kernel_create(&init_net, NETLINK_USERSOCK, MY_GROUP, nl_data_ready, NULL, THIS_MODULE);
if (!socket) {
printk("Error creating socket.\n");
return -10;
}
else
{
printk("\n\nSOCKET WAS CREATED SUCCESSFULLY\n\n");
}
printk("The message to be sent to the user is: %s", buf);
send_to_user(buf);
netlink_kernel_release(socket);
return 0;
}
用户空间代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <unistd.h>
#include <errno.h>
#include <unistd.h>
#define MAX_PAYLOAD 1024 /* maximum payload size*/
#define MY_GROUP 1
int main(void)
{
int sock_fd;
struct sockaddr_nl user_sockaddr;
struct nlmsghdr *nl_msghdr;
struct msghdr msghdr;
struct iovec iov;
char* kernel_msg;
sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USERSOCK);
if(sock_fd<0)
{
printf("Error creating socket because: %s\n", strerror(errno));
return -1;
}
memset(&user_sockaddr, 0, sizeof(user_sockaddr));
user_sockaddr.nl_family = AF_NETLINK;
user_sockaddr.nl_pid = getpid();
user_sockaddr.nl_groups = MY_GROUP;
bind(sock_fd, (struct sockaddr*)&user_sockaddr, sizeof(user_sockaddr));
while (1) {
nl_msghdr = (struct nlmsghdr*) malloc(NLMSG_SPACE(1024));
memset(nl_msghdr, 0, NLMSG_SPACE(1024));
iov.iov_base = (void*) nl_msghdr;
iov.iov_len = NLMSG_SPACE(1024);
msghdr.msg_name = (void*) &user_sockaddr;
msghdr.msg_namelen = sizeof(user_sockaddr);
msghdr.msg_iov = &iov;
msghdr.msg_iovlen = 1;
printf("Waiting to receive message\n");
recvmsg(sock_fd, &msghdr, 0);
kernel_msg = (char*)NLMSG_DATA(nl_msghdr);
printf("Kernel message: %s\n", kernel_msg); // print to android logs
}
close(sock_fd);
}
另外,我相信 netlink_kernel_create()
函数在不同的内核版本中有不同的实现。因此,我在此处提供的某些功能可能因您的内核版本而有所不同(取决于它是什么)。
此外,我认为内核代码需要一个回调函数。我没有在您的代码中注意到这一点。代码应该可以工作,但我链接到的文章对于弄清楚到底发生了什么更有用。
干杯
关于c - c中linux内核3.10中从内核到用户空间错误的netlink多播,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36782659/