LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   A question about netlink sockets (https://www.linuxquestions.org/questions/linux-newbie-8/a-question-about-netlink-sockets-693062/)

alfrag 12-26-2008 07:13 AM

A question about netlink sockets
 
Hi all,
i'm trying to use netlink sockets to send messages from user to kernel space. I've found on the net the following code:

User space:

/******************************************************************/
/** @file netlink-u2k.c
*
* @author marco corvi <marco_corvi@geocities.com>
* @date feb 2005
*
* @brief test program for user to kernel netlink communication
*/
#include <stdio.h>
#include <string.h>
#include <sys/types.h> // socket, getpid, bind
#include <sys/socket.h> // socket, bind
#include <unistd.h> // getpid
#include <asm/types.h>
#include <linux/netlink.h>

// this value is not used in knetlink.c
#define KNETLINK 17

#define PAYLOAD_SIZE 1024

int main( int argc, char ** argv )
{
int sock;
int i, j;
unsigned char payload[PAYLOAD_SIZE]; // payload

unsigned char rpayload[PAYLOAD_SIZE]; // payload

struct msghdr msg; // message-header
struct sockaddr_nl addr; // my netlink address
struct sockaddr_nl peer; // peer address
struct nlmsghdr nlh; // netlink message header
struct iovec iov[2]; // iovec array

sock = socket( AF_NETLINK, SOCK_DGRAM, KNETLINK /* NETLINK_ARPD */ );
if ( sock < 0 ) {
perror("Socket error");
exit(1);
}

memset( &addr, 0, sizeof(addr) );
addr.nl_family = AF_NETLINK;
addr.nl_pad = 0;
addr.nl_pid = getpid();
addr.nl_groups = 0;

{ //**************** sender *****************************
printf("Sender: my pid %d\n", getpid() );
memset( &peer, 0, sizeof(peer) );

peer.nl_family = AF_NETLINK;
peer.nl_pad = 0;
peer.nl_pid = 0; // peer is the kernel
peer.nl_groups = 0; // unicast

printf("server pid %d\n", peer.nl_pid);

nlh.nlmsg_len = sizeof(nlh) + PAYLOAD_SIZE;
nlh.nlmsg_type = 5;
nlh.nlmsg_flags = 0;
nlh.nlmsg_seq = 1;
nlh.nlmsg_pid = getpid();

iov[0].iov_base = (void *)&nlh;
iov[0].iov_len = sizeof(nlh);

iov[1].iov_base = (void *)payload;
iov[1].iov_len = PAYLOAD_SIZE;

for (i=0; i<PAYLOAD_SIZE; ++i) payload[i] = i % 0xff;

msg.msg_name = (void *)&(peer);
msg.msg_namelen = sizeof(peer);
msg.msg_iov = iov;
msg.msg_iovlen = 2;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0; // flags are not used by sendmsg

if ( sendmsg( sock, &msg, 0 ) < 0 ) {
perror("Sendmsg error");
exit(1);
}

// receive the kernel reply
// memset( rpayload, 0, PAYLOAD_SIZE );
// memset( &nlh, 0, sizeof(nlh) );

iov[0].iov_base = (void *)&nlh;
iov[0].iov_len = sizeof(nlh);
iov[1].iov_base = (void *)rpayload;
iov[1].iov_len = PAYLOAD_SIZE;

memset( &msg, 0, sizeof(msg) );
msg.msg_name = (void *)&peer;
msg.msg_namelen = sizeof(peer);
msg.msg_iov = iov;
msg.msg_iovlen = 2;

if ( recvmsg( sock, &msg, 0 ) < 0 ) {
perror("Recvmsg error");
exit(1);
}
printf("recv iov %d %p\n", msg.msg_iovlen, (void *)&(msg.msg_iov) );
printf(" peer:len %d, family %d, pid %d\n",
msg.msg_namelen, peer.nl_family, peer.nl_pid );
printf(" iov size [0] %d [1] %d\n", iov[0].iov_len, iov[1].iov_len);
printf(" nl: len %d, type %d, flags %d, seq %d, pid %d\n",
nlh.nlmsg_len, nlh.nlmsg_type, nlh.nlmsg_flags,
nlh.nlmsg_seq, nlh.nlmsg_pid );

for ( i=0; i<PAYLOAD_SIZE; ++i)
if ( rpayload[i] != 0xff - (i % 0xff) ) break;
if (i == PAYLOAD_SIZE) {
printf("payload is ok \n");
} else {
printf("payload is broken at %d \n", i );
for ( j=0; j<i+5 && j<PAYLOAD_SIZE; ++j )
printf("%02x ", rpayload[j] );
}


}
close(sock);
return 0;
}
/******************************************************************/

and in kernel space:

/******************************************************************/

/** @file knetlink.c
*
* @author marco corvi <marco_corvi@geocities.com>
* @date feb 2005
*
* @brief netlink kernel module
*
* inspired and heavily taken from the article
* K. Kaichuan He, "Why and how to use netlink socket"
* Linux Journal, Feb 2005
*
*/
#ifndef __KERNEL__
# define __KERNEL__
#endif

#define __NO_VERSION__ /* don't define kernel_verion in module.h */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/net.h>
#include <net/sock.h>
#include <linux/socket.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>


#define KNETLINK_UNIT 17


static struct sock * knetlink_sk = NULL;


/** process a netlink message
* @param skb socket buffer containing the netlink message
*
* The netlink message is in skb-> data
* This function does some printout, modifies the bytes of the payload,
* and send a reply message back to the sender user process.
*/
void knetlink_process( struct sk_buff * skb )
{
int k;
struct nlmsghdr * nlh = NULL;
u8 * payload = NULL;
int payload_size;
int length;
int seq;
pid_t pid;
struct sk_buff * rskb;

/* process netlink message pointed by skb->data */
nlh = (struct nlmsghdr *)skb->data;
pid = nlh->nlmsg_pid;
length = nlh->nlmsg_len;
seq = nlh->nlmsg_seq;

printk("knetlink_process: nlmsg len %d type %d pid %d seq %d\n",
length, nlh->nlmsg_type, pid, seq );

/* process the payload */
payload_size = nlh->nlmsg_len - NLMSG_LENGTH(0);
if ( payload_size > 0 ) {
payload = NLMSG_DATA( nlh );

printk("knetlink_process: process payload ");

for (k=0; k<10; k++) printk("%02x ", payload[k]);
printk("...\n");

for ( k=0; k<payload_size; ++k)
payload[k] = 0xff - payload[k];
/* ... */
}
// reply
rskb = alloc_skb( nlh->nlmsg_len, GFP_KERNEL );

if ( rskb ) {
memcpy( rskb->data, skb->data, length );
skb_put( rskb, length );
kfree_skb( skb );
} else {
printk("knetlink_process: replies with the same socket_buffer\n");
rskb = skb;
}
nlh = (struct nlmsghdr *) rskb->data;
nlh->nlmsg_len=length;
nlh->nlmsg_pid=0; /* from kernel */
nlh->nlmsg_flags=0;
nlh->nlmsg_type=2;
nlh->nlmsg_seq=seq+1;

//NETLINK_CB(rskb).group=0;
NETLINK_CB(rskb).pid= 0;
NETLINK_CB(rskb).dst_group = 0;

//NETLINK_CB(rskb).dst_pid= pid;
payload = NLMSG_DATA( nlh );


printk("knetlink_process: reply nlmsg len %d type %d pid %d\n",
nlh->nlmsg_len, nlh->nlmsg_type, nlh->nlmsg_pid );
printk("knetlink_process: payload ");

for (k=0; k<10; k++) printk("%02x ", payload[k]);
printk("...\n");

netlink_unicast( knetlink_sk, rskb, pid, MSG_DONTWAIT );

}


/** input function
* @param sk sock (namely knetlink_sk)
* @param len length of the data on the sock
*
* Either it calls the knetlink_process (no-thread model)
* or it wakes the knetlink thread up.
*/
void knetlink_input( struct sock *sk, int len )
{
printk("knetlink_input: sock %p, len %d\n", (void*)sk, len);

if ( knetlink_sk != sk ) {
printk("knetlink_input: wrong sock %p instead of %p\n",(void *)sk, (void *)knetlink_sk );
return;
}


struct sk_buff * skb;
while ( (skb = skb_dequeue( &sk->sk_receive_queue ) ) != NULL ) {
knetlink_process(skb);
}

}

/** module init
* @return 0 on success
*
* It creates the netlink, and (in the thread model) the * knetlink thread
*/
int knetlink_init( void )
{
if ( knetlink_sk != NULL ) {
printk("knetlink_init: sock already present\n");
return 1;
}

// knetlink_sk = netlink_kernel_create( KNETLINK_UNIT, knetlink_input);

knetlink_sk=netlink_kernel_create(&init_net,KNETLINK_UNIT,1,(void*)
knetlink_input,NULL,THIS_MODULE);

if ( knetlink_sk == NULL ) {
printk("knetlink_init: sock fail\n");
return 1;
}


printk("knetlink_init: sock %p\n", (void*)knetlink_sk );
return 0;
}

/** module exit
*
* In the thread model it stops the thread,
* then it releases the knetlink sock.
*/
void knetlink_exit( void )
{

if ( knetlink_sk != NULL ) {
printk("knetlink_exit: release sock %p\n", (void*)knetlink_sk);
sock_release( knetlink_sk->sk_socket );
} else {
printk("knetlink_exit: warning sock is NULL\n");
}

}

module_init( knetlink_init );
module_exit( knetlink_exit );

MODULE_LICENSE("GPL");
MODULE_AUTHOR("marco corvi");
MODULE_DESCRIPTION("Netlink example");
/***************************************************************/


When i try these modules cat /proc/net/netlink shows:

de2ec600 17 7458 00000000 0 0 00000000 2
dea46a00 17 0 00000000 0 0 00000000 2

meaning that there are two sockets opened; one in kernel space and one in user space.

But, kernel module refuses to accept the data saying:

knetlink_input: wrong sock dea753c0 instead of dea46a00

For some reason, the user space process send data to the kernel in a wrong socket.

Any ideas?

Many thanks in advance,

Alexandros

onebuck 12-26-2008 08:48 AM

Hi,

Welcome to LQ!

You should use the vbcode tags to post long data lists like you have provided in the OP. You will find them at the top of the reply window. The '#' is for code (long lists) and the Quote balloon to the left is for 'quoting'.

What about the error message that you got, is that complete?


All times are GMT -5. The time now is 11:58 PM.