Commit 9bb182a7007515239091b237fe7169b1328a61d3
1 parent
df8ea19b5d
Exists in
master
and in
4 other branches
[XFRM] MIP6: Fix address keys for routing search.
Each MIPv6 XFRM state (DSTOPT/RH2) holds either destination or source address to be mangled in the IPv6 header (that is "CoA"). On Inter-MN communication after both nodes binds each other, they use route optimized traffic two MIPv6 states applied, and both source and destination address in the IPv6 header are replaced by the states respectively. The packet format is correct, however, next-hop routing search are not. This patch fixes it by remembering address pairs for later states. Based on patch from Masahide NAKAMURA <nakam@linux-ipv6.org>. Signed-off-by: Masahide NAKAMURA <nakam@linux-ipv6.org> Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Showing 2 changed files with 57 additions and 9 deletions Side-by-side Diff
include/net/xfrm.h
... | ... | @@ -1045,6 +1045,23 @@ |
1045 | 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 | 1065 | static __inline__ int |
1049 | 1066 | __xfrm4_state_addr_check(struct xfrm_state *x, |
1050 | 1067 | xfrm_address_t *daddr, xfrm_address_t *saddr) |
net/xfrm/xfrm_policy.c
... | ... | @@ -97,25 +97,52 @@ |
97 | 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 | 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 | 122 | int family) |
102 | 123 | { |
103 | 124 | xfrm_address_t *saddr = &x->props.saddr; |
104 | 125 | xfrm_address_t *daddr = &x->id.daddr; |
105 | - struct xfrm_policy_afinfo *afinfo; | |
106 | 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 | 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 | 134 | daddr = x->coaddr; |
135 | + } | |
112 | 136 | |
113 | - afinfo = xfrm_policy_get_afinfo(family); | |
114 | - if (unlikely(afinfo == NULL)) | |
115 | - return ERR_PTR(-EAFNOSUPPORT); | |
137 | + dst = __xfrm_dst_lookup(tos, saddr, daddr, family); | |
116 | 138 | |
117 | - dst = afinfo->dst_lookup(tos, saddr, daddr); | |
118 | - xfrm_policy_put_afinfo(afinfo); | |
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 | + } | |
145 | + | |
119 | 146 | return dst; |
120 | 147 | } |
121 | 148 | |
122 | 149 | |
... | ... | @@ -1354,7 +1381,10 @@ |
1354 | 1381 | int trailer_len = 0; |
1355 | 1382 | int tos; |
1356 | 1383 | int family = policy->selector.family; |
1384 | + xfrm_address_t saddr, daddr; | |
1357 | 1385 | |
1386 | + xfrm_flowi_addr_get(fl, &saddr, &daddr, family); | |
1387 | + | |
1358 | 1388 | tos = xfrm_get_tos(fl, family); |
1359 | 1389 | err = tos; |
1360 | 1390 | if (tos < 0) |
... | ... | @@ -1384,7 +1414,8 @@ |
1384 | 1414 | |
1385 | 1415 | if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { |
1386 | 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 | 1419 | err = PTR_ERR(dst); |
1389 | 1420 | if (IS_ERR(dst)) |
1390 | 1421 | goto put_states; |