Ho lavorato anche all'utilizzo di socket Netlink nel kernel e ho avuto gli stessi problemi.
Utilizzando come base this previous stack overflow answer, sono riuscito a farlo funzionare. Tra 3,5 e 3,6 la funzione "netlink_kernel_create" è cambiata ... e io sono in 3.8. Il seguente codice dovrebbe funzionare per te.
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 (per 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
basta eseguire "fare", poi "netlinkUser.c gcc -o netlinkUser ", quindi" sudo insmod netlinkKernel.ko ", quindi quando si esegue" ./netlinkUser "si dovrebbe vedere che un messaggio è stato inviato a t Il modulo del kernel e una risposta sono stati ricevuti dall'applicazione dello spazio utente. Eseguendo "dmesg" nel terminale dopo vedrai i messaggi di debug stampati dal modulo del kernel.
Se hai altre domande, fammi sapere, mi trovo al ginocchio in questo momento con il mio progetto.
Hai trovato che l'implementazione dipende dalla versione del kernel? –
Sembra essere. Molto cambiato da 2.6 a 3.x per il codice del kernel in generale. Specifico per Netlink da quello che ho trovato, il modo in cui si crea un socket in modalità kernel è cambiato e non riesco a scoprire come farlo ora. –
Un po 'di codice del kernel "generico" utilizza socket netlink; esempi sono http://lxr.free-electrons.com/source/drivers/scsi/scsi_transport_iscsi.c (il livello di trasporto ISCSI - cerca l'uso della variabile 'nls'), o http: //lxr.free- electrons.com/source/kernel/audit.c (il servizio di revisione del kernel C2 - lo stesso per 'audit_sock'), sembrano dare una buona indicazione di come vengono utilizzati i socket netlink. –