sockets - Unable to receive customized message sent from kernel module to user application using NETLINK_ROUTE channel -
i working netlink sockets send customized notifications regarding state of ethernet interface kernel module user space application on netlink_route channel. have gone through several articles , papers of them demonstrate approach need define own family e.g. netlink_test in netlink.h header or using netlink_generic. aware socket using netlink_route owned kernel 1 cannot create in kernel module. unable receive message in user space. guidance highly appreciated. here 2 codes:
kernel module:
#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 registered notifier...", ((struct net_device *) ptr)->name); break; case netdev_up: sprintf (buf, "interface:: %s , running...", ((struct net_device *) ptr)->name); break; case netdev_going_down: sprintf (buf, "interface:: %s going down...", ((struct net_device *) ptr)->name); break; case netdev_down: sprintf (buf, "interface:: %s 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 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 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); user space application:
#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 kernel\n"); sendmsg(sockint, &msg, 0); printf("waiting message 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; /* 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; }
i think mistake should cast buf struct nlmsghdr * , fill info.
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 kernel\n"); sendmsg(sockint, &msg, 0);
Comments
Post a Comment