Netlink Sockets en C utilisant le kernel Linux 3.X

Bonjour, J’ai essayé de faire fonctionner les sockets Netlink pour le kernel Linux 3.2 , mais je n’arrive pas à comprendre comment le faire. J’ai cherché des exemples des bases des sockets Netlink , mais il semble que tous les exemples que je trouve concernent le kernel 2.6.

Ce que j’essaie de trouver, c’est comment envoyer des informations d’un module de kernel à une application en mode utilisateur et inversement à l’aide de sockets Netlink?

Toute aide serait grandement appréciée. Merci!

J’ai également travaillé sur l’utilisation de sockets Netlink dans le kernel et j’ai rencontré les mêmes problèmes que vous.

En utilisant cette réponse de débordement de stack précédente comme base, j’ai réussi à le faire fonctionner. Entre 3.5 et 3.6, la fonction “netlink_kernel_create” a changé … et je suis sur 3.8. Le code suivant devrait fonctionner pour vous.

netlinkKernel.c

 #include  #include  #include  #include  #define NETLINK_USER 31 struct sock *nl_sk = NULL; static void hello_nl_recv_msg(struct sk_buff *skb) { struct nlmsghdr *nlh; int pid; struct sk_buff *skb_out; int msg_size; char *msg="Hello from kernel"; int res; printk(KERN_INFO "Entering: %s\n", __FUNCTION__); msg_size=strlen(msg); nlh=(struct nlmsghdr*)skb->data; printk(KERN_INFO "Netlink received msg payload:%s\n",(char*)nlmsg_data(nlh)); pid = nlh->nlmsg_pid; /*pid of sending process */ skb_out = nlmsg_new(msg_size,0); if(!skb_out) { printk(KERN_ERR "Failed to allocate new skb\n"); return; } nlh=nlmsg_put(skb_out,0,0,NLMSG_DONE,msg_size,0); NETLINK_CB(skb_out).dst_group = 0; /* not in mcast group */ strncpy(nlmsg_data(nlh),msg,msg_size); res=nlmsg_unicast(nl_sk,skb_out,pid); if(res<0) printk(KERN_INFO "Error while sending bak to user\n"); } static int __init hello_init(void) { printk("Entering: %s\n",__FUNCTION__); /* This is for 3.6 kernels and above. struct netlink_kernel_cfg cfg = { .input = hello_nl_recv_msg, }; nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);*/ nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, 0, hello_nl_recv_msg,NULL,THIS_MODULE); if(!nl_sk) { printk(KERN_ALERT "Error creating socket.\n"); return -10; } return 0; } static void __exit hello_exit(void) { printk(KERN_INFO "exiting hello module\n"); netlink_kernel_release(nl_sk); } module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE("GPL"); 

netlinkUser.c

 #include  #include  #include  #include  #include  #define NETLINK_USER 31 #define MAX_PAYLOAD 1024 /* maximum payload size*/ struct sockaddr_nl src_addr, dest_addr; struct nlmsghdr *nlh = NULL; struct iovec iov; int sock_fd; struct msghdr msg; int main() { sock_fd=socket(PF_NETLINK, SOCK_RAW, NETLINK_USER); if(sock_fd<0) return -1; memset(&src_addr, 0, sizeof(src_addr)); src_addr.nl_family = AF_NETLINK; src_addr.nl_pid = getpid(); /* self pid */ bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr)); memset(&dest_addr, 0, sizeof(dest_addr)); 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 */ nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD)); memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD)); nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD); nlh->nlmsg_pid = getpid(); nlh->nlmsg_flags = 0; strcpy(NLMSG_DATA(nlh), "Hello"); iov.iov_base = (void *)nlh; iov.iov_len = nlh->nlmsg_len; msg.msg_name = (void *)&dest_addr; msg.msg_namelen = sizeof(dest_addr); msg.msg_iov = &iov; msg.msg_iovlen = 1; printf("Sending message to kernel\n"); sendmsg(sock_fd,&msg,0); printf("Waiting for message from kernel\n"); /* Read message from kernel */ recvmsg(sock_fd, &msg, 0); printf("Received message payload: %s\n", (char *)NLMSG_DATA(nlh)); close(sock_fd); } 

Makefile (pour netlinkKernel.c)

 KBUILD_CFLAGS += -w obj-m += netlinkKernel.o all: make -w -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules // Make sure the indentations before these "make" lines is a tab clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 

Il suffit de lancer "make", puis "gcc netlinkUser.c -o netlinkUser", puis "sudo insmod netlinkKernel.ko", puis lorsque vous exécutez "./netlinkUser", vous devriez voir qu'un message a été envoyé au module du kernel et une réponse. a été reçu par l'application de l'espace utilisateur. Lancer "dmesg" dans le terminal après avoir vu les messages de débogage imprimés par le module du kernel.

Si vous avez plus de questions, faites le moi savoir, je suis au fond des choses maintenant avec mon propre projet.