diff options
author | Masahide NAKAMURA <nakam@linux-ipv6.org> | 2007-12-20 23:41:12 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:59:36 -0500 |
commit | a1b051405bc16222d92c73b0c26d65b333a154ee (patch) | |
tree | 2950e34bbb51838f8da3e1d03c8ee608d3b56f55 | |
parent | bd515c3e48ececd774eb3128e81b669dbbd32637 (diff) |
[XFRM] IPv6: Fix dst/routing check at transformation.
IPv6 specific thing is wrongly removed from transformation at net-2.6.25.
This patch recovers it with current design.
o Update "path" of xfrm_dst since IPv6 transformation should
care about routing changes. It is required by MIPv6 and
off-link destined IPsec.
o Rename nfheader_len which is for non-fragment transformation used by
MIPv6 to rt6i_nfheader_len as IPv6 name space.
Signed-off-by: Masahide NAKAMURA <nakam@linux-ipv6.org>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/ip6_fib.h | 2 | ||||
-rw-r--r-- | include/net/xfrm.h | 3 | ||||
-rw-r--r-- | net/ipv4/xfrm4_policy.c | 7 | ||||
-rw-r--r-- | net/ipv6/ip6_output.c | 4 | ||||
-rw-r--r-- | net/ipv6/xfrm6_policy.c | 17 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 21 |
6 files changed, 51 insertions, 3 deletions
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 14830edc2ac0..d8d85b13364d 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h | |||
@@ -101,7 +101,7 @@ struct rt6_info | |||
101 | atomic_t rt6i_ref; | 101 | atomic_t rt6i_ref; |
102 | 102 | ||
103 | /* more non-fragment space at head required */ | 103 | /* more non-fragment space at head required */ |
104 | unsigned short nfheader_len; | 104 | unsigned short rt6i_nfheader_len; |
105 | 105 | ||
106 | u8 rt6i_protocol; | 106 | u8 rt6i_protocol; |
107 | 107 | ||
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index d6dae5ae7abe..eea1c327c93e 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -242,6 +242,9 @@ struct xfrm_policy_afinfo { | |||
242 | struct flowi *fl, | 242 | struct flowi *fl, |
243 | int reverse); | 243 | int reverse); |
244 | int (*get_tos)(struct flowi *fl); | 244 | int (*get_tos)(struct flowi *fl); |
245 | int (*init_path)(struct xfrm_dst *path, | ||
246 | struct dst_entry *dst, | ||
247 | int nfheader_len); | ||
245 | int (*fill_dst)(struct xfrm_dst *xdst, | 248 | int (*fill_dst)(struct xfrm_dst *xdst, |
246 | struct net_device *dev); | 249 | struct net_device *dev); |
247 | }; | 250 | }; |
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 5ccae3a463c2..656345f75e0d 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c | |||
@@ -84,6 +84,12 @@ static int xfrm4_get_tos(struct flowi *fl) | |||
84 | return fl->fl4_tos; | 84 | return fl->fl4_tos; |
85 | } | 85 | } |
86 | 86 | ||
87 | static int xfrm4_init_path(struct xfrm_dst *path, struct dst_entry *dst, | ||
88 | int nfheader_len) | ||
89 | { | ||
90 | return 0; | ||
91 | } | ||
92 | |||
87 | static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev) | 93 | static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev) |
88 | { | 94 | { |
89 | struct rtable *rt = (struct rtable *)xdst->route; | 95 | struct rtable *rt = (struct rtable *)xdst->route; |
@@ -251,6 +257,7 @@ static struct xfrm_policy_afinfo xfrm4_policy_afinfo = { | |||
251 | .find_bundle = __xfrm4_find_bundle, | 257 | .find_bundle = __xfrm4_find_bundle, |
252 | .decode_session = _decode_session4, | 258 | .decode_session = _decode_session4, |
253 | .get_tos = xfrm4_get_tos, | 259 | .get_tos = xfrm4_get_tos, |
260 | .init_path = xfrm4_init_path, | ||
254 | .fill_dst = xfrm4_fill_dst, | 261 | .fill_dst = xfrm4_fill_dst, |
255 | }; | 262 | }; |
256 | 263 | ||
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index d54da616e3af..4686646058d3 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -1126,7 +1126,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
1126 | sk->sk_sndmsg_page = NULL; | 1126 | sk->sk_sndmsg_page = NULL; |
1127 | sk->sk_sndmsg_off = 0; | 1127 | sk->sk_sndmsg_off = 0; |
1128 | exthdrlen = rt->u.dst.header_len + (opt ? opt->opt_flen : 0) - | 1128 | exthdrlen = rt->u.dst.header_len + (opt ? opt->opt_flen : 0) - |
1129 | rt->nfheader_len; | 1129 | rt->rt6i_nfheader_len; |
1130 | length += exthdrlen; | 1130 | length += exthdrlen; |
1131 | transhdrlen += exthdrlen; | 1131 | transhdrlen += exthdrlen; |
1132 | } else { | 1132 | } else { |
@@ -1141,7 +1141,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
1141 | 1141 | ||
1142 | hh_len = LL_RESERVED_SPACE(rt->u.dst.dev); | 1142 | hh_len = LL_RESERVED_SPACE(rt->u.dst.dev); |
1143 | 1143 | ||
1144 | fragheaderlen = sizeof(struct ipv6hdr) + rt->nfheader_len + | 1144 | fragheaderlen = sizeof(struct ipv6hdr) + rt->rt6i_nfheader_len + |
1145 | (opt ? opt->opt_nflen : 0); | 1145 | (opt ? opt->opt_nflen : 0); |
1146 | maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - sizeof(struct frag_hdr); | 1146 | maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - sizeof(struct frag_hdr); |
1147 | 1147 | ||
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index d26b7dc3f33b..cf373b46a1ba 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
@@ -98,6 +98,20 @@ static int xfrm6_get_tos(struct flowi *fl) | |||
98 | return 0; | 98 | return 0; |
99 | } | 99 | } |
100 | 100 | ||
101 | static int xfrm6_init_path(struct xfrm_dst *path, struct dst_entry *dst, | ||
102 | int nfheader_len) | ||
103 | { | ||
104 | if (dst->ops->family == AF_INET6) { | ||
105 | struct rt6_info *rt = (struct rt6_info*)dst; | ||
106 | if (rt->rt6i_node) | ||
107 | path->path_cookie = rt->rt6i_node->fn_sernum; | ||
108 | } | ||
109 | |||
110 | path->u.rt6.rt6i_nfheader_len = nfheader_len; | ||
111 | |||
112 | return 0; | ||
113 | } | ||
114 | |||
101 | static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev) | 115 | static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev) |
102 | { | 116 | { |
103 | struct rt6_info *rt = (struct rt6_info*)xdst->route; | 117 | struct rt6_info *rt = (struct rt6_info*)xdst->route; |
@@ -115,6 +129,8 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev) | |||
115 | RTF_LOCAL); | 129 | RTF_LOCAL); |
116 | xdst->u.rt6.rt6i_metric = rt->rt6i_metric; | 130 | xdst->u.rt6.rt6i_metric = rt->rt6i_metric; |
117 | xdst->u.rt6.rt6i_node = rt->rt6i_node; | 131 | xdst->u.rt6.rt6i_node = rt->rt6i_node; |
132 | if (rt->rt6i_node) | ||
133 | xdst->route_cookie = rt->rt6i_node->fn_sernum; | ||
118 | xdst->u.rt6.rt6i_gateway = rt->rt6i_gateway; | 134 | xdst->u.rt6.rt6i_gateway = rt->rt6i_gateway; |
119 | xdst->u.rt6.rt6i_dst = rt->rt6i_dst; | 135 | xdst->u.rt6.rt6i_dst = rt->rt6i_dst; |
120 | xdst->u.rt6.rt6i_src = rt->rt6i_src; | 136 | xdst->u.rt6.rt6i_src = rt->rt6i_src; |
@@ -266,6 +282,7 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = { | |||
266 | .find_bundle = __xfrm6_find_bundle, | 282 | .find_bundle = __xfrm6_find_bundle, |
267 | .decode_session = _decode_session6, | 283 | .decode_session = _decode_session6, |
268 | .get_tos = xfrm6_get_tos, | 284 | .get_tos = xfrm6_get_tos, |
285 | .init_path = xfrm6_init_path, | ||
269 | .fill_dst = xfrm6_fill_dst, | 286 | .fill_dst = xfrm6_fill_dst, |
270 | }; | 287 | }; |
271 | 288 | ||
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 8023a3c0dad5..521cb6e12561 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -1266,6 +1266,23 @@ static inline struct xfrm_dst *xfrm_alloc_dst(int family) | |||
1266 | return xdst; | 1266 | return xdst; |
1267 | } | 1267 | } |
1268 | 1268 | ||
1269 | static inline int xfrm_init_path(struct xfrm_dst *path, struct dst_entry *dst, | ||
1270 | int nfheader_len) | ||
1271 | { | ||
1272 | struct xfrm_policy_afinfo *afinfo = | ||
1273 | xfrm_policy_get_afinfo(dst->ops->family); | ||
1274 | int err; | ||
1275 | |||
1276 | if (!afinfo) | ||
1277 | return -EINVAL; | ||
1278 | |||
1279 | err = afinfo->init_path(path, dst, nfheader_len); | ||
1280 | |||
1281 | xfrm_policy_put_afinfo(afinfo); | ||
1282 | |||
1283 | return err; | ||
1284 | } | ||
1285 | |||
1269 | static inline int xfrm_fill_dst(struct xfrm_dst *xdst, struct net_device *dev) | 1286 | static inline int xfrm_fill_dst(struct xfrm_dst *xdst, struct net_device *dev) |
1270 | { | 1287 | { |
1271 | struct xfrm_policy_afinfo *afinfo = | 1288 | struct xfrm_policy_afinfo *afinfo = |
@@ -1298,6 +1315,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | |||
1298 | int i = 0; | 1315 | int i = 0; |
1299 | int err; | 1316 | int err; |
1300 | int header_len = 0; | 1317 | int header_len = 0; |
1318 | int nfheader_len = 0; | ||
1301 | int trailer_len = 0; | 1319 | int trailer_len = 0; |
1302 | int tos; | 1320 | int tos; |
1303 | int family = policy->selector.family; | 1321 | int family = policy->selector.family; |
@@ -1352,6 +1370,8 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | |||
1352 | dst_prev = dst1; | 1370 | dst_prev = dst1; |
1353 | 1371 | ||
1354 | header_len += xfrm[i]->props.header_len; | 1372 | header_len += xfrm[i]->props.header_len; |
1373 | if (xfrm[i]->type->flags & XFRM_TYPE_NON_FRAGMENT) | ||
1374 | nfheader_len += xfrm[i]->props.header_len; | ||
1355 | trailer_len += xfrm[i]->props.trailer_len; | 1375 | trailer_len += xfrm[i]->props.trailer_len; |
1356 | } | 1376 | } |
1357 | 1377 | ||
@@ -1366,6 +1386,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | |||
1366 | /* Copy neighbout for reachability confirmation */ | 1386 | /* Copy neighbout for reachability confirmation */ |
1367 | dst0->neighbour = neigh_clone(dst->neighbour); | 1387 | dst0->neighbour = neigh_clone(dst->neighbour); |
1368 | 1388 | ||
1389 | xfrm_init_path((struct xfrm_dst *)dst0, dst, nfheader_len); | ||
1369 | xfrm_init_pmtu(dst_prev); | 1390 | xfrm_init_pmtu(dst_prev); |
1370 | 1391 | ||
1371 | for (dst_prev = dst0; dst_prev != dst; dst_prev = dst_prev->child) { | 1392 | for (dst_prev = dst0; dst_prev != dst; dst_prev = dst_prev->child) { |