diff options
-rw-r--r-- | include/net/xfrm.h | 17 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 49 |
2 files changed, 57 insertions, 9 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index c435620dbb37..bed7d43932f6 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -1045,6 +1045,23 @@ xfrm_address_t *xfrm_flowi_saddr(struct flowi *fl, unsigned short family) | |||
1045 | return NULL; | 1045 | return NULL; |
1046 | } | 1046 | } |
1047 | 1047 | ||
1048 | static __inline__ | ||
1049 | void xfrm_flowi_addr_get(struct flowi *fl, | ||
1050 | xfrm_address_t *saddr, xfrm_address_t *daddr, | ||
1051 | unsigned short family) | ||
1052 | { | ||
1053 | switch(family) { | ||
1054 | case AF_INET: | ||
1055 | memcpy(&saddr->a4, &fl->fl4_src, sizeof(saddr->a4)); | ||
1056 | memcpy(&daddr->a4, &fl->fl4_dst, sizeof(daddr->a4)); | ||
1057 | break; | ||
1058 | case AF_INET6: | ||
1059 | ipv6_addr_copy((struct in6_addr *)&saddr->a6, &fl->fl6_src); | ||
1060 | ipv6_addr_copy((struct in6_addr *)&daddr->a6, &fl->fl6_dst); | ||
1061 | break; | ||
1062 | } | ||
1063 | } | ||
1064 | |||
1048 | static __inline__ int | 1065 | static __inline__ int |
1049 | __xfrm4_state_addr_check(struct xfrm_state *x, | 1066 | __xfrm4_state_addr_check(struct xfrm_state *x, |
1050 | xfrm_address_t *daddr, xfrm_address_t *saddr) | 1067 | xfrm_address_t *daddr, xfrm_address_t *saddr) |
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; |