#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>

#include <linux/types.h>

#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>

#define __USE_LARGEFILE64
#include <fcntl.h>

#include "bd.h"
#include "bd_fd.h"
#include "bd_acrypto.h"
#include "../crypto/crypto_def.h"

#define ulog(f, a...) fprintf(stderr, f, ##a)
struct table;

struct self
{
        char            device[BD_MAX_NAMESIZ];
        char            filter[BD_MAX_NAMESIZ];
};

struct table
{
        int             idx;
        char            name[BD_MAX_NAMESIZ];
        int             (* handler)(struct table *tblp, char *argv[], int argc);
        int             argc;

        struct self     *self;
};

struct param
{
        int             found;
        char            name[BD_MAX_NAMESIZ];
        char            *val;
};

#define walk_through_table(tblp, tbl, i) \
        for (i=sizeof(tbl)/sizeof(tbl[0])-1, tblp=&tbl[i]; i; --i, 
tblp=&tbl[i]) \

static struct self generic_self;

static int default_action_handler(struct table *tblp, char *argv[], int argc);
static int bind_action_handler(struct table *tblp, char *argv[], int argc);
static int unbind_action_handler(struct table *tblp, char *argv[], int argc);

static struct table action_table[] = 
{
        {0,     "default",      default_action_handler,         0,      
&generic_self},
        {0,     "bind",         bind_action_handler,            5,      
&generic_self},
        {0,     "unbind",       unbind_action_handler,          5,      
&generic_self},
};

static int fd_action_handler(struct table *tblp, char *argv[], int argc);
static int acrypto_action_handler(struct table *tblp, char *argv[], int argc);
static struct table bind_table[] = 
{
        {0,     "default",      default_action_handler,         0,      
&generic_self},
        {0,     "fd",           fd_action_handler,              2,      
&generic_self},
        {0,     "acrypto",      acrypto_action_handler,         10,     
&generic_self},
};

static int run_cmd(int fd, int request, void *arg)
{
        int err;

        err = ioctl(fd, request, arg);
        if (err)
        {
                ulog("Failed to make %d request : %s [%d].\n", 
                                request, strerror(errno), errno);
                return err;
        }

        return 0;
}

static int scmp(char *str1, char *str2)
{
        int l1, l2;

        l1 = strlen(str1);
        l2 = strlen(str2);

        if (l1 > l2)
                return strncmp(str1, str2, l2);
        else
                return strncmp(str1, str2, l1);
}

static int default_action_handler(struct table *tblp __attribute__((unused)), 
char *argv[], int argc __attribute__((unused)))
{
        ulog("Unsupported action \"%s\".\n", argv[0]);

        return -1;
}

static int generic_action_handler(char *argv[])
{
        if (scmp(argv[1], "dev"))
        {
                ulog("Unsupported \"%s\" parameter in \"%s\" action.\n", 
argv[1], argv[0]);
                return -1;
        }
        
        snprintf(generic_self.device, sizeof(generic_self.device), "%s", 
argv[2]);

        if (scmp(argv[3], "filter"))
        {
                ulog("Unsupported \"%s\" parameter in \"%s\" action.\n", 
argv[3], argv[0]);
                return -1;
        }

        snprintf(generic_self.filter, sizeof(generic_self.filter), "%s", 
argv[4]);
        
        //ulog("filter=%s, device=%s.\n", generic_self.filter, 
generic_self.device);

        return 0;
}

static int bind_action_handler(struct table *tblp, char *argv[], int argc)
{
        struct table *p;
        int err, i, fd;
        struct bd_user u;
        
        err = generic_action_handler(argv);
        if (err)
                return err;

        argc -= tblp->argc;
        argv += tblp->argc-1;

        //ulog("%s: argv[0]=%s, argc=%d.\n", __func__, argv[0], argc);

        walk_through_table(p, bind_table, i)
        {
                //ulog("i=%d, argc=%d, cnt=%d, name=%s.\n", i, argc, p->argc, 
p->name);

                if (argc < p->argc)
                        continue;

                if (!scmp(p->name, argv[0]))
                {
                        err = p->handler(p, argv, argc);
                        return err;
                }
        }
        
        fd = open(tblp->self->device, O_RDWR | O_LARGEFILE);
        if (fd == -1)
        {
                ulog("Failed to open device file %s when binding filter %s: %s 
[%d].\n",
                                tblp->self->device, tblp->self->filter,
                                strerror(errno), errno);
                return -errno;
        }

        strcpy(u.name, tblp->self->filter);
        u.size = 0;
        
        err = run_cmd(fd, BD_BIND_FILTER, &u);

        return err;
}

