diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2007-11-14 00:37:28 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:53:42 -0500 |
commit | 66cdb3ca27323a92712d289fc5edc7841d74a139 (patch) | |
tree | 443c864e4cab413743c3ca755a50f8a5d0ec300d | |
parent | f04e7e8d7f175c05bbde3ae748bf2541da53721d (diff) |
[IPSEC]: Move flow construction into xfrm_dst_lookup
This patch moves the flow construction from the callers of
xfrm_dst_lookup into that function. It also changes xfrm_dst_lookup
so that it takes an xfrm state as its argument instead of explicit
addresses.
This removes any address-specific logic from the callers of
xfrm_dst_lookup which is needed to correctly support inter-family
transforms.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/xfrm.h | 10 | ||||
-rw-r--r-- | net/ipv4/xfrm4_policy.c | 80 | ||||
-rw-r--r-- | net/ipv6/xfrm6_policy.c | 97 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 25 |
4 files changed, 91 insertions, 121 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 3434fdc7de37..d427343f527b 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -233,7 +233,8 @@ struct xfrm_policy_afinfo { | |||
233 | unsigned short family; | 233 | unsigned short family; |
234 | struct dst_ops *dst_ops; | 234 | struct dst_ops *dst_ops; |
235 | void (*garbage_collect)(void); | 235 | void (*garbage_collect)(void); |
236 | int (*dst_lookup)(struct xfrm_dst **dst, struct flowi *fl); | 236 | struct dst_entry *(*dst_lookup)(int tos, xfrm_address_t *saddr, |
237 | xfrm_address_t *daddr); | ||
237 | int (*get_saddr)(xfrm_address_t *saddr, xfrm_address_t *daddr); | 238 | int (*get_saddr)(xfrm_address_t *saddr, xfrm_address_t *daddr); |
238 | struct dst_entry *(*find_bundle)(struct flowi *fl, struct xfrm_policy *policy); | 239 | struct dst_entry *(*find_bundle)(struct flowi *fl, struct xfrm_policy *policy); |
239 | int (*bundle_create)(struct xfrm_policy *policy, | 240 | int (*bundle_create)(struct xfrm_policy *policy, |
@@ -1079,7 +1080,6 @@ extern int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb, | |||
1079 | #ifdef CONFIG_XFRM | 1080 | #ifdef CONFIG_XFRM |
1080 | extern int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb); | 1081 | extern int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb); |
1081 | extern int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen); | 1082 | extern int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen); |
1082 | extern int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, unsigned short family); | ||
1083 | #else | 1083 | #else |
1084 | static inline int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen) | 1084 | static inline int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen) |
1085 | { | 1085 | { |
@@ -1092,13 +1092,9 @@ static inline int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb) | |||
1092 | kfree_skb(skb); | 1092 | kfree_skb(skb); |
1093 | return 0; | 1093 | return 0; |
1094 | } | 1094 | } |
1095 | |||
1096 | static inline int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, unsigned short family) | ||
1097 | { | ||
1098 | return -EINVAL; | ||
1099 | } | ||
1100 | #endif | 1095 | #endif |
1101 | 1096 | ||
1097 | extern struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos); | ||
1102 | struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp); | 1098 | struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp); |
1103 | extern int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), void *); | 1099 | extern int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), void *); |
1104 | int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); | 1100 | int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); |
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index d903c8bdffcd..cebc84731969 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c | |||
@@ -8,7 +8,8 @@ | |||
8 | * | 8 | * |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/compiler.h> | 11 | #include <linux/err.h> |
12 | #include <linux/kernel.h> | ||
12 | #include <linux/inetdevice.h> | 13 | #include <linux/inetdevice.h> |
13 | #include <net/dst.h> | 14 | #include <net/dst.h> |
14 | #include <net/xfrm.h> | 15 | #include <net/xfrm.h> |
@@ -17,28 +18,44 @@ | |||
17 | static struct dst_ops xfrm4_dst_ops; | 18 | static struct dst_ops xfrm4_dst_ops; |
18 | static struct xfrm_policy_afinfo xfrm4_policy_afinfo; | 19 | static struct xfrm_policy_afinfo xfrm4_policy_afinfo; |
19 | 20 | ||
20 | static int xfrm4_dst_lookup(struct xfrm_dst **dst, struct flowi *fl) | 21 | static struct dst_entry *xfrm4_dst_lookup(int tos, xfrm_address_t *saddr, |
22 | xfrm_address_t *daddr) | ||
21 | { | 23 | { |
22 | return __ip_route_output_key((struct rtable**)dst, fl); | 24 | struct flowi fl = { |
23 | } | ||
24 | |||
25 | static int xfrm4_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr) | ||
26 | { | ||
27 | struct rtable *rt; | ||
28 | struct flowi fl_tunnel = { | ||
29 | .nl_u = { | 25 | .nl_u = { |
30 | .ip4_u = { | 26 | .ip4_u = { |
27 | .tos = tos, | ||
31 | .daddr = daddr->a4, | 28 | .daddr = daddr->a4, |
32 | }, | 29 | }, |
33 | }, | 30 | }, |
34 | }; | 31 | }; |
32 | struct dst_entry *dst; | ||
33 | struct rtable *rt; | ||
34 | int err; | ||
35 | 35 | ||
36 | if (!xfrm4_dst_lookup((struct xfrm_dst **)&rt, &fl_tunnel)) { | 36 | if (saddr) |
37 | saddr->a4 = rt->rt_src; | 37 | fl.fl4_src = saddr->a4; |
38 | dst_release(&rt->u.dst); | 38 | |
39 | return 0; | 39 | err = __ip_route_output_key(&rt, &fl); |
40 | } | 40 | dst = &rt->u.dst; |
41 | return -EHOSTUNREACH; | 41 | if (err) |
42 | dst = ERR_PTR(err); | ||
43 | return dst; | ||
44 | } | ||
45 | |||
46 | static int xfrm4_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr) | ||
47 | { | ||
48 | struct dst_entry *dst; | ||
49 | struct rtable *rt; | ||
50 | |||
51 | dst = xfrm4_dst_lookup(0, NULL, daddr); | ||
52 | if (IS_ERR(dst)) | ||
53 | return -EHOSTUNREACH; | ||
54 | |||
55 | rt = (struct rtable *)dst; | ||
56 | saddr->a4 = rt->rt_src; | ||
57 | dst_release(dst); | ||
58 | return 0; | ||
42 | } | 59 | } |
43 | 60 | ||
44 | static struct dst_entry * | 61 | static struct dst_entry * |
@@ -73,15 +90,7 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
73 | struct dst_entry *dst, *dst_prev; | 90 | struct dst_entry *dst, *dst_prev; |
74 | struct rtable *rt0 = (struct rtable*)(*dst_p); | 91 | struct rtable *rt0 = (struct rtable*)(*dst_p); |
75 | struct rtable *rt = rt0; | 92 | struct rtable *rt = rt0; |
76 | struct flowi fl_tunnel = { | 93 | int tos = fl->fl4_tos; |
77 | .nl_u = { | ||
78 | .ip4_u = { | ||
79 | .saddr = fl->fl4_src, | ||
80 | .daddr = fl->fl4_dst, | ||
81 | .tos = fl->fl4_tos | ||
82 | } | ||
83 | } | ||
84 | }; | ||
85 | int i; | 94 | int i; |
86 | int err; | 95 | int err; |
87 | int header_len = 0; | 96 | int header_len = 0; |
@@ -119,25 +128,12 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
119 | trailer_len += xfrm[i]->props.trailer_len; | 128 | trailer_len += xfrm[i]->props.trailer_len; |
120 | 129 | ||
121 | if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { | 130 | if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { |
122 | unsigned short encap_family = xfrm[i]->props.family; | 131 | dst1 = xfrm_dst_lookup(xfrm[i], tos); |
123 | switch (encap_family) { | 132 | err = PTR_ERR(dst1); |
124 | case AF_INET: | 133 | if (IS_ERR(dst1)) |
125 | fl_tunnel.fl4_dst = xfrm[i]->id.daddr.a4; | ||
126 | fl_tunnel.fl4_src = xfrm[i]->props.saddr.a4; | ||
127 | break; | ||
128 | #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) | ||
129 | case AF_INET6: | ||
130 | ipv6_addr_copy(&fl_tunnel.fl6_dst, (struct in6_addr*)&xfrm[i]->id.daddr.a6); | ||
131 | ipv6_addr_copy(&fl_tunnel.fl6_src, (struct in6_addr*)&xfrm[i]->props.saddr.a6); | ||
132 | break; | ||
133 | #endif | ||
134 | default: | ||
135 | BUG_ON(1); | ||
136 | } | ||
137 | err = xfrm_dst_lookup((struct xfrm_dst **)&rt, | ||
138 | &fl_tunnel, encap_family); | ||
139 | if (err) | ||
140 | goto error; | 134 | goto error; |
135 | |||
136 | rt = (struct rtable *)dst1; | ||
141 | } else | 137 | } else |
142 | dst_hold(&rt->u.dst); | 138 | dst_hold(&rt->u.dst); |
143 | } | 139 | } |
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 3b38e493d151..8e78530865a6 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
@@ -11,7 +11,8 @@ | |||
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/compiler.h> | 14 | #include <linux/err.h> |
15 | #include <linux/kernel.h> | ||
15 | #include <linux/netdevice.h> | 16 | #include <linux/netdevice.h> |
16 | #include <net/addrconf.h> | 17 | #include <net/addrconf.h> |
17 | #include <net/dst.h> | 18 | #include <net/dst.h> |
@@ -26,35 +27,40 @@ | |||
26 | static struct dst_ops xfrm6_dst_ops; | 27 | static struct dst_ops xfrm6_dst_ops; |
27 | static struct xfrm_policy_afinfo xfrm6_policy_afinfo; | 28 | static struct xfrm_policy_afinfo xfrm6_policy_afinfo; |
28 | 29 | ||
29 | static int xfrm6_dst_lookup(struct xfrm_dst **xdst, struct flowi *fl) | 30 | static struct dst_entry *xfrm6_dst_lookup(int tos, xfrm_address_t *saddr, |
31 | xfrm_address_t *daddr) | ||
30 | { | 32 | { |
31 | struct dst_entry *dst = ip6_route_output(NULL, fl); | 33 | struct flowi fl = {}; |
32 | int err = dst->error; | 34 | struct dst_entry *dst; |
33 | if (!err) | 35 | int err; |
34 | *xdst = (struct xfrm_dst *) dst; | 36 | |
35 | else | 37 | memcpy(&fl.fl6_dst, daddr, sizeof(fl.fl6_dst)); |
38 | if (saddr) | ||
39 | memcpy(&fl.fl6_src, saddr, sizeof(fl.fl6_src)); | ||
40 | |||
41 | dst = ip6_route_output(NULL, &fl); | ||
42 | |||
43 | err = dst->error; | ||
44 | if (dst->error) { | ||
36 | dst_release(dst); | 45 | dst_release(dst); |
37 | return err; | 46 | dst = ERR_PTR(err); |
47 | } | ||
48 | |||
49 | return dst; | ||
38 | } | 50 | } |
39 | 51 | ||
40 | static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr) | 52 | static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr) |
41 | { | 53 | { |
42 | struct rt6_info *rt; | 54 | struct dst_entry *dst; |
43 | struct flowi fl_tunnel = { | 55 | |
44 | .nl_u = { | 56 | dst = xfrm6_dst_lookup(0, NULL, daddr); |
45 | .ip6_u = { | 57 | if (IS_ERR(dst)) |
46 | .daddr = *(struct in6_addr *)&daddr->a6, | 58 | return -EHOSTUNREACH; |
47 | }, | 59 | |
48 | }, | 60 | ipv6_get_saddr(dst, (struct in6_addr *)&daddr->a6, |
49 | }; | 61 | (struct in6_addr *)&saddr->a6); |
50 | 62 | dst_release(dst); | |
51 | if (!xfrm6_dst_lookup((struct xfrm_dst **)&rt, &fl_tunnel)) { | 63 | return 0; |
52 | ipv6_get_saddr(&rt->u.dst, (struct in6_addr *)&daddr->a6, | ||
53 | (struct in6_addr *)&saddr->a6); | ||
54 | dst_release(&rt->u.dst); | ||
55 | return 0; | ||
56 | } | ||
57 | return -EHOSTUNREACH; | ||
58 | } | 64 | } |
59 | 65 | ||
60 | static struct dst_entry * | 66 | static struct dst_entry * |
@@ -87,18 +93,6 @@ __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy) | |||
87 | return dst; | 93 | return dst; |
88 | } | 94 | } |
89 | 95 | ||
90 | static inline xfrm_address_t *__xfrm6_bundle_addr_remote(struct xfrm_state *x) | ||
91 | { | ||
92 | return (x->type->flags & XFRM_TYPE_REMOTE_COADDR) ? x->coaddr : | ||
93 | &x->id.daddr; | ||
94 | } | ||
95 | |||
96 | static inline xfrm_address_t *__xfrm6_bundle_addr_local(struct xfrm_state *x) | ||
97 | { | ||
98 | return (x->type->flags & XFRM_TYPE_LOCAL_COADDR) ? x->coaddr : | ||
99 | &x->props.saddr; | ||
100 | } | ||
101 | |||
102 | /* Allocate chain of dst_entry's, attach known xfrm's, calculate | 96 | /* Allocate chain of dst_entry's, attach known xfrm's, calculate |
103 | * all the metrics... Shortly, bundle a bundle. | 97 | * all the metrics... Shortly, bundle a bundle. |
104 | */ | 98 | */ |
@@ -110,14 +104,6 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
110 | struct dst_entry *dst, *dst_prev; | 104 | struct dst_entry *dst, *dst_prev; |
111 | struct rt6_info *rt0 = (struct rt6_info*)(*dst_p); | 105 | struct rt6_info *rt0 = (struct rt6_info*)(*dst_p); |
112 | struct rt6_info *rt = rt0; | 106 | struct rt6_info *rt = rt0; |
113 | struct flowi fl_tunnel = { | ||
114 | .nl_u = { | ||
115 | .ip6_u = { | ||
116 | .saddr = fl->fl6_src, | ||
117 | .daddr = fl->fl6_dst, | ||
118 | } | ||
119 | } | ||
120 | }; | ||
121 | int i; | 107 | int i; |
122 | int err; | 108 | int err; |
123 | int header_len = 0; | 109 | int header_len = 0; |
@@ -160,25 +146,12 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
160 | trailer_len += xfrm[i]->props.trailer_len; | 146 | trailer_len += xfrm[i]->props.trailer_len; |
161 | 147 | ||
162 | if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { | 148 | if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { |
163 | unsigned short encap_family = xfrm[i]->props.family; | 149 | dst1 = xfrm_dst_lookup(xfrm[i], 0); |
164 | switch(encap_family) { | 150 | err = PTR_ERR(dst1); |
165 | case AF_INET: | 151 | if (IS_ERR(dst1)) |
166 | fl_tunnel.fl4_dst = xfrm[i]->id.daddr.a4; | ||
167 | fl_tunnel.fl4_src = xfrm[i]->props.saddr.a4; | ||
168 | break; | ||
169 | case AF_INET6: | ||
170 | ipv6_addr_copy(&fl_tunnel.fl6_dst, (struct in6_addr *)__xfrm6_bundle_addr_remote(xfrm[i])); | ||
171 | |||
172 | ipv6_addr_copy(&fl_tunnel.fl6_src, (struct in6_addr *)__xfrm6_bundle_addr_local(xfrm[i])); | ||
173 | break; | ||
174 | default: | ||
175 | BUG_ON(1); | ||
176 | } | ||
177 | |||
178 | err = xfrm_dst_lookup((struct xfrm_dst **) &rt, | ||
179 | &fl_tunnel, encap_family); | ||
180 | if (err) | ||
181 | goto error; | 152 | goto error; |
153 | |||
154 | rt = (struct rt6_info *)dst1; | ||
182 | } else | 155 | } else |
183 | dst_hold(&rt->u.dst); | 156 | dst_hold(&rt->u.dst); |
184 | } | 157 | } |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index df5bfa837eb3..085c19d4d1b7 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -13,6 +13,7 @@ | |||
13 | * | 13 | * |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/err.h> | ||
16 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
17 | #include <linux/kmod.h> | 18 | #include <linux/kmod.h> |
18 | #include <linux/list.h> | 19 | #include <linux/list.h> |
@@ -84,21 +85,25 @@ int xfrm_selector_match(struct xfrm_selector *sel, struct flowi *fl, | |||
84 | return 0; | 85 | return 0; |
85 | } | 86 | } |
86 | 87 | ||
87 | int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, | 88 | struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos) |
88 | unsigned short family) | ||
89 | { | 89 | { |
90 | struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); | 90 | xfrm_address_t *saddr = &x->props.saddr; |
91 | int err = 0; | 91 | xfrm_address_t *daddr = &x->id.daddr; |
92 | struct xfrm_policy_afinfo *afinfo; | ||
93 | struct dst_entry *dst; | ||
92 | 94 | ||
95 | if (x->type->flags & XFRM_TYPE_LOCAL_COADDR) | ||
96 | saddr = x->coaddr; | ||
97 | if (x->type->flags & XFRM_TYPE_REMOTE_COADDR) | ||
98 | daddr = x->coaddr; | ||
99 | |||
100 | afinfo = xfrm_policy_get_afinfo(x->props.family); | ||
93 | if (unlikely(afinfo == NULL)) | 101 | if (unlikely(afinfo == NULL)) |
94 | return -EAFNOSUPPORT; | 102 | return ERR_PTR(-EAFNOSUPPORT); |
95 | 103 | ||
96 | if (likely(afinfo->dst_lookup != NULL)) | 104 | dst = afinfo->dst_lookup(tos, saddr, daddr); |
97 | err = afinfo->dst_lookup(dst, fl); | ||
98 | else | ||
99 | err = -EINVAL; | ||
100 | xfrm_policy_put_afinfo(afinfo); | 105 | xfrm_policy_put_afinfo(afinfo); |
101 | return err; | 106 | return dst; |
102 | } | 107 | } |
103 | EXPORT_SYMBOL(xfrm_dst_lookup); | 108 | EXPORT_SYMBOL(xfrm_dst_lookup); |
104 | 109 | ||