diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2007-12-11 12:32:34 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:53:43 -0500 |
commit | 25ee3286dcbc830a833354bb1d15567956844813 (patch) | |
tree | bb5597d9e148f363bf0bbcd1a7269b5f677f0103 /net/ipv4 | |
parent | 66cdb3ca27323a92712d289fc5edc7841d74a139 (diff) |
[IPSEC]: Merge common code into xfrm_bundle_create
Half of the code in xfrm4_bundle_create and xfrm6_bundle_create are
common. This patch extracts that logic and puts it into
xfrm_bundle_create. The rest of it are then accessed through afinfo.
As a result this fixes the problem with inter-family transforms where
we treat every xfrm dst in the bundle as if it belongs to the top
family.
This patch also fixes a long-standing error-path bug where we may free
the xfrm states twice.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/xfrm4_policy.c | 134 |
1 files changed, 26 insertions, 108 deletions
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index cebc84731969..1d7524375b49 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c | |||
@@ -79,122 +79,39 @@ __xfrm4_find_bundle(struct flowi *fl, struct xfrm_policy *policy) | |||
79 | return dst; | 79 | return dst; |
80 | } | 80 | } |
81 | 81 | ||
82 | /* Allocate chain of dst_entry's, attach known xfrm's, calculate | 82 | static int xfrm4_get_tos(struct flowi *fl) |
83 | * all the metrics... Shortly, bundle a bundle. | ||
84 | */ | ||
85 | |||
86 | static int | ||
87 | __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int nx, | ||
88 | struct flowi *fl, struct dst_entry **dst_p) | ||
89 | { | 83 | { |
90 | struct dst_entry *dst, *dst_prev; | 84 | return fl->fl4_tos; |
91 | struct rtable *rt0 = (struct rtable*)(*dst_p); | 85 | } |
92 | struct rtable *rt = rt0; | ||
93 | int tos = fl->fl4_tos; | ||
94 | int i; | ||
95 | int err; | ||
96 | int header_len = 0; | ||
97 | int trailer_len = 0; | ||
98 | |||
99 | dst = dst_prev = NULL; | ||
100 | dst_hold(&rt->u.dst); | ||
101 | |||
102 | for (i = 0; i < nx; i++) { | ||
103 | struct dst_entry *dst1 = dst_alloc(&xfrm4_dst_ops); | ||
104 | struct xfrm_dst *xdst; | ||
105 | |||
106 | if (unlikely(dst1 == NULL)) { | ||
107 | err = -ENOBUFS; | ||
108 | dst_release(&rt->u.dst); | ||
109 | goto error; | ||
110 | } | ||
111 | 86 | ||
112 | if (!dst) | 87 | static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev) |
113 | dst = dst1; | 88 | { |
114 | else { | 89 | struct rtable *rt = (struct rtable *)xdst->route; |
115 | dst_prev->child = dst1; | ||
116 | dst1->flags |= DST_NOHASH; | ||
117 | dst_clone(dst1); | ||
118 | } | ||
119 | 90 | ||
120 | xdst = (struct xfrm_dst *)dst1; | 91 | xdst->u.rt.fl = rt->fl; |
121 | xdst->route = &rt->u.dst; | ||
122 | xdst->genid = xfrm[i]->genid; | ||
123 | 92 | ||
124 | dst1->next = dst_prev; | 93 | xdst->u.dst.dev = dev; |
125 | dst_prev = dst1; | 94 | dev_hold(dev); |
126 | 95 | ||
127 | header_len += xfrm[i]->props.header_len; | 96 | xdst->u.rt.idev = in_dev_get(dev); |
128 | trailer_len += xfrm[i]->props.trailer_len; | 97 | if (!xdst->u.rt.idev) |
98 | return -ENODEV; | ||
129 | 99 | ||
130 | if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { | 100 | xdst->u.rt.peer = rt->peer; |
131 | dst1 = xfrm_dst_lookup(xfrm[i], tos); | 101 | if (rt->peer) |
132 | err = PTR_ERR(dst1); | 102 | atomic_inc(&rt->peer->refcnt); |
133 | if (IS_ERR(dst1)) | ||
134 | goto error; | ||
135 | 103 | ||
136 | rt = (struct rtable *)dst1; | 104 | /* Sheit... I remember I did this right. Apparently, |
137 | } else | 105 | * it was magically lost, so this code needs audit */ |
138 | dst_hold(&rt->u.dst); | 106 | xdst->u.rt.rt_flags = rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST | |
139 | } | 107 | RTCF_LOCAL); |
108 | xdst->u.rt.rt_type = rt->rt_type; | ||
109 | xdst->u.rt.rt_src = rt->rt_src; | ||
110 | xdst->u.rt.rt_dst = rt->rt_dst; | ||
111 | xdst->u.rt.rt_gateway = rt->rt_gateway; | ||
112 | xdst->u.rt.rt_spec_dst = rt->rt_spec_dst; | ||
140 | 113 | ||
141 | dst_prev->child = &rt->u.dst; | ||
142 | dst->path = &rt->u.dst; | ||
143 | |||
144 | /* Copy neighbout for reachability confirmation */ | ||
145 | dst->neighbour = neigh_clone(rt->u.dst.neighbour); | ||
146 | |||
147 | *dst_p = dst; | ||
148 | dst = dst_prev; | ||
149 | |||
150 | dst_prev = *dst_p; | ||
151 | i = 0; | ||
152 | err = -ENODEV; | ||
153 | for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) { | ||
154 | struct xfrm_dst *x = (struct xfrm_dst*)dst_prev; | ||
155 | x->u.rt.fl = *fl; | ||
156 | |||
157 | dst_prev->xfrm = xfrm[i++]; | ||
158 | dst_prev->dev = rt->u.dst.dev; | ||
159 | if (!rt->u.dst.dev) | ||
160 | goto error; | ||
161 | dev_hold(rt->u.dst.dev); | ||
162 | |||
163 | x->u.rt.idev = in_dev_get(rt->u.dst.dev); | ||
164 | if (!x->u.rt.idev) | ||
165 | goto error; | ||
166 | |||
167 | dst_prev->obsolete = -1; | ||
168 | dst_prev->flags |= DST_HOST; | ||
169 | dst_prev->lastuse = jiffies; | ||
170 | dst_prev->header_len = header_len; | ||
171 | dst_prev->trailer_len = trailer_len; | ||
172 | memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics)); | ||
173 | |||
174 | dst_prev->input = dst_discard; | ||
175 | dst_prev->output = dst_prev->xfrm->outer_mode->afinfo->output; | ||
176 | if (rt0->peer) | ||
177 | atomic_inc(&rt0->peer->refcnt); | ||
178 | x->u.rt.peer = rt0->peer; | ||
179 | /* Sheit... I remember I did this right. Apparently, | ||
180 | * it was magically lost, so this code needs audit */ | ||
181 | x->u.rt.rt_flags = rt0->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL); | ||
182 | x->u.rt.rt_type = rt0->rt_type; | ||
183 | x->u.rt.rt_src = rt0->rt_src; | ||
184 | x->u.rt.rt_dst = rt0->rt_dst; | ||
185 | x->u.rt.rt_gateway = rt0->rt_gateway; | ||
186 | x->u.rt.rt_spec_dst = rt0->rt_spec_dst; | ||
187 | header_len -= x->u.dst.xfrm->props.header_len; | ||
188 | trailer_len -= x->u.dst.xfrm->props.trailer_len; | ||
189 | } | ||
190 | |||
191 | xfrm_init_pmtu(dst); | ||
192 | return 0; | 114 | return 0; |
193 | |||
194 | error: | ||
195 | if (dst) | ||
196 | dst_free(dst); | ||
197 | return err; | ||
198 | } | 115 | } |
199 | 116 | ||
200 | static void | 117 | static void |
@@ -330,8 +247,9 @@ static struct xfrm_policy_afinfo xfrm4_policy_afinfo = { | |||
330 | .dst_lookup = xfrm4_dst_lookup, | 247 | .dst_lookup = xfrm4_dst_lookup, |
331 | .get_saddr = xfrm4_get_saddr, | 248 | .get_saddr = xfrm4_get_saddr, |
332 | .find_bundle = __xfrm4_find_bundle, | 249 | .find_bundle = __xfrm4_find_bundle, |
333 | .bundle_create = __xfrm4_bundle_create, | ||
334 | .decode_session = _decode_session4, | 250 | .decode_session = _decode_session4, |
251 | .get_tos = xfrm4_get_tos, | ||
252 | .fill_dst = xfrm4_fill_dst, | ||
335 | }; | 253 | }; |
336 | 254 | ||
337 | static void __init xfrm4_policy_init(void) | 255 | static void __init xfrm4_policy_init(void) |