我试图实现的任务实际上非常简单(将字符串“TEST”多播到用户域守护进程),但是内核模块无法编译。它停止与错误:
passing argument 4 of ‘genlmsg_multicast_allns’ makes integer from pointer without a cast [enabled by default]
字符串
但它不应该只是我定义的多播组吗?
以下是“澄清”的代码:
#include <linux/module.h>
#include <net/sock.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#include <linux/string.h>
#include <net/netlink.h>
#include <net/genetlink.h>
struct sock *nl_sk = NULL;
static void daemon(void){
struct sk_buff *skb;
void* msg_head;
unsigned char *msg;
struct genl_family my_genl_family = {
.id = GENL_ID_GENERATE,
.hdrsize = 0,
.name = "family_name",
.version = 1,
.maxattr = 5
};
struct genl_multicast_group my_mc_group = {
.name = "mc_group",
};
msg = "TEST";
skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
msg_head = genlmsg_put(skb, 0, 0, &my_genl_family, 0, 21);
nla_put(skb, 0, sizeof(msg), msg);
genlmsg_end(skb, msg_head);
genlmsg_multicast_allns( &my_genl_family, skb, 0, my_mc_group, GFP_KERNEL);
}
static int __init hello_init(void)
{
printk("Entering: %s\n", __FUNCTION__);
printk(KERN_INFO "Calling main function with sockets\n");
struct netlink_kernel_cfg cfg = {
.groups = 1,
.flags = NL_CFG_F_NONROOT_RECV,
};
nl_sk = netlink_kernel_create(&init_net, NETLINK_GENERIC, &cfg);
daemon();
return 0;
}
static void __exit hello_exit(void)
{
printk(KERN_INFO "exiting hello module\n");
netlink_kernel_release(nl_sk);
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
型
谢谢你的帮助。
编辑
这是客户端代码:
#include <netlink/netlink.h>
#include <netlink/socket.h>
#include <netlink/msg.h>
#include <netlink/genl/genl.h>
#include <linux/genetlink.h>
/*
* This function will be called for each valid netlink message received
* in nl_recvmsgs_default()
*/
static int my_func(struct nl_msg *msg, void *arg)
{
//struct nl_msg *nlmsg = nlmsg_alloc_size(GENL_HDRLEN+nla_total_size(sizeof(msg))+36);
printf("Test\n");
return 0;
}
int main(){
struct nl_sock *sk;
int gr_id;
/* Allocate a new socket */
sk = nl_socket_alloc();
/*
* Notifications do not use sequence numbers, disable sequence number
* checking.
*/
nl_socket_disable_seq_check(sk);
/*
* Define a callback function, which will be called for each notification
* received
*/
nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, my_func, NULL);
/* Connect to netlink generic protocol */
nl_connect(sk, NETLINK_GENERIC);
gr_id = genl_family_get_id("family_name");
/* Subscribe to link notifications group */
nl_socket_add_memberships(sk, gr_id, 0);
/*
* Start receiving messages. The function nl_recvmsgs_default() will block
* until one or more netlink messages (notification) are received which
* will be passed on to my_func().
*/
while (1){
nl_recvmsgs_default(sk);
}
return 0;
}
型
2条答案
按热度按时间f87krz0w1#
您的核心问题是,在使用通用Netlink系列之前,您必须首先注册它(这也适用于普通Netlink系列)。内核不能处理它不知道的家族。除非您正在使用一个已经存在的族,否则这将决定您使用Netlink的方式。
通用Netlink系列属于内核模块。这意味着用户空间客户端无法创建族。反过来,这意味着您不能只启动客户端,然后让模块在创建族之后立即发送消息。这是因为在客户端希望将其自身绑定到该族时,该族不存在。
你需要做的是:
1.在插入模块时创建并注册族和多播组。
1.启动用户空间客户机并将其自身绑定到家庭和多播组。
1.让内核模块在某个时刻发送消息(在客户端绑定之后)。
1.用户空间客户端现在接收到消息。
1.删除模块后,应取消注册该族。
我的代码版本如下。这是
driver.c
,内核模块。如您所见,我决定在每两秒运行一次的计时器上重复发送消息。这将为您提供启动客户端的时间:字符串
这是
app.c
,用户空间客户端:型
这里也是一个示例Makefile(请验证您的目录):
型
ff29svar2#
这不是对网络链接问题的直接回答,而是另一种解决方案。请参阅上面有关netlink限制的注解。
UDP套接字可以在Linux上用于在用户模式进程(如守护进程)和内核模式组件(如可加载模块)之间进行通信。
守护程序代码my_udp.c:
字符串
内核模块代码k_udp.c:
型
注意:我已经重命名了我正在使用的代码中的一些变量和函数名,因此您可能需要进行更改以进行编译(如果我遗漏了什么)。确保用户/内核组件之间的端口匹配。
上面的代码是从网上和Linux内核中的多个示例中派生出来的。