Tuesday 7 January 2014

Socket Programming in Kernel

Here is sample code for socket programming via kernel modules.

-------------------------------------------------------------------------------------------------------------------
client.c
-------------------------------------------------------------------------------------------------------------------

#include <linux/module.h>
#include <linux/init.h>
#include <linux/in.h>
#include <net/sock.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/inet.h>
#include <linux/kthread.h>
#define MODULE_NAME "Client Module"

struct kthread_t
{
        struct task_struct *thread;
        struct sockaddr_in sock_addr;
        struct socket *sock_client;
       };

struct kthread_t *kthread;

int socket_send(struct socket *sock, struct sockaddr_in *addr, unsigned char *buf, int len)
{
        struct msghdr msg;
        struct iovec iov;
        mm_segment_t oldfs;
        int size = 0;

        if (sock->sk==NULL)
           return 0;

        iov.iov_base = buf;
        iov.iov_len = len;

        msg.msg_flags = 0;
        msg.msg_name = addr;
        msg.msg_namelen  = sizeof(struct sockaddr_in);
        msg.msg_control = NULL;
        msg.msg_controllen = 0;
        msg.msg_iov = &iov;
        msg.msg_iovlen = 1;
        msg.msg_control = NULL;

        oldfs = get_fs();
        set_fs(KERNEL_DS);
        size = sock_sendmsg(sock,&msg,len);
        set_fs(oldfs);

        return size;
}


int socket_receive(struct socket* sock, struct sockaddr_in* addr, unsigned char* buf, int len)
{
        struct msghdr msg;
        struct iovec iov;
        mm_segment_t oldfs;
        int size = 0;

        if (sock->sk==NULL) return 0;

        iov.iov_base = buf;
        iov.iov_len = len;

        msg.msg_flags = 0;
        msg.msg_name = addr;
        msg.msg_namelen  = sizeof(struct sockaddr_in);
        msg.msg_control = NULL;
        msg.msg_controllen = 0;
        msg.msg_iov = &iov;
        msg.msg_iovlen = 1;
        msg.msg_control = NULL;

        oldfs = get_fs();
        set_fs(KERNEL_DS);
        size = sock_recvmsg(sock,&msg,len,msg.msg_flags);
        set_fs(oldfs);

        return size;
}  

void socket_start(void)
        {
        int err=0,ret=0;
int bufsize = 30;
unsigned long int server_addr;
        unsigned char buf[bufsize+1];
err =sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &kthread->sock_client) ;
        if ( err <0   ){
        printk(KERN_INFO"\n Client : Socket creation failed\n");
        goto out;
        }
printk(KERN_INFO"\nClient : socket created sucessfully\n");


        memset(&kthread->sock_addr, 0, sizeof(struct sockaddr));   // ?????
        kthread->sock_addr.sin_family = AF_INET;
//server_addr = in_aton("127.0.0.1");  // local machine as server
server_addr = in_aton("172.17.27.16");  //   server ip
        kthread->sock_addr.sin_addr.s_addr =server_addr;
        kthread->sock_addr.sin_port = htons(65123);
/* ----------------conneaction Request---------------- */

      err = (kthread->sock_client->ops->connect(kthread->sock_client, (struct sockaddr *)&kthread->sock_addr, sizeof(struct sockaddr), 0) ) ;
if (err  < 0){
printk(KERN_INFO"\n Client : Socket connection failed\n");
         goto out;
}
printk(KERN_INFO"\nClient : socket connected sucessfully\n");
        memset(buf, 0, bufsize+1);
        strcat(buf, "This is client data ");
/* ----------------Send data---------------- */

        ret=socket_send(kthread->sock_client, &kthread->sock_addr, buf, strlen(buf));
printk(KERN_INFO"\n Client : retrun value from socket send is  = %d\n",ret);

ret=0;
memset(buf, 0, bufsize+1);
        /* ----------------Recieve data ---------------- */  ret = socket_receive(kthread->sock_client, &kthread->sock_addr, buf, bufsize);
printk(KERN_INFO"\n Client : retrun value from socket recieve is  = %d\n",ret);
printk(KERN_INFO"\nClient : Data received is -> %s\n",buf);


out :
printk("\nClient thread is done\n");
sock_release(kthread->sock_client);
        kthread->sock_client = NULL;      
kthread->thread = NULL;
     }



int __init socket_init(void)
        {
        printk(KERN_INFO"\n\ Client side : Module registered...\n");

        kthread = kmalloc(sizeof(struct kthread_t), GFP_KERNEL);
        memset(kthread, 0, sizeof(struct kthread_t));
kthread->thread = kthread_run((void *)socket_start, NULL, MODULE_NAME);
        if (IS_ERR(kthread->thread))
        {
                printk(KERN_INFO MODULE_NAME": unable to start kernel thread\n");
                kfree(kthread);
                kthread = NULL;
                return -ENOMEM;
        }

        return 0;
  }

void __exit socket_exit(void)
{
 printk(KERN_INFO"\nClient side : Module unregistered...\n");


if (kthread->sock_client != NULL)
        {
                sock_release(kthread->sock_client);
                kthread->sock_client = NULL;
        }
kfree(kthread);
        kthread = NULL;
}



module_init(socket_init);
module_exit(socket_exit);

/* module information */
MODULE_DESCRIPTION("kernel thread as client");
MODULE_AUTHOR("Narendra Pal ");
MODULE_LICENSE("GPL");


-----------------------------------------------------------------------------------------------------------------------
server.c
-----------------------------------------------------------------------------------------------------------------------

