diff -Nru /tmp/empty/acrypto.h linux-2.6/drivers/acrypto/acrypto.h --- /tmp/empty/acrypto.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/acrypto.h 2004-12-14 18:53:11.000000000 +0300 @@ -0,0 +1,226 @@ +/* + * acrypto.h + * + * Copyright (c) 2004 Evgeniy Polyakov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ACRYPTO_H +#define __ACRYPTO_H + +#define SCACHE_NAMELEN 32 + +struct crypto_session_initializer; +struct crypto_data; +typedef void (*crypto_callback_t) (struct crypto_session_initializer *, + struct crypto_data *); + +extern void crypto_wake_lb(void); + +#define SESSION_COMPLETED (1<<15) +#define SESSION_FINISHED (1<<14) +#define SESSION_STARTED (1<<13) +#define SESSION_PROCESSED (1<<12) +#define SESSION_BINDED (1<<11) +#define SESSION_BROKEN (1<<10) + +#define session_completed(s) (s->ci.flags & SESSION_COMPLETED) +#define complete_session(s) do {s->ci.flags |= SESSION_COMPLETED;} while(0) +#define uncomplete_session(s) do {s->ci.flags &= ~SESSION_COMPLETED;} while (0) + +#define session_finished(s) (s->ci.flags & SESSION_FINISHED) +#define finish_session(s) do {s->ci.flags |= SESSION_FINISHED;} while(0) +#define unfinish_session(s) do {s->ci.flags &= ~SESSION_FINISHED;} while (0) + +#define session_started(s) (s->ci.flags & SESSION_STARTED) +#define start_session(s) do {s->ci.flags |= SESSION_STARTED;} while(0) +#define unstart_session(s) do {s->ci.flags &= ~SESSION_STARTED;} while (0) + +#define session_is_processed(s) (s->ci.flags & SESSION_PROCESSED) +#define start_process_session(s) do {s->ci.flags |= SESSION_PROCESSED; s->ci.ptime = jiffies;} while(0) +#define stop_process_session(s) do {s->ci.flags &= ~SESSION_PROCESSED; s->ci.ptime = jiffies - s->ci.ptime; crypto_wake_lb();} while (0) + +#define session_binded(s) (s->ci.flags & SESSION_BINDED) +#define bind_session(s) do {s->ci.flags |= SESSION_BINDED;} while(0) +#define unbind_session(s) do {s->ci.flags &= ~SESSION_BINDED;} while (0) +#define sci_binded(ci) (ci->flags & SESSION_BINDED) + +#define session_broken(s) (s->ci.flags & SESSION_BROKEN) +#define broke_session(s) do {s->ci.flags |= SESSION_BROKEN;} while(0) +#define unbroke_session(s) do {s->ci.flags &= ~SESSION_BROKEN;} while (0) + +struct crypto_device_stat { + __u64 scompleted; + __u64 sfinished; + __u64 sstarted; + __u64 kmem_failed; +}; + +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include +#include + +#include + +#define DEBUG +#ifdef DEBUG +#define dprintk(f, a...) printk("%d " f, smp_processor_id(), ##a) +#else +#define dprintk(f, a...) +#endif + +#define CRYPTO_MAX_PRIV_SIZE 1024 + +#define DEVICE_BROKEN (1<<0) + +#define device_broken(dev) (dev->flags & DEVICE_BROKEN) +#define broke_device(dev) do {dev->flags |= DEVICE_BROKEN;} while(0) +#define repair_device(dev) do {dev->flags &= ~DEVICE_BROKEN;} while(0) + +struct crypto_capability { + u16 operation; + u16 type; + u16 mode; + u16 qlen; + u64 ptime; + u64 scomp; +}; + +struct crypto_session_initializer { + u16 operation; + u16 type; + u16 mode; + u16 priority; + + u64 id; + u64 dev_id; + + u32 flags; + + u32 bdev; + + u64 ptime; + + crypto_callback_t callback; +}; + +struct crypto_data { + int sg_src_num; + struct scatterlist sg_src; + struct scatterlist sg_dst; + struct scatterlist sg_key; + struct scatterlist sg_iv; + + void *priv; + unsigned int priv_size; +}; + +struct crypto_device { + char name[SCACHE_NAMELEN]; + + spinlock_t session_lock; + struct list_head session_list; + + u64 sid; + spinlock_t lock; + + atomic_t refcnt; + + u32 flags; + + u32 id; + + struct list_head cdev_entry; + + void (*data_ready)(struct crypto_device *); + + struct device_driver *driver; + struct device device; + struct class_device class_device; + struct completion dev_released; + + spinlock_t stat_lock; + struct crypto_device_stat stat; + + struct crypto_capability *cap; + int cap_number; + + void *priv; +}; + +struct crypto_route_head { + struct crypto_route *next; + struct crypto_route *prev; + + __u32 qlen; + spinlock_t lock; +}; + +struct crypto_route { + struct crypto_route *next; + struct crypto_route *prev; + + struct crypto_route_head *list; + struct crypto_device *dev; + + struct crypto_session_initializer ci; +}; + +struct crypto_session { + struct list_head dev_queue_entry; + struct list_head main_queue_entry; + + struct crypto_session_initializer ci; + + struct crypto_data data; + + spinlock_t lock; + + struct work_struct work; + + struct crypto_route_head route_list; +}; + +struct crypto_session *crypto_session_alloc(struct crypto_session_initializer *, struct crypto_data *); +struct crypto_session *crypto_session_create(struct crypto_session_initializer *, struct crypto_data *); +void crypto_session_add(struct crypto_session *); +void crypto_session_dequeue_main(struct crypto_session *); +void __crypto_session_dequeue_main(struct crypto_session *); +void __crypto_session_dequeue_route(struct crypto_session *); +void crypto_session_dequeue_route(struct crypto_session *); + +void crypto_device_get(struct crypto_device *); +void crypto_device_put(struct crypto_device *); +struct crypto_device *crypto_device_get_name(char *); + +int __crypto_device_add(struct crypto_device *); +int crypto_device_add(struct crypto_device *); +void __crypto_device_remove(struct crypto_device *); +void crypto_device_remove(struct crypto_device *); +int match_initializer(struct crypto_device *, struct crypto_session_initializer *); +int __match_initializer(struct crypto_capability *, struct crypto_session_initializer *); + +void crypto_session_insert_main(struct crypto_device *dev, struct crypto_session *s); +void crypto_session_insert(struct crypto_device *dev, struct crypto_session *s); + +#endif /* __KERNEL__ */ +#endif /* __ACRYPTO_H */ diff -Nru /tmp/empty/.arch-ids/acrypto.h.id linux-2.6/drivers/acrypto/.arch-ids/acrypto.h.id --- /tmp/empty/.arch-ids/acrypto.h.id 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/.arch-ids/acrypto.h.id 2004-12-14 17:50:04.000000000 +0300 @@ -0,0 +1 @@ +Evgeniy Polyakov Sun Oct 3 20:33:25 2004 2957.0 diff -Nru /tmp/empty/.arch-ids/consumer.c.id linux-2.6/drivers/acrypto/.arch-ids/consumer.c.id --- /tmp/empty/.arch-ids/consumer.c.id 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/.arch-ids/consumer.c.id 2004-12-14 17:50:04.000000000 +0300 @@ -0,0 +1 @@ +Evgeniy Polyakov Wed Oct 6 02:34:04 2004 4902.0 diff -Nru /tmp/empty/.arch-ids/crypto_conn.c.id linux-2.6/drivers/acrypto/.arch-ids/crypto_conn.c.id --- /tmp/empty/.arch-ids/crypto_conn.c.id 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/.arch-ids/crypto_conn.c.id 2004-12-14 17:50:04.000000000 +0300 @@ -0,0 +1 @@ +Evgeniy Polyakov Wed Oct 6 03:19:44 2004 5558.0 diff -Nru /tmp/empty/.arch-ids/crypto_conn.h.id linux-2.6/drivers/acrypto/.arch-ids/crypto_conn.h.id --- /tmp/empty/.arch-ids/crypto_conn.h.id 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/.arch-ids/crypto_conn.h.id 2004-12-14 17:50:04.000000000 +0300 @@ -0,0 +1 @@ +Evgeniy Polyakov Wed Oct 6 03:19:44 2004 5558.1 diff -Nru /tmp/empty/.arch-ids/crypto_def.h.id linux-2.6/drivers/acrypto/.arch-ids/crypto_def.h.id --- /tmp/empty/.arch-ids/crypto_def.h.id 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/.arch-ids/crypto_def.h.id 2004-12-14 17:50:04.000000000 +0300 @@ -0,0 +1 @@ +Evgeniy Polyakov Tue Oct 26 20:26:53 2004 2903.0 diff -Nru /tmp/empty/.arch-ids/crypto_dev.c.id linux-2.6/drivers/acrypto/.arch-ids/crypto_dev.c.id --- /tmp/empty/.arch-ids/crypto_dev.c.id 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/.arch-ids/crypto_dev.c.id 2004-12-14 17:50:04.000000000 +0300 @@ -0,0 +1 @@ +Evgeniy Polyakov Sun Oct 3 22:27:13 2004 4211.0 diff -Nru /tmp/empty/.arch-ids/crypto_lb.c.id linux-2.6/drivers/acrypto/.arch-ids/crypto_lb.c.id --- /tmp/empty/.arch-ids/crypto_lb.c.id 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/.arch-ids/crypto_lb.c.id 2004-12-14 17:50:04.000000000 +0300 @@ -0,0 +1 @@ +Evgeniy Polyakov Sun Oct 3 22:27:09 2004 4210.0 diff -Nru /tmp/empty/.arch-ids/crypto_lb.h.id linux-2.6/drivers/acrypto/.arch-ids/crypto_lb.h.id --- /tmp/empty/.arch-ids/crypto_lb.h.id 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/.arch-ids/crypto_lb.h.id 2004-12-14 17:50:04.000000000 +0300 @@ -0,0 +1 @@ +Evgeniy Polyakov Sun Oct 3 22:27:09 2004 4210.1 diff -Nru /tmp/empty/.arch-ids/crypto_main.c.id linux-2.6/drivers/acrypto/.arch-ids/crypto_main.c.id --- /tmp/empty/.arch-ids/crypto_main.c.id 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/.arch-ids/crypto_main.c.id 2004-12-14 17:50:04.000000000 +0300 @@ -0,0 +1 @@ +Evgeniy Polyakov Sun Oct 3 20:28:05 2004 2950.1 diff -Nru /tmp/empty/.arch-ids/crypto_route.h.id linux-2.6/drivers/acrypto/.arch-ids/crypto_route.h.id --- /tmp/empty/.arch-ids/crypto_route.h.id 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/.arch-ids/crypto_route.h.id 2004-12-14 17:50:04.000000000 +0300 @@ -0,0 +1 @@ +Evgeniy Polyakov Tue Oct 12 19:25:27 2004 2518.0 diff -Nru /tmp/empty/.arch-ids/crypto_stat.c.id linux-2.6/drivers/acrypto/.arch-ids/crypto_stat.c.id --- /tmp/empty/.arch-ids/crypto_stat.c.id 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/.arch-ids/crypto_stat.c.id 2004-12-14 17:50:04.000000000 +0300 @@ -0,0 +1 @@ +Evgeniy Polyakov Thu Oct 7 23:08:48 2004 4384.0 diff -Nru /tmp/empty/.arch-ids/crypto_stat.h.id linux-2.6/drivers/acrypto/.arch-ids/crypto_stat.h.id --- /tmp/empty/.arch-ids/crypto_stat.h.id 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/.arch-ids/crypto_stat.h.id 2004-12-14 17:50:04.000000000 +0300 @@ -0,0 +1 @@ +Evgeniy Polyakov Thu Oct 7 23:08:48 2004 4384.1 diff -Nru /tmp/empty/.arch-ids/Makefile.id linux-2.6/drivers/acrypto/.arch-ids/Makefile.id --- /tmp/empty/.arch-ids/Makefile.id 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/.arch-ids/Makefile.id 2004-12-14 17:50:04.000000000 +0300 @@ -0,0 +1 @@ +Evgeniy Polyakov Sun Oct 3 20:28:05 2004 2950.0 diff -Nru /tmp/empty/.arch-ids/provider.c.id linux-2.6/drivers/acrypto/.arch-ids/provider.c.id --- /tmp/empty/.arch-ids/provider.c.id 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/.arch-ids/provider.c.id 2004-12-14 17:50:04.000000000 +0300 @@ -0,0 +1 @@ +Evgeniy Polyakov Wed Oct 6 02:34:04 2004 4902.1 diff -Nru /tmp/empty/.arch-ids/sha1_provider.c.id linux-2.6/drivers/acrypto/.arch-ids/sha1_provider.c.id --- /tmp/empty/.arch-ids/sha1_provider.c.id 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/.arch-ids/sha1_provider.c.id 2004-12-14 17:50:04.000000000 +0300 @@ -0,0 +1 @@ +Evgeniy Polyakov Wed Oct 20 20:26:53 2004 25654.0 diff -Nru /tmp/empty/.arch-ids/simple_lb.c.id linux-2.6/drivers/acrypto/.arch-ids/simple_lb.c.id --- /tmp/empty/.arch-ids/simple_lb.c.id 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/.arch-ids/simple_lb.c.id 2004-12-14 17:50:04.000000000 +0300 @@ -0,0 +1 @@ +Evgeniy Polyakov Mon Oct 4 00:58:07 2004 4691.0 diff -Nru /tmp/empty/consumer.c linux-2.6/drivers/acrypto/consumer.c --- /tmp/empty/consumer.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/consumer.c 2004-12-14 18:53:11.000000000 +0300 @@ -0,0 +1,288 @@ +/* + * consumer.c + * + * Copyright (c) 2004 Evgeniy Polyakov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG +#include "acrypto.h" +#include "crypto_def.h" +#include "via-padlock/padlock.h" + +#undef dprintk +#define dprintk(f, a...) do {} while(0) + +#define KEY_LENGTH 16 +static char ckey[KEY_LENGTH]; +static int key_length = sizeof(ckey); + +static void ctest_callback(struct crypto_session_initializer *ci, + struct crypto_data *data); + +static struct crypto_session_initializer ci = { + .operation = CRYPTO_OP_ENCRYPT, + .type = CRYPTO_TYPE_AES_128, + .mode = CRYPTO_MODE_ECB, + .priority = 4, + .callback = ctest_callback, +}; + +static struct crypto_data cdata; + +#define CSESSION_MAX 1000 +static struct crypto_session *s; +static int watermark; +//static struct completion callback_completed; +static struct timer_list ctimer; + +static void ctest_callback(struct crypto_session_initializer *ci, + struct crypto_data *data) +{ + int i, off, size, ssize; + struct scatterlist *sg; + unsigned char *ptr; + + watermark--; + + printk("%s: session %llu [%llu]\n", __func__, ci->id, ci->dev_id); + dprintk("src=%s, len=%d.\n", + ((char *)page_address(data->sg_src.page)) + data->sg_src.offset, + data->sg_src.length); + + sg = &data->sg_key; + ptr = (unsigned char *)page_address(sg->page); + off = sg->offset; + size = sg->length; + + if (size > 16) { + dprintk("key sg is broken, size=%d.\n", size); + goto err_out; + } + + dprintk("key[%d]=", size); + for (i = 0; i < size; ++i) + dprintk("0x%02x, ", ptr[i + off]); + dprintk("\n"); + + sg = &data->sg_src; + ptr = (unsigned char *)page_address(sg->page); + off = sg->offset; + ssize = size = sg->length; + if (size > 32) { + dprintk("src sg is broken, size=%d.\n", size); + goto err_out; + } + + dprintk("src[%d]=", size); + for (i = 0; i < size; ++i) + dprintk("0x%02x, ", ptr[i + off]); + dprintk("\n"); + + sg = &data->sg_dst; + ptr = (unsigned char *)page_address(sg->page); + off = sg->offset; + size = sg->length; + if (size > 32) { + dprintk("dst sg is broken, size=%d.\n", size); + goto err_out; + } + + if (size == 0) { + dprintk("size=0, setting to %d.\n", ssize); + size = ssize; + } + + dprintk("dst[%d]=", size); + for (i = 0; i < size; ++i) + dprintk("0x%02x, ", ptr[i + off]); + dprintk("\n"); + +err_out: + //complete(&callback_completed); + return; +} + +int ctimer_func(void *data, int size, int op) +{ + u8 *ptr; + + if (size > PAGE_SIZE) + size = PAGE_SIZE; + + ptr = (u8 *)page_address(cdata.sg_src.page) + cdata.sg_src.offset; + memcpy(ptr, data, size); + cdata.sg_src.length = size; + cdata.sg_dst.length = size; + + ci.operation = op; + s = crypto_session_alloc(&ci, &cdata); + if (s) + watermark++; + else + dprintk("allocation failed.\n"); + + return (s) ? 0 : -EINVAL; +} + +static int alloc_sg(struct scatterlist *sg, void *data, int size) +{ + sg->offset = 0; + sg->page = alloc_pages(GFP_KERNEL, get_order(size)); + if (!sg->page) { + printk(KERN_ERR "Failed to allocate page.\n"); + return -ENOMEM; + } + + memset(page_address(sg->page), 0, PAGE_SIZE); + + if (data) + memcpy(page_address(sg->page), data, size); + + sg->length = size; + + return 0; +} + +static void ctimerf(unsigned long data) +{ + char str[] = "test message qwerty asdzxc\n"; + int size = sizeof(str), err; + + printk("%s started\n", __func__); + + err = ctimer_func(str, size, CRYPTO_OP_ENCRYPT); + + if (!err) + mod_timer(&ctimer, jiffies + 3); + else + mod_timer(&ctimer, jiffies + HZ); + + printk("%s finished.\n", __func__); +} + +int consumer_init(void) +{ + int err; + + cdata.sg_src_num = 1; + + err = alloc_sg(&cdata.sg_src, NULL, PAGE_SIZE); + if (err) + goto err_out_return; + + err = alloc_sg(&cdata.sg_dst, NULL, PAGE_SIZE); + if (err) + goto err_out_src; + + err = alloc_sg(&cdata.sg_key, ckey, key_length); + if (err) + goto err_out_dst; + + err = alloc_sg(&cdata.sg_iv, NULL, PAGE_SIZE); + if (err) + goto err_out_key; + + cdata.priv_size = sizeof(struct aes_ctx); + + init_timer(&ctimer); + ctimer.function = &ctimerf; + ctimer.expires = jiffies + HZ; + ctimer.data = 0; + + add_timer(&ctimer); + + return 0; +#if 0 + char str[] = "test message qwerty asdzxc\n"; + int size; + + init_completion(&callback_completed); + + size = 32; + err = ctimer_func(str, size, CRYPTO_OP_ENCRYPT); + if (err) + goto err_out_iv; + + wait_for_completion(&callback_completed); + init_completion(&callback_completed); + + err = + ctimer_func(page_address(cdata.sg_dst.page), cdata.sg_dst.length, + CRYPTO_OP_DECRYPT); + if (err) + goto err_out_iv; + + wait_for_completion(&callback_completed); + + dprintk("dst: %s\n", + ((char *)page_address(cdata.sg_dst.page)) + + cdata.sg_dst.offset); + err_out_iv: +#endif + + __free_pages(cdata.sg_iv.page, get_order(1)); + err_out_key: + __free_pages(cdata.sg_key.page, get_order(key_length)); + err_out_dst: + __free_pages(cdata.sg_dst.page, get_order(1)); + err_out_src: + __free_pages(cdata.sg_src.page, get_order(1)); + err_out_return: + return -ENODEV; +} + +void consumer_fini(void) +{ + del_timer_sync(&ctimer); + while (watermark) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ); + + printk(KERN_INFO "Waiting for sessions to be freed: watermark=%d.\n", + watermark); + } + + if (!cdata.sg_key.length) + printk("BUG: key length is 0 in %s.\n", __func__); + + __free_pages(cdata.sg_iv.page, get_order(1)); + __free_pages(cdata.sg_key.page, get_order(key_length)); + __free_pages(cdata.sg_dst.page, get_order(1)); + __free_pages(cdata.sg_src.page, get_order(1)); + + printk(KERN_INFO "Test crypto module consumer is unloaded.\n"); +} + +module_init(consumer_init); +module_exit(consumer_fini); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Evgeniy Polyakov "); +MODULE_DESCRIPTION("Test crypto module consumer."); Binary files /tmp/empty/.consumer.c.swp and linux-2.6/drivers/acrypto/.consumer.c.swp differ diff -Nru /tmp/empty/crypto_conn.c linux-2.6/drivers/acrypto/crypto_conn.c --- /tmp/empty/crypto_conn.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/crypto_conn.c 2004-12-14 18:53:11.000000000 +0300 @@ -0,0 +1,191 @@ +/* + * crypto_conn.c + * + * Copyright (c) 2004 Evgeniy Polyakov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "acrypto.h" +#include "crypto_lb.h" + +#include "../connector/connector.h" + +#include "crypto_conn.h" + +static struct cb_id crypto_conn_id = { 0xdead, 0x0000 }; +static char crypto_conn_name[] = "crconn"; + +static void crypto_conn_callback(void *data) +{ + struct cn_msg *msg, *reply; + struct crypto_conn_data *d, *cmd; + struct crypto_device *dev; + u32 sessions; + + msg = (struct cn_msg *)data; + d = (struct crypto_conn_data *)msg->data; + + if (msg->len < sizeof(*d)) { + dprintk(KERN_ERR "Wrong message to crypto connector: msg->len=%u < %u.\n", + msg->len, sizeof(*d)); + return; + } + + if (msg->len != sizeof(*d) + d->len) { + dprintk(KERN_ERR "Wrong message to crypto connector: msg->len=%u != %u.\n", + msg->len, sizeof(*d) + d->len); + return; + } + + dev = crypto_device_get_name(d->name); + if (!dev) { + dprintk(KERN_INFO "Crypto device %s was not found.\n", d->name); + return; + } + + switch (d->cmd) { + case CRYPTO_CONN_READ_SESSIONS: + reply = kmalloc(sizeof(*msg) + sizeof(*cmd) + sizeof(sessions), GFP_ATOMIC); + if (reply) { + memcpy(reply, msg, sizeof(*reply)); + reply->len = sizeof(*cmd) + sizeof(sessions); + + /* + * See protocol description in connector.c + */ + reply->ack++; + + cmd = (struct crypto_conn_data *)(reply + 1); + memcpy(cmd, d, sizeof(*cmd)); + cmd->len = sizeof(sessions); + + sessions = atomic_read(&dev->refcnt); + + memcpy(cmd + 1, &sessions, sizeof(sessions)); + + cn_netlink_send(reply, 0); + + kfree(reply); + } else + dprintk(KERN_ERR "Failed to allocate %d bytes in reply to comamnd 0x%x.\n", + sizeof(*msg) + sizeof(*cmd), d->cmd); + break; + case CRYPTO_CONN_DUMP_QUEUE: + reply = kmalloc(sizeof(*msg) + sizeof(*cmd) + + 1024 * sizeof(struct crypto_session_initializer), GFP_ATOMIC); + if (reply) { + struct crypto_session *s; + struct crypto_session_initializer *ptr; + + memcpy(reply, msg, sizeof(*reply)); + + /* + * See protocol description in connector.c + */ + reply->ack++; + + cmd = (struct crypto_conn_data *)(reply + 1); + memcpy(cmd, d, sizeof(*cmd)); + + ptr = (struct crypto_session_initializer *)(cmd + 1); + + sessions = 0; + spin_lock_irq(&dev->session_lock); + list_for_each_entry(s, &dev->session_list, dev_queue_entry) { + memcpy(ptr, &s->ci, sizeof(*ptr)); + sessions++; + ptr++; + + if (sessions >= 1024) + break; + } + spin_unlock_irq(&dev->session_lock); + + cmd->len = sizeof(*ptr) * sessions; + reply->len = sizeof(*cmd) + cmd->len; + + cn_netlink_send(reply, 0); + + kfree(reply); + } else + dprintk(KERN_ERR "Failed to allocate %d bytes in reply to comamnd 0x%x.\n", + sizeof(*msg) + sizeof(*cmd), d->cmd); + break; + case CRYPTO_GET_STAT: + reply = + kmalloc(sizeof(*msg) + sizeof(*cmd) + sizeof(struct crypto_device_stat), GFP_ATOMIC); + if (reply) { + struct crypto_device_stat *ptr; + + memcpy(reply, msg, sizeof(*reply)); + reply->len = sizeof(*cmd) + sizeof(*ptr); + + /* + * See protocol description in connector.c + */ + reply->ack++; + + cmd = (struct crypto_conn_data *)(reply + 1); + memcpy(cmd, d, sizeof(*cmd)); + cmd->len = sizeof(*ptr); + + ptr = (struct crypto_device_stat *)(cmd + 1); + memcpy(ptr, &dev->stat, sizeof(*ptr)); + + cn_netlink_send(reply, 0); + + kfree(reply); + } else + dprintk(KERN_ERR "Failed to allocate %d bytes in reply to comamnd 0x%x.\n", + sizeof(*msg) + sizeof(*cmd), d->cmd); + break; + default: + dprintk(KERN_ERR "Wrong operation 0x%04x for crypto connector.\n", + d->cmd); + return; + } + + crypto_device_put(dev); +} + +int crypto_conn_init(void) +{ + int err; + + err = cn_add_callback(&crypto_conn_id, crypto_conn_name, crypto_conn_callback); + if (err) + return err; + + dprintk(KERN_INFO "Crypto connector callback is registered.\n"); + + return 0; +} + +void crypto_conn_fini(void) +{ + cn_del_callback(&crypto_conn_id); + dprintk(KERN_INFO "Crypto connector callback is unregistered.\n"); +} diff -Nru /tmp/empty/crypto_conn.h linux-2.6/drivers/acrypto/crypto_conn.h --- /tmp/empty/crypto_conn.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/crypto_conn.h 2004-12-14 18:53:11.000000000 +0300 @@ -0,0 +1,44 @@ +/* + * crypto_conn.h + * + * Copyright (c) 2004 Evgeniy Polyakov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __CRYPTO_CONN_H +#define __CRYPTO_CONN_H + +#include "acrypto.h" + +#define CRYPTO_CONN_READ_SESSIONS 0 +#define CRYPTO_CONN_DUMP_QUEUE 1 +#define CRYPTO_GET_STAT 2 + +struct crypto_conn_data { + char name[SCACHE_NAMELEN]; + __u16 cmd; + __u16 len; + __u8 data[0]; +}; + +#ifdef __KERNEL__ + +int crypto_conn_init(void); +void crypto_conn_fini(void); + +#endif /* __KERNEL__ */ +#endif /* __CRYPTO_CONN_H */ diff -Nru /tmp/empty/crypto_def.h linux-2.6/drivers/acrypto/crypto_def.h --- /tmp/empty/crypto_def.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/crypto_def.h 2004-12-14 18:53:11.000000000 +0300 @@ -0,0 +1,38 @@ +/* + * crypto_def.h + * + * Copyright (c) 2004 Evgeniy Polyakov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __CRYPTO_DEF_H +#define __CRYPTO_DEF_H + +#define CRYPTO_OP_DECRYPT 0 +#define CRYPTO_OP_ENCRYPT 1 +#define CRYPTO_OP_HMAC 2 + +#define CRYPTO_MODE_ECB 0 +#define CRYPTO_MODE_CBC 1 +#define CRYPTO_MODE_CFB 2 +#define CRYPTO_MODE_OFB 3 + +#define CRYPTO_TYPE_AES_128 0 +#define CRYPTO_TYPE_AES_192 1 +#define CRYPTO_TYPE_AES_256 2 + +#endif /* __CRYPTO_DEF_H */ diff -Nru /tmp/empty/crypto_dev.c linux-2.6/drivers/acrypto/crypto_dev.c --- /tmp/empty/crypto_dev.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/crypto_dev.c 2004-12-14 18:53:11.000000000 +0300 @@ -0,0 +1,371 @@ +/* + * crypto_dev.c + * + * Copyright (c) 2004 Evgeniy Polyakov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "acrypto.h" + +static LIST_HEAD(cdev_list); +static spinlock_t cdev_lock = SPIN_LOCK_UNLOCKED; +static u32 cdev_ids; + +struct list_head *crypto_device_list = &cdev_list; +spinlock_t *crypto_device_lock = &cdev_lock; + +static int crypto_match(struct device *dev, struct device_driver *drv) +{ + return 1; +} + +static int crypto_probe(struct device *dev) +{ + return -ENODEV; +} + +static int crypto_remove(struct device *dev) +{ + return 0; +} + +static void crypto_release(struct device *dev) +{ + struct crypto_device *d = container_of(dev, struct crypto_device, device); + + complete(&d->dev_released); +} + +static void crypto_class_release(struct class *class) +{ +} + +static void crypto_class_release_device(struct class_device *class_dev) +{ +} + +struct class crypto_class = { + .name = "acrypto", + .class_release = crypto_class_release, + .release = crypto_class_release_device +}; + +struct bus_type crypto_bus_type = { + .name = "acrypto", + .match = crypto_match +}; + +struct device_driver crypto_driver = { + .name = "crypto_driver", + .bus = &crypto_bus_type, + .probe = crypto_probe, + .remove = crypto_remove, +}; + +struct device crypto_dev = { + .parent = NULL, + .bus = &crypto_bus_type, + .bus_id = "Asynchronous crypto", + .driver = &crypto_driver, + .release = &crypto_release +}; + +static ssize_t sessions_show(struct class_device *dev, char *buf) +{ + struct crypto_device *d = container_of(dev, struct crypto_device, class_device); + + return sprintf(buf, "%d\n", atomic_read(&d->refcnt)); +} +static ssize_t name_show(struct class_device *dev, char *buf) +{ + struct crypto_device *d = container_of(dev, struct crypto_device, class_device); + + return sprintf(buf, "%s\n", d->name); +} +static ssize_t devices_show(struct class_device *dev, char *buf) +{ + struct crypto_device *d; + int off = 0; + + spin_lock_irq(&cdev_lock); + list_for_each_entry(d, &cdev_list, cdev_entry) { + off += sprintf(buf + off, "%s ", d->name); + } + spin_unlock_irq(&cdev_lock); + + if (!off) + off = sprintf(buf, "No devices registered yet."); + + off += sprintf(buf + off, "\n"); + + return off; +} + +static ssize_t kmem_failed_show(struct class_device *dev, char *buf) +{ + struct crypto_device *d = container_of(dev, struct crypto_device, class_device); + + return sprintf(buf, "%llu\n", d->stat.kmem_failed); +} +static ssize_t sstarted_show(struct class_device *dev, char *buf) +{ + struct crypto_device *d = container_of(dev, struct crypto_device, class_device); + + return sprintf(buf, "%llu\n", d->stat.sstarted); +} +static ssize_t sfinished_show(struct class_device *dev, char *buf) +{ + struct crypto_device *d = container_of(dev, struct crypto_device, class_device); + + return sprintf(buf, "%llu\n", d->stat.sfinished); +} +static ssize_t scompleted_show(struct class_device *dev, char *buf) +{ + struct crypto_device *d = container_of(dev, struct crypto_device, class_device); + + return sprintf(buf, "%llu\n", d->stat.scompleted); +} + +static CLASS_DEVICE_ATTR(sessions, 0444, sessions_show, NULL); +static CLASS_DEVICE_ATTR(name, 0444, name_show, NULL); +CLASS_DEVICE_ATTR(devices, 0444, devices_show, NULL); +static CLASS_DEVICE_ATTR(scompleted, 0444, scompleted_show, NULL); +static CLASS_DEVICE_ATTR(sstarted, 0444, sstarted_show, NULL); +static CLASS_DEVICE_ATTR(sfinished, 0444, sfinished_show, NULL); +static CLASS_DEVICE_ATTR(kmem_failed, 0444, kmem_failed_show, NULL); + +static int compare_device(struct crypto_device *d1, struct crypto_device *d2) +{ + if (!strncmp(d1->name, d2->name, sizeof(d1->name))) + return 1; + + return 0; +} + +static void create_device_attributes(struct crypto_device *dev) +{ + class_device_create_file(&dev->class_device, &class_device_attr_sessions); + class_device_create_file(&dev->class_device, &class_device_attr_name); + class_device_create_file(&dev->class_device, &class_device_attr_scompleted); + class_device_create_file(&dev->class_device, &class_device_attr_sstarted); + class_device_create_file(&dev->class_device, &class_device_attr_sfinished); + class_device_create_file(&dev->class_device, &class_device_attr_kmem_failed); +} + +static void remove_device_attributes(struct crypto_device *dev) +{ + class_device_remove_file(&dev->class_device, &class_device_attr_sessions); + class_device_remove_file(&dev->class_device, &class_device_attr_name); + class_device_remove_file(&dev->class_device, &class_device_attr_scompleted); + class_device_remove_file(&dev->class_device, &class_device_attr_sstarted); + class_device_remove_file(&dev->class_device, &class_device_attr_sfinished); + class_device_remove_file(&dev->class_device, &class_device_attr_kmem_failed); +} + +int __match_initializer(struct crypto_capability *cap, struct crypto_session_initializer *ci) +{ + if (cap->operation == ci->operation && cap->type == ci->type && + cap->mode == (ci->mode & 0x1fff)) + return 1; + + return 0; +} + +int match_initializer(struct crypto_device *dev, struct crypto_session_initializer *ci) +{ + int i; + + for (i = 0; i < dev->cap_number; ++i) { + struct crypto_capability *cap = &dev->cap[i]; + + if (__match_initializer(cap, ci)) { + if (cap->qlen >= atomic_read(&dev->refcnt) + 1) { + dprintk("cap->len=%u, req=%u.\n", + cap->qlen, atomic_read(&dev->refcnt) + 1); + return 1; + } + } + } + + return 0; +} + +void crypto_device_get(struct crypto_device *dev) +{ + atomic_inc(&dev->refcnt); +} + +struct crypto_device *crypto_device_get_name(char *name) +{ + struct crypto_device *dev; + int found = 0; + + spin_lock_irq(&cdev_lock); + list_for_each_entry(dev, &cdev_list, cdev_entry) { + if (!strcmp(dev->name, name)) { + found = 1; + crypto_device_get(dev); + break; + } + } + spin_unlock_irq(&cdev_lock); + + if (!found) + return NULL; + + return dev; +} + +void crypto_device_put(struct crypto_device *dev) +{ + atomic_dec(&dev->refcnt); +} + +int __crypto_device_add(struct crypto_device *dev) +{ + int err; + + memset(&dev->stat, 0, sizeof(dev->stat)); + spin_lock_init(&dev->stat_lock); + spin_lock_init(&dev->lock); + spin_lock_init(&dev->session_lock); + INIT_LIST_HEAD(&dev->session_list); + atomic_set(&dev->refcnt, 0); + dev->sid = 0; + dev->flags = 0; + init_completion(&dev->dev_released); + memcpy(&dev->device, &crypto_dev, sizeof(struct device)); + dev->driver = &crypto_driver; + + snprintf(dev->device.bus_id, sizeof(dev->device.bus_id), "%s", dev->name); + err = device_register(&dev->device); + if (err) { + dprintk(KERN_ERR "Failed to register crypto device %s: err=%d.\n", + dev->name, err); + return err; + } + + snprintf(dev->class_device.class_id, sizeof(dev->class_device.class_id), "%s", dev->name); + dev->class_device.dev = &dev->device; + dev->class_device.class = &crypto_class; + + err = class_device_register(&dev->class_device); + if (err) { + dprintk(KERN_ERR "Failed to register crypto class device %s: err=%d.\n", + dev->name, err); + device_unregister(&dev->device); + return err; + } + + create_device_attributes(dev); + + return 0; +} + +void __crypto_device_remove(struct crypto_device *dev) +{ + remove_device_attributes(dev); + class_device_unregister(&dev->class_device); + device_unregister(&dev->device); +} + +int crypto_device_add(struct crypto_device *dev) +{ + int err; + + err = __crypto_device_add(dev); + if (err) + return err; + + spin_lock_irq(&cdev_lock); + list_add(&dev->cdev_entry, &cdev_list); + dev->id = ++cdev_ids; + spin_unlock_irq(&cdev_lock); + + dprintk(KERN_INFO "Crypto device %s was registered with ID=%x.\n", + dev->name, dev->id); + + return 0; +} + +void crypto_device_remove(struct crypto_device *dev) +{ + struct crypto_device *__dev, *n; + + __crypto_device_remove(dev); + + spin_lock_irq(&cdev_lock); + list_for_each_entry_safe(__dev, n, &cdev_list, cdev_entry) { + if (compare_device(__dev, dev)) { + list_del_init(&__dev->cdev_entry); + spin_unlock_irq(&cdev_lock); + + /* + * In test cases or when crypto device driver is not written correctly, + * it's ->data_ready() method will not be callen anymore + * after device is removed from crypto device list. + * + * For such cases we either should provide ->flush() call + * or properly write ->data_ready() method. + */ + + while (atomic_read(&__dev->refcnt)) { + + dprintk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n", + __dev->name, atomic_read(&dev->refcnt)); + + /* + * Hack zone: you need to write good ->data_ready() + * and crypto device driver itself. + * + * Driver shoud not buzz if it has pending sessions + * in it's queue and it was removed from global device list. + * + * Although I can workaround it here, for example by + * flushing the whole queue and drop all pending sessions. + */ + + __dev->data_ready(__dev); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ); + } + + dprintk(KERN_ERR "Crypto device %s was unregistered.\n", + dev->name); + return; + } + } + spin_unlock_irq(&cdev_lock); + + dprintk(KERN_ERR "Crypto device %s was not registered.\n", dev->name); +} + +EXPORT_SYMBOL_GPL(crypto_device_add); +EXPORT_SYMBOL_GPL(crypto_device_remove); +EXPORT_SYMBOL_GPL(crypto_device_get); +EXPORT_SYMBOL_GPL(crypto_device_get_name); +EXPORT_SYMBOL_GPL(crypto_device_put); diff -Nru /tmp/empty/crypto_lb.c linux-2.6/drivers/acrypto/crypto_lb.c --- /tmp/empty/crypto_lb.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/crypto_lb.c 2004-12-14 18:53:11.000000000 +0300 @@ -0,0 +1,631 @@ +/* + * crypto_lb.c + * + * Copyright (c) 2004 Evgeniy Polyakov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "acrypto.h" +#include "crypto_lb.h" +#include "crypto_stat.h" +#include "crypto_route.h" + +static LIST_HEAD(crypto_lb_list); +static spinlock_t crypto_lb_lock = SPIN_LOCK_UNLOCKED; +static int lb_num = 0; +static struct crypto_lb *current_lb, *default_lb; +static struct completion thread_exited; +static int need_exit; +static struct workqueue_struct *crypto_lb_queue; +static DECLARE_WAIT_QUEUE_HEAD(crypto_lb_wait_queue); + +extern struct list_head *crypto_device_list; +extern spinlock_t *crypto_device_lock; + +extern int force_lb_remove; +extern struct crypto_device main_crypto_device; + +static int lb_is_current(struct crypto_lb *l) +{ + return (l->crypto_device_list != NULL && l->crypto_device_lock != NULL); +} + +static int lb_is_default(struct crypto_lb *l) +{ + return (l == default_lb); +} + +static void __lb_set_current(struct crypto_lb *l) +{ + struct crypto_lb *c = current_lb; + + if (c) { + l->crypto_device_list = crypto_device_list; + l->crypto_device_lock = crypto_device_lock; + current_lb = l; + c->crypto_device_list = NULL; + c->crypto_device_lock = NULL; + } else { + l->crypto_device_list = crypto_device_list; + l->crypto_device_lock = crypto_device_lock; + current_lb = l; + } +} + +static void lb_set_current(struct crypto_lb *l) +{ + struct crypto_lb *c = current_lb; + + if (c) { + spin_lock_irq(&c->lock); + __lb_set_current(l); + spin_unlock_irq(&c->lock); + } else + __lb_set_current(l); +} + +static void __lb_set_default(struct crypto_lb *l) +{ + default_lb = l; +} + +static void lb_set_default(struct crypto_lb *l) +{ + struct crypto_lb *c = default_lb; + + if (c) { + spin_lock_irq(&c->lock); + __lb_set_default(l); + spin_unlock_irq(&c->lock); + } else + __lb_set_default(l); +} + +static int crypto_lb_match(struct device *dev, struct device_driver *drv) +{ + return 1; +} + +static int crypto_lb_probe(struct device *dev) +{ + return -ENODEV; +} + +static int crypto_lb_remove(struct device *dev) +{ + return 0; +} + +static void crypto_lb_release(struct device *dev) +{ + struct crypto_lb *d = container_of(dev, struct crypto_lb, device); + + complete(&d->dev_released); +} + +static void crypto_lb_class_release(struct class *class) +{ +} + +static void crypto_lb_class_release_device(struct class_device *class_dev) +{ +} + +struct class crypto_lb_class = { + .name = "crypto_lb", + .class_release = crypto_lb_class_release, + .release = crypto_lb_class_release_device +}; + +struct bus_type crypto_lb_bus_type = { + .name = "crypto_lb", + .match = crypto_lb_match +}; + +struct device_driver crypto_lb_driver = { + .name = "crypto_lb_driver", + .bus = &crypto_lb_bus_type, + .probe = crypto_lb_probe, + .remove = crypto_lb_remove, +}; + +struct device crypto_lb_dev = { + .parent = NULL, + .bus = &crypto_lb_bus_type, + .bus_id = "crypto load balancer", + .driver = &crypto_lb_driver, + .release = &crypto_lb_release +}; + +static ssize_t name_show(struct class_device *dev, char *buf) +{ + struct crypto_lb *lb = container_of(dev, struct crypto_lb, class_device); + + return sprintf(buf, "%s\n", lb->name); +} + +static ssize_t current_show(struct class_device *dev, char *buf) +{ + struct crypto_lb *lb; + int off = 0; + + spin_lock_irq(&crypto_lb_lock); + + list_for_each_entry(lb, &crypto_lb_list, lb_entry) { + if (lb_is_current(lb)) + off += sprintf(buf + off, "["); + if (lb_is_default(lb)) + off += sprintf(buf + off, "("); + off += sprintf(buf + off, "%s", lb->name); + if (lb_is_default(lb)) + off += sprintf(buf + off, ")"); + if (lb_is_current(lb)) + off += sprintf(buf + off, "]"); + } + + spin_unlock_irq(&crypto_lb_lock); + + if (!off) + off = sprintf(buf, "No load balancers regitered yet."); + + off += sprintf(buf + off, "\n"); + + return off; +} +static ssize_t current_store(struct class_device *dev, const char *buf, size_t count) +{ + struct crypto_lb *lb; + + spin_lock_irq(&crypto_lb_lock); + + list_for_each_entry(lb, &crypto_lb_list, lb_entry) { + if (count == strlen(lb->name) && !strcmp(buf, lb->name)) { + lb_set_current(lb); + lb_set_default(lb); + + dprintk(KERN_INFO "Load balancer %s is set as current and default.\n", + lb->name); + + break; + } + } + spin_unlock_irq(&crypto_lb_lock); + + return count; +} + +static CLASS_DEVICE_ATTR(name, 0444, name_show, NULL); +CLASS_DEVICE_ATTR(lbs, 0644, current_show, current_store); + +static void create_device_attributes(struct crypto_lb *lb) +{ + class_device_create_file(&lb->class_device, &class_device_attr_name); +} + +static void remove_device_attributes(struct crypto_lb *lb) +{ + class_device_remove_file(&lb->class_device, &class_device_attr_name); +} + +static int compare_lb(struct crypto_lb *l1, struct crypto_lb *l2) +{ + if (!strncmp(l1->name, l2->name, sizeof(l1->name))) + return 1; + + return 0; +} + +void crypto_lb_rehash(void) +{ + if (!current_lb) + return; + + spin_lock_irq(¤t_lb->lock); + + current_lb->rehash(current_lb); + + spin_unlock_irq(¤t_lb->lock); + + wake_up_interruptible(&crypto_lb_wait_queue); +} + +struct crypto_device *crypto_lb_find_device(struct crypto_session_initializer *ci, struct crypto_data *data) +{ + struct crypto_device *dev; + + if (!current_lb) + return NULL; + + if (sci_binded(ci)) { + int found = 0; + + spin_lock_irq(crypto_device_lock); + + list_for_each_entry(dev, crypto_device_list, cdev_entry) { + if (dev->id == ci->bdev) { + found = 1; + break; + } + } + + spin_unlock_irq(crypto_device_lock); + + return (found) ? dev : NULL; + } + + spin_lock_irq(¤t_lb->lock); + + current_lb->rehash(current_lb); + + spin_lock(crypto_device_lock); + + dev = current_lb->find_device(current_lb, ci, data); + if (dev) + crypto_device_get(dev); + + spin_unlock(crypto_device_lock); + + spin_unlock_irq(¤t_lb->lock); + + wake_up_interruptible(&crypto_lb_wait_queue); + + return dev; +} + +static int __crypto_lb_register(struct crypto_lb *lb) +{ + int err; + + spin_lock_init(&lb->lock); + + init_completion(&lb->dev_released); + memcpy(&lb->device, &crypto_lb_dev, sizeof(struct device)); + lb->driver = &crypto_lb_driver; + + snprintf(lb->device.bus_id, sizeof(lb->device.bus_id), "%s", lb->name); + err = device_register(&lb->device); + if (err) { + dprintk(KERN_ERR + "Failed to register crypto load balancer device %s: err=%d.\n", + lb->name, err); + return err; + } + + snprintf(lb->class_device.class_id, sizeof(lb->class_device.class_id), "%s", lb->name); + lb->class_device.dev = &lb->device; + lb->class_device.class = &crypto_lb_class; + + err = class_device_register(&lb->class_device); + if (err) { + dprintk(KERN_ERR "Failed to register crypto load balancer class device %s: err=%d.\n", + lb->name, err); + device_unregister(&lb->device); + return err; + } + + create_device_attributes(lb); + wake_up_interruptible(&crypto_lb_wait_queue); + + return 0; + +} + +static void __crypto_lb_unregister(struct crypto_lb *lb) +{ + wake_up_interruptible(&crypto_lb_wait_queue); + remove_device_attributes(lb); + class_device_unregister(&lb->class_device); + device_unregister(&lb->device); +} + +int crypto_lb_register(struct crypto_lb *lb, int set_current, int set_default) +{ + struct crypto_lb *__lb; + int err; + + spin_lock_irq(&crypto_lb_lock); + + list_for_each_entry(__lb, &crypto_lb_list, lb_entry) { + if (unlikely(compare_lb(__lb, lb))) { + spin_unlock_irq(&crypto_lb_lock); + + dprintk(KERN_ERR "Crypto load balancer %s is already registered.\n", + lb->name); + return -EINVAL; + } + } + + list_add(&lb->lb_entry, &crypto_lb_list); + + spin_unlock_irq(&crypto_lb_lock); + + err = __crypto_lb_register(lb); + if (err) { + spin_lock_irq(&crypto_lb_lock); + list_del_init(&lb->lb_entry); + spin_unlock_irq(&crypto_lb_lock); + + return err; + } + + if (!default_lb || set_default) + lb_set_default(lb); + + if (!current_lb || set_current) + lb_set_current(lb); + + dprintk(KERN_INFO "Crypto load balancer %s was registered and set to be [%s.%s].\n", + lb->name, (lb_is_current(lb)) ? "current" : "not current", + (lb_is_default(lb)) ? "default" : "not default"); + + lb_num++; + + return 0; +} + +void crypto_lb_unregister(struct crypto_lb *lb) +{ + struct crypto_lb *__lb, *n; + + if (lb_num == 1) { + dprintk(KERN_INFO "You are removing crypto load balancer %s which is current and default.\n" + "There is no other crypto load balancers. " + "Removing %s delayed untill new load balancer is registered.\n", + lb->name, (force_lb_remove) ? "is not" : "is"); + while (lb_num == 1 && !force_lb_remove) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ); + + if (signal_pending(current)) + flush_signals(current); + } + } + + __crypto_lb_unregister(lb); + + spin_lock_irq(&crypto_lb_lock); + + list_for_each_entry_safe(__lb, n, &crypto_lb_list, lb_entry) { + if (compare_lb(__lb, lb)) { + lb_num--; + list_del_init(&__lb->lb_entry); + + dprintk(KERN_ERR "Crypto load balancer %s was unregistered.\n", + lb->name); + } else if (lb_num) { + if (lb_is_default(lb)) + lb_set_default(__lb); + if (lb_is_current(lb)) + lb_set_current(default_lb); + } + } + + spin_unlock_irq(&crypto_lb_lock); +} + +static void crypto_lb_queue_wrapper(void *data) +{ + struct crypto_device *dev = &main_crypto_device; + struct crypto_session *s = (struct crypto_session *)data; + + dprintk(KERN_INFO "%s: Calling callback for session %llu [%llu] flags=%x, " + "op=%04u, type=%04x, mode=%04x, priority=%04x\n", __func__, + s->ci.id, s->ci.dev_id, s->ci.flags, s->ci.operation, + s->ci.type, s->ci.mode, s->ci.priority); + + spin_lock_irq(&s->lock); + crypto_stat_finish_inc(s); + + finish_session(s); + unstart_session(s); + spin_unlock_irq(&s->lock); + + s->ci.callback(&s->ci, &s->data); + + if (session_finished(s)) { + kfree(s); + return; + } else { + /* + * Special case: crypto consumer marks session as "not finished" + * in it's callback - it means that crypto consumer wants + * this session to be processed further, + * for example crypto consumer can add new route and then + * mark session as "not finished". + */ + + uncomplete_session(s); + unstart_session(s); + crypto_session_insert_main(dev, s); + } + spin_unlock_irq(&s->lock); +} + +static void crypto_lb_process_next_route(struct crypto_session *s) +{ + struct crypto_route *rt; + struct crypto_device *dev; + + rt = crypto_route_dequeue(s); + if (rt) { + dev = rt->dev; + + spin_lock_irq(&dev->session_lock); + list_del_init(&s->dev_queue_entry); + spin_unlock_irq(&dev->session_lock); + + crypto_route_free(rt); + + dev = crypto_route_get_current_device(s); + if (dev) { + dprintk(KERN_INFO "%s: processing new route to %s.\n", + __func__, dev->name); + + memcpy(&s->ci, &rt->ci, sizeof(s->ci)); + crypto_session_insert(dev, s); + + /* + * Reference to this device was already hold when + * new routing was added. + */ + crypto_device_put(dev); + } + } +} + +void crypto_wake_lb(void) +{ + wake_up_interruptible(&crypto_lb_wait_queue); +} + +int crypto_lb_thread(void *data) +{ + struct crypto_session *s, *n; + struct crypto_device *dev = (struct crypto_device *)data; + + daemonize("%s", dev->name); + allow_signal(SIGTERM); + + while (!need_exit) { + list_for_each_entry_safe(s, n, &dev->session_list, + main_queue_entry) { + dprintk("session %llu [%llu]: flags=%x, route_num=%d, %s,%s,%s,%s.\n", + s->ci.id, s->ci.dev_id, s->ci.flags, + crypto_route_queue_len(s), + (session_completed(s)) ? "completed" : "not completed", + (session_finished(s)) ? "finished" : "not finished", + (session_started(s)) ? "started" : "not started", + (session_is_processed(s)) ? "is being processed" : "is not being processed"); + + if (!spin_trylock(&s->lock)) + continue; + + if (session_is_processed(s)) + goto unlock; + if (session_started(s)) + goto unlock; + + if (session_completed(s)) { + crypto_stat_ptime_inc(s); + + if (crypto_route_queue_len(s) > 1) { + crypto_lb_process_next_route(s); + } else { + start_session(s); + crypto_stat_start_inc(s); + + dprintk("%s: going to remove session %llu [%llu].\n", + __func__, s->ci.id, s->ci.dev_id); + + crypto_session_dequeue_main(s); + spin_unlock(&s->lock); + + INIT_WORK(&s->work, &crypto_lb_queue_wrapper, s); + queue_work(crypto_lb_queue, &s->work); + continue; + } + } + unlock: + spin_unlock(&s->lock); + } + + interruptible_sleep_on_timeout(&crypto_lb_wait_queue, 100); + } + + flush_workqueue(crypto_lb_queue); + complete_and_exit(&thread_exited, 0); +} + +int crypto_lb_init(void) +{ + int err; + long pid; + + err = bus_register(&crypto_lb_bus_type); + if (err) { + dprintk(KERN_ERR "Failed to register crypto load balancer bus: err=%d.\n", err); + goto err_out_exit; + } + + err = driver_register(&crypto_lb_driver); + if (err) { + dprintk(KERN_ERR "Failed to register crypto load balancer driver: err=%d.\n", err); + goto err_out_bus_unregister; + } + + crypto_lb_class.class_dev_attrs = &class_device_attr_lbs; + + err = class_register(&crypto_lb_class); + if (err) { + dprintk(KERN_ERR "Failed to register crypto load balancer class: err=%d.\n", err); + goto err_out_driver_unregister; + } + + crypto_lb_queue = create_workqueue("clbq"); + if (!crypto_lb_queue) { + dprintk(KERN_ERR "Failed to create crypto load balaner work queue.\n"); + goto err_out_class_unregister; + } + + init_completion(&thread_exited); + pid = kernel_thread(crypto_lb_thread, &main_crypto_device, CLONE_FS | CLONE_FILES); + if (IS_ERR((void *)pid)) { + dprintk(KERN_ERR "Failed to create kernel load balancing thread.\n"); + goto err_out_destroy_workqueue; + } + + return 0; + +err_out_destroy_workqueue: + destroy_workqueue(crypto_lb_queue); +err_out_class_unregister: + class_unregister(&crypto_lb_class); +err_out_driver_unregister: + driver_unregister(&crypto_lb_driver); +err_out_bus_unregister: + bus_unregister(&crypto_lb_bus_type); +err_out_exit: + return err; +} + +void crypto_lb_fini(void) +{ + need_exit = 1; + wait_for_completion(&thread_exited); + flush_workqueue(crypto_lb_queue); + destroy_workqueue(crypto_lb_queue); + class_unregister(&crypto_lb_class); + driver_unregister(&crypto_lb_driver); + bus_unregister(&crypto_lb_bus_type); +} + +EXPORT_SYMBOL_GPL(crypto_lb_register); +EXPORT_SYMBOL_GPL(crypto_lb_unregister); +EXPORT_SYMBOL_GPL(crypto_lb_rehash); +EXPORT_SYMBOL_GPL(crypto_lb_find_device); +EXPORT_SYMBOL_GPL(crypto_wake_lb); Binary files /tmp/empty/.crypto_lb.c.swn and linux-2.6/drivers/acrypto/.crypto_lb.c.swn differ Binary files /tmp/empty/.crypto_lb.c.swo and linux-2.6/drivers/acrypto/.crypto_lb.c.swo differ Binary files /tmp/empty/.crypto_lb.c.swp and linux-2.6/drivers/acrypto/.crypto_lb.c.swp differ diff -Nru /tmp/empty/crypto_lb.h linux-2.6/drivers/acrypto/crypto_lb.h --- /tmp/empty/crypto_lb.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/crypto_lb.h 2004-12-14 18:53:11.000000000 +0300 @@ -0,0 +1,62 @@ +/* + * crypto_lb.h + * + * Copyright (c) 2004 Evgeniy Polyakov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __CRYPTO_LB_H +#define __CRYPTO_LB_H + +#include "acrypto.h" + +#define CRYPTO_LB_NAMELEN 32 + +struct crypto_lb { + struct list_head lb_entry; + + char name[CRYPTO_LB_NAMELEN]; + + void (*rehash)(struct crypto_lb *); + struct crypto_device * (*find_device) (struct crypto_lb *, + struct crypto_session_initializer *, + struct crypto_data *); + + spinlock_t lock; + + spinlock_t *crypto_device_lock; + struct list_head *crypto_device_list; + + struct device_driver *driver; + struct device device; + struct class_device class_device; + struct completion dev_released; + +}; + +int crypto_lb_register(struct crypto_lb *lb, int set_current, int set_default); +void crypto_lb_unregister(struct crypto_lb *); + +inline void crypto_lb_rehash(void); +struct crypto_device *crypto_lb_find_device(struct crypto_session_initializer *, struct crypto_data *); + +void crypto_wake_lb(void); + +int crypto_lb_init(void); +void crypto_lb_fini(void); + +#endif /* __CRYPTO_LB_H */ diff -Nru /tmp/empty/crypto_main.c linux-2.6/drivers/acrypto/crypto_main.c --- /tmp/empty/crypto_main.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/crypto_main.c 2004-12-14 18:53:11.000000000 +0300 @@ -0,0 +1,340 @@ +/* + * crypto_main.c + * + * Copyright (c) 2004 Evgeniy Polyakov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "acrypto.h" +#include "crypto_lb.h" +#include "crypto_conn.h" +#include "crypto_route.h" + +int force_lb_remove; +module_param(force_lb_remove, int, 0); + +struct crypto_device main_crypto_device; + +extern struct bus_type crypto_bus_type; +extern struct device_driver crypto_driver; +extern struct class crypto_class; +extern struct device crypto_dev; + +extern struct class_device_attribute class_device_attr_devices; +extern struct class_device_attribute class_device_attr_lbs; + +static void dump_ci(struct crypto_session_initializer *ci) +{ + dprintk("%llu [%llu] op=%04u, type=%04x, mode=%04x, priority=%04x", + ci->id, ci->dev_id, + ci->operation, ci->type, ci->mode, ci->priority); +} + +static void __crypto_session_insert(struct crypto_device *dev, struct crypto_session *s) +{ + struct crypto_session *__s; + + if (unlikely(list_empty(&dev->session_list))) { + list_add(&s->dev_queue_entry, &dev->session_list); + } else { + int inserted = 0; + + list_for_each_entry(__s, &dev->session_list, dev_queue_entry) { + if (__s->ci.priority < s->ci.priority) { + list_add_tail(&s->dev_queue_entry, &__s->dev_queue_entry); + inserted = 1; + break; + } + } + + if (!inserted) + list_add_tail(&s->dev_queue_entry, &dev->session_list); + } + + dump_ci(&s->ci); + dprintk(" added to crypto device %s [%d].\n", dev->name, atomic_read(&dev->refcnt)); +} + +void crypto_session_insert_main(struct crypto_device *dev, struct crypto_session *s) +{ + struct crypto_session *__s; + + spin_lock_irq(&dev->session_lock); + + crypto_device_get(dev); + if (unlikely(list_empty(&dev->session_list))) { + list_add(&s->main_queue_entry, &dev->session_list); + } else { + int inserted = 0; + + list_for_each_entry(__s, &dev->session_list, main_queue_entry) { + if (__s->ci.priority < s->ci.priority) { + list_add_tail(&s->main_queue_entry, + &__s->main_queue_entry); + inserted = 1; + break; + } + } + + if (!inserted) + list_add_tail(&s->main_queue_entry, &dev->session_list); + } + + spin_unlock_irq(&dev->session_lock); +} + +void crypto_session_insert(struct crypto_device *dev, struct crypto_session *s) +{ + spin_lock_irq(&dev->session_lock); + __crypto_session_insert(dev, s); + spin_unlock_irq(&dev->session_lock); +} + +struct crypto_session *crypto_session_create(struct crypto_session_initializer *ci, struct crypto_data *d) +{ + struct crypto_device *dev = &main_crypto_device; + struct crypto_device *ldev; + struct crypto_session *s; + int err; + + if (d->priv_size > CRYPTO_MAX_PRIV_SIZE) { + dprintk("priv_size %u is too big, maximum allowed %u.\n", + d->priv_size, CRYPTO_MAX_PRIV_SIZE); + return NULL; + } + + ldev = crypto_lb_find_device(ci, d); + if (!ldev) { + dprintk("Cannot find suitable device.\n"); + return NULL; + } + + s = kmalloc(sizeof(*s) + d->priv_size, GFP_ATOMIC); + if (!s) { + ldev->stat.kmem_failed++; + goto err_out_device_put; + } + + memset(s, 0xAB, sizeof(*s)); + + crypto_route_head_init(&s->route_list); + INIT_LIST_HEAD(&s->dev_queue_entry); + INIT_LIST_HEAD(&s->main_queue_entry); + + spin_lock_init(&s->lock); + + memcpy(&s->ci, ci, sizeof(s->ci)); + memcpy(&s->data, d, sizeof(s->data)); + s->data.priv = s + 1; + if (d->priv_size) { + s->data.priv = s + 1; + if (d->priv) + memcpy(s->data.priv, d->priv, d->priv_size); + } + + s->ci.id = dev->sid++; + s->ci.dev_id = ldev->sid++; + s->ci.flags = 0; + + err = crypto_route_add_direct(ldev, s, ci); + if (err) { + dprintk("Can not add route to device %s.\n", ldev->name); + goto err_out_session_free; + } + + return s; + +err_out_session_free: + kfree(s); +err_out_device_put: + crypto_device_put(ldev); + + return NULL; +} + +void crypto_session_add(struct crypto_session *s) +{ + struct crypto_device *ldev; + struct crypto_device *dev = &main_crypto_device; + + ldev = crypto_route_get_current_device(s); + BUG_ON(!ldev); /* This can not happen. */ + + spin_lock_irq(&s->lock); + crypto_session_insert(ldev, s); + crypto_device_put(ldev); + crypto_session_insert_main(dev, s); + spin_unlock_irq(&s->lock); + + if (ldev->data_ready) + ldev->data_ready(ldev); +} + +struct crypto_session *crypto_session_alloc(struct crypto_session_initializer *ci, struct crypto_data *d) +{ + struct crypto_session *s; + + s = crypto_session_create(ci, d); + if (!s) + return NULL; + + crypto_session_add(s); + + return s; +} + +void crypto_session_dequeue_route(struct crypto_session *s) +{ + struct crypto_route *rt; + struct crypto_device *dev; + + BUG_ON(crypto_route_queue_len(s) > 1); + + while ((rt = crypto_route_dequeue(s))) { + dev = rt->dev; + + dprintk(KERN_INFO "Removing route entry for device %s.\n", dev->name); + + spin_lock_irq(&dev->session_lock); + + list_del_init(&s->dev_queue_entry); + + spin_unlock_irq(&dev->session_lock); + + crypto_route_free(rt); + } +} + +void __crypto_session_dequeue_main(struct crypto_session *s) +{ + struct crypto_device *dev = &main_crypto_device; + + list_del(&s->main_queue_entry); + crypto_device_put(dev); +} + +void crypto_session_dequeue_main(struct crypto_session *s) +{ + struct crypto_device *dev = &main_crypto_device; + + spin_lock_irq(&dev->session_lock); + + __crypto_session_dequeue_main(s); + + spin_unlock_irq(&dev->session_lock); +} + +int __devinit cmain_init(void) +{ + struct crypto_device *dev = &main_crypto_device; + int err; + + snprintf(dev->name, sizeof(dev->name), "crypto_sessions"); + + err = bus_register(&crypto_bus_type); + if (err) { + dprintk(KERN_ERR "Failed to register crypto bus: err=%d.\n", + err); + return err; + } + + err = driver_register(&crypto_driver); + if (err) { + dprintk(KERN_ERR "Failed to register crypto driver: err=%d.\n", + err); + goto err_out_bus_unregister; + } + + err = class_register(&crypto_class); + if (err) { + dprintk(KERN_ERR "Failed to register crypto class: err=%d.\n", + err); + goto err_out_driver_unregister; + } + + err = crypto_lb_init(); + if (err) + goto err_out_class_unregister; + + err = crypto_conn_init(); + if (err) + goto err_out_crypto_lb_fini; + + err = __crypto_device_add(dev); + if (err) + goto err_out_crypto_conn_fini; + + err = class_device_create_file(&dev->class_device, &class_device_attr_devices); + if (err) + dprintk("Failed to create \"devices\" attribute: err=%d.\n", + err); + err = class_device_create_file(&dev->class_device, &class_device_attr_lbs); + if (err) + dprintk("Failed to create \"lbs\" attribute: err=%d.\n", err); + + return 0; + +err_out_crypto_conn_fini: + crypto_conn_fini(); +err_out_crypto_lb_fini: + crypto_lb_fini(); +err_out_class_unregister: + class_unregister(&crypto_class); +err_out_driver_unregister: + driver_unregister(&crypto_driver); +err_out_bus_unregister: + bus_unregister(&crypto_bus_type); + + return err; +} + +void __devexit cmain_fini(void) +{ + struct crypto_device *dev = &main_crypto_device; + + class_device_remove_file(&dev->class_device, &class_device_attr_devices); + class_device_remove_file(&dev->class_device, &class_device_attr_lbs); + __crypto_device_remove(dev); + + crypto_conn_fini(); + crypto_lb_fini(); + + class_unregister(&crypto_class); + driver_unregister(&crypto_driver); + bus_unregister(&crypto_bus_type); +} + +module_init(cmain_init); +module_exit(cmain_fini); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Evgeniy Polyakov "); +MODULE_DESCRIPTION("Asynchronous crypto layer."); + +EXPORT_SYMBOL(crypto_session_alloc); +EXPORT_SYMBOL_GPL(crypto_session_create); +EXPORT_SYMBOL_GPL(crypto_session_add); +EXPORT_SYMBOL_GPL(crypto_session_dequeue_route); diff -Nru /tmp/empty/crypto_provider.c linux-2.6/drivers/acrypto/crypto_provider.c --- /tmp/empty/crypto_provider.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/crypto_provider.c 2004-12-14 18:53:11.000000000 +0300 @@ -0,0 +1,183 @@ +/* + * crypto_provider.c + * + * Copyright (c) 2004 Evgeniy Polyakov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG +#include "acrypto.h" +#include "crypto_stat.h" +#include "crypto_def.h" + +static void prov_data_ready(struct crypto_device *dev); + +static struct crypto_capability prov_caps[] = { + {CRYPTO_OP_ENCRYPT, CRYPTO_TYPE_AES_128, CRYPTO_MODE_ECB, 1000}, + {CRYPTO_OP_DECRYPT, CRYPTO_TYPE_AES_128, CRYPTO_MODE_ECB, 1000}, +}; +static int prov_cap_number = sizeof(prov_caps) / sizeof(prov_caps[0]); + +static struct completion thread_exited; +static DECLARE_WAIT_QUEUE_HEAD(crypto_wait_queue); +static int need_exit; +static struct crypto_tfm *tfm; + +static struct crypto_device pdev = { + .name = "crypto_provider", + .data_ready = prov_data_ready, + .cap = &prov_caps[0], +}; + +static void prov_data_ready(struct crypto_device *dev) +{ + wake_up(&crypto_wait_queue); +} + +static int crypto_thread(void *data) +{ + struct crypto_device *dev = (struct crypto_device *)data; + u8 *key; + unsigned int keylen; + int err; + struct crypto_session *s, *n; + + daemonize("%s", dev->name); + allow_signal(SIGTERM); + + while (!need_exit) { + interruptible_sleep_on_timeout(&crypto_wait_queue, 100); + + if (need_exit) + break; + + list_for_each_entry_safe(s, n, &dev->session_list, dev_queue_entry) { + if (!spin_trylock(&s->lock)) + continue; + + if (session_completed(s)) { + goto unlock; + } + start_process_session(s); + + dprintk("Begin to process session %llu [%llu] in %s.\n", + s->ci.id, s->ci.dev_id, pdev.name); + + key = ((u8 *) page_address(s->data.sg_key.page)) + s->data.sg_key.offset; + keylen = s->data.sg_key.length; + + err = crypto_cipher_setkey(tfm, key, keylen); + if (err) { + dprintk(KERN_ERR "Failed to set key [keylen=%d]: err=%d.\n", + keylen, err); + broke_session(s); + goto out; + } + + if (s->ci.operation == CRYPTO_OP_ENCRYPT) + crypto_cipher_encrypt(tfm, &s->data.sg_dst, &s->data.sg_src, s->data.sg_src.length); + else + crypto_cipher_decrypt(tfm, &s->data.sg_dst, &s->data.sg_src, s->data.sg_src.length); + + s->data.sg_dst.length = s->data.sg_src.length; + s->data.sg_dst.offset = 0; + + dprintk(KERN_INFO "Completing session %llu [%llu] in %s.\n", + s->ci.id, s->ci.dev_id, pdev.name); + +out: + crypto_stat_complete_inc(s); + crypto_session_dequeue_route(s); + complete_session(s); + stop_process_session(s); +unlock: + spin_unlock(&s->lock); + } + } + + complete_and_exit(&thread_exited, 0); +} + +int prov_init(void) +{ + int err, pid; + + tfm = crypto_alloc_tfm("aes", 0); + if (!tfm) { + printk(KERN_ERR "Failed to allocate SHA1 tfm.\n"); + return -EINVAL; + } + + init_completion(&thread_exited); + pid = kernel_thread(crypto_thread, &pdev, CLONE_FS | CLONE_FILES); + if (IS_ERR((void *)pid)) { + err = -EINVAL; + dprintk(KERN_ERR "Failed to create kernel load balancing thread.\n"); + goto err_out_free_tfm; + } + + pdev.cap_number = prov_cap_number; + + err = crypto_device_add(&pdev); + if (err) + goto err_out_remove_thread; + + dprintk(KERN_INFO "Test crypto provider module %s is loaded.\n", pdev.name); + + return 0; + +err_out_remove_thread: + need_exit = 1; + wake_up(&crypto_wait_queue); + wait_for_completion(&thread_exited); +err_out_free_tfm: + crypto_free_tfm(tfm); + + return err; +} + +void prov_fini(void) +{ + need_exit = 1; + wake_up(&crypto_wait_queue); + wait_for_completion(&thread_exited); + + crypto_device_remove(&pdev); + crypto_free_tfm(tfm); + + dprintk(KERN_INFO "Test crypto provider module %s is unloaded.\n", pdev.name); +} + +module_init(prov_init); +module_exit(prov_fini); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Evgeniy Polyakov "); +MODULE_DESCRIPTION("Test crypto module provider."); Binary files /tmp/empty/.crypto_provider.c.swp and linux-2.6/drivers/acrypto/.crypto_provider.c.swp differ diff -Nru /tmp/empty/crypto_route.h linux-2.6/drivers/acrypto/crypto_route.h --- /tmp/empty/crypto_route.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/crypto_route.h 2004-12-14 18:53:11.000000000 +0300 @@ -0,0 +1,242 @@ +/* + * crypto_route.h + * + * Copyright (c) 2004 Evgeniy Polyakov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __CRYPTO_ROUTE_H +#define __CRYPTO_ROUTE_H + +#include +#include +#include + +#include "acrypto.h" + +static inline struct crypto_route *crypto_route_alloc_direct(struct crypto_device *dev, + struct crypto_session_initializer *ci) +{ + struct crypto_route *rt; + + rt = kmalloc(sizeof(*rt), GFP_ATOMIC); + if (!rt) { + crypto_device_put(dev); + return NULL; + } + + memset(rt, 0, sizeof(*rt)); + memcpy(&rt->ci, ci, sizeof(*ci)); + + rt->dev = dev; + + return rt; +} + +static inline struct crypto_route *crypto_route_alloc(struct crypto_device *dev, + struct crypto_session_initializer *ci) +{ + struct crypto_route *rt; + + if (!match_initializer(dev, ci)) + return NULL; + + rt = crypto_route_alloc_direct(dev, ci); + + return rt; +} + +static inline void crypto_route_free(struct crypto_route *rt) +{ + crypto_device_put(rt->dev); + rt->dev = NULL; + kfree(rt); +} + +static inline void __crypto_route_del(struct crypto_route *rt, struct crypto_route_head *list) +{ + struct crypto_route *next, *prev; + + list->qlen--; + next = rt->next; + prev = rt->prev; + rt->next = rt->prev = NULL; + rt->list = NULL; + next->prev = prev; + prev->next = next; +} + +static inline void crypto_route_del(struct crypto_route *rt) +{ + struct crypto_route_head *list = rt->list; + + if (list) { + spin_lock_irq(&list->lock); + if (list == rt->list) + __crypto_route_del(rt, rt->list); + spin_unlock_irq(&list->lock); + + crypto_route_free(rt); + } +} + +static inline struct crypto_route *__crypto_route_dequeue(struct crypto_route_head *list) +{ + struct crypto_route *next, *prev, *result; + + prev = (struct crypto_route *)list; + next = prev->next; + result = NULL; + if (next != prev) { + result = next; + next = next->next; + list->qlen--; + next->prev = prev; + prev->next = next; + result->next = result->prev = NULL; + result->list = NULL; + } + return result; +} + +static inline struct crypto_route *crypto_route_dequeue(struct crypto_session *s) +{ + struct crypto_route *rt; + + spin_lock_irq(&s->route_list.lock); + + rt = __crypto_route_dequeue(&s->route_list); + + spin_unlock_irq(&s->route_list.lock); + + return rt; +} + +static inline void __crypto_route_queue(struct crypto_route *rt, struct crypto_route_head *list) +{ + struct crypto_route *prev, *next; + + rt->list = list; + list->qlen++; + next = (struct crypto_route *)list; + prev = next->prev; + rt->next = next; + rt->prev = prev; + next->prev = prev->next = rt; +} + +static inline void crypto_route_queue(struct crypto_route *rt, struct crypto_session *s) +{ + + spin_lock_irq(&s->route_list.lock); + + __crypto_route_queue(rt, &s->route_list); + + spin_unlock_irq(&s->route_list.lock); +} + +static inline int crypto_route_add(struct crypto_device *dev, struct crypto_session *s, + struct crypto_session_initializer *ci) +{ + struct crypto_route *rt; + + rt = crypto_route_alloc(dev, ci); + if (!rt) + return -ENOMEM; + + crypto_route_queue(rt, s); + + return 0; +} + +static inline int crypto_route_add_direct(struct crypto_device *dev, struct crypto_session *s, + struct crypto_session_initializer *ci) +{ + struct crypto_route *rt; + + rt = crypto_route_alloc_direct(dev, ci); + if (!rt) + return -ENOMEM; + + crypto_route_queue(rt, s); + + return 0; +} + +static inline int crypto_route_queue_len(struct crypto_session *s) +{ + return s->route_list.qlen; +} + +static inline void crypto_route_head_init(struct crypto_route_head *list) +{ + spin_lock_init(&list->lock); + list->prev = list->next = (struct crypto_route *)list; + list->qlen = 0; +} + +static inline struct crypto_route *__crypto_route_current(struct crypto_route_head *list) +{ + struct crypto_route *next, *prev, *result; + + prev = (struct crypto_route *)list; + next = prev->next; + result = NULL; + if (next != prev) + result = next; + + return result; +} + +static inline struct crypto_route *crypto_route_current(struct crypto_session *s) +{ + struct crypto_route_head *list; + struct crypto_route *rt = NULL; + + list = &s->route_list; + + if (list) { + spin_lock_irq(&list->lock); + + rt = __crypto_route_current(list); + + spin_unlock_irq(&list->lock); + } + + return rt; +} + +static inline struct crypto_device *crypto_route_get_current_device(struct crypto_session *s) +{ + struct crypto_route *rt = NULL; + struct crypto_device *dev = NULL; + struct crypto_route_head *list = &s->route_list; + + spin_lock_irq(&list->lock); + + rt = __crypto_route_current(list); + if (rt) { + dev = rt->dev; + crypto_device_get(dev); + } + + spin_unlock_irq(&list->lock); + + return dev; +} + +#endif /* __CRYPTO_ROUTE_H */ diff -Nru /tmp/empty/crypto_stat.c linux-2.6/drivers/acrypto/crypto_stat.c --- /tmp/empty/crypto_stat.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/crypto_stat.c 2004-12-14 18:53:11.000000000 +0300 @@ -0,0 +1,100 @@ +/* + * crypto_stat.c + * + * Copyright (c) 2004 Evgeniy Polyakov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "acrypto.h" +#include "crypto_route.h" + +void crypto_stat_start_inc(struct crypto_session *s) +{ + struct crypto_device *dev; + + dev = crypto_route_get_current_device(s); + if (dev) { + spin_lock_irq(&dev->stat_lock); + dev->stat.sstarted++; + spin_unlock_irq(&dev->stat_lock); + + crypto_device_put(dev); + } +} + +void crypto_stat_finish_inc(struct crypto_session *s) +{ + struct crypto_device *dev; + + dev = crypto_route_get_current_device(s); + if (dev) { + spin_lock_irq(&dev->stat_lock); + dev->stat.sfinished++; + spin_unlock_irq(&dev->stat_lock); + + crypto_device_put(dev); + } +} + +void crypto_stat_complete_inc(struct crypto_session *s) +{ + struct crypto_device *dev; + + dev = crypto_route_get_current_device(s); + if (dev) { + spin_lock_irq(&dev->stat_lock); + dev->stat.scompleted++; + spin_unlock_irq(&dev->stat_lock); + + crypto_device_put(dev); + } +} + +void crypto_stat_ptime_inc(struct crypto_session *s) +{ + struct crypto_device *dev; + + dev = crypto_route_get_current_device(s); + if (dev) { + int i; + + spin_lock_irq(&dev->stat_lock); + for (i = 0; i < dev->cap_number; ++i) { + if (__match_initializer(&dev->cap[i], &s->ci)) { + dev->cap[i].ptime += s->ci.ptime; + dev->cap[i].scomp++; + break; + } + } + spin_unlock_irq(&dev->stat_lock); + + crypto_device_put(dev); + } +} + +EXPORT_SYMBOL(crypto_stat_start_inc); +EXPORT_SYMBOL(crypto_stat_finish_inc); +EXPORT_SYMBOL(crypto_stat_complete_inc); diff -Nru /tmp/empty/crypto_stat.h linux-2.6/drivers/acrypto/crypto_stat.h --- /tmp/empty/crypto_stat.h 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/crypto_stat.h 2004-12-14 18:53:11.000000000 +0300 @@ -0,0 +1,32 @@ +/* + * crypto_stat.h + * + * Copyright (c) 2004 Evgeniy Polyakov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __CRYPTO_STAT_H +#define __CRYPTO_STAT_H + +#include "acrypto.h" + +void crypto_stat_start_inc(struct crypto_session *s); +void crypto_stat_finish_inc(struct crypto_session *s); +void crypto_stat_complete_inc(struct crypto_session *s); +void crypto_stat_ptime_inc(struct crypto_session *s); + +#endif /* __CRYPTO_STAT_H */ diff -Nru /tmp/empty/Kconfig linux-2.6/drivers/acrypto/Kconfig --- /tmp/empty/Kconfig 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/Kconfig 2004-12-14 18:04:35.000000000 +0300 @@ -0,0 +1,40 @@ +menu "Asynchronous crypto layer" + +config ACRYPTO + tristate "Asyncronous crypto layer" + depends on CONNECTOR + help + Say Y here if you want to use new Linux asynchronous crypto layer. + This support is also available as a module. If so, the module + will be called acrypto.ko. + +config SIMPLE_LB + tristate "Simple asyncronous crypto load balancer" + depends on ACRYPTO + help + Say Y here if you want to compile simple load balancer which takes into + account only crypto device's queue length. + This support is also available as a module. If so, the module + will be called simpl_lb.ko. + +config TEST_CRYPTO_PROVIDER + tristate "Simple crypto provider" + depends on CRYPTO && ACRYPTO + help + Say Y here if you want to compile test bridge between + synchronous crypto layer and asyncronous one. + It supports only AES-128-ECB. + This support is also available as a module. If so, the module + will be called crypto_provider.ko. + +config TEST_CRYPTO_CONSUMER + tristate "Simple crypto consumer" + depends on ACRYPTO + help + Say Y here if you want to compile test crypto consumer + which injects crypto session one time per jiffie. + It supports only AES-128-ECB. + This support is also available as a module. If so, the module + will be called consumer.ko. + +endmenu diff -Nru /tmp/empty/Makefile linux-2.6/drivers/acrypto/Makefile --- /tmp/empty/Makefile 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/Makefile 2004-12-14 17:52:25.000000000 +0300 @@ -0,0 +1,6 @@ +obj-$(CONFIG_ACRYPTO) += acrypto.o +obj-$(CONFIG_SIMPLE_LB) += simple_lb.o +obj-$(CONFIG_TEST_CRYPTO_PROVIDER) += crypto_provider.o +obj-$(CONFIG_TEST_CRYPTO_CONSUMER) += consumer.o + +acrypto-objs := crypto_main.o crypto_lb.o crypto_dev.o crypto_conn.o crypto_stat.o diff -Nru /tmp/empty/simple_lb.c linux-2.6/drivers/acrypto/simple_lb.c --- /tmp/empty/simple_lb.c 1970-01-01 03:00:00.000000000 +0300 +++ linux-2.6/drivers/acrypto/simple_lb.c 2004-12-14 18:53:11.000000000 +0300 @@ -0,0 +1,91 @@ +/* + * simple_lb.c + * + * Copyright (c) 2004 Evgeniy Polyakov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include + +#include "crypto_lb.h" + +static void simple_lb_rehash(struct crypto_lb *); +static struct crypto_device *simple_lb_find_device(struct crypto_lb *, + struct + crypto_session_initializer *, + struct crypto_data *); + +struct crypto_lb simple_lb = { + .name = "simple_lb", + .rehash = simple_lb_rehash, + .find_device = simple_lb_find_device +}; + +static void simple_lb_rehash(struct crypto_lb *lb) +{ +} + +static struct crypto_device *simple_lb_find_device(struct crypto_lb *lb, + struct + crypto_session_initializer + *ci, + struct crypto_data *data) +{ + struct crypto_device *dev, *__dev; + int min = 0x7ffffff; + + __dev = NULL; + list_for_each_entry(dev, lb->crypto_device_list, cdev_entry) { + if (device_broken(dev)) + continue; + if (!match_initializer(dev, ci)) + continue; + + if (atomic_read(&dev->refcnt) < min) { + min = atomic_read(&dev->refcnt); + __dev = dev; + } + } + + return __dev; +} + +int __devinit simple_lb_init(void) +{ + dprintk(KERN_INFO "Registering simple crypto load balancer.\n"); + + return crypto_lb_register(&simple_lb, 1, 1); +} + +void __devexit simple_lb_fini(void) +{ + dprintk(KERN_INFO "Unregistering simple crypto load balancer.\n"); + + crypto_lb_unregister(&simple_lb); +} + +module_init(simple_lb_init); +module_exit(simple_lb_fini); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Evgeniy Polyakov "); +MODULE_DESCRIPTION("Simple crypto load balancer.");