LQ Newbie
Registered: Dec 2008
Posts: 3
Rep:
|
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
|