aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/xfrm.h13
-rw-r--r--net/ipv4/xfrm4_policy.c20
-rw-r--r--net/ipv4/xfrm4_state.c15
-rw-r--r--net/ipv6/xfrm6_policy.c21
-rw-r--r--net/ipv6/xfrm6_state.c16
-rw-r--r--net/xfrm/xfrm_policy.c21
6 files changed, 75 insertions, 31 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 4d6dc627df9..11e0b1d6bd4 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -222,6 +222,7 @@ struct xfrm_policy_afinfo {
222 struct dst_ops *dst_ops; 222 struct dst_ops *dst_ops;
223 void (*garbage_collect)(void); 223 void (*garbage_collect)(void);
224 int (*dst_lookup)(struct xfrm_dst **dst, struct flowi *fl); 224 int (*dst_lookup)(struct xfrm_dst **dst, struct flowi *fl);
225 int (*get_saddr)(xfrm_address_t *saddr, xfrm_address_t *daddr);
225 struct dst_entry *(*find_bundle)(struct flowi *fl, struct xfrm_policy *policy); 226 struct dst_entry *(*find_bundle)(struct flowi *fl, struct xfrm_policy *policy);
226 int (*bundle_create)(struct xfrm_policy *policy, 227 int (*bundle_create)(struct xfrm_policy *policy,
227 struct xfrm_state **xfrm, 228 struct xfrm_state **xfrm,
@@ -631,6 +632,18 @@ secpath_reset(struct sk_buff *skb)
631} 632}
632 633
633static inline int 634static inline int
635xfrm_addr_any(xfrm_address_t *addr, unsigned short family)
636{
637 switch (family) {
638 case AF_INET:
639 return addr->a4 == 0;
640 case AF_INET6:
641 return ipv6_addr_any((struct in6_addr *)&addr->a6);
642 }
643 return 0;
644}
645
646static inline int
634__xfrm4_state_addr_cmp(struct xfrm_tmpl *tmpl, struct xfrm_state *x) 647__xfrm4_state_addr_cmp(struct xfrm_tmpl *tmpl, struct xfrm_state *x)
635{ 648{
636 return (tmpl->saddr.a4 && 649 return (tmpl->saddr.a4 &&
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 479598566f1..eabcd27b176 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -21,6 +21,25 @@ static int xfrm4_dst_lookup(struct xfrm_dst **dst, struct flowi *fl)
21 return __ip_route_output_key((struct rtable**)dst, fl); 21 return __ip_route_output_key((struct rtable**)dst, fl);
22} 22}
23 23
24static int xfrm4_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)
25{
26 struct rtable *rt;
27 struct flowi fl_tunnel = {
28 .nl_u = {
29 .ip4_u = {
30 .daddr = daddr->a4,
31 },
32 },
33 };
34
35 if (!xfrm4_dst_lookup((struct xfrm_dst **)&rt, &fl_tunnel)) {
36 saddr->a4 = rt->rt_src;
37 dst_release(&rt->u.dst);
38 return 0;
39 }
40 return -EHOSTUNREACH;
41}
42
24static struct dst_entry * 43static struct dst_entry *
25__xfrm4_find_bundle(struct flowi *fl, struct xfrm_policy *policy) 44__xfrm4_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
26{ 45{
@@ -298,6 +317,7 @@ static struct xfrm_policy_afinfo xfrm4_policy_afinfo = {
298 .family = AF_INET, 317 .family = AF_INET,
299 .dst_ops = &xfrm4_dst_ops, 318 .dst_ops = &xfrm4_dst_ops,
300 .dst_lookup = xfrm4_dst_lookup, 319 .dst_lookup = xfrm4_dst_lookup,
320 .get_saddr = xfrm4_get_saddr,
301 .find_bundle = __xfrm4_find_bundle, 321 .find_bundle = __xfrm4_find_bundle,
302 .bundle_create = __xfrm4_bundle_create, 322 .bundle_create = __xfrm4_bundle_create,
303 .decode_session = _decode_session4, 323 .decode_session = _decode_session4,
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c
index 6a2a4ab4277..fe2034494d0 100644
--- a/net/ipv4/xfrm4_state.c
+++ b/net/ipv4/xfrm4_state.c
@@ -42,21 +42,6 @@ __xfrm4_init_tempsel(struct xfrm_state *x, struct flowi *fl,
42 x->props.saddr = tmpl->saddr; 42 x->props.saddr = tmpl->saddr;
43 if (x->props.saddr.a4 == 0) 43 if (x->props.saddr.a4 == 0)
44 x->props.saddr.a4 = saddr->a4; 44 x->props.saddr.a4 = saddr->a4;
45 if (tmpl->mode == XFRM_MODE_TUNNEL && x->props.saddr.a4 == 0) {
46 struct rtable *rt;
47 struct flowi fl_tunnel = {
48 .nl_u = {
49 .ip4_u = {
50 .daddr = x->id.daddr.a4,
51 }
52 }
53 };
54 if (!xfrm_dst_lookup((struct xfrm_dst **)&rt,
55 &fl_tunnel, AF_INET)) {
56 x->props.saddr.a4 = rt->rt_src;
57 dst_release(&rt->u.dst);
58 }
59 }
60 x->props.mode = tmpl->mode; 45 x->props.mode = tmpl->mode;
61 x->props.reqid = tmpl->reqid; 46 x->props.reqid = tmpl->reqid;
62 x->props.family = AF_INET; 47 x->props.family = AF_INET;
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 9391c4c94fe..6a252e2134d 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -34,6 +34,26 @@ static int xfrm6_dst_lookup(struct xfrm_dst **dst, struct flowi *fl)
34 return err; 34 return err;
35} 35}
36 36
37static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)
38{
39 struct rt6_info *rt;
40 struct flowi fl_tunnel = {
41 .nl_u = {
42 .ip6_u = {
43 .daddr = *(struct in6_addr *)&daddr->a6,
44 },
45 },
46 };
47
48 if (!xfrm6_dst_lookup((struct xfrm_dst **)&rt, &fl_tunnel)) {
49 ipv6_get_saddr(&rt->u.dst, (struct in6_addr *)&daddr->a6,
50 (struct in6_addr *)&saddr->a6);
51 dst_release(&rt->u.dst);
52 return 0;
53 }
54 return -EHOSTUNREACH;
55}
56
37static struct dst_entry * 57static struct dst_entry *
38__xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy) 58__xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
39{ 59{
@@ -362,6 +382,7 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
362 .family = AF_INET6, 382 .family = AF_INET6,
363 .dst_ops = &xfrm6_dst_ops, 383 .dst_ops = &xfrm6_dst_ops,
364 .dst_lookup = xfrm6_dst_lookup, 384 .dst_lookup = xfrm6_dst_lookup,
385 .get_saddr = xfrm6_get_saddr,
365 .find_bundle = __xfrm6_find_bundle, 386 .find_bundle = __xfrm6_find_bundle,
366 .bundle_create = __xfrm6_bundle_create, 387 .bundle_create = __xfrm6_bundle_create,
367 .decode_session = _decode_session6, 388 .decode_session = _decode_session6,
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index d88cd92c864..711bfafb247 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -42,22 +42,6 @@ __xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl,
42 memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr)); 42 memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr));
43 if (ipv6_addr_any((struct in6_addr*)&x->props.saddr)) 43 if (ipv6_addr_any((struct in6_addr*)&x->props.saddr))
44 memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr)); 44 memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr));
45 if (tmpl->mode == XFRM_MODE_TUNNEL && ipv6_addr_any((struct in6_addr*)&x->props.saddr)) {
46 struct rt6_info *rt;
47 struct flowi fl_tunnel = {
48 .nl_u = {
49 .ip6_u = {
50 .daddr = *(struct in6_addr *)daddr,
51 }
52 }
53 };
54 if (!xfrm_dst_lookup((struct xfrm_dst **)&rt,
55 &fl_tunnel, AF_INET6)) {
56 ipv6_get_saddr(&rt->u.dst, (struct in6_addr *)daddr,
57 (struct in6_addr *)&x->props.saddr);
58 dst_release(&rt->u.dst);
59 }
60 }
61 x->props.mode = tmpl->mode; 45 x->props.mode = tmpl->mode;
62 x->props.reqid = tmpl->reqid; 46 x->props.reqid = tmpl->reqid;
63 x->props.family = AF_INET6; 47 x->props.family = AF_INET6;
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 537854fe47c..b6e2e79d726 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1107,6 +1107,20 @@ int __xfrm_sk_clone_policy(struct sock *sk)
1107 return 0; 1107 return 0;
1108} 1108}
1109 1109
1110static int
1111xfrm_get_saddr(xfrm_address_t *local, xfrm_address_t *remote,
1112 unsigned short family)
1113{
1114 int err;
1115 struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
1116
1117 if (unlikely(afinfo == NULL))
1118 return -EINVAL;
1119 err = afinfo->get_saddr(local, remote);
1120 xfrm_policy_put_afinfo(afinfo);
1121 return err;
1122}
1123
1110/* Resolve list of templates for the flow, given policy. */ 1124/* Resolve list of templates for the flow, given policy. */
1111 1125
1112static int 1126static int
@@ -1118,6 +1132,7 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, struct flowi *fl,
1118 int i, error; 1132 int i, error;
1119 xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family); 1133 xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family);
1120 xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family); 1134 xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family);
1135 xfrm_address_t tmp;
1121 1136
1122 for (nx=0, i = 0; i < policy->xfrm_nr; i++) { 1137 for (nx=0, i = 0; i < policy->xfrm_nr; i++) {
1123 struct xfrm_state *x; 1138 struct xfrm_state *x;
@@ -1128,6 +1143,12 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, struct flowi *fl,
1128 if (tmpl->mode == XFRM_MODE_TUNNEL) { 1143 if (tmpl->mode == XFRM_MODE_TUNNEL) {
1129 remote = &tmpl->id.daddr; 1144 remote = &tmpl->id.daddr;
1130 local = &tmpl->saddr; 1145 local = &tmpl->saddr;
1146 if (xfrm_addr_any(local, family)) {
1147 error = xfrm_get_saddr(&tmp, remote, family);
1148 if (error)
1149 goto fail;
1150 local = &tmp;
1151 }
1131 } 1152 }
1132 1153
1133 x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family); 1154 x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family);