static int unbind_action_handler(struct table *tblp, char *argv[], int argc 
__attribute__((unused)))
{
        int err, fd;
        struct bd_user u;
        
        err = generic_action_handler(argv);
        if (err)
                return err;

        fd = open(tblp->self->device, O_RDWR | O_LARGEFILE);
        if (fd == -1)
        {
                ulog("Failed to open device file %s when binding filter %s: %s 
[%d].\n",
                                tblp->self->device, tblp->self->filter,
                                strerror(errno), errno);
                return -errno;
        }

        strcpy(u.name, tblp->self->filter);
        u.size = 0;
        
        err = run_cmd(fd, BD_UNBIND_FILTER, &u);

        return err;
}

static int fd_action_handler(struct table *tblp, char *argv[], int argc 
__attribute__((unused)))
{
        int err, fd, len, tfd;
        char name[BD_MAX_NAMESIZ];
        char buf[128];
        struct bd_user *u;
        struct bd_fd_user *fdu;
                
        if (scmp(argv[1], "file"))
        {
                ulog("Unsupported \"%s\" parameter in \"%s\" action.\n", 
argv[1], argv[0]);
                return -1;
        }

        len = snprintf(name, sizeof(name), "%s", argv[2]);

        fd = open(tblp->self->device, O_RDWR | O_LARGEFILE);
        if (fd == -1)
        {
                ulog("Failed to open device file %s when binding filter %s: %s 
[%d].\n",
                                tblp->self->device, tblp->self->filter,
                                strerror(errno), errno);
                return -errno;
        }

        tfd = open(name, O_RDWR | O_LARGEFILE);
        if (tfd == -1)
        {
                ulog("Failed to open target file %s: %s [%d].\n",
                                name, strerror(errno), errno);
                close(fd);
                return -errno;
        }

        u = (struct bd_user *)buf;
        fdu = (struct bd_fd_user *)(u+1);
        
        strcpy(u->name, tblp->self->filter);
        u->size = sizeof(*fdu);
        fdu->fd = tfd;
        
        err = run_cmd(fd, BD_BIND_FILTER, u);
        if (err)
                ulog("Failed to bind filter %s to device %s: err=%d.\n",
                                tblp->self->filter, tblp->self->device, err);

        close(tfd);
        close(fd);
        
        //ulog("%s: len=%d, name=%s, err=%d.\n", __func__, len, name, err);

        
        return err;
}

