2013-03-05 5 views
6

Hallo verwenden, ich habe zu versuchen, gearbeitet Netlink Buchsen für den 3.2 Linux-Kernel, zur Arbeit zu kommen, aber ich kann nicht scheinen, um herauszufinden, wie es zu tun . Ich habe nach Beispielen für die Grundlagen von Netlink Sockets gesucht, aber es scheint, dass alle Beispiele, die ich finde, für den Kernel 2.6 sind.Netlink Sockets in C den 3.X Linux-Kernel

Was ich versuche zu finden ist, wie Informationen von einem Kernel-Modul zu Benutzermodus-Anwendung und umgekehrt Netlink-Sockets senden?

Jede Hilfe würde sehr geschätzt werden. Vielen Dank!

+0

Haben Sie die Implementierung abhängig von der Kernel-Version gefunden? –

+0

Es scheint zu sein. Vieles hat sich von 2.6 auf 3.x für den Kernel-Code geändert. Speziell für Netlink von dem, was ich gefunden habe, hat sich die Art, wie Sie einen Socket im Kernel-Modus erstellen, geändert und ich kann nicht herausfinden, wie es jetzt geht. –

+0

Ein bisschen "generischer" Kernel-Code verwendet Netlink-Sockets; Beispiele sind http://lxr.free-electronics.com/source/drivers/scsi/scsi_transport_iscsi.c (die ISCSI-Transportschicht - suchen Sie nach der Variable 'nls') oder http: //lxr.free- electronics.com/source/kernel/audit.c (der Kernel-C2-Audit-Service - das gleiche gilt für 'audit_sock'), scheinen diese einen guten Hinweis darauf zu geben, wie die Netlink-Sockets verwendet werden. –

Antwort

6

Ich habe auch an der Verwendung von Netlink Sockets im Kernel gearbeitet und stieß auf die gleichen Probleme wie Sie.

Mit this previous stack overflow answer als Basis, habe ich es zum Laufen gebracht. Zwischen 3.5 und 3.6 hat sich die Funktion "netlink_kernel_create" geändert ... und ich bin auf 3.8. Der folgende Code sollte für Sie funktionieren.

netlinkKernel.c

#include <linux/module.h> 
#include <net/sock.h> 
#include <linux/netlink.h> 
#include <linux/skbuff.h> 


#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 <sys/socket.h> 
#include <linux/netlink.h> 
#include <stdlib.h> 
#include <string.h> 
#include <stdio.h> 

#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 (für 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 

Führen Sie einfach "machen", dann „gcc netlinkUser.c -o netlinkUser ", dann" sudo insmod netlinkKernel.ko ", wenn Sie" ./netlinkUser "ausführen, sollten Sie sehen, dass eine Nachricht an t gesendet wurde Das Kernel-Modul und eine Antwort wurde von der User-Space-Anwendung empfangen. Führen Sie "dmesg" im Terminal aus, nachdem Sie die vom Kernel-Modul gedruckten Debug-Meldungen sehen.

Wenn Sie weitere Fragen haben, lassen Sie es mich wissen, ich bin jetzt tief in diesem Projekt mit meinem eigenen Projekt.

+0

Was, wenn ich eine Struktur anstelle eines Zeichens senden wollte? Sollte ich copy_to_user? – alexandernst

+0

Hijavid ich brauche Ihre Hilfe zu diesem, http://StackOverflow.com/Questions/20138945/communicate-between-a-linux-Device-and-Perl-Scripts können Sie bitte helfen – user2714949