diff options
author | Masahide NAKAMURA <nakam@linux-ipv6.org> | 2006-08-24 01:43:30 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-09-22 18:08:34 -0400 |
commit | 4e81bb8336a0ac50289d4d4c7a55e559b994ee8f (patch) | |
tree | fefa71843c3f8152dd0a008b3b40fe2e42d204d7 /net/xfrm | |
parent | c11f1a15c522ddd3bbd2c32b5ce3e0b1831b22f2 (diff) |
[XFRM] POLICY: sub policy support.
Sub policy is introduced. Main and sub policy are applied the same flow.
(Policy that current kernel uses is named as main.)
It is required another transformation policy management to keep IPsec
and Mobile IPv6 lives separate.
Policy which lives shorter time in kernel should be a sub i.e. normally
main is for IPsec and sub is for Mobile IPv6.
(Such usage as two IPsec policies on different database can be used, too.)
Limitation or TODOs:
- Sub policy is not supported for per socket one (it is always inserted as main).
- Current kernel makes cached outbound with flowi to skip searching database.
However this patch makes it disabled only when "two policies are used and
the first matched one is bypass case" because neither flowi nor bundle
information knows about transformation template size.
Signed-off-by: Masahide NAKAMURA <nakam@linux-ipv6.org>
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Diffstat (limited to 'net/xfrm')
-rw-r--r-- | net/xfrm/xfrm_policy.c | 252 |
1 files changed, 216 insertions, 36 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index d125a2649037..96de6c76ed57 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -32,6 +32,24 @@ static DEFINE_RWLOCK(xfrm_policy_lock); | |||
32 | 32 | ||
33 | struct xfrm_policy *xfrm_policy_list[XFRM_POLICY_MAX*2]; | 33 | struct xfrm_policy *xfrm_policy_list[XFRM_POLICY_MAX*2]; |
34 | EXPORT_SYMBOL(xfrm_policy_list); | 34 | EXPORT_SYMBOL(xfrm_policy_list); |
35 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
36 | struct xfrm_policy *xfrm_policy_list_sub[XFRM_POLICY_MAX*2]; | ||
37 | EXPORT_SYMBOL(xfrm_policy_list_sub); | ||
38 | |||
39 | #define XFRM_POLICY_LISTS(type) \ | ||
40 | ((type == XFRM_POLICY_TYPE_SUB) ? xfrm_policy_list_sub : \ | ||
41 | xfrm_policy_list) | ||
42 | #define XFRM_POLICY_LISTHEAD(type, dir) \ | ||
43 | ((type == XFRM_POLICY_TYPE_SUB) ? xfrm_policy_list_sub[dir] : \ | ||
44 | xfrm_policy_list[dir]) | ||
45 | #define XFRM_POLICY_LISTHEADP(type, dir) \ | ||
46 | ((type == XFRM_POLICY_TYPE_SUB) ? &xfrm_policy_list_sub[dir] : \ | ||
47 | &xfrm_policy_list[dir]) | ||
48 | #else | ||
49 | #define XFRM_POLICY_LISTS(type) xfrm_policy_list | ||
50 | #define XFRM_POLICY_LISTHEAD(type, dif) xfrm_policy_list[dir] | ||
51 | #define XFRM_POLICY_LISTHEADP(type, dif) &xfrm_policy_list[dir] | ||
52 | #endif | ||
35 | 53 | ||
36 | static DEFINE_RWLOCK(xfrm_policy_afinfo_lock); | 54 | static DEFINE_RWLOCK(xfrm_policy_afinfo_lock); |
37 | static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO]; | 55 | static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO]; |
@@ -397,7 +415,7 @@ static void xfrm_policy_kill(struct xfrm_policy *policy) | |||
397 | 415 | ||
398 | /* Generate new index... KAME seems to generate them ordered by cost | 416 | /* Generate new index... KAME seems to generate them ordered by cost |
399 | * of an absolute inpredictability of ordering of rules. This will not pass. */ | 417 | * of an absolute inpredictability of ordering of rules. This will not pass. */ |
400 | static u32 xfrm_gen_index(int dir) | 418 | static u32 xfrm_gen_index(u8 type, int dir) |
401 | { | 419 | { |
402 | u32 idx; | 420 | u32 idx; |
403 | struct xfrm_policy *p; | 421 | struct xfrm_policy *p; |
@@ -408,7 +426,7 @@ static u32 xfrm_gen_index(int dir) | |||
408 | idx_generator += 8; | 426 | idx_generator += 8; |
409 | if (idx == 0) | 427 | if (idx == 0) |
410 | idx = 8; | 428 | idx = 8; |
411 | for (p = xfrm_policy_list[dir]; p; p = p->next) { | 429 | for (p = XFRM_POLICY_LISTHEAD(type, dir); p; p = p->next) { |
412 | if (p->index == idx) | 430 | if (p->index == idx) |
413 | break; | 431 | break; |
414 | } | 432 | } |
@@ -425,7 +443,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
425 | struct dst_entry *gc_list; | 443 | struct dst_entry *gc_list; |
426 | 444 | ||
427 | write_lock_bh(&xfrm_policy_lock); | 445 | write_lock_bh(&xfrm_policy_lock); |
428 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL;) { | 446 | for (p = XFRM_POLICY_LISTHEADP(policy->type, dir); (pol=*p)!=NULL;) { |
429 | if (!delpol && memcmp(&policy->selector, &pol->selector, sizeof(pol->selector)) == 0 && | 447 | if (!delpol && memcmp(&policy->selector, &pol->selector, sizeof(pol->selector)) == 0 && |
430 | xfrm_sec_ctx_match(pol->security, policy->security)) { | 448 | xfrm_sec_ctx_match(pol->security, policy->security)) { |
431 | if (excl) { | 449 | if (excl) { |
@@ -452,7 +470,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
452 | policy->next = *p; | 470 | policy->next = *p; |
453 | *p = policy; | 471 | *p = policy; |
454 | atomic_inc(&flow_cache_genid); | 472 | atomic_inc(&flow_cache_genid); |
455 | policy->index = delpol ? delpol->index : xfrm_gen_index(dir); | 473 | policy->index = delpol ? delpol->index : xfrm_gen_index(policy->type, dir); |
456 | policy->curlft.add_time = (unsigned long)xtime.tv_sec; | 474 | policy->curlft.add_time = (unsigned long)xtime.tv_sec; |
457 | policy->curlft.use_time = 0; | 475 | policy->curlft.use_time = 0; |
458 | if (!mod_timer(&policy->timer, jiffies + HZ)) | 476 | if (!mod_timer(&policy->timer, jiffies + HZ)) |
@@ -493,13 +511,14 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
493 | } | 511 | } |
494 | EXPORT_SYMBOL(xfrm_policy_insert); | 512 | EXPORT_SYMBOL(xfrm_policy_insert); |
495 | 513 | ||
496 | struct xfrm_policy *xfrm_policy_bysel_ctx(int dir, struct xfrm_selector *sel, | 514 | struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir, |
515 | struct xfrm_selector *sel, | ||
497 | struct xfrm_sec_ctx *ctx, int delete) | 516 | struct xfrm_sec_ctx *ctx, int delete) |
498 | { | 517 | { |
499 | struct xfrm_policy *pol, **p; | 518 | struct xfrm_policy *pol, **p; |
500 | 519 | ||
501 | write_lock_bh(&xfrm_policy_lock); | 520 | write_lock_bh(&xfrm_policy_lock); |
502 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) { | 521 | for (p = XFRM_POLICY_LISTHEADP(type, dir); (pol=*p)!=NULL; p = &pol->next) { |
503 | if ((memcmp(sel, &pol->selector, sizeof(*sel)) == 0) && | 522 | if ((memcmp(sel, &pol->selector, sizeof(*sel)) == 0) && |
504 | (xfrm_sec_ctx_match(ctx, pol->security))) { | 523 | (xfrm_sec_ctx_match(ctx, pol->security))) { |
505 | xfrm_pol_hold(pol); | 524 | xfrm_pol_hold(pol); |
@@ -518,12 +537,12 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(int dir, struct xfrm_selector *sel, | |||
518 | } | 537 | } |
519 | EXPORT_SYMBOL(xfrm_policy_bysel_ctx); | 538 | EXPORT_SYMBOL(xfrm_policy_bysel_ctx); |
520 | 539 | ||
521 | struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete) | 540 | struct xfrm_policy *xfrm_policy_byid(u8 type, int dir, u32 id, int delete) |
522 | { | 541 | { |
523 | struct xfrm_policy *pol, **p; | 542 | struct xfrm_policy *pol, **p; |
524 | 543 | ||
525 | write_lock_bh(&xfrm_policy_lock); | 544 | write_lock_bh(&xfrm_policy_lock); |
526 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) { | 545 | for (p = XFRM_POLICY_LISTHEADP(type, dir); (pol=*p)!=NULL; p = &pol->next) { |
527 | if (pol->index == id) { | 546 | if (pol->index == id) { |
528 | xfrm_pol_hold(pol); | 547 | xfrm_pol_hold(pol); |
529 | if (delete) | 548 | if (delete) |
@@ -541,15 +560,16 @@ struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete) | |||
541 | } | 560 | } |
542 | EXPORT_SYMBOL(xfrm_policy_byid); | 561 | EXPORT_SYMBOL(xfrm_policy_byid); |
543 | 562 | ||
544 | void xfrm_policy_flush(void) | 563 | void xfrm_policy_flush(u8 type) |
545 | { | 564 | { |
546 | struct xfrm_policy *xp; | 565 | struct xfrm_policy *xp; |
566 | struct xfrm_policy **p_list = XFRM_POLICY_LISTS(type); | ||
547 | int dir; | 567 | int dir; |
548 | 568 | ||
549 | write_lock_bh(&xfrm_policy_lock); | 569 | write_lock_bh(&xfrm_policy_lock); |
550 | for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { | 570 | for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { |
551 | while ((xp = xfrm_policy_list[dir]) != NULL) { | 571 | while ((xp = p_list[dir]) != NULL) { |
552 | xfrm_policy_list[dir] = xp->next; | 572 | p_list[dir] = xp->next; |
553 | write_unlock_bh(&xfrm_policy_lock); | 573 | write_unlock_bh(&xfrm_policy_lock); |
554 | 574 | ||
555 | xfrm_policy_kill(xp); | 575 | xfrm_policy_kill(xp); |
@@ -562,7 +582,7 @@ void xfrm_policy_flush(void) | |||
562 | } | 582 | } |
563 | EXPORT_SYMBOL(xfrm_policy_flush); | 583 | EXPORT_SYMBOL(xfrm_policy_flush); |
564 | 584 | ||
565 | int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), | 585 | int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), |
566 | void *data) | 586 | void *data) |
567 | { | 587 | { |
568 | struct xfrm_policy *xp; | 588 | struct xfrm_policy *xp; |
@@ -572,7 +592,7 @@ int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), | |||
572 | 592 | ||
573 | read_lock_bh(&xfrm_policy_lock); | 593 | read_lock_bh(&xfrm_policy_lock); |
574 | for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { | 594 | for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { |
575 | for (xp = xfrm_policy_list[dir]; xp; xp = xp->next) | 595 | for (xp = XFRM_POLICY_LISTHEAD(type, dir); xp; xp = xp->next) |
576 | count++; | 596 | count++; |
577 | } | 597 | } |
578 | 598 | ||
@@ -582,7 +602,7 @@ int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), | |||
582 | } | 602 | } |
583 | 603 | ||
584 | for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { | 604 | for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { |
585 | for (xp = xfrm_policy_list[dir]; xp; xp = xp->next) { | 605 | for (xp = XFRM_POLICY_LISTHEAD(type, dir); xp; xp = xp->next) { |
586 | error = func(xp, dir%XFRM_POLICY_MAX, --count, data); | 606 | error = func(xp, dir%XFRM_POLICY_MAX, --count, data); |
587 | if (error) | 607 | if (error) |
588 | goto out; | 608 | goto out; |
@@ -597,13 +617,13 @@ EXPORT_SYMBOL(xfrm_policy_walk); | |||
597 | 617 | ||
598 | /* Find policy to apply to this flow. */ | 618 | /* Find policy to apply to this flow. */ |
599 | 619 | ||
600 | static void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, | 620 | static struct xfrm_policy *xfrm_policy_lookup_bytype(u8 type, struct flowi *fl, |
601 | void **objp, atomic_t **obj_refp) | 621 | u16 family, u8 dir) |
602 | { | 622 | { |
603 | struct xfrm_policy *pol; | 623 | struct xfrm_policy *pol; |
604 | 624 | ||
605 | read_lock_bh(&xfrm_policy_lock); | 625 | read_lock_bh(&xfrm_policy_lock); |
606 | for (pol = xfrm_policy_list[dir]; pol; pol = pol->next) { | 626 | for (pol = XFRM_POLICY_LISTHEAD(type, dir); pol; pol = pol->next) { |
607 | struct xfrm_selector *sel = &pol->selector; | 627 | struct xfrm_selector *sel = &pol->selector; |
608 | int match; | 628 | int match; |
609 | 629 | ||
@@ -620,6 +640,25 @@ static void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, | |||
620 | } | 640 | } |
621 | } | 641 | } |
622 | read_unlock_bh(&xfrm_policy_lock); | 642 | read_unlock_bh(&xfrm_policy_lock); |
643 | |||
644 | return pol; | ||
645 | } | ||
646 | |||
647 | static void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, | ||
648 | void **objp, atomic_t **obj_refp) | ||
649 | { | ||
650 | struct xfrm_policy *pol; | ||
651 | |||
652 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
653 | pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_SUB, fl, family, dir); | ||
654 | if (pol) | ||
655 | goto end; | ||
656 | #endif | ||
657 | pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, fl, family, dir); | ||
658 | |||
659 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
660 | end: | ||
661 | #endif | ||
623 | if ((*objp = (void *) pol) != NULL) | 662 | if ((*objp = (void *) pol) != NULL) |
624 | *obj_refp = &pol->refcnt; | 663 | *obj_refp = &pol->refcnt; |
625 | } | 664 | } |
@@ -665,8 +704,10 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struc | |||
665 | 704 | ||
666 | static void __xfrm_policy_link(struct xfrm_policy *pol, int dir) | 705 | static void __xfrm_policy_link(struct xfrm_policy *pol, int dir) |
667 | { | 706 | { |
668 | pol->next = xfrm_policy_list[dir]; | 707 | struct xfrm_policy **p_list = XFRM_POLICY_LISTS(pol->type); |
669 | xfrm_policy_list[dir] = pol; | 708 | |
709 | pol->next = p_list[dir]; | ||
710 | p_list[dir] = pol; | ||
670 | xfrm_pol_hold(pol); | 711 | xfrm_pol_hold(pol); |
671 | } | 712 | } |
672 | 713 | ||
@@ -675,7 +716,7 @@ static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, | |||
675 | { | 716 | { |
676 | struct xfrm_policy **polp; | 717 | struct xfrm_policy **polp; |
677 | 718 | ||
678 | for (polp = &xfrm_policy_list[dir]; | 719 | for (polp = XFRM_POLICY_LISTHEADP(pol->type, dir); |
679 | *polp != NULL; polp = &(*polp)->next) { | 720 | *polp != NULL; polp = &(*polp)->next) { |
680 | if (*polp == pol) { | 721 | if (*polp == pol) { |
681 | *polp = pol->next; | 722 | *polp = pol->next; |
@@ -704,12 +745,17 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) | |||
704 | { | 745 | { |
705 | struct xfrm_policy *old_pol; | 746 | struct xfrm_policy *old_pol; |
706 | 747 | ||
748 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
749 | if (pol && pol->type != XFRM_POLICY_TYPE_MAIN) | ||
750 | return -EINVAL; | ||
751 | #endif | ||
752 | |||
707 | write_lock_bh(&xfrm_policy_lock); | 753 | write_lock_bh(&xfrm_policy_lock); |
708 | old_pol = sk->sk_policy[dir]; | 754 | old_pol = sk->sk_policy[dir]; |
709 | sk->sk_policy[dir] = pol; | 755 | sk->sk_policy[dir] = pol; |
710 | if (pol) { | 756 | if (pol) { |
711 | pol->curlft.add_time = (unsigned long)xtime.tv_sec; | 757 | pol->curlft.add_time = (unsigned long)xtime.tv_sec; |
712 | pol->index = xfrm_gen_index(XFRM_POLICY_MAX+dir); | 758 | pol->index = xfrm_gen_index(pol->type, XFRM_POLICY_MAX+dir); |
713 | __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir); | 759 | __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir); |
714 | } | 760 | } |
715 | if (old_pol) | 761 | if (old_pol) |
@@ -738,6 +784,7 @@ static struct xfrm_policy *clone_policy(struct xfrm_policy *old, int dir) | |||
738 | newp->flags = old->flags; | 784 | newp->flags = old->flags; |
739 | newp->xfrm_nr = old->xfrm_nr; | 785 | newp->xfrm_nr = old->xfrm_nr; |
740 | newp->index = old->index; | 786 | newp->index = old->index; |
787 | newp->type = old->type; | ||
741 | memcpy(newp->xfrm_vec, old->xfrm_vec, | 788 | memcpy(newp->xfrm_vec, old->xfrm_vec, |
742 | newp->xfrm_nr*sizeof(struct xfrm_tmpl)); | 789 | newp->xfrm_nr*sizeof(struct xfrm_tmpl)); |
743 | write_lock_bh(&xfrm_policy_lock); | 790 | write_lock_bh(&xfrm_policy_lock); |
@@ -764,9 +811,9 @@ int __xfrm_sk_clone_policy(struct sock *sk) | |||
764 | /* Resolve list of templates for the flow, given policy. */ | 811 | /* Resolve list of templates for the flow, given policy. */ |
765 | 812 | ||
766 | static int | 813 | static int |
767 | xfrm_tmpl_resolve(struct xfrm_policy *policy, struct flowi *fl, | 814 | xfrm_tmpl_resolve_one(struct xfrm_policy *policy, struct flowi *fl, |
768 | struct xfrm_state **xfrm, | 815 | struct xfrm_state **xfrm, |
769 | unsigned short family) | 816 | unsigned short family) |
770 | { | 817 | { |
771 | int nx; | 818 | int nx; |
772 | int i, error; | 819 | int i, error; |
@@ -809,6 +856,38 @@ fail: | |||
809 | return error; | 856 | return error; |
810 | } | 857 | } |
811 | 858 | ||
859 | static int | ||
860 | xfrm_tmpl_resolve(struct xfrm_policy **pols, int npols, struct flowi *fl, | ||
861 | struct xfrm_state **xfrm, | ||
862 | unsigned short family) | ||
863 | { | ||
864 | int cnx = 0; | ||
865 | int error; | ||
866 | int ret; | ||
867 | int i; | ||
868 | |||
869 | for (i = 0; i < npols; i++) { | ||
870 | if (cnx + pols[i]->xfrm_nr >= XFRM_MAX_DEPTH) { | ||
871 | error = -ENOBUFS; | ||
872 | goto fail; | ||
873 | } | ||
874 | ret = xfrm_tmpl_resolve_one(pols[i], fl, &xfrm[cnx], family); | ||
875 | if (ret < 0) { | ||
876 | error = ret; | ||
877 | goto fail; | ||
878 | } else | ||
879 | cnx += ret; | ||
880 | } | ||
881 | |||
882 | return cnx; | ||
883 | |||
884 | fail: | ||
885 | for (cnx--; cnx>=0; cnx--) | ||
886 | xfrm_state_put(xfrm[cnx]); | ||
887 | return error; | ||
888 | |||
889 | } | ||
890 | |||
812 | /* Check that the bundle accepts the flow and its components are | 891 | /* Check that the bundle accepts the flow and its components are |
813 | * still valid. | 892 | * still valid. |
814 | */ | 893 | */ |
@@ -855,6 +934,11 @@ int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, | |||
855 | struct sock *sk, int flags) | 934 | struct sock *sk, int flags) |
856 | { | 935 | { |
857 | struct xfrm_policy *policy; | 936 | struct xfrm_policy *policy; |
937 | struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; | ||
938 | int npols; | ||
939 | int pol_dead; | ||
940 | int xfrm_nr; | ||
941 | int pi; | ||
858 | struct xfrm_state *xfrm[XFRM_MAX_DEPTH]; | 942 | struct xfrm_state *xfrm[XFRM_MAX_DEPTH]; |
859 | struct dst_entry *dst, *dst_orig = *dst_p; | 943 | struct dst_entry *dst, *dst_orig = *dst_p; |
860 | int nx = 0; | 944 | int nx = 0; |
@@ -866,12 +950,18 @@ int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, | |||
866 | restart: | 950 | restart: |
867 | genid = atomic_read(&flow_cache_genid); | 951 | genid = atomic_read(&flow_cache_genid); |
868 | policy = NULL; | 952 | policy = NULL; |
953 | for (pi = 0; pi < ARRAY_SIZE(pols); pi++) | ||
954 | pols[pi] = NULL; | ||
955 | npols = 0; | ||
956 | pol_dead = 0; | ||
957 | xfrm_nr = 0; | ||
958 | |||
869 | if (sk && sk->sk_policy[1]) | 959 | if (sk && sk->sk_policy[1]) |
870 | policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl); | 960 | policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl); |
871 | 961 | ||
872 | if (!policy) { | 962 | if (!policy) { |
873 | /* To accelerate a bit... */ | 963 | /* To accelerate a bit... */ |
874 | if ((dst_orig->flags & DST_NOXFRM) || !xfrm_policy_list[XFRM_POLICY_OUT]) | 964 | if ((dst_orig->flags & DST_NOXFRM) || xfrm_policy_lists_empty(XFRM_POLICY_OUT)) |
875 | return 0; | 965 | return 0; |
876 | 966 | ||
877 | policy = flow_cache_lookup(fl, dst_orig->ops->family, | 967 | policy = flow_cache_lookup(fl, dst_orig->ops->family, |
@@ -883,6 +973,9 @@ restart: | |||
883 | 973 | ||
884 | family = dst_orig->ops->family; | 974 | family = dst_orig->ops->family; |
885 | policy->curlft.use_time = (unsigned long)xtime.tv_sec; | 975 | policy->curlft.use_time = (unsigned long)xtime.tv_sec; |
976 | pols[0] = policy; | ||
977 | npols ++; | ||
978 | xfrm_nr += pols[0]->xfrm_nr; | ||
886 | 979 | ||
887 | switch (policy->action) { | 980 | switch (policy->action) { |
888 | case XFRM_POLICY_BLOCK: | 981 | case XFRM_POLICY_BLOCK: |
@@ -891,11 +984,13 @@ restart: | |||
891 | goto error; | 984 | goto error; |
892 | 985 | ||
893 | case XFRM_POLICY_ALLOW: | 986 | case XFRM_POLICY_ALLOW: |
987 | #ifndef CONFIG_XFRM_SUB_POLICY | ||
894 | if (policy->xfrm_nr == 0) { | 988 | if (policy->xfrm_nr == 0) { |
895 | /* Flow passes not transformed. */ | 989 | /* Flow passes not transformed. */ |
896 | xfrm_pol_put(policy); | 990 | xfrm_pol_put(policy); |
897 | return 0; | 991 | return 0; |
898 | } | 992 | } |
993 | #endif | ||
899 | 994 | ||
900 | /* Try to find matching bundle. | 995 | /* Try to find matching bundle. |
901 | * | 996 | * |
@@ -911,7 +1006,36 @@ restart: | |||
911 | if (dst) | 1006 | if (dst) |
912 | break; | 1007 | break; |
913 | 1008 | ||
914 | nx = xfrm_tmpl_resolve(policy, fl, xfrm, family); | 1009 | #ifdef CONFIG_XFRM_SUB_POLICY |
1010 | if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) { | ||
1011 | pols[1] = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, | ||
1012 | fl, family, | ||
1013 | XFRM_POLICY_OUT); | ||
1014 | if (pols[1]) { | ||
1015 | if (pols[1]->action == XFRM_POLICY_BLOCK) { | ||
1016 | err = -EPERM; | ||
1017 | goto error; | ||
1018 | } | ||
1019 | npols ++; | ||
1020 | xfrm_nr += pols[1]->xfrm_nr; | ||
1021 | } | ||
1022 | } | ||
1023 | |||
1024 | /* | ||
1025 | * Because neither flowi nor bundle information knows about | ||
1026 | * transformation template size. On more than one policy usage | ||
1027 | * we can realize whether all of them is bypass or not after | ||
1028 | * they are searched. See above not-transformed bypass | ||
1029 | * is surrounded by non-sub policy configuration, too. | ||
1030 | */ | ||
1031 | if (xfrm_nr == 0) { | ||
1032 | /* Flow passes not transformed. */ | ||
1033 | xfrm_pols_put(pols, npols); | ||
1034 | return 0; | ||
1035 | } | ||
1036 | |||
1037 | #endif | ||
1038 | nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family); | ||
915 | 1039 | ||
916 | if (unlikely(nx<0)) { | 1040 | if (unlikely(nx<0)) { |
917 | err = nx; | 1041 | err = nx; |
@@ -924,7 +1048,7 @@ restart: | |||
924 | set_current_state(TASK_RUNNING); | 1048 | set_current_state(TASK_RUNNING); |
925 | remove_wait_queue(&km_waitq, &wait); | 1049 | remove_wait_queue(&km_waitq, &wait); |
926 | 1050 | ||
927 | nx = xfrm_tmpl_resolve(policy, fl, xfrm, family); | 1051 | nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family); |
928 | 1052 | ||
929 | if (nx == -EAGAIN && signal_pending(current)) { | 1053 | if (nx == -EAGAIN && signal_pending(current)) { |
930 | err = -ERESTART; | 1054 | err = -ERESTART; |
@@ -932,7 +1056,7 @@ restart: | |||
932 | } | 1056 | } |
933 | if (nx == -EAGAIN || | 1057 | if (nx == -EAGAIN || |
934 | genid != atomic_read(&flow_cache_genid)) { | 1058 | genid != atomic_read(&flow_cache_genid)) { |
935 | xfrm_pol_put(policy); | 1059 | xfrm_pols_put(pols, npols); |
936 | goto restart; | 1060 | goto restart; |
937 | } | 1061 | } |
938 | err = nx; | 1062 | err = nx; |
@@ -942,7 +1066,7 @@ restart: | |||
942 | } | 1066 | } |
943 | if (nx == 0) { | 1067 | if (nx == 0) { |
944 | /* Flow passes not transformed. */ | 1068 | /* Flow passes not transformed. */ |
945 | xfrm_pol_put(policy); | 1069 | xfrm_pols_put(pols, npols); |
946 | return 0; | 1070 | return 0; |
947 | } | 1071 | } |
948 | 1072 | ||
@@ -956,8 +1080,14 @@ restart: | |||
956 | goto error; | 1080 | goto error; |
957 | } | 1081 | } |
958 | 1082 | ||
1083 | for (pi = 0; pi < npols; pi++) { | ||
1084 | read_lock_bh(&pols[pi]->lock); | ||
1085 | pol_dead |= pols[pi]->dead; | ||
1086 | read_unlock_bh(&pols[pi]->lock); | ||
1087 | } | ||
1088 | |||
959 | write_lock_bh(&policy->lock); | 1089 | write_lock_bh(&policy->lock); |
960 | if (unlikely(policy->dead || stale_bundle(dst))) { | 1090 | if (unlikely(pol_dead || stale_bundle(dst))) { |
961 | /* Wow! While we worked on resolving, this | 1091 | /* Wow! While we worked on resolving, this |
962 | * policy has gone. Retry. It is not paranoia, | 1092 | * policy has gone. Retry. It is not paranoia, |
963 | * we just cannot enlist new bundle to dead object. | 1093 | * we just cannot enlist new bundle to dead object. |
@@ -977,12 +1107,12 @@ restart: | |||
977 | } | 1107 | } |
978 | *dst_p = dst; | 1108 | *dst_p = dst; |
979 | dst_release(dst_orig); | 1109 | dst_release(dst_orig); |
980 | xfrm_pol_put(policy); | 1110 | xfrm_pols_put(pols, npols); |
981 | return 0; | 1111 | return 0; |
982 | 1112 | ||
983 | error: | 1113 | error: |
984 | dst_release(dst_orig); | 1114 | dst_release(dst_orig); |
985 | xfrm_pol_put(policy); | 1115 | xfrm_pols_put(pols, npols); |
986 | *dst_p = NULL; | 1116 | *dst_p = NULL; |
987 | return err; | 1117 | return err; |
988 | } | 1118 | } |
@@ -1090,6 +1220,10 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1090 | unsigned short family) | 1220 | unsigned short family) |
1091 | { | 1221 | { |
1092 | struct xfrm_policy *pol; | 1222 | struct xfrm_policy *pol; |
1223 | struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; | ||
1224 | int npols = 0; | ||
1225 | int xfrm_nr; | ||
1226 | int pi; | ||
1093 | struct flowi fl; | 1227 | struct flowi fl; |
1094 | u8 fl_dir = policy_to_flow_dir(dir); | 1228 | u8 fl_dir = policy_to_flow_dir(dir); |
1095 | int xerr_idx = -1; | 1229 | int xerr_idx = -1; |
@@ -1128,22 +1262,50 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1128 | 1262 | ||
1129 | pol->curlft.use_time = (unsigned long)xtime.tv_sec; | 1263 | pol->curlft.use_time = (unsigned long)xtime.tv_sec; |
1130 | 1264 | ||
1265 | pols[0] = pol; | ||
1266 | npols ++; | ||
1267 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
1268 | if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) { | ||
1269 | pols[1] = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, | ||
1270 | &fl, family, | ||
1271 | XFRM_POLICY_IN); | ||
1272 | if (pols[1]) { | ||
1273 | pols[1]->curlft.use_time = (unsigned long)xtime.tv_sec; | ||
1274 | npols ++; | ||
1275 | } | ||
1276 | } | ||
1277 | #endif | ||
1278 | |||
1131 | if (pol->action == XFRM_POLICY_ALLOW) { | 1279 | if (pol->action == XFRM_POLICY_ALLOW) { |
1132 | struct sec_path *sp; | 1280 | struct sec_path *sp; |
1133 | static struct sec_path dummy; | 1281 | static struct sec_path dummy; |
1282 | struct xfrm_tmpl *tp[XFRM_MAX_DEPTH]; | ||
1283 | struct xfrm_tmpl **tpp = tp; | ||
1284 | int ti = 0; | ||
1134 | int i, k; | 1285 | int i, k; |
1135 | 1286 | ||
1136 | if ((sp = skb->sp) == NULL) | 1287 | if ((sp = skb->sp) == NULL) |
1137 | sp = &dummy; | 1288 | sp = &dummy; |
1138 | 1289 | ||
1290 | for (pi = 0; pi < npols; pi++) { | ||
1291 | if (pols[pi] != pol && | ||
1292 | pols[pi]->action != XFRM_POLICY_ALLOW) | ||
1293 | goto reject; | ||
1294 | if (ti + pols[pi]->xfrm_nr >= XFRM_MAX_DEPTH) | ||
1295 | goto reject_error; | ||
1296 | for (i = 0; i < pols[pi]->xfrm_nr; i++) | ||
1297 | tpp[ti++] = &pols[pi]->xfrm_vec[i]; | ||
1298 | } | ||
1299 | xfrm_nr = ti; | ||
1300 | |||
1139 | /* For each tunnel xfrm, find the first matching tmpl. | 1301 | /* For each tunnel xfrm, find the first matching tmpl. |
1140 | * For each tmpl before that, find corresponding xfrm. | 1302 | * For each tmpl before that, find corresponding xfrm. |
1141 | * Order is _important_. Later we will implement | 1303 | * Order is _important_. Later we will implement |
1142 | * some barriers, but at the moment barriers | 1304 | * some barriers, but at the moment barriers |
1143 | * are implied between each two transformations. | 1305 | * are implied between each two transformations. |
1144 | */ | 1306 | */ |
1145 | for (i = pol->xfrm_nr-1, k = 0; i >= 0; i--) { | 1307 | for (i = xfrm_nr-1, k = 0; i >= 0; i--) { |
1146 | k = xfrm_policy_ok(pol->xfrm_vec+i, sp, k, family); | 1308 | k = xfrm_policy_ok(tpp[i], sp, k, family); |
1147 | if (k < 0) { | 1309 | if (k < 0) { |
1148 | if (k < -1 && xerr_idxp) | 1310 | if (k < -1 && xerr_idxp) |
1149 | *xerr_idxp = -(2+k); | 1311 | *xerr_idxp = -(2+k); |
@@ -1154,13 +1316,14 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1154 | if (secpath_has_nontransport(sp, k, xerr_idxp)) | 1316 | if (secpath_has_nontransport(sp, k, xerr_idxp)) |
1155 | goto reject; | 1317 | goto reject; |
1156 | 1318 | ||
1157 | xfrm_pol_put(pol); | 1319 | xfrm_pols_put(pols, npols); |
1158 | return 1; | 1320 | return 1; |
1159 | } | 1321 | } |
1160 | 1322 | ||
1161 | reject: | 1323 | reject: |
1162 | xfrm_secpath_reject(xerr_idx, skb, &fl); | 1324 | xfrm_secpath_reject(xerr_idx, skb, &fl); |
1163 | xfrm_pol_put(pol); | 1325 | reject_error: |
1326 | xfrm_pols_put(pols, npols); | ||
1164 | return 0; | 1327 | return 0; |
1165 | } | 1328 | } |
1166 | EXPORT_SYMBOL(__xfrm_policy_check); | 1329 | EXPORT_SYMBOL(__xfrm_policy_check); |
@@ -1246,6 +1409,23 @@ static void xfrm_prune_bundles(int (*func)(struct dst_entry *)) | |||
1246 | 1409 | ||
1247 | read_lock_bh(&xfrm_policy_lock); | 1410 | read_lock_bh(&xfrm_policy_lock); |
1248 | for (i=0; i<2*XFRM_POLICY_MAX; i++) { | 1411 | for (i=0; i<2*XFRM_POLICY_MAX; i++) { |
1412 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
1413 | for (pol = xfrm_policy_list_sub[i]; pol; pol = pol->next) { | ||
1414 | write_lock(&pol->lock); | ||
1415 | dstp = &pol->bundles; | ||
1416 | while ((dst=*dstp) != NULL) { | ||
1417 | if (func(dst)) { | ||
1418 | *dstp = dst->next; | ||
1419 | dst->next = gc_list; | ||
1420 | gc_list = dst; | ||
1421 | } else { | ||
1422 | dstp = &dst->next; | ||
1423 | } | ||
1424 | } | ||
1425 | write_unlock(&pol->lock); | ||
1426 | } | ||
1427 | |||
1428 | #endif | ||
1249 | for (pol = xfrm_policy_list[i]; pol; pol = pol->next) { | 1429 | for (pol = xfrm_policy_list[i]; pol; pol = pol->next) { |
1250 | write_lock(&pol->lock); | 1430 | write_lock(&pol->lock); |
1251 | dstp = &pol->bundles; | 1431 | dstp = &pol->bundles; |