diff options
Diffstat (limited to 'net/xfrm/xfrm_policy.c')
-rw-r--r-- | net/xfrm/xfrm_policy.c | 49 |
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 | ||
100 | static 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 | |||
100 | static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos, | 119 | static 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; |