/* * 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(struct crypto_device *dev, struct crypto_session_initializer *ci) { struct crypto_route *rt; crypto_device_get(dev); if (!match_initializer(dev, ci)) { crypto_device_put(dev); return NULL; } 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 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_bh(&list->lock); if (list == rt->list) __crypto_route_del(rt, rt->list); spin_unlock_bh(&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_bh(&s->route_list.lock); rt = __crypto_route_dequeue(&s->route_list); spin_unlock_bh(&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_bh(&s->route_list.lock); __crypto_route_queue(rt, &s->route_list); spin_unlock_bh(&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_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_bh(&list->lock); rt = __crypto_route_current(list); spin_unlock_bh(&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_bh(&list->lock); rt = __crypto_route_current(list); if (rt) { dev = rt->dev; crypto_device_get(dev); } spin_unlock_bh(&list->lock); return dev; } #endif /* __CRYPTO_ROUTE_H */