diff options
Diffstat (limited to 'net/xfrm/xfrm_policy.c')
-rw-r--r-- | net/xfrm/xfrm_policy.c | 901 |
1 files changed, 737 insertions, 164 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 3da67ca2c3ce..b6e2e79d7261 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -22,16 +22,19 @@ | |||
22 | #include <linux/netdevice.h> | 22 | #include <linux/netdevice.h> |
23 | #include <linux/netfilter.h> | 23 | #include <linux/netfilter.h> |
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/cache.h> | ||
25 | #include <net/xfrm.h> | 26 | #include <net/xfrm.h> |
26 | #include <net/ip.h> | 27 | #include <net/ip.h> |
27 | 28 | ||
29 | #include "xfrm_hash.h" | ||
30 | |||
28 | DEFINE_MUTEX(xfrm_cfg_mutex); | 31 | DEFINE_MUTEX(xfrm_cfg_mutex); |
29 | EXPORT_SYMBOL(xfrm_cfg_mutex); | 32 | EXPORT_SYMBOL(xfrm_cfg_mutex); |
30 | 33 | ||
31 | static DEFINE_RWLOCK(xfrm_policy_lock); | 34 | static DEFINE_RWLOCK(xfrm_policy_lock); |
32 | 35 | ||
33 | struct xfrm_policy *xfrm_policy_list[XFRM_POLICY_MAX*2]; | 36 | unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2]; |
34 | EXPORT_SYMBOL(xfrm_policy_list); | 37 | EXPORT_SYMBOL(xfrm_policy_count); |
35 | 38 | ||
36 | static DEFINE_RWLOCK(xfrm_policy_afinfo_lock); | 39 | static DEFINE_RWLOCK(xfrm_policy_afinfo_lock); |
37 | static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO]; | 40 | static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO]; |
@@ -39,8 +42,7 @@ static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO]; | |||
39 | static kmem_cache_t *xfrm_dst_cache __read_mostly; | 42 | static kmem_cache_t *xfrm_dst_cache __read_mostly; |
40 | 43 | ||
41 | static struct work_struct xfrm_policy_gc_work; | 44 | static struct work_struct xfrm_policy_gc_work; |
42 | static struct list_head xfrm_policy_gc_list = | 45 | static HLIST_HEAD(xfrm_policy_gc_list); |
43 | LIST_HEAD_INIT(xfrm_policy_gc_list); | ||
44 | static DEFINE_SPINLOCK(xfrm_policy_gc_lock); | 46 | static DEFINE_SPINLOCK(xfrm_policy_gc_lock); |
45 | 47 | ||
46 | static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family); | 48 | static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family); |
@@ -310,8 +312,10 @@ struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp) | |||
310 | policy = kzalloc(sizeof(struct xfrm_policy), gfp); | 312 | policy = kzalloc(sizeof(struct xfrm_policy), gfp); |
311 | 313 | ||
312 | if (policy) { | 314 | if (policy) { |
313 | atomic_set(&policy->refcnt, 1); | 315 | INIT_HLIST_NODE(&policy->bydst); |
316 | INIT_HLIST_NODE(&policy->byidx); | ||
314 | rwlock_init(&policy->lock); | 317 | rwlock_init(&policy->lock); |
318 | atomic_set(&policy->refcnt, 1); | ||
315 | init_timer(&policy->timer); | 319 | init_timer(&policy->timer); |
316 | policy->timer.data = (unsigned long)policy; | 320 | policy->timer.data = (unsigned long)policy; |
317 | policy->timer.function = xfrm_policy_timer; | 321 | policy->timer.function = xfrm_policy_timer; |
@@ -357,17 +361,16 @@ static void xfrm_policy_gc_kill(struct xfrm_policy *policy) | |||
357 | static void xfrm_policy_gc_task(void *data) | 361 | static void xfrm_policy_gc_task(void *data) |
358 | { | 362 | { |
359 | struct xfrm_policy *policy; | 363 | struct xfrm_policy *policy; |
360 | struct list_head *entry, *tmp; | 364 | struct hlist_node *entry, *tmp; |
361 | struct list_head gc_list = LIST_HEAD_INIT(gc_list); | 365 | struct hlist_head gc_list; |
362 | 366 | ||
363 | spin_lock_bh(&xfrm_policy_gc_lock); | 367 | spin_lock_bh(&xfrm_policy_gc_lock); |
364 | list_splice_init(&xfrm_policy_gc_list, &gc_list); | 368 | gc_list.first = xfrm_policy_gc_list.first; |
369 | INIT_HLIST_HEAD(&xfrm_policy_gc_list); | ||
365 | spin_unlock_bh(&xfrm_policy_gc_lock); | 370 | spin_unlock_bh(&xfrm_policy_gc_lock); |
366 | 371 | ||
367 | list_for_each_safe(entry, tmp, &gc_list) { | 372 | hlist_for_each_entry_safe(policy, entry, tmp, &gc_list, bydst) |
368 | policy = list_entry(entry, struct xfrm_policy, list); | ||
369 | xfrm_policy_gc_kill(policy); | 373 | xfrm_policy_gc_kill(policy); |
370 | } | ||
371 | } | 374 | } |
372 | 375 | ||
373 | /* Rule must be locked. Release descentant resources, announce | 376 | /* Rule must be locked. Release descentant resources, announce |
@@ -389,70 +392,275 @@ static void xfrm_policy_kill(struct xfrm_policy *policy) | |||
389 | } | 392 | } |
390 | 393 | ||
391 | spin_lock(&xfrm_policy_gc_lock); | 394 | spin_lock(&xfrm_policy_gc_lock); |
392 | list_add(&policy->list, &xfrm_policy_gc_list); | 395 | hlist_add_head(&policy->bydst, &xfrm_policy_gc_list); |
393 | spin_unlock(&xfrm_policy_gc_lock); | 396 | spin_unlock(&xfrm_policy_gc_lock); |
394 | 397 | ||
395 | schedule_work(&xfrm_policy_gc_work); | 398 | schedule_work(&xfrm_policy_gc_work); |
396 | } | 399 | } |
397 | 400 | ||
401 | struct xfrm_policy_hash { | ||
402 | struct hlist_head *table; | ||
403 | unsigned int hmask; | ||
404 | }; | ||
405 | |||
406 | static struct hlist_head xfrm_policy_inexact[XFRM_POLICY_MAX*2]; | ||
407 | static struct xfrm_policy_hash xfrm_policy_bydst[XFRM_POLICY_MAX*2] __read_mostly; | ||
408 | static struct hlist_head *xfrm_policy_byidx __read_mostly; | ||
409 | static unsigned int xfrm_idx_hmask __read_mostly; | ||
410 | static unsigned int xfrm_policy_hashmax __read_mostly = 1 * 1024 * 1024; | ||
411 | |||
412 | static inline unsigned int idx_hash(u32 index) | ||
413 | { | ||
414 | return __idx_hash(index, xfrm_idx_hmask); | ||
415 | } | ||
416 | |||
417 | static struct hlist_head *policy_hash_bysel(struct xfrm_selector *sel, unsigned short family, int dir) | ||
418 | { | ||
419 | unsigned int hmask = xfrm_policy_bydst[dir].hmask; | ||
420 | unsigned int hash = __sel_hash(sel, family, hmask); | ||
421 | |||
422 | return (hash == hmask + 1 ? | ||
423 | &xfrm_policy_inexact[dir] : | ||
424 | xfrm_policy_bydst[dir].table + hash); | ||
425 | } | ||
426 | |||
427 | static struct hlist_head *policy_hash_direct(xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family, int dir) | ||
428 | { | ||
429 | unsigned int hmask = xfrm_policy_bydst[dir].hmask; | ||
430 | unsigned int hash = __addr_hash(daddr, saddr, family, hmask); | ||
431 | |||
432 | return xfrm_policy_bydst[dir].table + hash; | ||
433 | } | ||
434 | |||
435 | static void xfrm_dst_hash_transfer(struct hlist_head *list, | ||
436 | struct hlist_head *ndsttable, | ||
437 | unsigned int nhashmask) | ||
438 | { | ||
439 | struct hlist_node *entry, *tmp; | ||
440 | struct xfrm_policy *pol; | ||
441 | |||
442 | hlist_for_each_entry_safe(pol, entry, tmp, list, bydst) { | ||
443 | unsigned int h; | ||
444 | |||
445 | h = __addr_hash(&pol->selector.daddr, &pol->selector.saddr, | ||
446 | pol->family, nhashmask); | ||
447 | hlist_add_head(&pol->bydst, ndsttable+h); | ||
448 | } | ||
449 | } | ||
450 | |||
451 | static void xfrm_idx_hash_transfer(struct hlist_head *list, | ||
452 | struct hlist_head *nidxtable, | ||
453 | unsigned int nhashmask) | ||
454 | { | ||
455 | struct hlist_node *entry, *tmp; | ||
456 | struct xfrm_policy *pol; | ||
457 | |||
458 | hlist_for_each_entry_safe(pol, entry, tmp, list, byidx) { | ||
459 | unsigned int h; | ||
460 | |||
461 | h = __idx_hash(pol->index, nhashmask); | ||
462 | hlist_add_head(&pol->byidx, nidxtable+h); | ||
463 | } | ||
464 | } | ||
465 | |||
466 | static unsigned long xfrm_new_hash_mask(unsigned int old_hmask) | ||
467 | { | ||
468 | return ((old_hmask + 1) << 1) - 1; | ||
469 | } | ||
470 | |||
471 | static void xfrm_bydst_resize(int dir) | ||
472 | { | ||
473 | unsigned int hmask = xfrm_policy_bydst[dir].hmask; | ||
474 | unsigned int nhashmask = xfrm_new_hash_mask(hmask); | ||
475 | unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head); | ||
476 | struct hlist_head *odst = xfrm_policy_bydst[dir].table; | ||
477 | struct hlist_head *ndst = xfrm_hash_alloc(nsize); | ||
478 | int i; | ||
479 | |||
480 | if (!ndst) | ||
481 | return; | ||
482 | |||
483 | write_lock_bh(&xfrm_policy_lock); | ||
484 | |||
485 | for (i = hmask; i >= 0; i--) | ||
486 | xfrm_dst_hash_transfer(odst + i, ndst, nhashmask); | ||
487 | |||
488 | xfrm_policy_bydst[dir].table = ndst; | ||
489 | xfrm_policy_bydst[dir].hmask = nhashmask; | ||
490 | |||
491 | write_unlock_bh(&xfrm_policy_lock); | ||
492 | |||
493 | xfrm_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head)); | ||
494 | } | ||
495 | |||
496 | static void xfrm_byidx_resize(int total) | ||
497 | { | ||
498 | unsigned int hmask = xfrm_idx_hmask; | ||
499 | unsigned int nhashmask = xfrm_new_hash_mask(hmask); | ||
500 | unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head); | ||
501 | struct hlist_head *oidx = xfrm_policy_byidx; | ||
502 | struct hlist_head *nidx = xfrm_hash_alloc(nsize); | ||
503 | int i; | ||
504 | |||
505 | if (!nidx) | ||
506 | return; | ||
507 | |||
508 | write_lock_bh(&xfrm_policy_lock); | ||
509 | |||
510 | for (i = hmask; i >= 0; i--) | ||
511 | xfrm_idx_hash_transfer(oidx + i, nidx, nhashmask); | ||
512 | |||
513 | xfrm_policy_byidx = nidx; | ||
514 | xfrm_idx_hmask = nhashmask; | ||
515 | |||
516 | write_unlock_bh(&xfrm_policy_lock); | ||
517 | |||
518 | xfrm_hash_free(oidx, (hmask + 1) * sizeof(struct hlist_head)); | ||
519 | } | ||
520 | |||
521 | static inline int xfrm_bydst_should_resize(int dir, int *total) | ||
522 | { | ||
523 | unsigned int cnt = xfrm_policy_count[dir]; | ||
524 | unsigned int hmask = xfrm_policy_bydst[dir].hmask; | ||
525 | |||
526 | if (total) | ||
527 | *total += cnt; | ||
528 | |||
529 | if ((hmask + 1) < xfrm_policy_hashmax && | ||
530 | cnt > hmask) | ||
531 | return 1; | ||
532 | |||
533 | return 0; | ||
534 | } | ||
535 | |||
536 | static inline int xfrm_byidx_should_resize(int total) | ||
537 | { | ||
538 | unsigned int hmask = xfrm_idx_hmask; | ||
539 | |||
540 | if ((hmask + 1) < xfrm_policy_hashmax && | ||
541 | total > hmask) | ||
542 | return 1; | ||
543 | |||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | static DEFINE_MUTEX(hash_resize_mutex); | ||
548 | |||
549 | static void xfrm_hash_resize(void *__unused) | ||
550 | { | ||
551 | int dir, total; | ||
552 | |||
553 | mutex_lock(&hash_resize_mutex); | ||
554 | |||
555 | total = 0; | ||
556 | for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { | ||
557 | if (xfrm_bydst_should_resize(dir, &total)) | ||
558 | xfrm_bydst_resize(dir); | ||
559 | } | ||
560 | if (xfrm_byidx_should_resize(total)) | ||
561 | xfrm_byidx_resize(total); | ||
562 | |||
563 | mutex_unlock(&hash_resize_mutex); | ||
564 | } | ||
565 | |||
566 | static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize, NULL); | ||
567 | |||
398 | /* Generate new index... KAME seems to generate them ordered by cost | 568 | /* Generate new index... KAME seems to generate them ordered by cost |
399 | * of an absolute inpredictability of ordering of rules. This will not pass. */ | 569 | * of an absolute inpredictability of ordering of rules. This will not pass. */ |
400 | static u32 xfrm_gen_index(int dir) | 570 | static u32 xfrm_gen_index(u8 type, int dir) |
401 | { | 571 | { |
402 | u32 idx; | ||
403 | struct xfrm_policy *p; | ||
404 | static u32 idx_generator; | 572 | static u32 idx_generator; |
405 | 573 | ||
406 | for (;;) { | 574 | for (;;) { |
575 | struct hlist_node *entry; | ||
576 | struct hlist_head *list; | ||
577 | struct xfrm_policy *p; | ||
578 | u32 idx; | ||
579 | int found; | ||
580 | |||
407 | idx = (idx_generator | dir); | 581 | idx = (idx_generator | dir); |
408 | idx_generator += 8; | 582 | idx_generator += 8; |
409 | if (idx == 0) | 583 | if (idx == 0) |
410 | idx = 8; | 584 | idx = 8; |
411 | for (p = xfrm_policy_list[dir]; p; p = p->next) { | 585 | list = xfrm_policy_byidx + idx_hash(idx); |
412 | if (p->index == idx) | 586 | found = 0; |
587 | hlist_for_each_entry(p, entry, list, byidx) { | ||
588 | if (p->index == idx) { | ||
589 | found = 1; | ||
413 | break; | 590 | break; |
591 | } | ||
414 | } | 592 | } |
415 | if (!p) | 593 | if (!found) |
416 | return idx; | 594 | return idx; |
417 | } | 595 | } |
418 | } | 596 | } |
419 | 597 | ||
598 | static inline int selector_cmp(struct xfrm_selector *s1, struct xfrm_selector *s2) | ||
599 | { | ||
600 | u32 *p1 = (u32 *) s1; | ||
601 | u32 *p2 = (u32 *) s2; | ||
602 | int len = sizeof(struct xfrm_selector) / sizeof(u32); | ||
603 | int i; | ||
604 | |||
605 | for (i = 0; i < len; i++) { | ||
606 | if (p1[i] != p2[i]) | ||
607 | return 1; | ||
608 | } | ||
609 | |||
610 | return 0; | ||
611 | } | ||
612 | |||
420 | int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | 613 | int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) |
421 | { | 614 | { |
422 | struct xfrm_policy *pol, **p; | 615 | struct xfrm_policy *pol; |
423 | struct xfrm_policy *delpol = NULL; | 616 | struct xfrm_policy *delpol; |
424 | struct xfrm_policy **newpos = NULL; | 617 | struct hlist_head *chain; |
618 | struct hlist_node *entry, *newpos, *last; | ||
425 | struct dst_entry *gc_list; | 619 | struct dst_entry *gc_list; |
426 | 620 | ||
427 | write_lock_bh(&xfrm_policy_lock); | 621 | write_lock_bh(&xfrm_policy_lock); |
428 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL;) { | 622 | chain = policy_hash_bysel(&policy->selector, policy->family, dir); |
429 | if (!delpol && memcmp(&policy->selector, &pol->selector, sizeof(pol->selector)) == 0 && | 623 | delpol = NULL; |
624 | newpos = NULL; | ||
625 | last = NULL; | ||
626 | hlist_for_each_entry(pol, entry, chain, bydst) { | ||
627 | if (!delpol && | ||
628 | pol->type == policy->type && | ||
629 | !selector_cmp(&pol->selector, &policy->selector) && | ||
430 | xfrm_sec_ctx_match(pol->security, policy->security)) { | 630 | xfrm_sec_ctx_match(pol->security, policy->security)) { |
431 | if (excl) { | 631 | if (excl) { |
432 | write_unlock_bh(&xfrm_policy_lock); | 632 | write_unlock_bh(&xfrm_policy_lock); |
433 | return -EEXIST; | 633 | return -EEXIST; |
434 | } | 634 | } |
435 | *p = pol->next; | ||
436 | delpol = pol; | 635 | delpol = pol; |
437 | if (policy->priority > pol->priority) | 636 | if (policy->priority > pol->priority) |
438 | continue; | 637 | continue; |
439 | } else if (policy->priority >= pol->priority) { | 638 | } else if (policy->priority >= pol->priority) { |
440 | p = &pol->next; | 639 | last = &pol->bydst; |
441 | continue; | 640 | continue; |
442 | } | 641 | } |
443 | if (!newpos) | 642 | if (!newpos) |
444 | newpos = p; | 643 | newpos = &pol->bydst; |
445 | if (delpol) | 644 | if (delpol) |
446 | break; | 645 | break; |
447 | p = &pol->next; | 646 | last = &pol->bydst; |
448 | } | 647 | } |
648 | if (!newpos) | ||
649 | newpos = last; | ||
449 | if (newpos) | 650 | if (newpos) |
450 | p = newpos; | 651 | hlist_add_after(newpos, &policy->bydst); |
652 | else | ||
653 | hlist_add_head(&policy->bydst, chain); | ||
451 | xfrm_pol_hold(policy); | 654 | xfrm_pol_hold(policy); |
452 | policy->next = *p; | 655 | xfrm_policy_count[dir]++; |
453 | *p = policy; | ||
454 | atomic_inc(&flow_cache_genid); | 656 | atomic_inc(&flow_cache_genid); |
455 | policy->index = delpol ? delpol->index : xfrm_gen_index(dir); | 657 | if (delpol) { |
658 | hlist_del(&delpol->bydst); | ||
659 | hlist_del(&delpol->byidx); | ||
660 | xfrm_policy_count[dir]--; | ||
661 | } | ||
662 | policy->index = delpol ? delpol->index : xfrm_gen_index(policy->type, dir); | ||
663 | hlist_add_head(&policy->byidx, xfrm_policy_byidx+idx_hash(policy->index)); | ||
456 | policy->curlft.add_time = (unsigned long)xtime.tv_sec; | 664 | policy->curlft.add_time = (unsigned long)xtime.tv_sec; |
457 | policy->curlft.use_time = 0; | 665 | policy->curlft.use_time = 0; |
458 | if (!mod_timer(&policy->timer, jiffies + HZ)) | 666 | if (!mod_timer(&policy->timer, jiffies + HZ)) |
@@ -461,10 +669,13 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
461 | 669 | ||
462 | if (delpol) | 670 | if (delpol) |
463 | xfrm_policy_kill(delpol); | 671 | xfrm_policy_kill(delpol); |
672 | else if (xfrm_bydst_should_resize(dir, NULL)) | ||
673 | schedule_work(&xfrm_hash_work); | ||
464 | 674 | ||
465 | read_lock_bh(&xfrm_policy_lock); | 675 | read_lock_bh(&xfrm_policy_lock); |
466 | gc_list = NULL; | 676 | gc_list = NULL; |
467 | for (policy = policy->next; policy; policy = policy->next) { | 677 | entry = &policy->bydst; |
678 | hlist_for_each_entry_continue(policy, entry, bydst) { | ||
468 | struct dst_entry *dst; | 679 | struct dst_entry *dst; |
469 | 680 | ||
470 | write_lock(&policy->lock); | 681 | write_lock(&policy->lock); |
@@ -493,87 +704,146 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
493 | } | 704 | } |
494 | EXPORT_SYMBOL(xfrm_policy_insert); | 705 | EXPORT_SYMBOL(xfrm_policy_insert); |
495 | 706 | ||
496 | struct xfrm_policy *xfrm_policy_bysel_ctx(int dir, struct xfrm_selector *sel, | 707 | struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir, |
708 | struct xfrm_selector *sel, | ||
497 | struct xfrm_sec_ctx *ctx, int delete) | 709 | struct xfrm_sec_ctx *ctx, int delete) |
498 | { | 710 | { |
499 | struct xfrm_policy *pol, **p; | 711 | struct xfrm_policy *pol, *ret; |
712 | struct hlist_head *chain; | ||
713 | struct hlist_node *entry; | ||
500 | 714 | ||
501 | write_lock_bh(&xfrm_policy_lock); | 715 | write_lock_bh(&xfrm_policy_lock); |
502 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) { | 716 | chain = policy_hash_bysel(sel, sel->family, dir); |
503 | if ((memcmp(sel, &pol->selector, sizeof(*sel)) == 0) && | 717 | ret = NULL; |
504 | (xfrm_sec_ctx_match(ctx, pol->security))) { | 718 | hlist_for_each_entry(pol, entry, chain, bydst) { |
719 | if (pol->type == type && | ||
720 | !selector_cmp(sel, &pol->selector) && | ||
721 | xfrm_sec_ctx_match(ctx, pol->security)) { | ||
505 | xfrm_pol_hold(pol); | 722 | xfrm_pol_hold(pol); |
506 | if (delete) | 723 | if (delete) { |
507 | *p = pol->next; | 724 | hlist_del(&pol->bydst); |
725 | hlist_del(&pol->byidx); | ||
726 | xfrm_policy_count[dir]--; | ||
727 | } | ||
728 | ret = pol; | ||
508 | break; | 729 | break; |
509 | } | 730 | } |
510 | } | 731 | } |
511 | write_unlock_bh(&xfrm_policy_lock); | 732 | write_unlock_bh(&xfrm_policy_lock); |
512 | 733 | ||
513 | if (pol && delete) { | 734 | if (ret && delete) { |
514 | atomic_inc(&flow_cache_genid); | 735 | atomic_inc(&flow_cache_genid); |
515 | xfrm_policy_kill(pol); | 736 | xfrm_policy_kill(ret); |
516 | } | 737 | } |
517 | return pol; | 738 | return ret; |
518 | } | 739 | } |
519 | EXPORT_SYMBOL(xfrm_policy_bysel_ctx); | 740 | EXPORT_SYMBOL(xfrm_policy_bysel_ctx); |
520 | 741 | ||
521 | struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete) | 742 | struct xfrm_policy *xfrm_policy_byid(u8 type, int dir, u32 id, int delete) |
522 | { | 743 | { |
523 | struct xfrm_policy *pol, **p; | 744 | struct xfrm_policy *pol, *ret; |
745 | struct hlist_head *chain; | ||
746 | struct hlist_node *entry; | ||
524 | 747 | ||
525 | write_lock_bh(&xfrm_policy_lock); | 748 | write_lock_bh(&xfrm_policy_lock); |
526 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) { | 749 | chain = xfrm_policy_byidx + idx_hash(id); |
527 | if (pol->index == id) { | 750 | ret = NULL; |
751 | hlist_for_each_entry(pol, entry, chain, byidx) { | ||
752 | if (pol->type == type && pol->index == id) { | ||
528 | xfrm_pol_hold(pol); | 753 | xfrm_pol_hold(pol); |
529 | if (delete) | 754 | if (delete) { |
530 | *p = pol->next; | 755 | hlist_del(&pol->bydst); |
756 | hlist_del(&pol->byidx); | ||
757 | xfrm_policy_count[dir]--; | ||
758 | } | ||
759 | ret = pol; | ||
531 | break; | 760 | break; |
532 | } | 761 | } |
533 | } | 762 | } |
534 | write_unlock_bh(&xfrm_policy_lock); | 763 | write_unlock_bh(&xfrm_policy_lock); |
535 | 764 | ||
536 | if (pol && delete) { | 765 | if (ret && delete) { |
537 | atomic_inc(&flow_cache_genid); | 766 | atomic_inc(&flow_cache_genid); |
538 | xfrm_policy_kill(pol); | 767 | xfrm_policy_kill(ret); |
539 | } | 768 | } |
540 | return pol; | 769 | return ret; |
541 | } | 770 | } |
542 | EXPORT_SYMBOL(xfrm_policy_byid); | 771 | EXPORT_SYMBOL(xfrm_policy_byid); |
543 | 772 | ||
544 | void xfrm_policy_flush(void) | 773 | void xfrm_policy_flush(u8 type) |
545 | { | 774 | { |
546 | struct xfrm_policy *xp; | ||
547 | int dir; | 775 | int dir; |
548 | 776 | ||
549 | write_lock_bh(&xfrm_policy_lock); | 777 | write_lock_bh(&xfrm_policy_lock); |
550 | for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { | 778 | for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { |
551 | while ((xp = xfrm_policy_list[dir]) != NULL) { | 779 | struct xfrm_policy *pol; |
552 | xfrm_policy_list[dir] = xp->next; | 780 | struct hlist_node *entry; |
781 | int i; | ||
782 | |||
783 | again1: | ||
784 | hlist_for_each_entry(pol, entry, | ||
785 | &xfrm_policy_inexact[dir], bydst) { | ||
786 | if (pol->type != type) | ||
787 | continue; | ||
788 | hlist_del(&pol->bydst); | ||
789 | hlist_del(&pol->byidx); | ||
553 | write_unlock_bh(&xfrm_policy_lock); | 790 | write_unlock_bh(&xfrm_policy_lock); |
554 | 791 | ||
555 | xfrm_policy_kill(xp); | 792 | xfrm_policy_kill(pol); |
556 | 793 | ||
557 | write_lock_bh(&xfrm_policy_lock); | 794 | write_lock_bh(&xfrm_policy_lock); |
795 | goto again1; | ||
558 | } | 796 | } |
797 | |||
798 | for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) { | ||
799 | again2: | ||
800 | hlist_for_each_entry(pol, entry, | ||
801 | xfrm_policy_bydst[dir].table + i, | ||
802 | bydst) { | ||
803 | if (pol->type != type) | ||
804 | continue; | ||
805 | hlist_del(&pol->bydst); | ||
806 | hlist_del(&pol->byidx); | ||
807 | write_unlock_bh(&xfrm_policy_lock); | ||
808 | |||
809 | xfrm_policy_kill(pol); | ||
810 | |||
811 | write_lock_bh(&xfrm_policy_lock); | ||
812 | goto again2; | ||
813 | } | ||
814 | } | ||
815 | |||
816 | xfrm_policy_count[dir] = 0; | ||
559 | } | 817 | } |
560 | atomic_inc(&flow_cache_genid); | 818 | atomic_inc(&flow_cache_genid); |
561 | write_unlock_bh(&xfrm_policy_lock); | 819 | write_unlock_bh(&xfrm_policy_lock); |
562 | } | 820 | } |
563 | EXPORT_SYMBOL(xfrm_policy_flush); | 821 | EXPORT_SYMBOL(xfrm_policy_flush); |
564 | 822 | ||
565 | int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), | 823 | int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), |
566 | void *data) | 824 | void *data) |
567 | { | 825 | { |
568 | struct xfrm_policy *xp; | 826 | struct xfrm_policy *pol; |
569 | int dir; | 827 | struct hlist_node *entry; |
570 | int count = 0; | 828 | int dir, count, error; |
571 | int error = 0; | ||
572 | 829 | ||
573 | read_lock_bh(&xfrm_policy_lock); | 830 | read_lock_bh(&xfrm_policy_lock); |
831 | count = 0; | ||
574 | for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { | 832 | for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { |
575 | for (xp = xfrm_policy_list[dir]; xp; xp = xp->next) | 833 | struct hlist_head *table = xfrm_policy_bydst[dir].table; |
576 | count++; | 834 | int i; |
835 | |||
836 | hlist_for_each_entry(pol, entry, | ||
837 | &xfrm_policy_inexact[dir], bydst) { | ||
838 | if (pol->type == type) | ||
839 | count++; | ||
840 | } | ||
841 | for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) { | ||
842 | hlist_for_each_entry(pol, entry, table + i, bydst) { | ||
843 | if (pol->type == type) | ||
844 | count++; | ||
845 | } | ||
846 | } | ||
577 | } | 847 | } |
578 | 848 | ||
579 | if (count == 0) { | 849 | if (count == 0) { |
@@ -582,13 +852,28 @@ int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), | |||
582 | } | 852 | } |
583 | 853 | ||
584 | for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { | 854 | for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { |
585 | for (xp = xfrm_policy_list[dir]; xp; xp = xp->next) { | 855 | struct hlist_head *table = xfrm_policy_bydst[dir].table; |
586 | error = func(xp, dir%XFRM_POLICY_MAX, --count, data); | 856 | int i; |
857 | |||
858 | hlist_for_each_entry(pol, entry, | ||
859 | &xfrm_policy_inexact[dir], bydst) { | ||
860 | if (pol->type != type) | ||
861 | continue; | ||
862 | error = func(pol, dir % XFRM_POLICY_MAX, --count, data); | ||
587 | if (error) | 863 | if (error) |
588 | goto out; | 864 | goto out; |
589 | } | 865 | } |
866 | for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) { | ||
867 | hlist_for_each_entry(pol, entry, table + i, bydst) { | ||
868 | if (pol->type != type) | ||
869 | continue; | ||
870 | error = func(pol, dir % XFRM_POLICY_MAX, --count, data); | ||
871 | if (error) | ||
872 | goto out; | ||
873 | } | ||
874 | } | ||
590 | } | 875 | } |
591 | 876 | error = 0; | |
592 | out: | 877 | out: |
593 | read_unlock_bh(&xfrm_policy_lock); | 878 | read_unlock_bh(&xfrm_policy_lock); |
594 | return error; | 879 | return error; |
@@ -597,29 +882,79 @@ EXPORT_SYMBOL(xfrm_policy_walk); | |||
597 | 882 | ||
598 | /* Find policy to apply to this flow. */ | 883 | /* Find policy to apply to this flow. */ |
599 | 884 | ||
600 | static void xfrm_policy_lookup(struct flowi *fl, u32 sk_sid, u16 family, u8 dir, | 885 | static int xfrm_policy_match(struct xfrm_policy *pol, struct flowi *fl, |
601 | void **objp, atomic_t **obj_refp) | 886 | u8 type, u16 family, int dir) |
602 | { | 887 | { |
603 | struct xfrm_policy *pol; | 888 | struct xfrm_selector *sel = &pol->selector; |
889 | int match; | ||
604 | 890 | ||
605 | read_lock_bh(&xfrm_policy_lock); | 891 | if (pol->family != family || |
606 | for (pol = xfrm_policy_list[dir]; pol; pol = pol->next) { | 892 | pol->type != type) |
607 | struct xfrm_selector *sel = &pol->selector; | 893 | return 0; |
608 | int match; | ||
609 | 894 | ||
610 | if (pol->family != family) | 895 | match = xfrm_selector_match(sel, fl, family); |
611 | continue; | 896 | if (match) { |
897 | if (!security_xfrm_policy_lookup(pol, fl->secid, dir)) | ||
898 | return 1; | ||
899 | } | ||
612 | 900 | ||
613 | match = xfrm_selector_match(sel, fl, family); | 901 | return 0; |
902 | } | ||
614 | 903 | ||
615 | if (match) { | 904 | static struct xfrm_policy *xfrm_policy_lookup_bytype(u8 type, struct flowi *fl, |
616 | if (!security_xfrm_policy_lookup(pol, sk_sid, dir)) { | 905 | u16 family, u8 dir) |
617 | xfrm_pol_hold(pol); | 906 | { |
618 | break; | 907 | struct xfrm_policy *pol, *ret; |
619 | } | 908 | xfrm_address_t *daddr, *saddr; |
909 | struct hlist_node *entry; | ||
910 | struct hlist_head *chain; | ||
911 | u32 priority = ~0U; | ||
912 | |||
913 | daddr = xfrm_flowi_daddr(fl, family); | ||
914 | saddr = xfrm_flowi_saddr(fl, family); | ||
915 | if (unlikely(!daddr || !saddr)) | ||
916 | return NULL; | ||
917 | |||
918 | read_lock_bh(&xfrm_policy_lock); | ||
919 | chain = policy_hash_direct(daddr, saddr, family, dir); | ||
920 | ret = NULL; | ||
921 | hlist_for_each_entry(pol, entry, chain, bydst) { | ||
922 | if (xfrm_policy_match(pol, fl, type, family, dir)) { | ||
923 | ret = pol; | ||
924 | priority = ret->priority; | ||
925 | break; | ||
926 | } | ||
927 | } | ||
928 | chain = &xfrm_policy_inexact[dir]; | ||
929 | hlist_for_each_entry(pol, entry, chain, bydst) { | ||
930 | if (xfrm_policy_match(pol, fl, type, family, dir) && | ||
931 | pol->priority < priority) { | ||
932 | ret = pol; | ||
933 | break; | ||
620 | } | 934 | } |
621 | } | 935 | } |
936 | if (ret) | ||
937 | xfrm_pol_hold(ret); | ||
622 | read_unlock_bh(&xfrm_policy_lock); | 938 | read_unlock_bh(&xfrm_policy_lock); |
939 | |||
940 | return ret; | ||
941 | } | ||
942 | |||
943 | static void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, | ||
944 | void **objp, atomic_t **obj_refp) | ||
945 | { | ||
946 | struct xfrm_policy *pol; | ||
947 | |||
948 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
949 | pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_SUB, fl, family, dir); | ||
950 | if (pol) | ||
951 | goto end; | ||
952 | #endif | ||
953 | pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, fl, family, dir); | ||
954 | |||
955 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
956 | end: | ||
957 | #endif | ||
623 | if ((*objp = (void *) pol) != NULL) | 958 | if ((*objp = (void *) pol) != NULL) |
624 | *obj_refp = &pol->refcnt; | 959 | *obj_refp = &pol->refcnt; |
625 | } | 960 | } |
@@ -641,7 +976,7 @@ static inline int policy_to_flow_dir(int dir) | |||
641 | }; | 976 | }; |
642 | } | 977 | } |
643 | 978 | ||
644 | static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl, u32 sk_sid) | 979 | static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl) |
645 | { | 980 | { |
646 | struct xfrm_policy *pol; | 981 | struct xfrm_policy *pol; |
647 | 982 | ||
@@ -652,7 +987,7 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struc | |||
652 | int err = 0; | 987 | int err = 0; |
653 | 988 | ||
654 | if (match) | 989 | if (match) |
655 | err = security_xfrm_policy_lookup(pol, sk_sid, policy_to_flow_dir(dir)); | 990 | err = security_xfrm_policy_lookup(pol, fl->secid, policy_to_flow_dir(dir)); |
656 | 991 | ||
657 | if (match && !err) | 992 | if (match && !err) |
658 | xfrm_pol_hold(pol); | 993 | xfrm_pol_hold(pol); |
@@ -665,24 +1000,29 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struc | |||
665 | 1000 | ||
666 | static void __xfrm_policy_link(struct xfrm_policy *pol, int dir) | 1001 | static void __xfrm_policy_link(struct xfrm_policy *pol, int dir) |
667 | { | 1002 | { |
668 | pol->next = xfrm_policy_list[dir]; | 1003 | struct hlist_head *chain = policy_hash_bysel(&pol->selector, |
669 | xfrm_policy_list[dir] = pol; | 1004 | pol->family, dir); |
1005 | |||
1006 | hlist_add_head(&pol->bydst, chain); | ||
1007 | hlist_add_head(&pol->byidx, xfrm_policy_byidx+idx_hash(pol->index)); | ||
1008 | xfrm_policy_count[dir]++; | ||
670 | xfrm_pol_hold(pol); | 1009 | xfrm_pol_hold(pol); |
1010 | |||
1011 | if (xfrm_bydst_should_resize(dir, NULL)) | ||
1012 | schedule_work(&xfrm_hash_work); | ||
671 | } | 1013 | } |
672 | 1014 | ||
673 | static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, | 1015 | static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, |
674 | int dir) | 1016 | int dir) |
675 | { | 1017 | { |
676 | struct xfrm_policy **polp; | 1018 | if (hlist_unhashed(&pol->bydst)) |
1019 | return NULL; | ||
677 | 1020 | ||
678 | for (polp = &xfrm_policy_list[dir]; | 1021 | hlist_del(&pol->bydst); |
679 | *polp != NULL; polp = &(*polp)->next) { | 1022 | hlist_del(&pol->byidx); |
680 | if (*polp == pol) { | 1023 | xfrm_policy_count[dir]--; |
681 | *polp = pol->next; | 1024 | |
682 | return pol; | 1025 | return pol; |
683 | } | ||
684 | } | ||
685 | return NULL; | ||
686 | } | 1026 | } |
687 | 1027 | ||
688 | int xfrm_policy_delete(struct xfrm_policy *pol, int dir) | 1028 | int xfrm_policy_delete(struct xfrm_policy *pol, int dir) |
@@ -704,12 +1044,17 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) | |||
704 | { | 1044 | { |
705 | struct xfrm_policy *old_pol; | 1045 | struct xfrm_policy *old_pol; |
706 | 1046 | ||
1047 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
1048 | if (pol && pol->type != XFRM_POLICY_TYPE_MAIN) | ||
1049 | return -EINVAL; | ||
1050 | #endif | ||
1051 | |||
707 | write_lock_bh(&xfrm_policy_lock); | 1052 | write_lock_bh(&xfrm_policy_lock); |
708 | old_pol = sk->sk_policy[dir]; | 1053 | old_pol = sk->sk_policy[dir]; |
709 | sk->sk_policy[dir] = pol; | 1054 | sk->sk_policy[dir] = pol; |
710 | if (pol) { | 1055 | if (pol) { |
711 | pol->curlft.add_time = (unsigned long)xtime.tv_sec; | 1056 | pol->curlft.add_time = (unsigned long)xtime.tv_sec; |
712 | pol->index = xfrm_gen_index(XFRM_POLICY_MAX+dir); | 1057 | pol->index = xfrm_gen_index(pol->type, XFRM_POLICY_MAX+dir); |
713 | __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir); | 1058 | __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir); |
714 | } | 1059 | } |
715 | if (old_pol) | 1060 | if (old_pol) |
@@ -738,6 +1083,7 @@ static struct xfrm_policy *clone_policy(struct xfrm_policy *old, int dir) | |||
738 | newp->flags = old->flags; | 1083 | newp->flags = old->flags; |
739 | newp->xfrm_nr = old->xfrm_nr; | 1084 | newp->xfrm_nr = old->xfrm_nr; |
740 | newp->index = old->index; | 1085 | newp->index = old->index; |
1086 | newp->type = old->type; | ||
741 | memcpy(newp->xfrm_vec, old->xfrm_vec, | 1087 | memcpy(newp->xfrm_vec, old->xfrm_vec, |
742 | newp->xfrm_nr*sizeof(struct xfrm_tmpl)); | 1088 | newp->xfrm_nr*sizeof(struct xfrm_tmpl)); |
743 | write_lock_bh(&xfrm_policy_lock); | 1089 | write_lock_bh(&xfrm_policy_lock); |
@@ -761,17 +1107,32 @@ int __xfrm_sk_clone_policy(struct sock *sk) | |||
761 | return 0; | 1107 | return 0; |
762 | } | 1108 | } |
763 | 1109 | ||
1110 | static int | ||
1111 | xfrm_get_saddr(xfrm_address_t *local, xfrm_address_t *remote, | ||
1112 | unsigned short family) | ||
1113 | { | ||
1114 | int err; | ||
1115 | struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); | ||
1116 | |||
1117 | if (unlikely(afinfo == NULL)) | ||
1118 | return -EINVAL; | ||
1119 | err = afinfo->get_saddr(local, remote); | ||
1120 | xfrm_policy_put_afinfo(afinfo); | ||
1121 | return err; | ||
1122 | } | ||
1123 | |||
764 | /* Resolve list of templates for the flow, given policy. */ | 1124 | /* Resolve list of templates for the flow, given policy. */ |
765 | 1125 | ||
766 | static int | 1126 | static int |
767 | xfrm_tmpl_resolve(struct xfrm_policy *policy, struct flowi *fl, | 1127 | xfrm_tmpl_resolve_one(struct xfrm_policy *policy, struct flowi *fl, |
768 | struct xfrm_state **xfrm, | 1128 | struct xfrm_state **xfrm, |
769 | unsigned short family) | 1129 | unsigned short family) |
770 | { | 1130 | { |
771 | int nx; | 1131 | int nx; |
772 | int i, error; | 1132 | int i, error; |
773 | xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family); | 1133 | xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family); |
774 | xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family); | 1134 | xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family); |
1135 | xfrm_address_t tmp; | ||
775 | 1136 | ||
776 | for (nx=0, i = 0; i < policy->xfrm_nr; i++) { | 1137 | for (nx=0, i = 0; i < policy->xfrm_nr; i++) { |
777 | struct xfrm_state *x; | 1138 | struct xfrm_state *x; |
@@ -779,9 +1140,15 @@ xfrm_tmpl_resolve(struct xfrm_policy *policy, struct flowi *fl, | |||
779 | xfrm_address_t *local = saddr; | 1140 | xfrm_address_t *local = saddr; |
780 | struct xfrm_tmpl *tmpl = &policy->xfrm_vec[i]; | 1141 | struct xfrm_tmpl *tmpl = &policy->xfrm_vec[i]; |
781 | 1142 | ||
782 | if (tmpl->mode) { | 1143 | if (tmpl->mode == XFRM_MODE_TUNNEL) { |
783 | remote = &tmpl->id.daddr; | 1144 | remote = &tmpl->id.daddr; |
784 | local = &tmpl->saddr; | 1145 | local = &tmpl->saddr; |
1146 | if (xfrm_addr_any(local, family)) { | ||
1147 | error = xfrm_get_saddr(&tmp, remote, family); | ||
1148 | if (error) | ||
1149 | goto fail; | ||
1150 | local = &tmp; | ||
1151 | } | ||
785 | } | 1152 | } |
786 | 1153 | ||
787 | x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family); | 1154 | x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family); |
@@ -809,6 +1176,45 @@ fail: | |||
809 | return error; | 1176 | return error; |
810 | } | 1177 | } |
811 | 1178 | ||
1179 | static int | ||
1180 | xfrm_tmpl_resolve(struct xfrm_policy **pols, int npols, struct flowi *fl, | ||
1181 | struct xfrm_state **xfrm, | ||
1182 | unsigned short family) | ||
1183 | { | ||
1184 | struct xfrm_state *tp[XFRM_MAX_DEPTH]; | ||
1185 | struct xfrm_state **tpp = (npols > 1) ? tp : xfrm; | ||
1186 | int cnx = 0; | ||
1187 | int error; | ||
1188 | int ret; | ||
1189 | int i; | ||
1190 | |||
1191 | for (i = 0; i < npols; i++) { | ||
1192 | if (cnx + pols[i]->xfrm_nr >= XFRM_MAX_DEPTH) { | ||
1193 | error = -ENOBUFS; | ||
1194 | goto fail; | ||
1195 | } | ||
1196 | |||
1197 | ret = xfrm_tmpl_resolve_one(pols[i], fl, &tpp[cnx], family); | ||
1198 | if (ret < 0) { | ||
1199 | error = ret; | ||
1200 | goto fail; | ||
1201 | } else | ||
1202 | cnx += ret; | ||
1203 | } | ||
1204 | |||
1205 | /* found states are sorted for outbound processing */ | ||
1206 | if (npols > 1) | ||
1207 | xfrm_state_sort(xfrm, tpp, cnx, family); | ||
1208 | |||
1209 | return cnx; | ||
1210 | |||
1211 | fail: | ||
1212 | for (cnx--; cnx>=0; cnx--) | ||
1213 | xfrm_state_put(tpp[cnx]); | ||
1214 | return error; | ||
1215 | |||
1216 | } | ||
1217 | |||
812 | /* Check that the bundle accepts the flow and its components are | 1218 | /* Check that the bundle accepts the flow and its components are |
813 | * still valid. | 1219 | * still valid. |
814 | */ | 1220 | */ |
@@ -855,6 +1261,11 @@ int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, | |||
855 | struct sock *sk, int flags) | 1261 | struct sock *sk, int flags) |
856 | { | 1262 | { |
857 | struct xfrm_policy *policy; | 1263 | struct xfrm_policy *policy; |
1264 | struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; | ||
1265 | int npols; | ||
1266 | int pol_dead; | ||
1267 | int xfrm_nr; | ||
1268 | int pi; | ||
858 | struct xfrm_state *xfrm[XFRM_MAX_DEPTH]; | 1269 | struct xfrm_state *xfrm[XFRM_MAX_DEPTH]; |
859 | struct dst_entry *dst, *dst_orig = *dst_p; | 1270 | struct dst_entry *dst, *dst_orig = *dst_p; |
860 | int nx = 0; | 1271 | int nx = 0; |
@@ -862,19 +1273,26 @@ int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, | |||
862 | u32 genid; | 1273 | u32 genid; |
863 | u16 family; | 1274 | u16 family; |
864 | u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT); | 1275 | u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT); |
865 | u32 sk_sid = security_sk_sid(sk, fl, dir); | 1276 | |
866 | restart: | 1277 | restart: |
867 | genid = atomic_read(&flow_cache_genid); | 1278 | genid = atomic_read(&flow_cache_genid); |
868 | policy = NULL; | 1279 | policy = NULL; |
1280 | for (pi = 0; pi < ARRAY_SIZE(pols); pi++) | ||
1281 | pols[pi] = NULL; | ||
1282 | npols = 0; | ||
1283 | pol_dead = 0; | ||
1284 | xfrm_nr = 0; | ||
1285 | |||
869 | if (sk && sk->sk_policy[1]) | 1286 | if (sk && sk->sk_policy[1]) |
870 | policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl, sk_sid); | 1287 | policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl); |
871 | 1288 | ||
872 | if (!policy) { | 1289 | if (!policy) { |
873 | /* To accelerate a bit... */ | 1290 | /* To accelerate a bit... */ |
874 | if ((dst_orig->flags & DST_NOXFRM) || !xfrm_policy_list[XFRM_POLICY_OUT]) | 1291 | if ((dst_orig->flags & DST_NOXFRM) || |
1292 | !xfrm_policy_count[XFRM_POLICY_OUT]) | ||
875 | return 0; | 1293 | return 0; |
876 | 1294 | ||
877 | policy = flow_cache_lookup(fl, sk_sid, dst_orig->ops->family, | 1295 | policy = flow_cache_lookup(fl, dst_orig->ops->family, |
878 | dir, xfrm_policy_lookup); | 1296 | dir, xfrm_policy_lookup); |
879 | } | 1297 | } |
880 | 1298 | ||
@@ -883,6 +1301,9 @@ restart: | |||
883 | 1301 | ||
884 | family = dst_orig->ops->family; | 1302 | family = dst_orig->ops->family; |
885 | policy->curlft.use_time = (unsigned long)xtime.tv_sec; | 1303 | policy->curlft.use_time = (unsigned long)xtime.tv_sec; |
1304 | pols[0] = policy; | ||
1305 | npols ++; | ||
1306 | xfrm_nr += pols[0]->xfrm_nr; | ||
886 | 1307 | ||
887 | switch (policy->action) { | 1308 | switch (policy->action) { |
888 | case XFRM_POLICY_BLOCK: | 1309 | case XFRM_POLICY_BLOCK: |
@@ -891,11 +1312,13 @@ restart: | |||
891 | goto error; | 1312 | goto error; |
892 | 1313 | ||
893 | case XFRM_POLICY_ALLOW: | 1314 | case XFRM_POLICY_ALLOW: |
1315 | #ifndef CONFIG_XFRM_SUB_POLICY | ||
894 | if (policy->xfrm_nr == 0) { | 1316 | if (policy->xfrm_nr == 0) { |
895 | /* Flow passes not transformed. */ | 1317 | /* Flow passes not transformed. */ |
896 | xfrm_pol_put(policy); | 1318 | xfrm_pol_put(policy); |
897 | return 0; | 1319 | return 0; |
898 | } | 1320 | } |
1321 | #endif | ||
899 | 1322 | ||
900 | /* Try to find matching bundle. | 1323 | /* Try to find matching bundle. |
901 | * | 1324 | * |
@@ -911,7 +1334,36 @@ restart: | |||
911 | if (dst) | 1334 | if (dst) |
912 | break; | 1335 | break; |
913 | 1336 | ||
914 | nx = xfrm_tmpl_resolve(policy, fl, xfrm, family); | 1337 | #ifdef CONFIG_XFRM_SUB_POLICY |
1338 | if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) { | ||
1339 | pols[1] = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, | ||
1340 | fl, family, | ||
1341 | XFRM_POLICY_OUT); | ||
1342 | if (pols[1]) { | ||
1343 | if (pols[1]->action == XFRM_POLICY_BLOCK) { | ||
1344 | err = -EPERM; | ||
1345 | goto error; | ||
1346 | } | ||
1347 | npols ++; | ||
1348 | xfrm_nr += pols[1]->xfrm_nr; | ||
1349 | } | ||
1350 | } | ||
1351 | |||
1352 | /* | ||
1353 | * Because neither flowi nor bundle information knows about | ||
1354 | * transformation template size. On more than one policy usage | ||
1355 | * we can realize whether all of them is bypass or not after | ||
1356 | * they are searched. See above not-transformed bypass | ||
1357 | * is surrounded by non-sub policy configuration, too. | ||
1358 | */ | ||
1359 | if (xfrm_nr == 0) { | ||
1360 | /* Flow passes not transformed. */ | ||
1361 | xfrm_pols_put(pols, npols); | ||
1362 | return 0; | ||
1363 | } | ||
1364 | |||
1365 | #endif | ||
1366 | nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family); | ||
915 | 1367 | ||
916 | if (unlikely(nx<0)) { | 1368 | if (unlikely(nx<0)) { |
917 | err = nx; | 1369 | err = nx; |
@@ -924,7 +1376,7 @@ restart: | |||
924 | set_current_state(TASK_RUNNING); | 1376 | set_current_state(TASK_RUNNING); |
925 | remove_wait_queue(&km_waitq, &wait); | 1377 | remove_wait_queue(&km_waitq, &wait); |
926 | 1378 | ||
927 | nx = xfrm_tmpl_resolve(policy, fl, xfrm, family); | 1379 | nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family); |
928 | 1380 | ||
929 | if (nx == -EAGAIN && signal_pending(current)) { | 1381 | if (nx == -EAGAIN && signal_pending(current)) { |
930 | err = -ERESTART; | 1382 | err = -ERESTART; |
@@ -932,7 +1384,7 @@ restart: | |||
932 | } | 1384 | } |
933 | if (nx == -EAGAIN || | 1385 | if (nx == -EAGAIN || |
934 | genid != atomic_read(&flow_cache_genid)) { | 1386 | genid != atomic_read(&flow_cache_genid)) { |
935 | xfrm_pol_put(policy); | 1387 | xfrm_pols_put(pols, npols); |
936 | goto restart; | 1388 | goto restart; |
937 | } | 1389 | } |
938 | err = nx; | 1390 | err = nx; |
@@ -942,7 +1394,7 @@ restart: | |||
942 | } | 1394 | } |
943 | if (nx == 0) { | 1395 | if (nx == 0) { |
944 | /* Flow passes not transformed. */ | 1396 | /* Flow passes not transformed. */ |
945 | xfrm_pol_put(policy); | 1397 | xfrm_pols_put(pols, npols); |
946 | return 0; | 1398 | return 0; |
947 | } | 1399 | } |
948 | 1400 | ||
@@ -956,8 +1408,14 @@ restart: | |||
956 | goto error; | 1408 | goto error; |
957 | } | 1409 | } |
958 | 1410 | ||
1411 | for (pi = 0; pi < npols; pi++) { | ||
1412 | read_lock_bh(&pols[pi]->lock); | ||
1413 | pol_dead |= pols[pi]->dead; | ||
1414 | read_unlock_bh(&pols[pi]->lock); | ||
1415 | } | ||
1416 | |||
959 | write_lock_bh(&policy->lock); | 1417 | write_lock_bh(&policy->lock); |
960 | if (unlikely(policy->dead || stale_bundle(dst))) { | 1418 | if (unlikely(pol_dead || stale_bundle(dst))) { |
961 | /* Wow! While we worked on resolving, this | 1419 | /* Wow! While we worked on resolving, this |
962 | * policy has gone. Retry. It is not paranoia, | 1420 | * policy has gone. Retry. It is not paranoia, |
963 | * we just cannot enlist new bundle to dead object. | 1421 | * we just cannot enlist new bundle to dead object. |
@@ -977,17 +1435,34 @@ restart: | |||
977 | } | 1435 | } |
978 | *dst_p = dst; | 1436 | *dst_p = dst; |
979 | dst_release(dst_orig); | 1437 | dst_release(dst_orig); |
980 | xfrm_pol_put(policy); | 1438 | xfrm_pols_put(pols, npols); |
981 | return 0; | 1439 | return 0; |
982 | 1440 | ||
983 | error: | 1441 | error: |
984 | dst_release(dst_orig); | 1442 | dst_release(dst_orig); |
985 | xfrm_pol_put(policy); | 1443 | xfrm_pols_put(pols, npols); |
986 | *dst_p = NULL; | 1444 | *dst_p = NULL; |
987 | return err; | 1445 | return err; |
988 | } | 1446 | } |
989 | EXPORT_SYMBOL(xfrm_lookup); | 1447 | EXPORT_SYMBOL(xfrm_lookup); |
990 | 1448 | ||
1449 | static inline int | ||
1450 | xfrm_secpath_reject(int idx, struct sk_buff *skb, struct flowi *fl) | ||
1451 | { | ||
1452 | struct xfrm_state *x; | ||
1453 | int err; | ||
1454 | |||
1455 | if (!skb->sp || idx < 0 || idx >= skb->sp->len) | ||
1456 | return 0; | ||
1457 | x = skb->sp->xvec[idx]; | ||
1458 | if (!x->type->reject) | ||
1459 | return 0; | ||
1460 | xfrm_state_hold(x); | ||
1461 | err = x->type->reject(x, skb, fl); | ||
1462 | xfrm_state_put(x); | ||
1463 | return err; | ||
1464 | } | ||
1465 | |||
991 | /* When skb is transformed back to its "native" form, we have to | 1466 | /* When skb is transformed back to its "native" form, we have to |
992 | * check policy restrictions. At the moment we make this in maximally | 1467 | * check policy restrictions. At the moment we make this in maximally |
993 | * stupid way. Shame on me. :-) Of course, connected sockets must | 1468 | * stupid way. Shame on me. :-) Of course, connected sockets must |
@@ -1004,10 +1479,19 @@ xfrm_state_ok(struct xfrm_tmpl *tmpl, struct xfrm_state *x, | |||
1004 | (x->id.spi == tmpl->id.spi || !tmpl->id.spi) && | 1479 | (x->id.spi == tmpl->id.spi || !tmpl->id.spi) && |
1005 | (x->props.reqid == tmpl->reqid || !tmpl->reqid) && | 1480 | (x->props.reqid == tmpl->reqid || !tmpl->reqid) && |
1006 | x->props.mode == tmpl->mode && | 1481 | x->props.mode == tmpl->mode && |
1007 | (tmpl->aalgos & (1<<x->props.aalgo)) && | 1482 | ((tmpl->aalgos & (1<<x->props.aalgo)) || |
1008 | !(x->props.mode && xfrm_state_addr_cmp(tmpl, x, family)); | 1483 | !(xfrm_id_proto_match(tmpl->id.proto, IPSEC_PROTO_ANY))) && |
1484 | !(x->props.mode != XFRM_MODE_TRANSPORT && | ||
1485 | xfrm_state_addr_cmp(tmpl, x, family)); | ||
1009 | } | 1486 | } |
1010 | 1487 | ||
1488 | /* | ||
1489 | * 0 or more than 0 is returned when validation is succeeded (either bypass | ||
1490 | * because of optional transport mode, or next index of the mathced secpath | ||
1491 | * state with the template. | ||
1492 | * -1 is returned when no matching template is found. | ||
1493 | * Otherwise "-2 - errored_index" is returned. | ||
1494 | */ | ||
1011 | static inline int | 1495 | static inline int |
1012 | xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start, | 1496 | xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start, |
1013 | unsigned short family) | 1497 | unsigned short family) |
@@ -1015,15 +1499,18 @@ xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start, | |||
1015 | int idx = start; | 1499 | int idx = start; |
1016 | 1500 | ||
1017 | if (tmpl->optional) { | 1501 | if (tmpl->optional) { |
1018 | if (!tmpl->mode) | 1502 | if (tmpl->mode == XFRM_MODE_TRANSPORT) |
1019 | return start; | 1503 | return start; |
1020 | } else | 1504 | } else |
1021 | start = -1; | 1505 | start = -1; |
1022 | for (; idx < sp->len; idx++) { | 1506 | for (; idx < sp->len; idx++) { |
1023 | if (xfrm_state_ok(tmpl, sp->xvec[idx], family)) | 1507 | if (xfrm_state_ok(tmpl, sp->xvec[idx], family)) |
1024 | return ++idx; | 1508 | return ++idx; |
1025 | if (sp->xvec[idx]->props.mode) | 1509 | if (sp->xvec[idx]->props.mode != XFRM_MODE_TRANSPORT) { |
1510 | if (start == -1) | ||
1511 | start = -2-idx; | ||
1026 | break; | 1512 | break; |
1513 | } | ||
1027 | } | 1514 | } |
1028 | return start; | 1515 | return start; |
1029 | } | 1516 | } |
@@ -1032,21 +1519,25 @@ int | |||
1032 | xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family) | 1519 | xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family) |
1033 | { | 1520 | { |
1034 | struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); | 1521 | struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); |
1522 | int err; | ||
1035 | 1523 | ||
1036 | if (unlikely(afinfo == NULL)) | 1524 | if (unlikely(afinfo == NULL)) |
1037 | return -EAFNOSUPPORT; | 1525 | return -EAFNOSUPPORT; |
1038 | 1526 | ||
1039 | afinfo->decode_session(skb, fl); | 1527 | afinfo->decode_session(skb, fl); |
1528 | err = security_xfrm_decode_session(skb, &fl->secid); | ||
1040 | xfrm_policy_put_afinfo(afinfo); | 1529 | xfrm_policy_put_afinfo(afinfo); |
1041 | return 0; | 1530 | return err; |
1042 | } | 1531 | } |
1043 | EXPORT_SYMBOL(xfrm_decode_session); | 1532 | EXPORT_SYMBOL(xfrm_decode_session); |
1044 | 1533 | ||
1045 | static inline int secpath_has_tunnel(struct sec_path *sp, int k) | 1534 | static inline int secpath_has_nontransport(struct sec_path *sp, int k, int *idxp) |
1046 | { | 1535 | { |
1047 | for (; k < sp->len; k++) { | 1536 | for (; k < sp->len; k++) { |
1048 | if (sp->xvec[k]->props.mode) | 1537 | if (sp->xvec[k]->props.mode != XFRM_MODE_TRANSPORT) { |
1538 | *idxp = k; | ||
1049 | return 1; | 1539 | return 1; |
1540 | } | ||
1050 | } | 1541 | } |
1051 | 1542 | ||
1052 | return 0; | 1543 | return 0; |
@@ -1056,16 +1547,18 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1056 | unsigned short family) | 1547 | unsigned short family) |
1057 | { | 1548 | { |
1058 | struct xfrm_policy *pol; | 1549 | struct xfrm_policy *pol; |
1550 | struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; | ||
1551 | int npols = 0; | ||
1552 | int xfrm_nr; | ||
1553 | int pi; | ||
1059 | struct flowi fl; | 1554 | struct flowi fl; |
1060 | u8 fl_dir = policy_to_flow_dir(dir); | 1555 | u8 fl_dir = policy_to_flow_dir(dir); |
1061 | u32 sk_sid; | 1556 | int xerr_idx = -1; |
1062 | 1557 | ||
1063 | if (xfrm_decode_session(skb, &fl, family) < 0) | 1558 | if (xfrm_decode_session(skb, &fl, family) < 0) |
1064 | return 0; | 1559 | return 0; |
1065 | nf_nat_decode_session(skb, &fl, family); | 1560 | nf_nat_decode_session(skb, &fl, family); |
1066 | 1561 | ||
1067 | sk_sid = security_sk_sid(sk, &fl, fl_dir); | ||
1068 | |||
1069 | /* First, check used SA against their selectors. */ | 1562 | /* First, check used SA against their selectors. */ |
1070 | if (skb->sp) { | 1563 | if (skb->sp) { |
1071 | int i; | 1564 | int i; |
@@ -1079,46 +1572,90 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1079 | 1572 | ||
1080 | pol = NULL; | 1573 | pol = NULL; |
1081 | if (sk && sk->sk_policy[dir]) | 1574 | if (sk && sk->sk_policy[dir]) |
1082 | pol = xfrm_sk_policy_lookup(sk, dir, &fl, sk_sid); | 1575 | pol = xfrm_sk_policy_lookup(sk, dir, &fl); |
1083 | 1576 | ||
1084 | if (!pol) | 1577 | if (!pol) |
1085 | pol = flow_cache_lookup(&fl, sk_sid, family, fl_dir, | 1578 | pol = flow_cache_lookup(&fl, family, fl_dir, |
1086 | xfrm_policy_lookup); | 1579 | xfrm_policy_lookup); |
1087 | 1580 | ||
1088 | if (!pol) | 1581 | if (!pol) { |
1089 | return !skb->sp || !secpath_has_tunnel(skb->sp, 0); | 1582 | if (skb->sp && secpath_has_nontransport(skb->sp, 0, &xerr_idx)) { |
1583 | xfrm_secpath_reject(xerr_idx, skb, &fl); | ||
1584 | return 0; | ||
1585 | } | ||
1586 | return 1; | ||
1587 | } | ||
1090 | 1588 | ||
1091 | pol->curlft.use_time = (unsigned long)xtime.tv_sec; | 1589 | pol->curlft.use_time = (unsigned long)xtime.tv_sec; |
1092 | 1590 | ||
1591 | pols[0] = pol; | ||
1592 | npols ++; | ||
1593 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
1594 | if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) { | ||
1595 | pols[1] = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, | ||
1596 | &fl, family, | ||
1597 | XFRM_POLICY_IN); | ||
1598 | if (pols[1]) { | ||
1599 | pols[1]->curlft.use_time = (unsigned long)xtime.tv_sec; | ||
1600 | npols ++; | ||
1601 | } | ||
1602 | } | ||
1603 | #endif | ||
1604 | |||
1093 | if (pol->action == XFRM_POLICY_ALLOW) { | 1605 | if (pol->action == XFRM_POLICY_ALLOW) { |
1094 | struct sec_path *sp; | 1606 | struct sec_path *sp; |
1095 | static struct sec_path dummy; | 1607 | static struct sec_path dummy; |
1608 | struct xfrm_tmpl *tp[XFRM_MAX_DEPTH]; | ||
1609 | struct xfrm_tmpl *stp[XFRM_MAX_DEPTH]; | ||
1610 | struct xfrm_tmpl **tpp = tp; | ||
1611 | int ti = 0; | ||
1096 | int i, k; | 1612 | int i, k; |
1097 | 1613 | ||
1098 | if ((sp = skb->sp) == NULL) | 1614 | if ((sp = skb->sp) == NULL) |
1099 | sp = &dummy; | 1615 | sp = &dummy; |
1100 | 1616 | ||
1617 | for (pi = 0; pi < npols; pi++) { | ||
1618 | if (pols[pi] != pol && | ||
1619 | pols[pi]->action != XFRM_POLICY_ALLOW) | ||
1620 | goto reject; | ||
1621 | if (ti + pols[pi]->xfrm_nr >= XFRM_MAX_DEPTH) | ||
1622 | goto reject_error; | ||
1623 | for (i = 0; i < pols[pi]->xfrm_nr; i++) | ||
1624 | tpp[ti++] = &pols[pi]->xfrm_vec[i]; | ||
1625 | } | ||
1626 | xfrm_nr = ti; | ||
1627 | if (npols > 1) { | ||
1628 | xfrm_tmpl_sort(stp, tpp, xfrm_nr, family); | ||
1629 | tpp = stp; | ||
1630 | } | ||
1631 | |||
1101 | /* For each tunnel xfrm, find the first matching tmpl. | 1632 | /* For each tunnel xfrm, find the first matching tmpl. |
1102 | * For each tmpl before that, find corresponding xfrm. | 1633 | * For each tmpl before that, find corresponding xfrm. |
1103 | * Order is _important_. Later we will implement | 1634 | * Order is _important_. Later we will implement |
1104 | * some barriers, but at the moment barriers | 1635 | * some barriers, but at the moment barriers |
1105 | * are implied between each two transformations. | 1636 | * are implied between each two transformations. |
1106 | */ | 1637 | */ |
1107 | for (i = pol->xfrm_nr-1, k = 0; i >= 0; i--) { | 1638 | for (i = xfrm_nr-1, k = 0; i >= 0; i--) { |
1108 | k = xfrm_policy_ok(pol->xfrm_vec+i, sp, k, family); | 1639 | k = xfrm_policy_ok(tpp[i], sp, k, family); |
1109 | if (k < 0) | 1640 | if (k < 0) { |
1641 | if (k < -1) | ||
1642 | /* "-2 - errored_index" returned */ | ||
1643 | xerr_idx = -(2+k); | ||
1110 | goto reject; | 1644 | goto reject; |
1645 | } | ||
1111 | } | 1646 | } |
1112 | 1647 | ||
1113 | if (secpath_has_tunnel(sp, k)) | 1648 | if (secpath_has_nontransport(sp, k, &xerr_idx)) |
1114 | goto reject; | 1649 | goto reject; |
1115 | 1650 | ||
1116 | xfrm_pol_put(pol); | 1651 | xfrm_pols_put(pols, npols); |
1117 | return 1; | 1652 | return 1; |
1118 | } | 1653 | } |
1119 | 1654 | ||
1120 | reject: | 1655 | reject: |
1121 | xfrm_pol_put(pol); | 1656 | xfrm_secpath_reject(xerr_idx, skb, &fl); |
1657 | reject_error: | ||
1658 | xfrm_pols_put(pols, npols); | ||
1122 | return 0; | 1659 | return 0; |
1123 | } | 1660 | } |
1124 | EXPORT_SYMBOL(__xfrm_policy_check); | 1661 | EXPORT_SYMBOL(__xfrm_policy_check); |
@@ -1166,7 +1703,7 @@ static struct dst_entry *xfrm_dst_check(struct dst_entry *dst, u32 cookie) | |||
1166 | 1703 | ||
1167 | static int stale_bundle(struct dst_entry *dst) | 1704 | static int stale_bundle(struct dst_entry *dst) |
1168 | { | 1705 | { |
1169 | return !xfrm_bundle_ok((struct xfrm_dst *)dst, NULL, AF_UNSPEC); | 1706 | return !xfrm_bundle_ok((struct xfrm_dst *)dst, NULL, AF_UNSPEC, 0); |
1170 | } | 1707 | } |
1171 | 1708 | ||
1172 | void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) | 1709 | void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) |
@@ -1196,33 +1733,50 @@ static struct dst_entry *xfrm_negative_advice(struct dst_entry *dst) | |||
1196 | return dst; | 1733 | return dst; |
1197 | } | 1734 | } |
1198 | 1735 | ||
1736 | static void prune_one_bundle(struct xfrm_policy *pol, int (*func)(struct dst_entry *), struct dst_entry **gc_list_p) | ||
1737 | { | ||
1738 | struct dst_entry *dst, **dstp; | ||
1739 | |||
1740 | write_lock(&pol->lock); | ||
1741 | dstp = &pol->bundles; | ||
1742 | while ((dst=*dstp) != NULL) { | ||
1743 | if (func(dst)) { | ||
1744 | *dstp = dst->next; | ||
1745 | dst->next = *gc_list_p; | ||
1746 | *gc_list_p = dst; | ||
1747 | } else { | ||
1748 | dstp = &dst->next; | ||
1749 | } | ||
1750 | } | ||
1751 | write_unlock(&pol->lock); | ||
1752 | } | ||
1753 | |||
1199 | static void xfrm_prune_bundles(int (*func)(struct dst_entry *)) | 1754 | static void xfrm_prune_bundles(int (*func)(struct dst_entry *)) |
1200 | { | 1755 | { |
1201 | int i; | 1756 | struct dst_entry *gc_list = NULL; |
1202 | struct xfrm_policy *pol; | 1757 | int dir; |
1203 | struct dst_entry *dst, **dstp, *gc_list = NULL; | ||
1204 | 1758 | ||
1205 | read_lock_bh(&xfrm_policy_lock); | 1759 | read_lock_bh(&xfrm_policy_lock); |
1206 | for (i=0; i<2*XFRM_POLICY_MAX; i++) { | 1760 | for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { |
1207 | for (pol = xfrm_policy_list[i]; pol; pol = pol->next) { | 1761 | struct xfrm_policy *pol; |
1208 | write_lock(&pol->lock); | 1762 | struct hlist_node *entry; |
1209 | dstp = &pol->bundles; | 1763 | struct hlist_head *table; |
1210 | while ((dst=*dstp) != NULL) { | 1764 | int i; |
1211 | if (func(dst)) { | 1765 | |
1212 | *dstp = dst->next; | 1766 | hlist_for_each_entry(pol, entry, |
1213 | dst->next = gc_list; | 1767 | &xfrm_policy_inexact[dir], bydst) |
1214 | gc_list = dst; | 1768 | prune_one_bundle(pol, func, &gc_list); |
1215 | } else { | 1769 | |
1216 | dstp = &dst->next; | 1770 | table = xfrm_policy_bydst[dir].table; |
1217 | } | 1771 | for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) { |
1218 | } | 1772 | hlist_for_each_entry(pol, entry, table + i, bydst) |
1219 | write_unlock(&pol->lock); | 1773 | prune_one_bundle(pol, func, &gc_list); |
1220 | } | 1774 | } |
1221 | } | 1775 | } |
1222 | read_unlock_bh(&xfrm_policy_lock); | 1776 | read_unlock_bh(&xfrm_policy_lock); |
1223 | 1777 | ||
1224 | while (gc_list) { | 1778 | while (gc_list) { |
1225 | dst = gc_list; | 1779 | struct dst_entry *dst = gc_list; |
1226 | gc_list = dst->next; | 1780 | gc_list = dst->next; |
1227 | dst_free(dst); | 1781 | dst_free(dst); |
1228 | } | 1782 | } |
@@ -1238,22 +1792,12 @@ static void __xfrm_garbage_collect(void) | |||
1238 | xfrm_prune_bundles(unused_bundle); | 1792 | xfrm_prune_bundles(unused_bundle); |
1239 | } | 1793 | } |
1240 | 1794 | ||
1241 | int xfrm_flush_bundles(void) | 1795 | static int xfrm_flush_bundles(void) |
1242 | { | 1796 | { |
1243 | xfrm_prune_bundles(stale_bundle); | 1797 | xfrm_prune_bundles(stale_bundle); |
1244 | return 0; | 1798 | return 0; |
1245 | } | 1799 | } |
1246 | 1800 | ||
1247 | static int always_true(struct dst_entry *dst) | ||
1248 | { | ||
1249 | return 1; | ||
1250 | } | ||
1251 | |||
1252 | void xfrm_flush_all_bundles(void) | ||
1253 | { | ||
1254 | xfrm_prune_bundles(always_true); | ||
1255 | } | ||
1256 | |||
1257 | void xfrm_init_pmtu(struct dst_entry *dst) | 1801 | void xfrm_init_pmtu(struct dst_entry *dst) |
1258 | { | 1802 | { |
1259 | do { | 1803 | do { |
@@ -1281,7 +1825,7 @@ EXPORT_SYMBOL(xfrm_init_pmtu); | |||
1281 | * still valid. | 1825 | * still valid. |
1282 | */ | 1826 | */ |
1283 | 1827 | ||
1284 | int xfrm_bundle_ok(struct xfrm_dst *first, struct flowi *fl, int family) | 1828 | int xfrm_bundle_ok(struct xfrm_dst *first, struct flowi *fl, int family, int strict) |
1285 | { | 1829 | { |
1286 | struct dst_entry *dst = &first->u.dst; | 1830 | struct dst_entry *dst = &first->u.dst; |
1287 | struct xfrm_dst *last; | 1831 | struct xfrm_dst *last; |
@@ -1298,8 +1842,16 @@ int xfrm_bundle_ok(struct xfrm_dst *first, struct flowi *fl, int family) | |||
1298 | 1842 | ||
1299 | if (fl && !xfrm_selector_match(&dst->xfrm->sel, fl, family)) | 1843 | if (fl && !xfrm_selector_match(&dst->xfrm->sel, fl, family)) |
1300 | return 0; | 1844 | return 0; |
1845 | if (fl && !security_xfrm_flow_state_match(fl, dst->xfrm)) | ||
1846 | return 0; | ||
1301 | if (dst->xfrm->km.state != XFRM_STATE_VALID) | 1847 | if (dst->xfrm->km.state != XFRM_STATE_VALID) |
1302 | return 0; | 1848 | return 0; |
1849 | if (xdst->genid != dst->xfrm->genid) | ||
1850 | return 0; | ||
1851 | |||
1852 | if (strict && fl && dst->xfrm->props.mode != XFRM_MODE_TUNNEL && | ||
1853 | !xfrm_state_addr_flow_check(dst->xfrm, fl, family)) | ||
1854 | return 0; | ||
1303 | 1855 | ||
1304 | mtu = dst_mtu(dst->child); | 1856 | mtu = dst_mtu(dst->child); |
1305 | if (xdst->child_mtu_cached != mtu) { | 1857 | if (xdst->child_mtu_cached != mtu) { |
@@ -1448,12 +2000,33 @@ static struct notifier_block xfrm_dev_notifier = { | |||
1448 | 2000 | ||
1449 | static void __init xfrm_policy_init(void) | 2001 | static void __init xfrm_policy_init(void) |
1450 | { | 2002 | { |
2003 | unsigned int hmask, sz; | ||
2004 | int dir; | ||
2005 | |||
1451 | xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache", | 2006 | xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache", |
1452 | sizeof(struct xfrm_dst), | 2007 | sizeof(struct xfrm_dst), |
1453 | 0, SLAB_HWCACHE_ALIGN, | 2008 | 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, |
1454 | NULL, NULL); | 2009 | NULL, NULL); |
1455 | if (!xfrm_dst_cache) | 2010 | |
1456 | panic("XFRM: failed to allocate xfrm_dst_cache\n"); | 2011 | hmask = 8 - 1; |
2012 | sz = (hmask+1) * sizeof(struct hlist_head); | ||
2013 | |||
2014 | xfrm_policy_byidx = xfrm_hash_alloc(sz); | ||
2015 | xfrm_idx_hmask = hmask; | ||
2016 | if (!xfrm_policy_byidx) | ||
2017 | panic("XFRM: failed to allocate byidx hash\n"); | ||
2018 | |||
2019 | for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { | ||
2020 | struct xfrm_policy_hash *htab; | ||
2021 | |||
2022 | INIT_HLIST_HEAD(&xfrm_policy_inexact[dir]); | ||
2023 | |||
2024 | htab = &xfrm_policy_bydst[dir]; | ||
2025 | htab->table = xfrm_hash_alloc(sz); | ||
2026 | htab->hmask = hmask; | ||
2027 | if (!htab->table) | ||
2028 | panic("XFRM: failed to allocate bydst hash\n"); | ||
2029 | } | ||
1457 | 2030 | ||
1458 | INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task, NULL); | 2031 | INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task, NULL); |
1459 | register_netdevice_notifier(&xfrm_dev_notifier); | 2032 | register_netdevice_notifier(&xfrm_dev_notifier); |