diff options
author | 2008-02-22 14:48:22 +0900 | |
---|---|---|
committer | 2008-03-25 10:23:57 +0900 | |
commit | 9bb182a7007515239091b237fe7169b1328a61d3 (patch) | |
tree | 7be7f556c58c650a547a0db34058f8ffffbf98aa /net | |
parent | [XFRM] IPV6: Optimize __xfrm_tunnel_alloc_spi(). (diff) | |
download | linux-9bb182a7007515239091b237fe7169b1328a61d3.tar.gz linux-9bb182a7007515239091b237fe7169b1328a61d3.tar.bz2 linux-9bb182a7007515239091b237fe7169b1328a61d3.zip |
[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>
Diffstat (limited to 'net')
-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, return 0; } +static inline struct dst_entry *__xfrm_dst_lookup(int tos, + xfrm_address_t *saddr, + xfrm_address_t *daddr, + int family) +{ + struct xfrm_policy_afinfo *afinfo; + struct dst_entry *dst; + + afinfo = xfrm_policy_get_afinfo(family); + if (unlikely(afinfo == NULL)) + return ERR_PTR(-EAFNOSUPPORT); + + dst = afinfo->dst_lookup(tos, saddr, daddr); + + xfrm_policy_put_afinfo(afinfo); + + return dst; +} + static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos, + xfrm_address_t *prev_saddr, + xfrm_address_t *prev_daddr, int family) { xfrm_address_t *saddr = &x->props.saddr; xfrm_address_t *daddr = &x->id.daddr; - struct xfrm_policy_afinfo *afinfo; struct dst_entry *dst; - if (x->type->flags & XFRM_TYPE_LOCAL_COADDR) + if (x->type->flags & XFRM_TYPE_LOCAL_COADDR) { saddr = x->coaddr; - if (x->type->flags & XFRM_TYPE_REMOTE_COADDR) + daddr = prev_daddr; + } + if (x->type->flags & XFRM_TYPE_REMOTE_COADDR) { + saddr = prev_saddr; daddr = x->coaddr; + } - afinfo = xfrm_policy_get_afinfo(family); - if (unlikely(afinfo == NULL)) - return ERR_PTR(-EAFNOSUPPORT); + dst = __xfrm_dst_lookup(tos, saddr, daddr, family); + + if (!IS_ERR(dst)) { + if (prev_saddr != saddr) + memcpy(prev_saddr, saddr, sizeof(*prev_saddr)); + if (prev_daddr != daddr) + memcpy(prev_daddr, daddr, sizeof(*prev_daddr)); + } - dst = afinfo->dst_lookup(tos, saddr, daddr); - xfrm_policy_put_afinfo(afinfo); return dst; } @@ -1354,6 +1381,9 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, int trailer_len = 0; int tos; int family = policy->selector.family; + xfrm_address_t saddr, daddr; + + xfrm_flowi_addr_get(fl, &saddr, &daddr, family); tos = xfrm_get_tos(fl, family); err = tos; @@ -1384,7 +1414,8 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { family = xfrm[i]->props.family; - dst = xfrm_dst_lookup(xfrm[i], tos, family); + dst = xfrm_dst_lookup(xfrm[i], tos, &saddr, &daddr, + family); err = PTR_ERR(dst); if (IS_ERR(dst)) goto put_states; |