aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm/xfrm_policy.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/xfrm/xfrm_policy.c')
-rw-r--r--net/xfrm/xfrm_policy.c49
1 files changed, 40 insertions, 9 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index bae94a8031a2..8e588f20c60c 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -97,25 +97,52 @@ int xfrm_selector_match(struct xfrm_selector *sel, struct flowi *fl,
97 return 0; 97 return 0;
98} 98}
99 99
100static inline struct dst_entry *__xfrm_dst_lookup(int tos,
101 xfrm_address_t *saddr,
102 xfrm_address_t *daddr,
103 int family)
104{
105 struct xfrm_policy_afinfo *afinfo;
106 struct dst_entry *dst;
107
108 afinfo = xfrm_policy_get_afinfo(family);
109 if (unlikely(afinfo == NULL))
110 return ERR_PTR(-EAFNOSUPPORT);
111
112 dst = afinfo->dst_lookup(tos, saddr, daddr);
113
114 xfrm_policy_put_afinfo(afinfo);
115
116 return dst;
117}
118
100static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos, 119static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos,
120 xfrm_address_t *prev_saddr,
121 xfrm_address_t *prev_daddr,
101 int family) 122 int family)
102{ 123{
103 xfrm_address_t *saddr = &x->props.saddr; 124 xfrm_address_t *saddr = &x->props.saddr;
104 xfrm_address_t *daddr = &x->id.daddr; 125 xfrm_address_t *daddr = &x->id.daddr;
105 struct xfrm_policy_afinfo *afinfo;
106 struct dst_entry *dst; 126 struct dst_entry *dst;
107 127
108 if (x->type->flags & XFRM_TYPE_LOCAL_COADDR) 128 if (x->type->flags & XFRM_TYPE_LOCAL_COADDR) {
109 saddr = x->coaddr; 129 saddr = x->coaddr;
110 if (x->type->flags & XFRM_TYPE_REMOTE_COADDR) 130 daddr = prev_daddr;
131 }
132 if (x->type->flags & XFRM_TYPE_REMOTE_COADDR) {
133 saddr = prev_saddr;
111 daddr = x->coaddr; 134 daddr = x->coaddr;
135 }
112 136
113 afinfo = xfrm_policy_get_afinfo(family); 137 dst = __xfrm_dst_lookup(tos, saddr, daddr, family);
114 if (unlikely(afinfo == NULL)) 138
115 return ERR_PTR(-EAFNOSUPPORT); 139 if (!IS_ERR(dst)) {
140 if (prev_saddr != saddr)
141 memcpy(prev_saddr, saddr, sizeof(*prev_saddr));
142 if (prev_daddr != daddr)
143 memcpy(prev_daddr, daddr, sizeof(*prev_daddr));
144 }
116 145
117 dst = afinfo->dst_lookup(tos, saddr, daddr);
118 xfrm_policy_put_afinfo(afinfo);
119 return dst; 146 return dst;
120} 147}
121 148
@@ -1354,6 +1381,9 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
1354 int trailer_len = 0; 1381 int trailer_len = 0;
1355 int tos; 1382 int tos;
1356 int family = policy->selector.family; 1383 int family = policy->selector.family;
1384 xfrm_address_t saddr, daddr;
1385
1386 xfrm_flowi_addr_get(fl, &saddr, &daddr, family);
1357 1387
1358 tos = xfrm_get_tos(fl, family); 1388 tos = xfrm_get_tos(fl, family);
1359 err = tos; 1389 err = tos;
@@ -1384,7 +1414,8 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
1384 1414
1385 if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { 1415 if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
1386 family = xfrm[i]->props.family; 1416 family = xfrm[i]->props.family;
1387 dst = xfrm_dst_lookup(xfrm[i], tos, family); 1417 dst = xfrm_dst_lookup(xfrm[i], tos, &saddr, &daddr,
1418 family);
1388 err = PTR_ERR(dst); 1419 err = PTR_ERR(dst);
1389 if (IS_ERR(dst)) 1420 if (IS_ERR(dst))
1390 goto put_states; 1421 goto put_states;