aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/xfrm.h10
-rw-r--r--net/ipv4/xfrm4_policy.c80
-rw-r--r--net/ipv6/xfrm6_policy.c97
-rw-r--r--net/xfrm/xfrm_policy.c25
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
1080extern int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb); 1081extern int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb);
1081extern int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen); 1082extern int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen);
1082extern int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, unsigned short family);
1083#else 1083#else
1084static inline int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen) 1084static 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
1096static 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
1097extern struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos);
1102struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp); 1098struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp);
1103extern int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), void *); 1099extern int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), void *);
1104int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); 1100int 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 @@
17static struct dst_ops xfrm4_dst_ops; 18static struct dst_ops xfrm4_dst_ops;
18static struct xfrm_policy_afinfo xfrm4_policy_afinfo; 19static struct xfrm_policy_afinfo xfrm4_policy_afinfo;
19 20
20static int xfrm4_dst_lookup(struct xfrm_dst **dst, struct flowi *fl) 21static 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
25static 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
46static 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
44static struct dst_entry * 61static 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 @@
26static struct dst_ops xfrm6_dst_ops; 27static struct dst_ops xfrm6_dst_ops;
27static struct xfrm_policy_afinfo xfrm6_policy_afinfo; 28static struct xfrm_policy_afinfo xfrm6_policy_afinfo;
28 29
29static int xfrm6_dst_lookup(struct xfrm_dst **xdst, struct flowi *fl) 30static 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
40static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr) 52static 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
60static struct dst_entry * 66static 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
90static 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
96static 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
87int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, 88struct 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}
103EXPORT_SYMBOL(xfrm_dst_lookup); 108EXPORT_SYMBOL(xfrm_dst_lookup);
104 109