aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/xfrm6_policy.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/xfrm6_policy.c')
-rw-r--r--net/ipv6/xfrm6_policy.c87
1 files changed, 81 insertions, 6 deletions
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 73cd250aecbb..6a252e2134d1 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -18,6 +18,9 @@
18#include <net/ip.h> 18#include <net/ip.h>
19#include <net/ipv6.h> 19#include <net/ipv6.h>
20#include <net/ip6_route.h> 20#include <net/ip6_route.h>
21#ifdef CONFIG_IPV6_MIP6
22#include <net/mip6.h>
23#endif
21 24
22static struct dst_ops xfrm6_dst_ops; 25static struct dst_ops xfrm6_dst_ops;
23static struct xfrm_policy_afinfo xfrm6_policy_afinfo; 26static struct xfrm_policy_afinfo xfrm6_policy_afinfo;
@@ -31,6 +34,26 @@ static int xfrm6_dst_lookup(struct xfrm_dst **dst, struct flowi *fl)
31 return err; 34 return err;
32} 35}
33 36
37static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)
38{
39 struct rt6_info *rt;
40 struct flowi fl_tunnel = {
41 .nl_u = {
42 .ip6_u = {
43 .daddr = *(struct in6_addr *)&daddr->a6,
44 },
45 },
46 };
47
48 if (!xfrm6_dst_lookup((struct xfrm_dst **)&rt, &fl_tunnel)) {
49 ipv6_get_saddr(&rt->u.dst, (struct in6_addr *)&daddr->a6,
50 (struct in6_addr *)&saddr->a6);
51 dst_release(&rt->u.dst);
52 return 0;
53 }
54 return -EHOSTUNREACH;
55}
56
34static struct dst_entry * 57static struct dst_entry *
35__xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy) 58__xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
36{ 59{
@@ -50,7 +73,9 @@ __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
50 xdst->u.rt6.rt6i_src.plen); 73 xdst->u.rt6.rt6i_src.plen);
51 if (ipv6_addr_equal(&xdst->u.rt6.rt6i_dst.addr, &fl_dst_prefix) && 74 if (ipv6_addr_equal(&xdst->u.rt6.rt6i_dst.addr, &fl_dst_prefix) &&
52 ipv6_addr_equal(&xdst->u.rt6.rt6i_src.addr, &fl_src_prefix) && 75 ipv6_addr_equal(&xdst->u.rt6.rt6i_src.addr, &fl_src_prefix) &&
53 xfrm_bundle_ok(xdst, fl, AF_INET6)) { 76 xfrm_bundle_ok(xdst, fl, AF_INET6,
77 (xdst->u.rt6.rt6i_dst.plen != 128 ||
78 xdst->u.rt6.rt6i_src.plen != 128))) {
54 dst_clone(dst); 79 dst_clone(dst);
55 break; 80 break;
56 } 81 }
@@ -59,6 +84,40 @@ __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
59 return dst; 84 return dst;
60} 85}
61 86
87static inline struct in6_addr*
88__xfrm6_bundle_addr_remote(struct xfrm_state *x, struct in6_addr *addr)
89{
90 return (x->type->remote_addr) ?
91 (struct in6_addr*)x->type->remote_addr(x, (xfrm_address_t *)addr) :
92 (struct in6_addr*)&x->id.daddr;
93}
94
95static inline struct in6_addr*
96__xfrm6_bundle_addr_local(struct xfrm_state *x, struct in6_addr *addr)
97{
98 return (x->type->local_addr) ?
99 (struct in6_addr*)x->type->local_addr(x, (xfrm_address_t *)addr) :
100 (struct in6_addr*)&x->props.saddr;
101}
102
103static inline void
104__xfrm6_bundle_len_inc(int *len, int *nflen, struct xfrm_state *x)
105{
106 if (x->type->flags & XFRM_TYPE_NON_FRAGMENT)
107 *nflen += x->props.header_len;
108 else
109 *len += x->props.header_len;
110}
111
112static inline void
113__xfrm6_bundle_len_dec(int *len, int *nflen, struct xfrm_state *x)
114{
115 if (x->type->flags & XFRM_TYPE_NON_FRAGMENT)
116 *nflen -= x->props.header_len;
117 else
118 *len -= x->props.header_len;
119}
120
62/* Allocate chain of dst_entry's, attach known xfrm's, calculate 121/* Allocate chain of dst_entry's, attach known xfrm's, calculate
63 * all the metrics... Shortly, bundle a bundle. 122 * all the metrics... Shortly, bundle a bundle.
64 */ 123 */
@@ -83,6 +142,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
83 int i; 142 int i;
84 int err = 0; 143 int err = 0;
85 int header_len = 0; 144 int header_len = 0;
145 int nfheader_len = 0;
86 int trailer_len = 0; 146 int trailer_len = 0;
87 147
88 dst = dst_prev = NULL; 148 dst = dst_prev = NULL;
@@ -109,17 +169,18 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
109 169
110 xdst = (struct xfrm_dst *)dst1; 170 xdst = (struct xfrm_dst *)dst1;
111 xdst->route = &rt->u.dst; 171 xdst->route = &rt->u.dst;
172 xdst->genid = xfrm[i]->genid;
112 if (rt->rt6i_node) 173 if (rt->rt6i_node)
113 xdst->route_cookie = rt->rt6i_node->fn_sernum; 174 xdst->route_cookie = rt->rt6i_node->fn_sernum;
114 175
115 dst1->next = dst_prev; 176 dst1->next = dst_prev;
116 dst_prev = dst1; 177 dst_prev = dst1;
117 if (xfrm[i]->props.mode) { 178 if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
118 remote = (struct in6_addr*)&xfrm[i]->id.daddr; 179 remote = __xfrm6_bundle_addr_remote(xfrm[i], remote);
119 local = (struct in6_addr*)&xfrm[i]->props.saddr; 180 local = __xfrm6_bundle_addr_local(xfrm[i], local);
120 tunnel = 1; 181 tunnel = 1;
121 } 182 }
122 header_len += xfrm[i]->props.header_len; 183 __xfrm6_bundle_len_inc(&header_len, &nfheader_len, xfrm[i]);
123 trailer_len += xfrm[i]->props.trailer_len; 184 trailer_len += xfrm[i]->props.trailer_len;
124 185
125 if (tunnel) { 186 if (tunnel) {
@@ -154,6 +215,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
154 dst_prev->flags |= DST_HOST; 215 dst_prev->flags |= DST_HOST;
155 dst_prev->lastuse = jiffies; 216 dst_prev->lastuse = jiffies;
156 dst_prev->header_len = header_len; 217 dst_prev->header_len = header_len;
218 dst_prev->nfheader_len = nfheader_len;
157 dst_prev->trailer_len = trailer_len; 219 dst_prev->trailer_len = trailer_len;
158 memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics)); 220 memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics));
159 221
@@ -172,7 +234,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
172 x->u.rt6.rt6i_src = rt0->rt6i_src; 234 x->u.rt6.rt6i_src = rt0->rt6i_src;
173 x->u.rt6.rt6i_idev = rt0->rt6i_idev; 235 x->u.rt6.rt6i_idev = rt0->rt6i_idev;
174 in6_dev_hold(rt0->rt6i_idev); 236 in6_dev_hold(rt0->rt6i_idev);
175 header_len -= x->u.dst.xfrm->props.header_len; 237 __xfrm6_bundle_len_dec(&header_len, &nfheader_len, x->u.dst.xfrm);
176 trailer_len -= x->u.dst.xfrm->props.trailer_len; 238 trailer_len -= x->u.dst.xfrm->props.trailer_len;
177 } 239 }
178 240
@@ -232,6 +294,18 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl)
232 fl->proto = nexthdr; 294 fl->proto = nexthdr;
233 return; 295 return;
234 296
297#ifdef CONFIG_IPV6_MIP6
298 case IPPROTO_MH:
299 if (pskb_may_pull(skb, skb->nh.raw + offset + 3 - skb->data)) {
300 struct ip6_mh *mh;
301 mh = (struct ip6_mh *)exthdr;
302
303 fl->fl_mh_type = mh->ip6mh_type;
304 }
305 fl->proto = nexthdr;
306 return;
307#endif
308
235 /* XXX Why are there these headers? */ 309 /* XXX Why are there these headers? */
236 case IPPROTO_AH: 310 case IPPROTO_AH:
237 case IPPROTO_ESP: 311 case IPPROTO_ESP:
@@ -308,6 +382,7 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
308 .family = AF_INET6, 382 .family = AF_INET6,
309 .dst_ops = &xfrm6_dst_ops, 383 .dst_ops = &xfrm6_dst_ops,
310 .dst_lookup = xfrm6_dst_lookup, 384 .dst_lookup = xfrm6_dst_lookup,
385 .get_saddr = xfrm6_get_saddr,
311 .find_bundle = __xfrm6_find_bundle, 386 .find_bundle = __xfrm6_find_bundle,
312 .bundle_create = __xfrm6_bundle_create, 387 .bundle_create = __xfrm6_bundle_create,
313 .decode_session = _decode_session6, 388 .decode_session = _decode_session6,