sockets - real - No se puede recibir un mensaje personalizado enviado desde el módulo kernel a la aplicación del usuario mediante el canal NETLINK_ROUTE
node js tiempo real (1)
Creo que tu error es que debes struct nlmsghdr *
buf
a struct nlmsghdr *
y luego completar la información.
char buf[4096];
struct iovec iov = { buf, sizeof(buf) };
struct msghdr msg = { (void *) &dest_addr, sizeof dest_addr, &iov, 1, NULL, 0, 0 };
struct nlmsghdr *h;
memset(buf, 0, sizeof(buf));
h = (struct nlmsghdr *)buf;
h->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
h->nlmsg_pid = getpid();
h->nlmsg_flags = 0;
strcpy(NLMSG_DATA(h), "Hello");
printf("Sending message to kernel/n");
sendmsg(sockint, &msg, 0);
Estoy trabajando con sockets de Netlink para enviar notificaciones personalizadas sobre el estado de una interfaz de ethernet desde un módulo kernel a una aplicación de espacio de usuario sobre el canal NETLINK_ROUTE
. He revisado varios artículos y documentos, pero todos ellos muestran un enfoque en el que necesita definir su propia familia, por ejemplo NETLINK_TEST en el encabezado netlink.h
o usando NETLINK_GENERIC
. Soy consciente de que el socket que usa NETLINK_ROUTE ya es propiedad del kernel, por lo que no se puede crear en el módulo kernel. No puedo recibir el mensaje en el espacio de usuario. Cualquier orientación será muy apreciada. Así que aquí están los dos códigos:
Módulo Kernel:
#include <linux/notifier.h>
#include <asm/kdebug.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
#include <linux/module.h>
#include <net/sock.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <asm/types.h>
#include <linux/skbuff.h>
MODULE_LICENSE("GPL");
int my_dev_event_handler(struct notifier_block *this, unsigned long event, void *ptr)
{
struct sk_buff *skb = NULL;
struct nlmsghdr *nlh;
int size = 0;
char buf[512];
switch (event) {
case NETDEV_REGISTER:
sprintf (buf, "Interface:: %s is Registered with the Notifier...", ((struct net_device *) ptr)->name);
break;
case NETDEV_UP:
sprintf (buf, "Interface:: %s is Up and Running...", ((struct net_device *) ptr)->name);
break;
case NETDEV_GOING_DOWN:
sprintf (buf, "Interface:: %s is going Down...", ((struct net_device *) ptr)->name);
break;
case NETDEV_DOWN:
sprintf (buf, "Interface:: %s is Down...", ((struct net_device *) ptr)->name);
break;
}
printk (KERN_INFO "Content of Buf :: %s" , buf);
size = sizeof(buf);
skb = nlmsg_new(size, GFP_ATOMIC);
if (skb == NULL)
{
printk(KERN_ERR "/nError Allocating skb for sending Netlink Message.../n");
return -1;
}
nlh = nlmsg_put(skb, 0, 0, NLMSG_DONE, size, 0);
if (nlh == NULL)
{
printk(KERN_ERR "/nError putting Netlink Message data into skb.../n");
goto nlmsg_failure;
}
NETLINK_CB(skb).dst_group = RTNLGRP_LINK;
strncpy(nlmsg_data(nlh), buf, size);
nlmsg_end(skb, nlh);
rtnl_notify(skb, &init_net, 0, RTNLGRP_LINK, nlh, 0);
return 0;
nlmsg_failure:
kfree_skb(skb);
return -EMSGSIZE;
}
static struct notifier_block my_dev_notifier =
{
.notifier_call = my_dev_event_handler,
};
static int __init my_init (void)
{
printk(KERN_ALERT "***IFM Module Loaded***/n");
register_netdevice_notifier (&my_dev_notifier);
return 0;
}
static void __exit my_end(void)
{
printk(KERN_ALERT "***IFM Module Unloaded***/n");
unregister_netdevice_notifier (&my_dev_notifier);
}
module_init(my_init);
module_exit(my_end);
Aplicación de espacio de usuario:
#include <asm/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <net/if.h>
#include <netinet/in.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#define MAX_PAYLOAD 1024
struct sockaddr_nl src_addr, dest_addr;
int read_event (int sockint)
{
int status;
int ret = 0;
char buf[4096];
struct iovec iov = { buf, sizeof(buf) };
struct msghdr msg = { (void *) &dest_addr, sizeof dest_addr, &iov, 1, NULL, 0, 0 };
struct nlmsghdr *h;
h = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
memset(h, 0, NLMSG_SPACE(MAX_PAYLOAD));
h->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
h->nlmsg_pid = getpid();
h->nlmsg_flags = 0;
strcpy(NLMSG_DATA(h), "Hello");
printf("Sending message to kernel/n");
sendmsg(sockint, &msg, 0);
printf("Waiting for message from kernel/n");
memset(h, 0, NLMSG_SPACE(MAX_PAYLOAD));
status = recvmsg (sockint, &msg, 0);
if (status < 0)
{
if (errno == EWOULDBLOCK || errno == EAGAIN)
return ret;
printf ("read_netlink: Error recvmsg: %d/n", status);
perror ("read_netlink: Error: ");
return status;
}
if (status == 0)
{
printf ("read_netlink: EOF/n");
}
printf("/nNo. of Bytes read : %d/n", status);
printf("Received Payload data : %s", NLMSG_DATA (h));
return ret;
}
int main (void)
{
fd_set rfds;
struct timeval tv;
int retval;
int nl_socket = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (nl_socket < 0)
{
printf ("Socket Open Error!");
exit (1);
}
memset ((void *) &src_addr, 0, sizeof (src_addr));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = getpid ();
//src_addr.nl_pid = 0;
src_addr.nl_groups = RTMGRP_LINK;
//src_addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;
if (bind (nl_socket, (struct sockaddr *) &src_addr, sizeof (src_addr)) < 0)
{
printf ("Socket bind failed!");
exit (1);
}
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.nl_family = AF_NETLINK;
dest_addr.nl_pid = 0; /* For Linux Kernel */
dest_addr.nl_groups = 0; /* unicast */
while (1)
{
FD_ZERO (&rfds);
//FD_CLR (nl_socket, &rfds);
FD_SET (nl_socket, &rfds);
tv.tv_sec = 5;
tv.tv_usec = 0;
retval = select (FD_SETSIZE, &rfds, NULL, NULL, &tv);
if (retval == -1)
printf ("Error in select() /n");
else if (retval)
{
printf ("Event received >> ");
read_event (nl_socket);
}
else
printf ("## Select Timed Out ## /n");
}
return 0;
}