aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm/xfrm_state.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/xfrm/xfrm_state.c')
-rw-r--r--net/xfrm/xfrm_state.c170
1 files changed, 170 insertions, 0 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 344f0a6abec5..dc438f2b9442 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -187,6 +187,176 @@ int __xfrm_state_delete(struct xfrm_state *x);
187int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); 187int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
188void km_state_expired(struct xfrm_state *x, int hard, u32 pid); 188void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
189 189
190static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family)
191{
192 struct xfrm_state_afinfo *afinfo;
193 if (unlikely(family >= NPROTO))
194 return NULL;
195 write_lock_bh(&xfrm_state_afinfo_lock);
196 afinfo = xfrm_state_afinfo[family];
197 if (unlikely(!afinfo))
198 write_unlock_bh(&xfrm_state_afinfo_lock);
199 return afinfo;
200}
201
202static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo)
203{
204 write_unlock_bh(&xfrm_state_afinfo_lock);
205}
206
207int xfrm_register_type(struct xfrm_type *type, unsigned short family)
208{
209 struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
210 struct xfrm_type **typemap;
211 int err = 0;
212
213 if (unlikely(afinfo == NULL))
214 return -EAFNOSUPPORT;
215 typemap = afinfo->type_map;
216
217 if (likely(typemap[type->proto] == NULL))
218 typemap[type->proto] = type;
219 else
220 err = -EEXIST;
221 xfrm_state_unlock_afinfo(afinfo);
222 return err;
223}
224EXPORT_SYMBOL(xfrm_register_type);
225
226int xfrm_unregister_type(struct xfrm_type *type, unsigned short family)
227{
228 struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
229 struct xfrm_type **typemap;
230 int err = 0;
231
232 if (unlikely(afinfo == NULL))
233 return -EAFNOSUPPORT;
234 typemap = afinfo->type_map;
235
236 if (unlikely(typemap[type->proto] != type))
237 err = -ENOENT;
238 else
239 typemap[type->proto] = NULL;
240 xfrm_state_unlock_afinfo(afinfo);
241 return err;
242}
243EXPORT_SYMBOL(xfrm_unregister_type);
244
245static struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
246{
247 struct xfrm_state_afinfo *afinfo;
248 struct xfrm_type **typemap;
249 struct xfrm_type *type;
250 int modload_attempted = 0;
251
252retry:
253 afinfo = xfrm_state_get_afinfo(family);
254 if (unlikely(afinfo == NULL))
255 return NULL;
256 typemap = afinfo->type_map;
257
258 type = typemap[proto];
259 if (unlikely(type && !try_module_get(type->owner)))
260 type = NULL;
261 if (!type && !modload_attempted) {
262 xfrm_state_put_afinfo(afinfo);
263 request_module("xfrm-type-%d-%d", family, proto);
264 modload_attempted = 1;
265 goto retry;
266 }
267
268 xfrm_state_put_afinfo(afinfo);
269 return type;
270}
271
272static void xfrm_put_type(struct xfrm_type *type)
273{
274 module_put(type->owner);
275}
276
277int xfrm_register_mode(struct xfrm_mode *mode, int family)
278{
279 struct xfrm_state_afinfo *afinfo;
280 struct xfrm_mode **modemap;
281 int err;
282
283 if (unlikely(mode->encap >= XFRM_MODE_MAX))
284 return -EINVAL;
285
286 afinfo = xfrm_state_lock_afinfo(family);
287 if (unlikely(afinfo == NULL))
288 return -EAFNOSUPPORT;
289
290 err = -EEXIST;
291 modemap = afinfo->mode_map;
292 if (likely(modemap[mode->encap] == NULL)) {
293 modemap[mode->encap] = mode;
294 err = 0;
295 }
296
297 xfrm_state_unlock_afinfo(afinfo);
298 return err;
299}
300EXPORT_SYMBOL(xfrm_register_mode);
301
302int xfrm_unregister_mode(struct xfrm_mode *mode, int family)
303{
304 struct xfrm_state_afinfo *afinfo;
305 struct xfrm_mode **modemap;
306 int err;
307
308 if (unlikely(mode->encap >= XFRM_MODE_MAX))
309 return -EINVAL;
310
311 afinfo = xfrm_state_lock_afinfo(family);
312 if (unlikely(afinfo == NULL))
313 return -EAFNOSUPPORT;
314
315 err = -ENOENT;
316 modemap = afinfo->mode_map;
317 if (likely(modemap[mode->encap] == mode)) {
318 modemap[mode->encap] = NULL;
319 err = 0;
320 }
321
322 xfrm_state_unlock_afinfo(afinfo);
323 return err;
324}
325EXPORT_SYMBOL(xfrm_unregister_mode);
326
327static struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family)
328{
329 struct xfrm_state_afinfo *afinfo;
330 struct xfrm_mode *mode;
331 int modload_attempted = 0;
332
333 if (unlikely(encap >= XFRM_MODE_MAX))
334 return NULL;
335
336retry:
337 afinfo = xfrm_state_get_afinfo(family);
338 if (unlikely(afinfo == NULL))
339 return NULL;
340
341 mode = afinfo->mode_map[encap];
342 if (unlikely(mode && !try_module_get(mode->owner)))
343 mode = NULL;
344 if (!mode && !modload_attempted) {
345 xfrm_state_put_afinfo(afinfo);
346 request_module("xfrm-mode-%d-%d", family, encap);
347 modload_attempted = 1;
348 goto retry;
349 }
350
351 xfrm_state_put_afinfo(afinfo);
352 return mode;
353}
354
355static void xfrm_put_mode(struct xfrm_mode *mode)
356{
357 module_put(mode->owner);
358}
359
190static void xfrm_state_gc_destroy(struct xfrm_state *x) 360static void xfrm_state_gc_destroy(struct xfrm_state *x)
191{ 361{
192 del_timer_sync(&x->timer); 362 del_timer_sync(&x->timer);