[Sockets] NETLINK_ROUTE 채널을 사용하여 커널 모듈에서 사용자 응용 프로그램으로 보낸 사용자 지정 메시지를받을 수 없습니다.



Answers

Question

Netlink 소켓을 사용하여 커널 모듈에서 NETLINK_ROUTE 채널을 통해 사용자 공간 응용 프로그램으로 이더넷 인터페이스의 상태에 관한 사용자 정의 알림을 보내고 있습니다. 필자는 여러 기사와 논문을 읽었지만 모두 자신의 가족을 정의 할 필요가있는 방법을 보여줍니다. 예를 들어 netlink.h 헤더에서 netlink.h 를 사용하거나 NETLINK_GENERIC 을 사용 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;
}