我正在使用Netlink套接字通过NETLINK_ROUTE
频道向内核模块向用户空间应用程序发送有关以太网接口状态的自定义通知。我已经阅读了几篇文章和论文,但所有这些都展示了一种方法,你需要定义自己的家庭,例如NETLINK_TEST位于netlink.h
标头中或使用NETLINK_GENERIC
。我知道使用NETLINK_ROUTE的套接字已经由内核拥有,因此无法在内核模块中创建它。我无法在用户空间中收到消息。任何指导将受到高度赞赏。所以这是两个代码:
内核模块:
#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);
用户空间应用程序:
#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;
}
答案 0 :(得分:0)
我认为您应该将buf
转换为struct nlmsghdr *
,然后填写信息。
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);