*
*/
+#include <linux/config.h>
#include <linux/slab.h>
#include <linux/kmod.h>
#include <linux/list.h>
static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family);
static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo);
-static struct xfrm_policy_afinfo *xfrm_policy_lock_afinfo(unsigned int family);
-static void xfrm_policy_unlock_afinfo(struct xfrm_policy_afinfo *afinfo);
int xfrm_register_type(struct xfrm_type *type, unsigned short family)
{
- struct xfrm_policy_afinfo *afinfo = xfrm_policy_lock_afinfo(family);
- struct xfrm_type **typemap;
+ struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
+ struct xfrm_type_map *typemap;
int err = 0;
if (unlikely(afinfo == NULL))
return -EAFNOSUPPORT;
typemap = afinfo->type_map;
- if (likely(typemap[type->proto] == NULL))
- typemap[type->proto] = type;
+ write_lock_bh(&typemap->lock);
+ if (likely(typemap->map[type->proto] == NULL))
+ typemap->map[type->proto] = type;
else
err = -EEXIST;
- xfrm_policy_unlock_afinfo(afinfo);
+ write_unlock_bh(&typemap->lock);
+ xfrm_policy_put_afinfo(afinfo);
return err;
}
EXPORT_SYMBOL(xfrm_register_type);
int xfrm_unregister_type(struct xfrm_type *type, unsigned short family)
{
- struct xfrm_policy_afinfo *afinfo = xfrm_policy_lock_afinfo(family);
- struct xfrm_type **typemap;
+ struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
+ struct xfrm_type_map *typemap;
int err = 0;
if (unlikely(afinfo == NULL))
return -EAFNOSUPPORT;
typemap = afinfo->type_map;
- if (unlikely(typemap[type->proto] != type))
+ write_lock_bh(&typemap->lock);
+ if (unlikely(typemap->map[type->proto] != type))
err = -ENOENT;
else
- typemap[type->proto] = NULL;
- xfrm_policy_unlock_afinfo(afinfo);
+ typemap->map[type->proto] = NULL;
+ write_unlock_bh(&typemap->lock);
+ xfrm_policy_put_afinfo(afinfo);
return err;
}
EXPORT_SYMBOL(xfrm_unregister_type);
struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
{
struct xfrm_policy_afinfo *afinfo;
- struct xfrm_type **typemap;
+ struct xfrm_type_map *typemap;
struct xfrm_type *type;
int modload_attempted = 0;
return NULL;
typemap = afinfo->type_map;
- type = typemap[proto];
+ read_lock(&typemap->lock);
+ type = typemap->map[proto];
if (unlikely(type && !try_module_get(type->owner)))
type = NULL;
+ read_unlock(&typemap->lock);
if (!type && !modload_attempted) {
xfrm_policy_put_afinfo(afinfo);
request_module("xfrm-type-%d-%d",
module_put(type->owner);
}
-int xfrm_register_mode(struct xfrm_mode *mode, int family)
-{
- struct xfrm_policy_afinfo *afinfo;
- struct xfrm_mode **modemap;
- int err;
-
- if (unlikely(mode->encap >= XFRM_MODE_MAX))
- return -EINVAL;
-
- afinfo = xfrm_policy_lock_afinfo(family);
- if (unlikely(afinfo == NULL))
- return -EAFNOSUPPORT;
-
- err = -EEXIST;
- modemap = afinfo->mode_map;
- if (likely(modemap[mode->encap] == NULL)) {
- modemap[mode->encap] = mode;
- err = 0;
- }
-
- xfrm_policy_unlock_afinfo(afinfo);
- return err;
-}
-EXPORT_SYMBOL(xfrm_register_mode);
-
-int xfrm_unregister_mode(struct xfrm_mode *mode, int family)
-{
- struct xfrm_policy_afinfo *afinfo;
- struct xfrm_mode **modemap;
- int err;
-
- if (unlikely(mode->encap >= XFRM_MODE_MAX))
- return -EINVAL;
-
- afinfo = xfrm_policy_lock_afinfo(family);
- if (unlikely(afinfo == NULL))
- return -EAFNOSUPPORT;
-
- err = -ENOENT;
- modemap = afinfo->mode_map;
- if (likely(modemap[mode->encap] == mode)) {
- modemap[mode->encap] = NULL;
- err = 0;
- }
-
- xfrm_policy_unlock_afinfo(afinfo);
- return err;
-}
-EXPORT_SYMBOL(xfrm_unregister_mode);
-
-struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family)
-{
- struct xfrm_policy_afinfo *afinfo;
- struct xfrm_mode *mode;
- int modload_attempted = 0;
-
- if (unlikely(encap >= XFRM_MODE_MAX))
- return NULL;
-
-retry:
- afinfo = xfrm_policy_get_afinfo(family);
- if (unlikely(afinfo == NULL))
- return NULL;
-
- mode = afinfo->mode_map[encap];
- if (unlikely(mode && !try_module_get(mode->owner)))
- mode = NULL;
- if (!mode && !modload_attempted) {
- xfrm_policy_put_afinfo(afinfo);
- request_module("xfrm-mode-%d-%d", family, encap);
- modload_attempted = 1;
- goto retry;
- }
-
- xfrm_policy_put_afinfo(afinfo);
- return mode;
-}
-
-void xfrm_put_mode(struct xfrm_mode *mode)
-{
- module_put(mode->owner);
-}
-
static inline unsigned long make_jiffies(long secs)
{
if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)
{
struct xfrm_policy *policy;
- policy = kzalloc(sizeof(struct xfrm_policy), gfp);
+ policy = kmalloc(sizeof(struct xfrm_policy), gfp);
if (policy) {
+ memset(policy, 0, sizeof(struct xfrm_policy));
atomic_set(&policy->refcnt, 1);
rwlock_init(&policy->lock);
init_timer(&policy->timer);
}
EXPORT_SYMBOL(__xfrm_route_forward);
-/* Optimize later using cookies and generation ids. */
-
static struct dst_entry *xfrm_dst_check(struct dst_entry *dst, u32 cookie)
{
- /* Code (such as __xfrm4_bundle_create()) sets dst->obsolete
- * to "-1" to force all XFRM destinations to get validated by
- * dst_ops->check on every use. We do this because when a
- * normal route referenced by an XFRM dst is obsoleted we do
- * not go looking around for all parent referencing XFRM dsts
- * so that we can invalidate them. It is just too much work.
- * Instead we make the checks here on every use. For example:
- *
- * XFRM dst A --> IPv4 dst X
- *
- * X is the "xdst->route" of A (X is also the "dst->path" of A
- * in this example). If X is marked obsolete, "A" will not
- * notice. That's what we are validating here via the
- * stale_bundle() check.
- *
- * When a policy's bundle is pruned, we dst_free() the XFRM
- * dst which causes it's ->obsolete field to be set to a
- * positive non-zero integer. If an XFRM dst has been pruned
- * like this, we want to force a new route lookup.
+ /* If it is marked obsolete, which is how we even get here,
+ * then we have purged it from the policy bundle list and we
+ * did that for a good reason.
*/
- if (dst->obsolete < 0 && !stale_bundle(dst))
- return dst;
-
return NULL;
}
return NULL;
read_lock(&xfrm_policy_afinfo_lock);
afinfo = xfrm_policy_afinfo[family];
- if (unlikely(!afinfo))
- read_unlock(&xfrm_policy_afinfo_lock);
- return afinfo;
-}
-
-static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo)
-{
+ if (likely(afinfo != NULL))
+ read_lock(&afinfo->lock);
read_unlock(&xfrm_policy_afinfo_lock);
-}
-
-static struct xfrm_policy_afinfo *xfrm_policy_lock_afinfo(unsigned int family)
-{
- struct xfrm_policy_afinfo *afinfo;
- if (unlikely(family >= NPROTO))
- return NULL;
- write_lock_bh(&xfrm_policy_afinfo_lock);
- afinfo = xfrm_policy_afinfo[family];
- if (unlikely(!afinfo))
- write_unlock_bh(&xfrm_policy_afinfo_lock);
return afinfo;
}
-static void xfrm_policy_unlock_afinfo(struct xfrm_policy_afinfo *afinfo)
+static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo)
{
- write_unlock_bh(&xfrm_policy_afinfo_lock);
+ if (unlikely(afinfo == NULL))
+ return;
+ read_unlock(&afinfo->lock);
}
static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr)