C Netlink多播内核组
我试图实现的任务实际上非常简单(将字符串“TEST”多播到userland守护进程),但内核模块不编译。它将停止并显示错误:C Netlink多播内核组,c,linux-kernel,kernel-module,multicast,netlink,C,Linux Kernel,Kernel Module,Multicast,Netlink,我试图实现的任务实际上非常简单(将字符串“TEST”多播到userland守护进程),但内核模块不编译。它将停止并显示错误: passing argument 4 of ‘genlmsg_multicast_allns’ makes integer from pointer without a cast [enabled by default] 但它不应该只是我定义的多播组吗 以下是“澄清”的代码: #包括 #包括 #包括 #包括 #包括 #包括 #包括 结构sock*nl_sk=NULL;
passing argument 4 of ‘genlmsg_multicast_allns’ makes integer from pointer without a cast [enabled by default]
但它不应该只是我定义的多播组吗
以下是“澄清”的代码:
#包括
#包括
#包括
#包括
#包括
#包括
#包括
结构sock*nl_sk=NULL;
静态void守护进程(void){
结构sk_buff*skb;
空*味精头;
无符号字符*msg;
结构genl_族my_genl_族={
.id=GENL\u id\u GENERATE,
.hdrsize=0,
.name=“姓氏”,
.version=1,
.maxattr=5
};
结构genl\u多播组my\u mc\u组={
.name=“mc_集团”,
};
msg=“测试”;
skb=genlmsg_new(NLMSG_GOODSIZE,GFP_内核);
msg_head=genlmsg_put(skb,0,0和my_genl_family,0,21);
nla_put(skb,0,sizeof(msg),msg);
genlmsg_端(skb、msg_端);
genlmsg_多播(和my_genl_系列、skb、0、my_mc_组、GFP_内核);
}
静态int\uu init hello\u init(void)
{
printk(“输入:%s\n”,函数);
printk(KERN_INFO“使用套接字调用主函数”\n);
结构netlink\u内核\u cfg={
.组=1,
.flags=NL_CFG_F_NONROOT_RECV,
};
nl_sk=netlink_kernel_create(&init_net,netlink_GENERIC,&cfg);
守护进程();
返回0;
}
静态无效\uuu退出你好\u退出(无效)
{
printk(KERN_INFO“退出hello模块”\n);
netlink内核发布(nl sk);
}
模块_init(hello_init);
模块退出(你好退出);
模块许可证(“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;
}
#包括
#包括
#包括
#包括
#包括
/*
*将为接收到的每个有效netlink消息调用此函数
*在nl_recvmsgs_default()中
*/
静态int my_func(结构nl_msg*msg,void*arg)
{
//结构nl_msg*nlmsg=nlmsg_alloc_size(GENL_HDRLEN+nla_total_size(sizeof(msg))+36);
printf(“测试”);
返回0;
}
int main(){
结构nl_sock*sk;
智力障碍;
/*分配一个新的套接字*/
sk=nl_socket_alloc();
/*
*通知不使用序列号,请禁用序列号
*检查。
*/
nl_插座_禁用_顺序检查(sk);
/*
*定义一个回调函数,该函数将为每个通知调用
*收到
*/
nl_socket_modify_cb(sk,nl_cb_VALID,nl_cb_CUSTOM,my_func,NULL);
/*连接到netlink通用协议*/
nl_连接(sk、NETLINK_通用);
gr_id=genl_family_get_id(“family_name”);
/*订阅链接通知组*/
nl_套接字_添加_成员身份(sk,gr_id,0);
/*
*开始接收消息。函数nl_recvmsgs_default()将阻止
*直到收到一条或多条netlink消息(通知),其中
*将传递到my_func()。
*/
而(1){
nl_recvmsgs_默认值(sk);
}
返回0;
}
这不是对netlink问题的直接回答,而是另一种解决方案。请参阅以上有关netlink限制的评论
UDP套接字可以在Linux上用于在用户模式进程(如守护进程)和内核模式组件(如可加载模块)之间进行通信
守护程序代码my_udp.c:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
static int rcv_sock;
static int snd_sock;
static struct sockaddr_in rcv_addr_in;
static struct sockaddr_in snd_addr_in;
static pthread_t rcv_thread;
static void *rcv_thread_fn(void *data);
int my_udp_init(void)
{
int sendlen, receivelen;
int received = 0;
if ((rcv_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("socket");
return -1;
}
if ((snd_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("socket");
return -1;
}
memset(&rcv_addr_in, 0, sizeof(rcv_addr_in));
rcv_addr_in.sin_family = AF_INET;
rcv_addr_in.sin_addr.s_addr = inet_addr("127.0.0.1");
rcv_addr_in.sin_port = htons(MY_IN_PORT);
receivelen = sizeof(rcv_addr_in);
if (bind(rcv_sock, (struct sockaddr *) &rcv_addr_in, receivelen) < 0) {
perror("bind");
return -1;
}
memset(&snd_addr_in, 0, sizeof(snd_addr_in));
snd_addr_in.sin_family = AF_INET;
snd_addr_in.sin_addr.s_addr = inet_addr("127.0.0.1");
snd_addr_in.sin_port = htons(MY_OUT_PORT);
if (pthread_create(&rcv_thread, NULL, rcv_thread_fn, (void *)"rcv_thread")) {
return -ENOMEM;
}
return 0;
}
void my_udp_cleanup(void)
{
pthread_join(rcv_thread, NULL);
close(rcv_sock);
close(snd_sock);
}
int my_snd_msg(const char *buf, int size)
{
sendto(snd_sock, buf, size, 0, (struct sockaddr *)&snd_addr_in, sizeof(snd_addr_in));
return 0;
}
int my_rcv_msg(char *buf, int size)
{
int cnt = 0;
if ((cnt = recv(rcv_sock, buf, size, MSG_DONTWAIT)) < 0) {
if (errno == EAGAIN) {
/* This is ok in the non-blocking case. */
sleep(1);
return 0;
} else {
perror("recv");
return -1;
}
}
return cnt;
}
static void *rcv_thread_fn(void *data)
{
char buffer[64];
int cnt;
while (!g_stop) {
cnt = my_rcv_msg(buffer, 63);
if (cnt > 0) {
printf("message: %s\n", buffer);
}
}
pthread_exit(0);
}
#include <linux/module.h>
#include <linux/init.h>
#include <linux/in.h>
#include <net/sock.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/inet.h>
#include <linux/kthread.h>
static struct work_struct rcv_worker;
static struct socket *in_socket = NULL;
static struct socket *out_socket = NULL;
static struct workqueue_struct *wq = NULL;
static struct task_struct *notify_thread = NULL;
void rcv_work_queue(struct work_struct *data)
{
int len;
printk(KERN_INFO "%s: *******\n", __func__);
while ((len = skb_queue_len(&in_socket->sk->sk_receive_queue)) > 0) {
struct sk_buff *skb = NULL;
skb = skb_dequeue(&in_socket->sk->sk_receive_queue);
printk("message len: %i message: %s\n", skb->len - 8, skb->data+8);
kfree_skb(skb);
}
}
static void cb_data(struct sock *sk, int bytes)
{
printk(KERN_INFO "%s: *******\n", __func__);
queue_work(wq, &rcv_worker);
}
void send_notification(char *text)
{
struct sockaddr_in to_addr;
struct msghdr msg;
struct iovec iov;
mm_segment_t oldfs;
int len = 0;
if (out_socket->sk == NULL) {
printk(KERN_ERR "%s: socket skbuff is null\n", __func__);
return;
}
iov.iov_base = text;
len = strlen(text);
iov.iov_len = len;
memset(&to_addr, 0, sizeof(to_addr));
to_addr.sin_family = AF_INET;
to_addr.sin_addr.s_addr = in_aton("127.0.0.1");
to_addr.sin_port = htons(MY_OUT_PORT);
msg.msg_flags = 0;
msg.msg_name = &to_addr;
msg.msg_namelen = sizeof(struct sockaddr_in);
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
oldfs = get_fs();
set_fs(KERNEL_DS);
sock_sendmsg(out_socket, &msg, len);
set_fs(oldfs);
}
static int k_udp_notify_thread(void *data)
{
int i = 0;
while (!kthread_should_stop()) {
char buf[64];
sprintf(buf, "test from kernel%d\n", i++);
send_notification(buf);
msleep(1000);
}
return 0;
}
int k_udp_init(void)
{
struct sockaddr_in addr_out;
struct sockaddr_in addr_in;
int rc = 0;
printk("%s\n", __func__);
if (in_socket) {
printk(KERN_INFO "%s: socket already set up\n", __func__);
return 0;
}
if (sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &in_socket) < 0) {
printk( KERN_ERR "%s: failed to create socket\n", __func__);
return -EIO;
}
addr_in.sin_family = AF_INET;
addr_in.sin_addr.s_addr = in_aton("127.0.0.1");
addr_in.sin_port = htons( (unsigned short)MY_IN_PORT);
rc = in_socket->ops->bind(in_socket, (struct sockaddr *)&addr_in, sizeof(addr_in));
if (rc) {
printk(KERN_ERR "%s: failed to bind\n", __func__);
sock_release(in_socket);
in_socket = NULL;
return -EIO;
}
in_socket->sk->sk_data_ready = cb_data;
if (sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &out_socket) < 0) {
printk( KERN_ERR "%s: failed to create socket\n", __func__);
sock_release(in_socket);
in_socket = NULL;
return -EIO;
}
addr_out.sin_family = AF_INET;
addr_out.sin_addr.s_addr = in_aton("127.0.0.1");
addr_out.sin_port = htons( (unsigned short)MY_OUT_PORT);
rc = out_socket->ops->connect(out_socket, (struct sockaddr *)&addr_out, sizeof(addr_out), 0);
if (rc) {
printk(KERN_ERR "%s: failed to connect\n", __func__);
sock_release(in_socket);
in_socket = NULL;
sock_release(out_socket);
out_socket = NULL;
return -EIO;
}
notify_thread = kthread_create(k_udp_notify_thread, NULL, "k_notify_thread");
if (notify_thread) {
printk(KERN_INFO "%s: notify thread created\n", __func__);
wake_up_process(notify_thread);
} else {
printk(KERN_ERR "%s: failed to create notify thread\n", __func__);
}
INIT_WORK(&rcv_worker, rcv_work_queue);
wq = create_singlethread_workqueue("k_rcv_wq");
if (!wq) {
return -ENOMEM;
}
printk(KERN_INFO "%s: success\n", __func__);
return 0;
}
void k_udp_cleanup(void)
{
/* Should we check that the thread is still valid (hasn't exited)? */
if (notify_thread) {
kthread_stop(notify_thread);
notify_thread = NULL;
}
if (in_socket) {
sock_release(in_socket);
in_socket = NULL;
}
if (out_socket) {
sock_release(out_socket);
out_socket = NULL;
}
if (wq) {
flush_workqueue(wq);
destroy_workqueue(wq);
wq = NULL;
}
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
静态内部rcv_插座;
静态int snd_袜子;
rcv_addr_中的静态结构sockaddr_;
snd_addr_中的静态结构sockaddr_;
静态pthread_t rcv_线程;
静态无效*rcv\U螺纹\U fn(无效*数据);
int my_udp_init(void)
{
内部发送,接收;
接收到的int=0;
如果((rcv_sock=socket(PF_INET,sock_DGRAM,IPPROTO_UDP))<0){
佩罗(“插座”);
返回-1;
}
如果((snd_sock=socket(PF_INET,sock_DGRAM,IPPROTO_UDP))<0){
佩罗(“插座”);
返回-1;
}
memset(&rcv_addr_in,0,sizeof(rcv_addr_in));
rcv\u addr\u in.sin\u family=AF\u INET;
rcv_addr_in.sin_addr.s_addr=inet_addr(“127.0.0.1”);
rcv_addr_in.sin_port=htons(我的_in_port);
receivelen=sizeof(rcv\u addr\u in);
if(绑定(rcv_sock,(struct sockaddr*)和rcv_addr_in,receivelen)<0){
佩罗(“绑定”);
返回-1;
}
memset(&snd_addr_in,0,sizeof(snd_addr_in));
snd_addr_in.sin_family=AF_INET;
snd_addr_in.sin_addr.s_addr=inet_addr(“127.0.0.1”);
snd_addr_in.sin_port=htons(MY_OUT_port);
if(pthread_create(&rcv_thread,NULL,rcv_thread_fn,(void*)“rcv_thread”)){
return-ENOMEM;
}
返回0;
}
void my_udp_清理(void)
{
pthread_join(rcv_线程,NULL);
关闭(rcv_短袜);
关闭(snd_袜子);
}
int my_snd_msg(常量字符*buf,int大小)
{
sendto(snd_sock,buf,size,0,(struct sockaddr*)和snd_addr_in,sizeof(snd_addr_in));
返回0;
}
int my_rcv_msg(字符*buf,整数大小)
{
int-cnt=0;
如果((cnt=recv(rcv_sock,buf,size,MSG_DONTWAIT))<0){
if(errno==EAGAIN){
/*这在非阻塞情况下是正常的*/
睡眠(1);
返回0;
}否则{
perror(“recv”);
返回-1;
}
}
返回cnt;
}
静态无效*rcv\U螺纹\U fn(无效*数据)
{
字符缓冲区[64];
int-cnt;
当(!g_停止){
cnt=my_rcv_msg(缓冲区,63);
如果(cnt>0){
printf(“消息:%s\n”,缓冲区);
}
}
pthread_退出(0);
}
内核模块代码k_udp.c:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
static int rcv_sock;
static int snd_sock;
static struct sockaddr_in rcv_addr_in;
static struct sockaddr_in snd_addr_in;
static pthread_t rcv_thread;
static void *rcv_thread_fn(void *data);
int my_udp_init(void)
{
int sendlen, receivelen;
int received = 0;
if ((rcv_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("socket");
return -1;
}
if ((snd_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("socket");
return -1;
}
memset(&rcv_addr_in, 0, sizeof(rcv_addr_in));
rcv_addr_in.sin_family = AF_INET;
rcv_addr_in.sin_addr.s_addr = inet_addr("127.0.0.1");
rcv_addr_in.sin_port = htons(MY_IN_PORT);
receivelen = sizeof(rcv_addr_in);
if (bind(rcv_sock, (struct sockaddr *) &rcv_addr_in, receivelen) < 0) {
perror("bind");
return -1;
}
memset(&snd_addr_in, 0, sizeof(snd_addr_in));
snd_addr_in.sin_family = AF_INET;
snd_addr_in.sin_addr.s_addr = inet_addr("127.0.0.1");
snd_addr_in.sin_port = htons(MY_OUT_PORT);
if (pthread_create(&rcv_thread, NULL, rcv_thread_fn, (void *)"rcv_thread")) {
return -ENOMEM;
}
return 0;
}
void my_udp_cleanup(void)
{
pthread_join(rcv_thread, NULL);
close(rcv_sock);
close(snd_sock);
}
int my_snd_msg(const char *buf, int size)
{
sendto(snd_sock, buf, size, 0, (struct sockaddr *)&snd_addr_in, sizeof(snd_addr_in));
return 0;
}
int my_rcv_msg(char *buf, int size)
{
int cnt = 0;
if ((cnt = recv(rcv_sock, buf, size, MSG_DONTWAIT)) < 0) {
if (errno == EAGAIN) {
/* This is ok in the non-blocking case. */
sleep(1);
return 0;
} else {
perror("recv");
return -1;
}
}
return cnt;
}
static void *rcv_thread_fn(void *data)
{
char buffer[64];
int cnt;
while (!g_stop) {
cnt = my_rcv_msg(buffer, 63);
if (cnt > 0) {
printf("message: %s\n", buffer);
}
}
pthread_exit(0);
}
#include <linux/module.h>
#include <linux/init.h>
#include <linux/in.h>
#include <net/sock.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/inet.h>
#include <linux/kthread.h>
static struct work_struct rcv_worker;
static struct socket *in_socket = NULL;
static struct socket *out_socket = NULL;
static struct workqueue_struct *wq = NULL;
static struct task_struct *notify_thread = NULL;
void rcv_work_queue(struct work_struct *data)
{
int len;
printk(KERN_INFO "%s: *******\n", __func__);
while ((len = skb_queue_len(&in_socket->sk->sk_receive_queue)) > 0) {
struct sk_buff *skb = NULL;
skb = skb_dequeue(&in_socket->sk->sk_receive_queue);
printk("message len: %i message: %s\n", skb->len - 8, skb->data+8);
kfree_skb(skb);
}
}
static void cb_data(struct sock *sk, int bytes)
{
printk(KERN_INFO "%s: *******\n", __func__);
queue_work(wq, &rcv_worker);
}
void send_notification(char *text)
{
struct sockaddr_in to_addr;
struct msghdr msg;
struct iovec iov;
mm_segment_t oldfs;
int len = 0;
if (out_socket->sk == NULL) {
printk(KERN_ERR "%s: socket skbuff is null\n", __func__);
return;
}
iov.iov_base = text;
len = strlen(text);
iov.iov_len = len;
memset(&to_addr, 0, sizeof(to_addr));
to_addr.sin_family = AF_INET;
to_addr.sin_addr.s_addr = in_aton("127.0.0.1");
to_addr.sin_port = htons(MY_OUT_PORT);
msg.msg_flags = 0;
msg.msg_name = &to_addr;
msg.msg_namelen = sizeof(struct sockaddr_in);
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
oldfs = get_fs();
set_fs(KERNEL_DS);
sock_sendmsg(out_socket, &msg, len);
set_fs(oldfs);
}
static int k_udp_notify_thread(void *data)
{
int i = 0;
while (!kthread_should_stop()) {
char buf[64];
sprintf(buf, "test from kernel%d\n", i++);
send_notification(buf);
msleep(1000);
}
return 0;
}
int k_udp_init(void)
{
struct sockaddr_in addr_out;
struct sockaddr_in addr_in;
int rc = 0;
printk("%s\n", __func__);
if (in_socket) {
printk(KERN_INFO "%s: socket already set up\n", __func__);
return 0;
}
if (sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &in_socket) < 0) {
printk( KERN_ERR "%s: failed to create socket\n", __func__);
return -EIO;
}
addr_in.sin_family = AF_INET;
addr_in.sin_addr.s_addr = in_aton("127.0.0.1");
addr_in.sin_port = htons( (unsigned short)MY_IN_PORT);
rc = in_socket->ops->bind(in_socket, (struct sockaddr *)&addr_in, sizeof(addr_in));
if (rc) {
printk(KERN_ERR "%s: failed to bind\n", __func__);
sock_release(in_socket);
in_socket = NULL;
return -EIO;
}
in_socket->sk->sk_data_ready = cb_data;
if (sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &out_socket) < 0) {
printk( KERN_ERR "%s: failed to create socket\n", __func__);
sock_release(in_socket);
in_socket = NULL;
return -EIO;
}
addr_out.sin_family = AF_INET;
addr_out.sin_addr.s_addr = in_aton("127.0.0.1");
addr_out.sin_port = htons( (unsigned short)MY_OUT_PORT);
rc = out_socket->ops->connect(out_socket, (struct sockaddr *)&addr_out, sizeof(addr_out), 0);
if (rc) {
printk(KERN_ERR "%s: failed to connect\n", __func__);
sock_release(in_socket);
in_socket = NULL;
sock_release(out_socket);
out_socket = NULL;
return -EIO;
}
notify_thread = kthread_create(k_udp_notify_thread, NULL, "k_notify_thread");
if (notify_thread) {
printk(KERN_INFO "%s: notify thread created\n", __func__);
wake_up_process(notify_thread);
} else {
printk(KERN_ERR "%s: failed to create notify thread\n", __func__);
}
INIT_WORK(&rcv_worker, rcv_work_queue);
wq = create_singlethread_workqueue("k_rcv_wq");
if (!wq) {
return -ENOMEM;
}
printk(KERN_INFO "%s: success\n", __func__);
return 0;
}
void k_udp_cleanup(void)
{
/* Should we check that the thread is still valid (hasn't exited)? */
if (notify_thread) {
kthread_stop(notify_thread);
notify_thread = NULL;
}
if (in_socket) {
sock_release(in_socket);
in_socket = NULL;
}
if (out_socket) {
sock_release(out_socket);
out_socket = NULL;
}
if (wq) {
flush_workqueue(wq);
destroy_workqueue(wq);
wq = NULL;
}
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
静态结构工作\u结构rcv_
#include <netlink/netlink.h>
#include <netlink/socket.h>
#include <netlink/msg.h>
#include <netlink/genl/genl.h>
static struct nl_sock *sk = NULL;
/**
* Attributes and commands have to be the same as in kernelspace, so you might
* want to move these enums to a .h and just #include that from both files.
*/
enum attributes {
ATTR_DUMMY,
ATTR_HELLO,
ATTR_FOO,
/* This must be last! */
__ATTR_MAX,
};
enum commands {
COMMAND_HELLO,
/* This must be last! */
__COMMAND_MAX,
};
static int fail(int error, char *func_name)
{
printf("%s() failed.\n", func_name);
return error;
}
static int nl_fail(int error, char *func_name)
{
printf("%s (%d)\n", nl_geterror(error), error);
return fail(error, func_name);
}
/*
* This function will be called for each valid netlink message received
* in nl_recvmsgs_default()
*/
static int cb(struct nl_msg *msg, void *arg)
{
struct nlmsghdr *nl_hdr;
struct genlmsghdr *genl_hdr;
struct nlattr *attrs[__ATTR_MAX];
int error;
printf("The kernel module sent a message.\n");
nl_hdr = nlmsg_hdr(msg);
genl_hdr = genlmsg_hdr(nl_hdr);
if (genl_hdr->cmd != COMMAND_HELLO) {
printf("Oops? The message type is not Hello; ignoring.\n");
return 0;
}
error = genlmsg_parse(nl_hdr, 0, attrs, __ATTR_MAX - 1, NULL);
if (error)
return nl_fail(error, "genlmsg_parse");
/* Remember: attrs[0] is a throwaway. */
if (attrs[1])
printf("ATTR_HELLO: len:%u type:%u data:%s\n",
attrs[1]->nla_len,
attrs[1]->nla_type,
(char *)nla_data(attrs[1]));
else
printf("ATTR_HELLO: null\n");
if (attrs[2])
printf("ATTR_FOO: len:%u type:%u data:%u\n",
attrs[2]->nla_len,
attrs[2]->nla_type,
*((__u32 *)nla_data(attrs[2])));
else
printf("ATTR_FOO: null\n");
return 0;
}
static int do_things(void)
{
struct genl_family *family;
int group;
int error;
/* Socket allocation yadda yadda. */
sk = nl_socket_alloc();
if (!sk)
return fail(-1, "nl_socket_alloc");
nl_socket_disable_seq_check(sk);
error = nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, cb, NULL);
if (error)
return nl_fail(error, "nl_socket_modify_cb");
error = genl_connect(sk);
if (error)
return nl_fail(error, "genl_connect");
/* Find the multicast group identifier and register ourselves to it. */
group = genl_ctrl_resolve_grp(sk, "PotatoFamily", "PotatoGroup");
if (group < 0)
return nl_fail(group, "genl_ctrl_resolve_grp");
printf("The group is %u.\n", group);
error = nl_socket_add_memberships(sk, group, 0);
if (error) {
printf("nl_socket_add_memberships() failed: %d\n", error);
return error;
}
/* Finally, receive the message. */
nl_recvmsgs_default(sk);
return 0;
}
int main(void)
{
int error;
error = do_things();
if (sk)
nl_socket_free(sk);
return error;
}