Commit 9bb182a7007515239091b237fe7169b1328a61d3

Authored by YOSHIFUJI Hideaki
1 parent df8ea19b5d

[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

... ... @@ -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;