#include <linux/workqueue.h>
#include <linux/notifier.h>
#include <linux/netdevice.h>
+#include <linux/module.h>
#include <net/xfrm.h>
#include <net/ip.h>
DECLARE_MUTEX(xfrm_cfg_sem);
+EXPORT_SYMBOL(xfrm_cfg_sem);
-static rwlock_t xfrm_policy_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(xfrm_policy_lock);
struct xfrm_policy *xfrm_policy_list[XFRM_POLICY_MAX*2];
+EXPORT_SYMBOL(xfrm_policy_list);
-static rwlock_t xfrm_policy_afinfo_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(xfrm_policy_afinfo_lock);
static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO];
-kmem_cache_t *xfrm_dst_cache;
+static kmem_cache_t *xfrm_dst_cache;
static struct work_struct xfrm_policy_gc_work;
static struct list_head xfrm_policy_gc_list =
LIST_HEAD_INIT(xfrm_policy_gc_list);
-static spinlock_t xfrm_policy_gc_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(xfrm_policy_gc_lock);
+
+static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family);
+static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo);
int xfrm_register_type(struct xfrm_type *type, unsigned short family)
{
xfrm_policy_put_afinfo(afinfo);
return err;
}
+EXPORT_SYMBOL(xfrm_register_type);
int xfrm_unregister_type(struct xfrm_type *type, unsigned short family)
{
xfrm_policy_put_afinfo(afinfo);
return err;
}
+EXPORT_SYMBOL(xfrm_unregister_type);
struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
{
xfrm_policy_put_afinfo(afinfo);
return type;
}
+EXPORT_SYMBOL(xfrm_get_type);
int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl,
unsigned short family)
xfrm_policy_put_afinfo(afinfo);
return err;
}
+EXPORT_SYMBOL(xfrm_dst_lookup);
void xfrm_put_type(struct xfrm_type *type)
{
if (policy) {
memset(policy, 0, sizeof(struct xfrm_policy));
atomic_set(&policy->refcnt, 1);
- policy->lock = RW_LOCK_UNLOCKED;
+ rwlock_init(&policy->lock);
init_timer(&policy->timer);
policy->timer.data = (unsigned long)policy;
policy->timer.function = xfrm_policy_timer;
}
return policy;
}
+EXPORT_SYMBOL(xfrm_policy_alloc);
/* Destroy xfrm_policy: descendant resources must be released to this moment. */
kfree(policy);
}
+EXPORT_SYMBOL(__xfrm_policy_destroy);
static void xfrm_policy_gc_kill(struct xfrm_policy *policy)
{
* entry dead. The rule must be unlinked from lists to the moment.
*/
-void xfrm_policy_kill(struct xfrm_policy *policy)
+static void xfrm_policy_kill(struct xfrm_policy *policy)
{
write_lock_bh(&policy->lock);
if (policy->dead)
struct xfrm_policy **newpos = NULL;
write_lock_bh(&xfrm_policy_lock);
- for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) {
+ for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL;) {
if (!delpol && memcmp(&policy->selector, &pol->selector, sizeof(pol->selector)) == 0) {
if (excl) {
write_unlock_bh(&xfrm_policy_lock);
delpol = pol;
if (policy->priority > pol->priority)
continue;
- } else if (policy->priority >= pol->priority)
+ } else if (policy->priority >= pol->priority) {
+ p = &pol->next;
continue;
+ }
if (!newpos)
newpos = p;
if (delpol)
break;
+ p = &pol->next;
}
if (newpos)
p = newpos;
}
return 0;
}
+EXPORT_SYMBOL(xfrm_policy_insert);
struct xfrm_policy *xfrm_policy_bysel(int dir, struct xfrm_selector *sel,
int delete)
}
return pol;
}
+EXPORT_SYMBOL(xfrm_policy_bysel);
struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete)
{
}
return pol;
}
+EXPORT_SYMBOL(xfrm_policy_byid);
void xfrm_policy_flush(void)
{
atomic_inc(&flow_cache_genid);
write_unlock_bh(&xfrm_policy_lock);
}
+EXPORT_SYMBOL(xfrm_policy_flush);
int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*),
void *data)
read_unlock_bh(&xfrm_policy_lock);
return error;
}
-
+EXPORT_SYMBOL(xfrm_policy_walk);
/* Find policy to apply to this flow. */
*obj_refp = &pol->refcnt;
}
-struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl)
+static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl)
{
struct xfrm_policy *pol;
*dst_p = NULL;
return err;
}
+EXPORT_SYMBOL(xfrm_lookup);
/* When skb is transformed back to its "native" form, we have to
* check policy restrictions. At the moment we make this in maximally
return 0;
}
+static inline int secpath_has_tunnel(struct sec_path *sp, int k)
+{
+ for (; k < sp->len; k++) {
+ if (sp->x[k].xvec->props.mode)
+ return 1;
+ }
+
+ return 0;
+}
+
int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
unsigned short family)
{
xfrm_policy_lookup);
if (!pol)
- return !skb->sp;
+ return !skb->sp || !secpath_has_tunnel(skb->sp, 0);
pol->curlft.use_time = (unsigned long)xtime.tv_sec;
goto reject;
}
- for (; k < sp->len; k++) {
- if (sp->x[k].xvec->props.mode)
- goto reject;
- }
+ if (secpath_has_tunnel(sp, k))
+ goto reject;
xfrm_pol_put(pol);
return 1;
xfrm_pol_put(pol);
return 0;
}
+EXPORT_SYMBOL(__xfrm_policy_check);
int __xfrm_route_forward(struct sk_buff *skb, unsigned short family)
{
return xfrm_lookup(&skb->dst, &fl, NULL, 0) == 0;
}
+EXPORT_SYMBOL(__xfrm_route_forward);
/* Optimize later using cookies and generation ids. */
dst->xfrm = NULL;
}
+static void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
+ int unregister)
+{
+ if (!unregister)
+ return;
+
+ while ((dst = dst->child) && dst->xfrm && dst->dev == dev) {
+ dst->dev = &loopback_dev;
+ dev_hold(&loopback_dev);
+ dev_put(dev);
+ }
+}
+
static void xfrm_link_failure(struct sk_buff *skb)
{
/* Impossible. Such dst must be popped before reaches point of failure. */
dst_ops->check = xfrm_dst_check;
if (likely(dst_ops->destroy == NULL))
dst_ops->destroy = xfrm_dst_destroy;
+ if (likely(dst_ops->ifdown == NULL))
+ dst_ops->ifdown = xfrm_dst_ifdown;
if (likely(dst_ops->negative_advice == NULL))
dst_ops->negative_advice = xfrm_negative_advice;
if (likely(dst_ops->link_failure == NULL))
write_unlock(&xfrm_policy_afinfo_lock);
return err;
}
+EXPORT_SYMBOL(xfrm_policy_register_afinfo);
int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo)
{
dst_ops->kmem_cachep = NULL;
dst_ops->check = NULL;
dst_ops->destroy = NULL;
+ dst_ops->ifdown = NULL;
dst_ops->negative_advice = NULL;
dst_ops->link_failure = NULL;
dst_ops->get_mss = NULL;
write_unlock(&xfrm_policy_afinfo_lock);
return err;
}
+EXPORT_SYMBOL(xfrm_policy_unregister_afinfo);
-struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family)
+static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family)
{
struct xfrm_policy_afinfo *afinfo;
if (unlikely(family >= NPROTO))
return afinfo;
}
-void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo)
+static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo)
{
if (unlikely(afinfo == NULL))
return;
return NOTIFY_DONE;
}
-struct notifier_block xfrm_dev_notifier = {
+static struct notifier_block xfrm_dev_notifier = {
xfrm_dev_event,
NULL,
0
};
-void __init xfrm_policy_init(void)
+static void __init xfrm_policy_init(void)
{
xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache",
sizeof(struct xfrm_dst),