Linux-kernel

Fork me on GitHub

I. Linux kernel articles

7. Sockets

I'm gonna write a tutorial on kernel sockets. A source code of mine is available here and here:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

#include <linux/kthread.h>
#include <linux/mutex.h>
#include <linux/semaphore.h>

#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/types.h>

#include <linux/netdevice.h>
#include <linux/ip.h>
#include <linux/in.h>

#define _bswap_16(x) ((unsigned short)(_builtin_bswap32(x) >> 16))

MODULE_LICENSE("Dual BSD/GPL");

#define PORT 1111
#define SERVER_ADDR "192.168.37.138"
struct task_struct *kthread = NULL;
struct mutex mutex;
struct socket *sock = NULL;

static char *init_msg = "Init message";
static int  size_init_msg = 13;
static char *exit_msg = "Exit message";
static int  size_exit_msg = 13;

static void convert_from_addr(const char *addr, unsigned char nbs[4])
{
    int i;
    int value;
    int pos;

    for (i = 0, pos = 0; addr[i] && pos < 4; ++i)
    {
        for (value = 0; addr[i] && addr[i] != '.'; ++i) {
            value *= 10;
            value += addr[i] - '0';
        }
        nbs[pos++] = value;
        if (!addr[i])
            return;
    }
}

static int send_msg(unsigned char *buf, int len)
{
    struct msghdr msg = {0};
    struct iovec iov;
    mm_segment_t oldfs;
    int size = 0;

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

    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

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

    if (size < 0)
        printk("thug_write_to_socket: sock_sendmsg error: %d\n", size);

    return size;
}

static int my_connect(struct socket **s, const char *s_addr)
{
    struct sockaddr_in address = {0};
    int len = sizeof(struct sockaddr_in), ret;
    unsigned char i_addr[4] = {0};
    if ((ret = sock_create(AF_INET, SOCK_STREAM, IPPROTO_TCP, s)) < 0)
    {
        printk("echo_server: sock_create error");
        return ret;
    }
    convert_from_addr(s_addr, i_addr);
    address.sin_addr.s_addr = *(unsigned int*)i_addr;
    address.sin_port = htons(PORT);
    address.sin_family = AF_INET;
    if ((ret = (*s)->ops->connect(sock, (struct sockaddr*)&address, len, 0)) < 0)
    {
        sock_release(*s);
        *s = NULL;
    }
    return ret;
}

static int echo_server_init(void)
{
    int ret;

    if ((ret = my_connect(&sock, "127.0.0.1")) < 0)
    {
        printk("echo_server: connect error");
        return ret;
    }
    printk(KERN_ALERT "echo-server is on !\n");  
    send_msg(init_msg, size_init_msg);
    return 0;
}

static void echo_server_exit(void)
{
    send_msg(exit_msg, size_exit_msg);
    if (sock != NULL)
    {
        sock_release(sock);
        sock = NULL;
    }   
    printk(KERN_ALERT "echo-server is now ending\n");
}

module_init(echo_server_init);

module_exit(echo_server_exit);