static int acrypto_action_handler(struct table *tblp, char *argv[], int argc)
{
        struct param args[] = {
                {0,     "cipher",       NULL},
                {0,     "key",          NULL},
                {0,     "iv",           NULL},
                {0,     "priority",     NULL},
                {0,     "mode",         NULL},
        };
        int i, j, found, sz, fd, err;
        char buf[128];
        struct bd_user *u;
        struct bd_acrypto_private *a;
        
        memset(buf, 0, sizeof(buf));

        u = (struct bd_user *)buf;
        a = (struct bd_acrypto_private *)(u+1);

        found = 0;
        for (i=0; i<(signed)(sizeof(args)/sizeof(args[0])); ++i)
        {
                for (j=1; j<argc; j+=2)
                {
                        if (scmp(args[i].name, argv[j]))
                                continue;

                        if (args[i].found)
                        {
                                ulog("dev=%s, filter=%s: parameter \"%s\" 
already found in \"%s\", ignoring.\n",
                                                tblp->self->device, 
tblp->self->filter, 
                                                args[i].name, argv[0]);
                                continue;
                        }

                        args[i].found = 1;
                        found++;

                        args[i].val = argv[j+1];
                }
        }

        if (found != sizeof(args)/sizeof(args[0]))
        {
                ulog("dev=%s, filter=%s: wrong parameters set: found=%d, 
sz=%u.\n", 
                                tblp->self->device, tblp->self->filter,
                                found, sizeof(args)/sizeof(args[0]));
                return -1;
        }

        if (!scmp(args[0].val, "aes128"))
                a->type = CRYPTO_TYPE_AES_128;
        else if (!scmp(args[0].val, "aes192"))
                a->type = CRYPTO_TYPE_AES_192;
        else if (!scmp(args[0].val, "aes256"))
                a->type = CRYPTO_TYPE_AES_256;
        else if (!scmp(args[0].val, "3des"))
                a->type = CRYPTO_TYPE_3DES;
        else
        {
                ulog("dev=%s, filter=%s: unsupported cipher \"%s\".\n", 
tblp->self->device, tblp->self->filter, args[0].val);
                return -1;
        }

        if (!scmp(args[4].val, "ecb"))
                a->mode = CRYPTO_MODE_ECB;
        else if (!scmp(args[4].val, "cbc"))
                a->mode = CRYPTO_MODE_CBC;
        else if (!scmp(args[4].val, "cfb"))
                a->mode = CRYPTO_MODE_CFB;
        else if (!scmp(args[4].val, "ofb"))
                a->mode = CRYPTO_MODE_OFB;
        else
        {
                ulog("dev=%s, filter=%s: unsupported mode \"%s\".\n", 
tblp->self->device, tblp->self->filter, args[4].val);
                return -1;
        }

        a->priority = (__u16)(atoi(args[3].val) & 0xffff);

        sz = (signed)strlen(args[1].val)/2;
        if (sz % 2 != 0 || sz > (signed)sizeof(a->key))
        {
                ulog("dev=%s, filter=%s: wrong length of the \"%s\".\n", 
tblp->self->device, tblp->self->filter, args[1].val);
                return -1;
        }

        
        j = 0;
        for (i=0; i<(signed)strlen(args[1].val)-1; i+=2)
        {
                unsigned char v[2] = {args[1].val[i], args[1].val[i+1]};
                unsigned char val;

                val = (unsigned char)(strtol(v, NULL, 16) & 0xff);

                a->key[j++] = val;
        }

        a->key_size = j;
        
        sz = (signed)strlen(args[2].val)/2;
        if (sz % 2 != 0 || sz > (signed)sizeof(a->iv))
        {
                ulog("dev=%s, filter=%s: wrong length of the \"%s\".\n", 
tblp->self->device, tblp->self->filter, args[2].val);
                return -1;
        }
        j = 0;
        for (i=0; i<(signed)strlen(args[2].val)-1; i+=2)
        {
                unsigned char v[2] = {args[2].val[i], args[2].val[i+1]};
                unsigned char val;

                val = (unsigned char)(strtol(v, NULL, 16) & 0xff);

                a->iv[j++] = val;
        }
        
        a->iv_size = j;

        ulog("dev=%s, filter=%s: cipher=%s, mode=%s, priority=%d, key_size=%u, 
iv_size=%u.\n", 
                        tblp->self->device, tblp->self->filter, args[0].val, 
args[4].val, a->priority,
                        a->key_size, a->iv_size);


        fd = open(tblp->self->device, O_RDWR | O_LARGEFILE);
        if (fd == -1)
        {
                ulog("Failed to open device file %s when binding filter %s: %s 
[%d].\n",
                                tblp->self->device, tblp->self->filter,
                                strerror(errno), errno);
                return -errno;
        }
        
        strcpy(u->name, tblp->self->filter);
        u->size = sizeof(*a);
        
        err = run_cmd(fd, BD_BIND_FILTER, u);
        if (err)
                ulog("Failed to bind filter %s to device %s: err=%d.\n",
                                tblp->self->filter, tblp->self->device, err);

        close(fd);
        
        return err;
}

int main(int argc, char *argv[])
{
        int i, err;
        struct table *atp;

        argc--;
        argv++;

        walk_through_table(atp, action_table, i)
        {
                if (argc < action_table[i].argc)
                        continue;
                
                //ulog("i=%d, argc=%d, cnt=%d, name=%s.\n", i, argc, atp->argc, 
atp->name);
                
                if (!scmp(argv[0], atp->name))
                {
                        err = atp->handler(atp, argv, argc);
                        return err;
                }
        }
        
        return action_table[0].handler(&action_table[0], argv, argc);
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to