#include <linux/module.h>
#include <linux/init.h>
#include <linux/in.h>
#include <net/sock.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/inet.h>
#include <linux/kthread.h>
#define MODULE_NAME "Client Module"

#define CONNECT_PORT 2344
#define INADDR_SEND INADDR_LOOPBACK

struct kthread_t
{
        struct task_struct *thread;
        struct socket *sock_server;
        struct sockaddr_in addr_server;
};

struct kthread_t *kthread;
//struct socket *newsocket=NULL;

int socket_receive(struct socket* sock, struct sockaddr_in* addr, unsigned char* buf, int len)
{
        struct msghdr msg;
        struct iovec iov;
        mm_segment_t oldfs;
        int size = 0;
        
        if (sock->sk==NULL) return 0;

        iov.iov_base = buf;
        iov.iov_len = len;

        msg.msg_flags = 0;
        msg.msg_name = addr;
        msg.msg_namelen  = sizeof(struct sockaddr_in);
        msg.msg_control = NULL;
        msg.msg_controllen = 0;
        msg.msg_iov = &iov;
        msg.msg_iovlen = 1;
        msg.msg_control = NULL;

        //for access to full virtual address space and perform syscall
oldfs = get_fs();
        set_fs(KERNEL_DS);
        size = sock_recvmsg(sock,&msg,len,msg.msg_flags);
        set_fs(oldfs);
        return size;
}

int socket_send(struct socket *sock, struct sockaddr_in *addr, unsigned char *buf, int len)
{
        struct msghdr msg;
        struct iovec iov;
        mm_segment_t oldfs;
        int size = 0;

        if (sock->sk==NULL)
           return 0;

        iov.iov_base = buf;
        iov.iov_len = len;

        msg.msg_flags = 0;
        msg.msg_name = addr;
        msg.msg_namelen  = sizeof(struct sockaddr_in);
        msg.msg_control = NULL;
        msg.msg_controllen = 0;
        msg.msg_iov = &iov;
        msg.msg_iovlen = 1;
        msg.msg_control = NULL;
        oldfs = get_fs();
        set_fs(KERNEL_DS);
        size = sock_sendmsg(sock,&msg,len);
        set_fs(oldfs);

        return size;
}


void socket_start(void)
        {
        int err=0,size=0;
int confd=0;
unsigned long int server_addr;                         // for local machine
int bufsize = 30;
        unsigned char buf[bufsize+1];
struct socket *newsocket=NULL;

err =sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &kthread->sock_server) ;
if ( err <0   ){
        printk(KERN_INFO"\nServer : Socket creation failed");
        goto out;
        }
printk(KERN_INFO"\nServer : Socket created sucessfully");
memset(&kthread->addr_server, 0, sizeof(struct sockaddr));   
        kthread->addr_server.sin_family = AF_INET;
//server_addr = in_aton("127.0.0.1");           // for local machine
        //kthread->addr_server.sin_addr.s_addr=server_addr; //for local machine
kthread->addr_server.sin_addr.s_addr =INADDR_ANY;              // for other machine
        
kthread->addr_server.sin_port = htons(65123);
      err = (kthread->sock_server->ops->bind(kthread->sock_server, (struct sockaddr *)&kthread->addr_server, sizeof(struct sockaddr) ) ) ;
if (err  < 0){
printk(KERN_INFO"\nServer : Socket binding failed");
         goto out;
}
printk(KERN_INFO"\nServer : Socket binded sucessfully");
printk(KERN_INFO"\nServer : Listening on port 65123");
/* ----------------Accept conneaction---------------- */
confd=kthread->sock_server->ops->accept(kthread->sock_server,newsocket,0);
/* -----------------Receive---------------- */
memset(buf, 0, bufsize+1);
  size = socket_receive(kthread->sock_server, &kthread->addr_server, buf, bufsize);
printk(KERN_INFO"\nServer : Data received is -> %s",buf);
/* -----------------Send---------------- */
memset(buf, 0, bufsize+1);
strcpy(buf,"i am server data");
size=0;
        size=socket_send(kthread->sock_server, &kthread->addr_server, buf, strlen(buf));
        out :
printk("\nServer : Server thread is finished");
sock_release(kthread->sock_server);
        kthread->sock_server = NULL;        
kthread->thread = NULL;
}


/*--------------------module functions---------------- */


int __init socket_init(void)
        {
        printk(KERN_INFO"\n\n\nServer : Module registered");

        kthread = kmalloc(sizeof(struct kthread_t), GFP_KERNEL);
        memset(kthread, 0, sizeof(struct kthread_t));
kthread->thread = kthread_run((void *)socket_start, NULL, MODULE_NAME);
        if (IS_ERR(kthread->thread)) 
        {
                printk(KERN_INFO"\nServer : unable to start kernel thread");
                kfree(kthread);
                kthread = NULL;
                return -ENOMEM;
        }

        return 0;


                                                 
}

void __exit socket_exit(void)
{
 printk(KERN_INFO"\nServer side : Module unregistered...");

if (kthread->sock_server != NULL) 
        {
                sock_release(kthread->sock_server);
                kthread->sock_server = NULL;
        }
kfree(kthread);
        kthread = NULL;
}



module_init(socket_init);
module_exit(socket_exit);

/*-----------------module information ---------------------*/
MODULE_DESCRIPTION("kernel thread as Server");
MODULE_AUTHOR("Narendra Pal ");
MODULE_LICENSE("GPL");


----------------------------------------------------------------------------------------------------------------------
Makefile
----------------------------------------------------------------------------------------------------------------------

obj-m+=server.o
obj-m+=client.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean: 
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean