Взаимодействие userspace и kernel-space через netliink сокеты
Здравствуйте, люди! Есть такое дело - организовать взаимодействие между модулем ядра и приложением, чтобы можно было в любой момент пересылать данные в обе стороны. Почитавши немного решил сделать через netlink, однако инфы маловато по этому поводу, так что есть проблемы. В общем, получился некий код, он даже частично работоспособен, однако частенько отправляет систему в корку.
Зависаем например после сообщения:knetlink_process: reply nlmsg len 1040 type 2 pid
dmesg:
knetlink_process: reply nlmsg len 1040 type 2 pid 5772
Mar 24 19:41:47 jamal kernel: [43646.512847] *pde = 00000000
Mar 24 19:41:47 jamal kernel: sys [last unloaded: scsi_wait_scan]
Mar 24 19:41:47 jamal kernel: [43646.513081]
Mar 24 19:41:47 jamal kernel: [43646.513092] Pid: 2918, comm: yakuake Not tainted (2.6.32-3-686 #1) F3Ka
Mar 24 19:41:47 jamal kernel: [43646.513103] EIP: 0060:[<c10ae892>] EFLAGS: 00010002 CPU: 0
....
Mar 24 19:41:47 jamal kernel: [43646.550269] *pde = 00000000
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <net/sock.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
DEFINE_MUTEX(mut);
#define KNETLINK_UNIT 17
static struct sock * knetlink_sk = NULL;
char data_string[] = "Hello Userspace! This is msg from Kernel";
int knetlink_process( struct sk_buff * skb, struct nlmsghdr *nlh )
{
u8 * payload = NULL;
int payload_size;
int length;
int seq;
pid_t pid;
pid = nlh->nlmsg_pid;
length = nlh->nlmsg_len;
seq = nlh->nlmsg_seq;
printk("\nknetlink_process: nlmsg len %d type %d pid %d seq %d\n",
length, nlh->nlmsg_type, pid, seq );
/* обработка полезной нагрузки */
payload_size = nlh->nlmsg_len - NLMSG_LENGTH(0);
if ( payload_size > 0 ) {
payload = NLMSG_DATA(nlh);
printk("\nknetlink_process: Payload is %s ", payload);
}
// ответ пользовательскому приложению
struct sk_buff *rskb = alloc_skb( nlh->nlmsg_len, GFP_KERNEL );
if ( rskb ) {
printk("\nknetlink_process: replies with the same socket_buffer\n");
*rskb = *skb;
} else {
printk("WTF????!!!!");
/* skb_put( rskb, length );
kfree_skb( skb ); */
}
nlh = (struct nlmsghdr *)rskb->data;
nlh->nlmsg_len = length;
nlh->nlmsg_pid = pid;
nlh->nlmsg_flags = 0;
nlh->nlmsg_type = 2;
nlh->nlmsg_seq = seq++;
payload = NLMSG_DATA( nlh );
//Частенько подвисаем после этого сообщения
printk("\nknetlink_process: reply nlmsg len %d type %d pid %d\n",
nlh->nlmsg_len, nlh->nlmsg_type, nlh->nlmsg_pid );
NETLINK_CB(rskb).pid = 0; //from kernel
netlink_unicast( knetlink_sk, rskb, pid, MSG_DONTWAIT );
return 0;
}
void knetlink_input( struct sk_buff * skb)
{
mutex_lock(&mut);
printk("\nFunction %s() called", __FUNCTION__);
netlink_rcv_skb(skb, &knetlink_process);
mutex_unlock(&mut);
}
int knetlink_init( void ) //Управление передаётся при загрузке модуля
{
if ( knetlink_sk != NULL ) {
printk("knetlink_init: sock already present\n");
return 1;
}
//struct sock * netlink_kernel_create ---- это API для создания сокета из kernel_space
knetlink_sk = netlink_kernel_create(&init_net, KNETLINK_UNIT, 0, knetlink_input, NULL, THIS_MODULE);
if ( knetlink_sk == NULL ) {
printk("knetlink_init: sock fail\n");
return 1;
}
// (void*)knetlink_sk
printk("knetlink_init: sock %p\n", knetlink_sk->sk_socket);
return 0;
}
void knetlink_exit( void )
{
mutex_lock(&mut);
if ( knetlink_sk != NULL ) {
printk("\nknetlink_exit: release sock %p\n", knetlink_sk->sk_socket);
kfree_skb( knetlink_sk);
} else {
printk("knetlink_exit: warning sock is NULL\n");
}
mutex_unlock(&mut);
}
module_init( knetlink_init );
module_exit( knetlink_exit );
MODULE_LICENSE("GPL");