summaryrefslogtreecommitdiff
path: root/net/xfrm
diff options
context:
space:
mode:
Diffstat (limited to 'net/xfrm')
-rw-r--r--net/xfrm/xfrm_input.c5
-rw-r--r--net/xfrm/xfrm_output.c4
-rw-r--r--net/xfrm/xfrm_policy.c179
-rw-r--r--net/xfrm/xfrm_state.c206
4 files changed, 207 insertions, 187 deletions
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index 113f444..cb97fda 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -49,13 +49,16 @@ EXPORT_SYMBOL(secpath_dup);
int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)
{
int offset, offset_seq;
+ int hlen;
switch (nexthdr) {
case IPPROTO_AH:
+ hlen = sizeof(struct ip_auth_hdr);
offset = offsetof(struct ip_auth_hdr, spi);
offset_seq = offsetof(struct ip_auth_hdr, seq_no);
break;
case IPPROTO_ESP:
+ hlen = sizeof(struct ip_esp_hdr);
offset = offsetof(struct ip_esp_hdr, spi);
offset_seq = offsetof(struct ip_esp_hdr, seq_no);
break;
@@ -69,7 +72,7 @@ int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)
return 1;
}
- if (!pskb_may_pull(skb, 16))
+ if (!pskb_may_pull(skb, hlen))
return -EINVAL;
*spi = *(__be32*)(skb_transport_header(skb) + offset);
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index 0eb3377..f4bfd6c 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -63,7 +63,7 @@ int xfrm_output(struct sk_buff *skb)
xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
}
- err = x->mode->output(x, skb);
+ err = x->outer_mode->output(x, skb);
if (err)
goto error;
@@ -82,7 +82,7 @@ int xfrm_output(struct sk_buff *skb)
}
dst = skb->dst;
x = dst->xfrm;
- } while (x && (x->props.mode != XFRM_MODE_TUNNEL));
+ } while (x && !(x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL));
err = 0;
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index af27c19..b702bd8 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -49,8 +49,6 @@ 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);
-static struct xfrm_policy_afinfo *xfrm_policy_lock_afinfo(unsigned int family);
-static void xfrm_policy_unlock_afinfo(struct xfrm_policy_afinfo *afinfo);
static inline int
__xfrm4_selector_match(struct xfrm_selector *sel, struct flowi *fl)
@@ -86,72 +84,6 @@ int xfrm_selector_match(struct xfrm_selector *sel, struct flowi *fl,
return 0;
}
-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;
- int err = 0;
-
- if (unlikely(afinfo == NULL))
- return -EAFNOSUPPORT;
- typemap = afinfo->type_map;
-
- if (likely(typemap[type->proto] == NULL))
- typemap[type->proto] = type;
- else
- err = -EEXIST;
- xfrm_policy_unlock_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;
- int err = 0;
-
- if (unlikely(afinfo == NULL))
- return -EAFNOSUPPORT;
- typemap = afinfo->type_map;
-
- if (unlikely(typemap[type->proto] != type))
- err = -ENOENT;
- else
- typemap[type->proto] = NULL;
- xfrm_policy_unlock_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 *type;
- int modload_attempted = 0;
-
-retry:
- afinfo = xfrm_policy_get_afinfo(family);
- if (unlikely(afinfo == NULL))
- return NULL;
- typemap = afinfo->type_map;
-
- type = typemap[proto];
- if (unlikely(type && !try_module_get(type->owner)))
- type = NULL;
- if (!type && !modload_attempted) {
- xfrm_policy_put_afinfo(afinfo);
- request_module("xfrm-type-%d-%d",
- (int) family, (int) proto);
- modload_attempted = 1;
- goto retry;
- }
-
- xfrm_policy_put_afinfo(afinfo);
- return type;
-}
-
int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl,
unsigned short family)
{
@@ -170,94 +102,6 @@ int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl,
}
EXPORT_SYMBOL(xfrm_dst_lookup);
-void xfrm_put_type(struct xfrm_type *type)
-{
- 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)
@@ -2096,7 +1940,8 @@ int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first,
if (xdst->genid != dst->xfrm->genid)
return 0;
- if (strict && fl && dst->xfrm->props.mode != XFRM_MODE_TUNNEL &&
+ if (strict && fl &&
+ !(dst->xfrm->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) &&
!xfrm_state_addr_flow_check(dst->xfrm, fl, family))
return 0;
@@ -2213,23 +2058,6 @@ static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo)
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)
-{
- write_unlock_bh(&xfrm_policy_afinfo_lock);
-}
-
static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
{
struct net_device *dev = ptr;
@@ -2464,7 +2292,8 @@ static int xfrm_policy_migrate(struct xfrm_policy *pol,
if (!migrate_tmpl_match(mp, &pol->xfrm_vec[i]))
continue;
n++;
- if (pol->xfrm_vec[i].mode != XFRM_MODE_TUNNEL)
+ if (pol->xfrm_vec[i].mode != XFRM_MODE_TUNNEL &&
+ pol->xfrm_vec[i].mode != XFRM_MODE_BEET)
continue;
/* update endpoints */
memcpy(&pol->xfrm_vec[i].id.daddr, &mp->new_daddr,
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 344f0a6..224b44e 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -57,6 +57,9 @@ static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
static unsigned int xfrm_state_num;
static unsigned int xfrm_state_genid;
+static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
+static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
+
static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr,
xfrm_address_t *saddr,
u32 reqid,
@@ -187,6 +190,184 @@ int __xfrm_state_delete(struct xfrm_state *x);
int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
+static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family)
+{
+ struct xfrm_state_afinfo *afinfo;
+ if (unlikely(family >= NPROTO))
+ return NULL;
+ write_lock_bh(&xfrm_state_afinfo_lock);
+ afinfo = xfrm_state_afinfo[family];
+ if (unlikely(!afinfo))
+ write_unlock_bh(&xfrm_state_afinfo_lock);
+ return afinfo;
+}
+
+static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo)
+{
+ write_unlock_bh(&xfrm_state_afinfo_lock);
+}
+
+int xfrm_register_type(struct xfrm_type *type, unsigned short family)
+{
+ struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
+ struct xfrm_type **typemap;
+ int err = 0;
+
+ if (unlikely(afinfo == NULL))
+ return -EAFNOSUPPORT;
+ typemap = afinfo->type_map;
+
+ if (likely(typemap[type->proto] == NULL))
+ typemap[type->proto] = type;
+ else
+ err = -EEXIST;
+ xfrm_state_unlock_afinfo(afinfo);
+ return err;
+}
+EXPORT_SYMBOL(xfrm_register_type);
+
+int xfrm_unregister_type(struct xfrm_type *type, unsigned short family)
+{
+ struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
+ struct xfrm_type **typemap;
+ int err = 0;
+
+ if (unlikely(afinfo == NULL))
+ return -EAFNOSUPPORT;
+ typemap = afinfo->type_map;
+
+ if (unlikely(typemap[type->proto] != type))
+ err = -ENOENT;
+ else
+ typemap[type->proto] = NULL;
+ xfrm_state_unlock_afinfo(afinfo);
+ return err;
+}
+EXPORT_SYMBOL(xfrm_unregister_type);
+
+static struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
+{
+ struct xfrm_state_afinfo *afinfo;
+ struct xfrm_type **typemap;
+ struct xfrm_type *type;
+ int modload_attempted = 0;
+
+retry:
+ afinfo = xfrm_state_get_afinfo(family);
+ if (unlikely(afinfo == NULL))
+ return NULL;
+ typemap = afinfo->type_map;
+
+ type = typemap[proto];
+ if (unlikely(type && !try_module_get(type->owner)))
+ type = NULL;
+ if (!type && !modload_attempted) {
+ xfrm_state_put_afinfo(afinfo);
+ request_module("xfrm-type-%d-%d", family, proto);
+ modload_attempted = 1;
+ goto retry;
+ }
+
+ xfrm_state_put_afinfo(afinfo);
+ return type;
+}
+
+static void xfrm_put_type(struct xfrm_type *type)
+{
+ module_put(type->owner);
+}
+
+int xfrm_register_mode(struct xfrm_mode *mode, int family)
+{
+ struct xfrm_state_afinfo *afinfo;
+ struct xfrm_mode **modemap;
+ int err;
+
+ if (unlikely(mode->encap >= XFRM_MODE_MAX))
+ return -EINVAL;
+
+ afinfo = xfrm_state_lock_afinfo(family);
+ if (unlikely(afinfo == NULL))
+ return -EAFNOSUPPORT;
+
+ err = -EEXIST;
+ modemap = afinfo->mode_map;
+ if (modemap[mode->encap])
+ goto out;
+
+ err = -ENOENT;
+ if (!try_module_get(afinfo->owner))
+ goto out;
+
+ mode->afinfo = afinfo;
+ modemap[mode->encap] = mode;
+ err = 0;
+
+out:
+ xfrm_state_unlock_afinfo(afinfo);
+ return err;
+}
+EXPORT_SYMBOL(xfrm_register_mode);
+
+int xfrm_unregister_mode(struct xfrm_mode *mode, int family)
+{
+ struct xfrm_state_afinfo *afinfo;
+ struct xfrm_mode **modemap;
+ int err;
+
+ if (unlikely(mode->encap >= XFRM_MODE_MAX))
+ return -EINVAL;
+
+ afinfo = xfrm_state_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;
+ module_put(mode->afinfo->owner);
+ err = 0;
+ }
+
+ xfrm_state_unlock_afinfo(afinfo);
+ return err;
+}
+EXPORT_SYMBOL(xfrm_unregister_mode);
+
+static struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family)
+{
+ struct xfrm_state_afinfo *afinfo;
+ struct xfrm_mode *mode;
+ int modload_attempted = 0;
+
+ if (unlikely(encap >= XFRM_MODE_MAX))
+ return NULL;
+
+retry:
+ afinfo = xfrm_state_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_state_put_afinfo(afinfo);
+ request_module("xfrm-mode-%d-%d", family, encap);
+ modload_attempted = 1;
+ goto retry;
+ }
+
+ xfrm_state_put_afinfo(afinfo);
+ return mode;
+}
+
+static void xfrm_put_mode(struct xfrm_mode *mode)
+{
+ module_put(mode->owner);
+}
+
static void xfrm_state_gc_destroy(struct xfrm_state *x)
{
del_timer_sync(&x->timer);
@@ -196,8 +377,10 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x)
kfree(x->calg);
kfree(x->encap);
kfree(x->coaddr);
- if (x->mode)
- xfrm_put_mode(x->mode);
+ if (x->inner_mode)
+ xfrm_put_mode(x->inner_mode);
+ if (x->outer_mode)
+ xfrm_put_mode(x->outer_mode);
if (x->type) {
x->type->destructor(x);
xfrm_put_type(x->type);
@@ -1699,7 +1882,7 @@ int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo)
}
EXPORT_SYMBOL(xfrm_state_unregister_afinfo);
-struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family)
+static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
{
struct xfrm_state_afinfo *afinfo;
if (unlikely(family >= NPROTO))
@@ -1711,14 +1894,11 @@ struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family)
return afinfo;
}
-void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
+static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
{
read_unlock(&xfrm_state_afinfo_lock);
}
-EXPORT_SYMBOL(xfrm_state_get_afinfo);
-EXPORT_SYMBOL(xfrm_state_put_afinfo);
-
/* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */
void xfrm_state_delete_tunnel(struct xfrm_state *x)
{
@@ -1769,6 +1949,14 @@ int xfrm_init_state(struct xfrm_state *x)
goto error;
err = -EPROTONOSUPPORT;
+ x->inner_mode = xfrm_get_mode(x->props.mode, x->sel.family);
+ if (x->inner_mode == NULL)
+ goto error;
+
+ if (!(x->inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) &&
+ family != x->sel.family)
+ goto error;
+
x->type = xfrm_get_type(x->id.proto, family);
if (x->type == NULL)
goto error;
@@ -1777,8 +1965,8 @@ int xfrm_init_state(struct xfrm_state *x)
if (err)
goto error;
- x->mode = xfrm_get_mode(x->props.mode, family);
- if (x->mode == NULL)
+ x->outer_mode = xfrm_get_mode(x->props.mode, family);
+ if (x->outer_mode == NULL)
goto error;
x->km.state = XFRM_STATE_VALID;