diff options
Diffstat (limited to 'net/xfrm/xfrm_state.c')
| -rw-r--r-- | net/xfrm/xfrm_state.c | 151 |
1 files changed, 89 insertions, 62 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index b36cc344474b..eb96ce52f178 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include <linux/audit.h> | 22 | #include <linux/audit.h> |
| 23 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
| 24 | #include <linux/ktime.h> | 24 | #include <linux/ktime.h> |
| 25 | #include <linux/slab.h> | ||
| 25 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
| 26 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
| 27 | 28 | ||
| @@ -37,7 +38,6 @@ | |||
| 37 | static DEFINE_SPINLOCK(xfrm_state_lock); | 38 | static DEFINE_SPINLOCK(xfrm_state_lock); |
| 38 | 39 | ||
| 39 | static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; | 40 | static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; |
| 40 | static unsigned int xfrm_state_genid; | ||
| 41 | 41 | ||
| 42 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); | 42 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); |
| 43 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); | 43 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); |
| @@ -603,13 +603,14 @@ xfrm_state_flush_secctx_check(struct net *net, u8 proto, struct xfrm_audit *audi | |||
| 603 | 603 | ||
| 604 | int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info) | 604 | int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info) |
| 605 | { | 605 | { |
| 606 | int i, err = 0; | 606 | int i, err = 0, cnt = 0; |
| 607 | 607 | ||
| 608 | spin_lock_bh(&xfrm_state_lock); | 608 | spin_lock_bh(&xfrm_state_lock); |
| 609 | err = xfrm_state_flush_secctx_check(net, proto, audit_info); | 609 | err = xfrm_state_flush_secctx_check(net, proto, audit_info); |
| 610 | if (err) | 610 | if (err) |
| 611 | goto out; | 611 | goto out; |
| 612 | 612 | ||
| 613 | err = -ESRCH; | ||
| 613 | for (i = 0; i <= net->xfrm.state_hmask; i++) { | 614 | for (i = 0; i <= net->xfrm.state_hmask; i++) { |
| 614 | struct hlist_node *entry; | 615 | struct hlist_node *entry; |
| 615 | struct xfrm_state *x; | 616 | struct xfrm_state *x; |
| @@ -626,13 +627,16 @@ restart: | |||
| 626 | audit_info->sessionid, | 627 | audit_info->sessionid, |
| 627 | audit_info->secid); | 628 | audit_info->secid); |
| 628 | xfrm_state_put(x); | 629 | xfrm_state_put(x); |
| 630 | if (!err) | ||
| 631 | cnt++; | ||
| 629 | 632 | ||
| 630 | spin_lock_bh(&xfrm_state_lock); | 633 | spin_lock_bh(&xfrm_state_lock); |
| 631 | goto restart; | 634 | goto restart; |
| 632 | } | 635 | } |
| 633 | } | 636 | } |
| 634 | } | 637 | } |
| 635 | err = 0; | 638 | if (cnt) |
| 639 | err = 0; | ||
| 636 | 640 | ||
| 637 | out: | 641 | out: |
| 638 | spin_unlock_bh(&xfrm_state_lock); | 642 | spin_unlock_bh(&xfrm_state_lock); |
| @@ -652,20 +656,28 @@ void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si) | |||
| 652 | EXPORT_SYMBOL(xfrm_sad_getinfo); | 656 | EXPORT_SYMBOL(xfrm_sad_getinfo); |
| 653 | 657 | ||
| 654 | static int | 658 | static int |
| 655 | xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl, | 659 | xfrm_init_tempstate(struct xfrm_state *x, struct flowi *fl, |
| 656 | struct xfrm_tmpl *tmpl, | 660 | struct xfrm_tmpl *tmpl, |
| 657 | xfrm_address_t *daddr, xfrm_address_t *saddr, | 661 | xfrm_address_t *daddr, xfrm_address_t *saddr, |
| 658 | unsigned short family) | 662 | unsigned short family) |
| 659 | { | 663 | { |
| 660 | struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); | 664 | struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); |
| 661 | if (!afinfo) | 665 | if (!afinfo) |
| 662 | return -1; | 666 | return -1; |
| 663 | afinfo->init_tempsel(x, fl, tmpl, daddr, saddr); | 667 | afinfo->init_tempsel(&x->sel, fl); |
| 668 | |||
| 669 | if (family != tmpl->encap_family) { | ||
| 670 | xfrm_state_put_afinfo(afinfo); | ||
| 671 | afinfo = xfrm_state_get_afinfo(tmpl->encap_family); | ||
| 672 | if (!afinfo) | ||
| 673 | return -1; | ||
| 674 | } | ||
| 675 | afinfo->init_temprop(x, tmpl, daddr, saddr); | ||
| 664 | xfrm_state_put_afinfo(afinfo); | 676 | xfrm_state_put_afinfo(afinfo); |
| 665 | return 0; | 677 | return 0; |
| 666 | } | 678 | } |
| 667 | 679 | ||
| 668 | static struct xfrm_state *__xfrm_state_lookup(struct net *net, xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family) | 680 | static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark, xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family) |
| 669 | { | 681 | { |
| 670 | unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family); | 682 | unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family); |
| 671 | struct xfrm_state *x; | 683 | struct xfrm_state *x; |
| @@ -678,6 +690,8 @@ static struct xfrm_state *__xfrm_state_lookup(struct net *net, xfrm_address_t *d | |||
| 678 | xfrm_addr_cmp(&x->id.daddr, daddr, family)) | 690 | xfrm_addr_cmp(&x->id.daddr, daddr, family)) |
| 679 | continue; | 691 | continue; |
| 680 | 692 | ||
| 693 | if ((mark & x->mark.m) != x->mark.v) | ||
| 694 | continue; | ||
| 681 | xfrm_state_hold(x); | 695 | xfrm_state_hold(x); |
| 682 | return x; | 696 | return x; |
| 683 | } | 697 | } |
| @@ -685,7 +699,7 @@ static struct xfrm_state *__xfrm_state_lookup(struct net *net, xfrm_address_t *d | |||
| 685 | return NULL; | 699 | return NULL; |
| 686 | } | 700 | } |
| 687 | 701 | ||
| 688 | static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family) | 702 | static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, u32 mark, xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family) |
| 689 | { | 703 | { |
| 690 | unsigned int h = xfrm_src_hash(net, daddr, saddr, family); | 704 | unsigned int h = xfrm_src_hash(net, daddr, saddr, family); |
| 691 | struct xfrm_state *x; | 705 | struct xfrm_state *x; |
| @@ -698,6 +712,8 @@ static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, xfrm_addre | |||
| 698 | xfrm_addr_cmp(&x->props.saddr, saddr, family)) | 712 | xfrm_addr_cmp(&x->props.saddr, saddr, family)) |
| 699 | continue; | 713 | continue; |
| 700 | 714 | ||
| 715 | if ((mark & x->mark.m) != x->mark.v) | ||
| 716 | continue; | ||
| 701 | xfrm_state_hold(x); | 717 | xfrm_state_hold(x); |
| 702 | return x; | 718 | return x; |
| 703 | } | 719 | } |
| @@ -709,12 +725,14 @@ static inline struct xfrm_state * | |||
| 709 | __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family) | 725 | __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family) |
| 710 | { | 726 | { |
| 711 | struct net *net = xs_net(x); | 727 | struct net *net = xs_net(x); |
| 728 | u32 mark = x->mark.v & x->mark.m; | ||
| 712 | 729 | ||
| 713 | if (use_spi) | 730 | if (use_spi) |
| 714 | return __xfrm_state_lookup(net, &x->id.daddr, x->id.spi, | 731 | return __xfrm_state_lookup(net, mark, &x->id.daddr, |
| 715 | x->id.proto, family); | 732 | x->id.spi, x->id.proto, family); |
| 716 | else | 733 | else |
| 717 | return __xfrm_state_lookup_byaddr(net, &x->id.daddr, | 734 | return __xfrm_state_lookup_byaddr(net, mark, |
| 735 | &x->id.daddr, | ||
| 718 | &x->props.saddr, | 736 | &x->props.saddr, |
| 719 | x->id.proto, family); | 737 | x->id.proto, family); |
| 720 | } | 738 | } |
| @@ -779,35 +797,39 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
| 779 | int acquire_in_progress = 0; | 797 | int acquire_in_progress = 0; |
| 780 | int error = 0; | 798 | int error = 0; |
| 781 | struct xfrm_state *best = NULL; | 799 | struct xfrm_state *best = NULL; |
| 800 | u32 mark = pol->mark.v & pol->mark.m; | ||
| 801 | unsigned short encap_family = tmpl->encap_family; | ||
| 782 | 802 | ||
| 783 | to_put = NULL; | 803 | to_put = NULL; |
| 784 | 804 | ||
| 785 | spin_lock_bh(&xfrm_state_lock); | 805 | spin_lock_bh(&xfrm_state_lock); |
| 786 | h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, family); | 806 | h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family); |
| 787 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { | 807 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { |
| 788 | if (x->props.family == family && | 808 | if (x->props.family == encap_family && |
| 789 | x->props.reqid == tmpl->reqid && | 809 | x->props.reqid == tmpl->reqid && |
| 810 | (mark & x->mark.m) == x->mark.v && | ||
| 790 | !(x->props.flags & XFRM_STATE_WILDRECV) && | 811 | !(x->props.flags & XFRM_STATE_WILDRECV) && |
| 791 | xfrm_state_addr_check(x, daddr, saddr, family) && | 812 | xfrm_state_addr_check(x, daddr, saddr, encap_family) && |
| 792 | tmpl->mode == x->props.mode && | 813 | tmpl->mode == x->props.mode && |
| 793 | tmpl->id.proto == x->id.proto && | 814 | tmpl->id.proto == x->id.proto && |
| 794 | (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) | 815 | (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) |
| 795 | xfrm_state_look_at(pol, x, fl, family, daddr, saddr, | 816 | xfrm_state_look_at(pol, x, fl, encap_family, daddr, saddr, |
| 796 | &best, &acquire_in_progress, &error); | 817 | &best, &acquire_in_progress, &error); |
| 797 | } | 818 | } |
| 798 | if (best) | 819 | if (best) |
| 799 | goto found; | 820 | goto found; |
| 800 | 821 | ||
| 801 | h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, family); | 822 | h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, encap_family); |
| 802 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h_wildcard, bydst) { | 823 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h_wildcard, bydst) { |
| 803 | if (x->props.family == family && | 824 | if (x->props.family == encap_family && |
| 804 | x->props.reqid == tmpl->reqid && | 825 | x->props.reqid == tmpl->reqid && |
| 826 | (mark & x->mark.m) == x->mark.v && | ||
| 805 | !(x->props.flags & XFRM_STATE_WILDRECV) && | 827 | !(x->props.flags & XFRM_STATE_WILDRECV) && |
| 806 | xfrm_state_addr_check(x, daddr, saddr, family) && | 828 | xfrm_state_addr_check(x, daddr, saddr, encap_family) && |
| 807 | tmpl->mode == x->props.mode && | 829 | tmpl->mode == x->props.mode && |
| 808 | tmpl->id.proto == x->id.proto && | 830 | tmpl->id.proto == x->id.proto && |
| 809 | (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) | 831 | (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) |
| 810 | xfrm_state_look_at(pol, x, fl, family, daddr, saddr, | 832 | xfrm_state_look_at(pol, x, fl, encap_family, daddr, saddr, |
| 811 | &best, &acquire_in_progress, &error); | 833 | &best, &acquire_in_progress, &error); |
| 812 | } | 834 | } |
| 813 | 835 | ||
| @@ -815,8 +837,8 @@ found: | |||
| 815 | x = best; | 837 | x = best; |
| 816 | if (!x && !error && !acquire_in_progress) { | 838 | if (!x && !error && !acquire_in_progress) { |
| 817 | if (tmpl->id.spi && | 839 | if (tmpl->id.spi && |
| 818 | (x0 = __xfrm_state_lookup(net, daddr, tmpl->id.spi, | 840 | (x0 = __xfrm_state_lookup(net, mark, daddr, tmpl->id.spi, |
| 819 | tmpl->id.proto, family)) != NULL) { | 841 | tmpl->id.proto, encap_family)) != NULL) { |
| 820 | to_put = x0; | 842 | to_put = x0; |
| 821 | error = -EEXIST; | 843 | error = -EEXIST; |
| 822 | goto out; | 844 | goto out; |
| @@ -826,9 +848,10 @@ found: | |||
| 826 | error = -ENOMEM; | 848 | error = -ENOMEM; |
| 827 | goto out; | 849 | goto out; |
| 828 | } | 850 | } |
| 829 | /* Initialize temporary selector matching only | 851 | /* Initialize temporary state matching only |
| 830 | * to current session. */ | 852 | * to current session. */ |
| 831 | xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family); | 853 | xfrm_init_tempstate(x, fl, tmpl, daddr, saddr, family); |
| 854 | memcpy(&x->mark, &pol->mark, sizeof(x->mark)); | ||
| 832 | 855 | ||
| 833 | error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid); | 856 | error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid); |
| 834 | if (error) { | 857 | if (error) { |
| @@ -842,10 +865,10 @@ found: | |||
| 842 | x->km.state = XFRM_STATE_ACQ; | 865 | x->km.state = XFRM_STATE_ACQ; |
| 843 | list_add(&x->km.all, &net->xfrm.state_all); | 866 | list_add(&x->km.all, &net->xfrm.state_all); |
| 844 | hlist_add_head(&x->bydst, net->xfrm.state_bydst+h); | 867 | hlist_add_head(&x->bydst, net->xfrm.state_bydst+h); |
| 845 | h = xfrm_src_hash(net, daddr, saddr, family); | 868 | h = xfrm_src_hash(net, daddr, saddr, encap_family); |
| 846 | hlist_add_head(&x->bysrc, net->xfrm.state_bysrc+h); | 869 | hlist_add_head(&x->bysrc, net->xfrm.state_bysrc+h); |
| 847 | if (x->id.spi) { | 870 | if (x->id.spi) { |
| 848 | h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, family); | 871 | h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, encap_family); |
| 849 | hlist_add_head(&x->byspi, net->xfrm.state_byspi+h); | 872 | hlist_add_head(&x->byspi, net->xfrm.state_byspi+h); |
| 850 | } | 873 | } |
| 851 | x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; | 874 | x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; |
| @@ -871,7 +894,7 @@ out: | |||
| 871 | } | 894 | } |
| 872 | 895 | ||
| 873 | struct xfrm_state * | 896 | struct xfrm_state * |
| 874 | xfrm_stateonly_find(struct net *net, | 897 | xfrm_stateonly_find(struct net *net, u32 mark, |
| 875 | xfrm_address_t *daddr, xfrm_address_t *saddr, | 898 | xfrm_address_t *daddr, xfrm_address_t *saddr, |
| 876 | unsigned short family, u8 mode, u8 proto, u32 reqid) | 899 | unsigned short family, u8 mode, u8 proto, u32 reqid) |
| 877 | { | 900 | { |
| @@ -884,6 +907,7 @@ xfrm_stateonly_find(struct net *net, | |||
| 884 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { | 907 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { |
| 885 | if (x->props.family == family && | 908 | if (x->props.family == family && |
| 886 | x->props.reqid == reqid && | 909 | x->props.reqid == reqid && |
| 910 | (mark & x->mark.m) == x->mark.v && | ||
| 887 | !(x->props.flags & XFRM_STATE_WILDRECV) && | 911 | !(x->props.flags & XFRM_STATE_WILDRECV) && |
| 888 | xfrm_state_addr_check(x, daddr, saddr, family) && | 912 | xfrm_state_addr_check(x, daddr, saddr, family) && |
| 889 | mode == x->props.mode && | 913 | mode == x->props.mode && |
| @@ -908,8 +932,6 @@ static void __xfrm_state_insert(struct xfrm_state *x) | |||
| 908 | struct net *net = xs_net(x); | 932 | struct net *net = xs_net(x); |
| 909 | unsigned int h; | 933 | unsigned int h; |
| 910 | 934 | ||
| 911 | x->genid = ++xfrm_state_genid; | ||
| 912 | |||
| 913 | list_add(&x->km.all, &net->xfrm.state_all); | 935 | list_add(&x->km.all, &net->xfrm.state_all); |
| 914 | 936 | ||
| 915 | h = xfrm_dst_hash(net, &x->id.daddr, &x->props.saddr, | 937 | h = xfrm_dst_hash(net, &x->id.daddr, &x->props.saddr, |
| @@ -946,14 +968,16 @@ static void __xfrm_state_bump_genids(struct xfrm_state *xnew) | |||
| 946 | struct xfrm_state *x; | 968 | struct xfrm_state *x; |
| 947 | struct hlist_node *entry; | 969 | struct hlist_node *entry; |
| 948 | unsigned int h; | 970 | unsigned int h; |
| 971 | u32 mark = xnew->mark.v & xnew->mark.m; | ||
| 949 | 972 | ||
| 950 | h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family); | 973 | h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family); |
| 951 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { | 974 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { |
| 952 | if (x->props.family == family && | 975 | if (x->props.family == family && |
| 953 | x->props.reqid == reqid && | 976 | x->props.reqid == reqid && |
| 977 | (mark & x->mark.m) == x->mark.v && | ||
| 954 | !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) && | 978 | !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) && |
| 955 | !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family)) | 979 | !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family)) |
| 956 | x->genid = xfrm_state_genid; | 980 | x->genid++; |
| 957 | } | 981 | } |
| 958 | } | 982 | } |
| 959 | 983 | ||
| @@ -967,11 +991,12 @@ void xfrm_state_insert(struct xfrm_state *x) | |||
| 967 | EXPORT_SYMBOL(xfrm_state_insert); | 991 | EXPORT_SYMBOL(xfrm_state_insert); |
| 968 | 992 | ||
| 969 | /* xfrm_state_lock is held */ | 993 | /* xfrm_state_lock is held */ |
| 970 | static struct xfrm_state *__find_acq_core(struct net *net, unsigned short family, u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create) | 994 | static struct xfrm_state *__find_acq_core(struct net *net, struct xfrm_mark *m, unsigned short family, u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create) |
| 971 | { | 995 | { |
| 972 | unsigned int h = xfrm_dst_hash(net, daddr, saddr, reqid, family); | 996 | unsigned int h = xfrm_dst_hash(net, daddr, saddr, reqid, family); |
| 973 | struct hlist_node *entry; | 997 | struct hlist_node *entry; |
| 974 | struct xfrm_state *x; | 998 | struct xfrm_state *x; |
| 999 | u32 mark = m->v & m->m; | ||
| 975 | 1000 | ||
| 976 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { | 1001 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { |
| 977 | if (x->props.reqid != reqid || | 1002 | if (x->props.reqid != reqid || |
| @@ -980,6 +1005,7 @@ static struct xfrm_state *__find_acq_core(struct net *net, unsigned short family | |||
| 980 | x->km.state != XFRM_STATE_ACQ || | 1005 | x->km.state != XFRM_STATE_ACQ || |
| 981 | x->id.spi != 0 || | 1006 | x->id.spi != 0 || |
| 982 | x->id.proto != proto || | 1007 | x->id.proto != proto || |
| 1008 | (mark & x->mark.m) != x->mark.v || | ||
| 983 | xfrm_addr_cmp(&x->id.daddr, daddr, family) || | 1009 | xfrm_addr_cmp(&x->id.daddr, daddr, family) || |
| 984 | xfrm_addr_cmp(&x->props.saddr, saddr, family)) | 1010 | xfrm_addr_cmp(&x->props.saddr, saddr, family)) |
| 985 | continue; | 1011 | continue; |
| @@ -1022,6 +1048,8 @@ static struct xfrm_state *__find_acq_core(struct net *net, unsigned short family | |||
| 1022 | x->props.family = family; | 1048 | x->props.family = family; |
| 1023 | x->props.mode = mode; | 1049 | x->props.mode = mode; |
| 1024 | x->props.reqid = reqid; | 1050 | x->props.reqid = reqid; |
| 1051 | x->mark.v = m->v; | ||
| 1052 | x->mark.m = m->m; | ||
| 1025 | x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; | 1053 | x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; |
| 1026 | xfrm_state_hold(x); | 1054 | xfrm_state_hold(x); |
| 1027 | tasklet_hrtimer_start(&x->mtimer, ktime_set(net->xfrm.sysctl_acq_expires, 0), HRTIMER_MODE_REL); | 1055 | tasklet_hrtimer_start(&x->mtimer, ktime_set(net->xfrm.sysctl_acq_expires, 0), HRTIMER_MODE_REL); |
| @@ -1038,7 +1066,7 @@ static struct xfrm_state *__find_acq_core(struct net *net, unsigned short family | |||
| 1038 | return x; | 1066 | return x; |
| 1039 | } | 1067 | } |
| 1040 | 1068 | ||
| 1041 | static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq); | 1069 | static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq); |
| 1042 | 1070 | ||
| 1043 | int xfrm_state_add(struct xfrm_state *x) | 1071 | int xfrm_state_add(struct xfrm_state *x) |
| 1044 | { | 1072 | { |
| @@ -1046,6 +1074,7 @@ int xfrm_state_add(struct xfrm_state *x) | |||
| 1046 | struct xfrm_state *x1, *to_put; | 1074 | struct xfrm_state *x1, *to_put; |
| 1047 | int family; | 1075 | int family; |
| 1048 | int err; | 1076 | int err; |
| 1077 | u32 mark = x->mark.v & x->mark.m; | ||
| 1049 | int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); | 1078 | int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); |
| 1050 | 1079 | ||
| 1051 | family = x->props.family; | 1080 | family = x->props.family; |
| @@ -1063,7 +1092,7 @@ int xfrm_state_add(struct xfrm_state *x) | |||
| 1063 | } | 1092 | } |
| 1064 | 1093 | ||
| 1065 | if (use_spi && x->km.seq) { | 1094 | if (use_spi && x->km.seq) { |
| 1066 | x1 = __xfrm_find_acq_byseq(net, x->km.seq); | 1095 | x1 = __xfrm_find_acq_byseq(net, mark, x->km.seq); |
| 1067 | if (x1 && ((x1->id.proto != x->id.proto) || | 1096 | if (x1 && ((x1->id.proto != x->id.proto) || |
| 1068 | xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) { | 1097 | xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) { |
| 1069 | to_put = x1; | 1098 | to_put = x1; |
| @@ -1072,8 +1101,8 @@ int xfrm_state_add(struct xfrm_state *x) | |||
| 1072 | } | 1101 | } |
| 1073 | 1102 | ||
| 1074 | if (use_spi && !x1) | 1103 | if (use_spi && !x1) |
| 1075 | x1 = __find_acq_core(net, family, x->props.mode, x->props.reqid, | 1104 | x1 = __find_acq_core(net, &x->mark, family, x->props.mode, |
| 1076 | x->id.proto, | 1105 | x->props.reqid, x->id.proto, |
| 1077 | &x->id.daddr, &x->props.saddr, 0); | 1106 | &x->id.daddr, &x->props.saddr, 0); |
| 1078 | 1107 | ||
| 1079 | __xfrm_state_bump_genids(x); | 1108 | __xfrm_state_bump_genids(x); |
| @@ -1102,7 +1131,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) | |||
| 1102 | int err = -ENOMEM; | 1131 | int err = -ENOMEM; |
| 1103 | struct xfrm_state *x = xfrm_state_alloc(net); | 1132 | struct xfrm_state *x = xfrm_state_alloc(net); |
| 1104 | if (!x) | 1133 | if (!x) |
| 1105 | goto error; | 1134 | goto out; |
| 1106 | 1135 | ||
| 1107 | memcpy(&x->id, &orig->id, sizeof(x->id)); | 1136 | memcpy(&x->id, &orig->id, sizeof(x->id)); |
| 1108 | memcpy(&x->sel, &orig->sel, sizeof(x->sel)); | 1137 | memcpy(&x->sel, &orig->sel, sizeof(x->sel)); |
| @@ -1147,6 +1176,8 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) | |||
| 1147 | goto error; | 1176 | goto error; |
| 1148 | } | 1177 | } |
| 1149 | 1178 | ||
| 1179 | memcpy(&x->mark, &orig->mark, sizeof(x->mark)); | ||
| 1180 | |||
| 1150 | err = xfrm_init_state(x); | 1181 | err = xfrm_init_state(x); |
| 1151 | if (err) | 1182 | if (err) |
| 1152 | goto error; | 1183 | goto error; |
| @@ -1160,16 +1191,10 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) | |||
| 1160 | return x; | 1191 | return x; |
| 1161 | 1192 | ||
| 1162 | error: | 1193 | error: |
| 1194 | xfrm_state_put(x); | ||
| 1195 | out: | ||
| 1163 | if (errp) | 1196 | if (errp) |
| 1164 | *errp = err; | 1197 | *errp = err; |
| 1165 | if (x) { | ||
| 1166 | kfree(x->aalg); | ||
| 1167 | kfree(x->ealg); | ||
| 1168 | kfree(x->calg); | ||
| 1169 | kfree(x->encap); | ||
| 1170 | kfree(x->coaddr); | ||
| 1171 | } | ||
| 1172 | kfree(x); | ||
| 1173 | return NULL; | 1198 | return NULL; |
| 1174 | } | 1199 | } |
| 1175 | 1200 | ||
| @@ -1344,41 +1369,41 @@ int xfrm_state_check_expire(struct xfrm_state *x) | |||
| 1344 | EXPORT_SYMBOL(xfrm_state_check_expire); | 1369 | EXPORT_SYMBOL(xfrm_state_check_expire); |
| 1345 | 1370 | ||
| 1346 | struct xfrm_state * | 1371 | struct xfrm_state * |
| 1347 | xfrm_state_lookup(struct net *net, xfrm_address_t *daddr, __be32 spi, u8 proto, | 1372 | xfrm_state_lookup(struct net *net, u32 mark, xfrm_address_t *daddr, __be32 spi, |
| 1348 | unsigned short family) | 1373 | u8 proto, unsigned short family) |
| 1349 | { | 1374 | { |
| 1350 | struct xfrm_state *x; | 1375 | struct xfrm_state *x; |
| 1351 | 1376 | ||
| 1352 | spin_lock_bh(&xfrm_state_lock); | 1377 | spin_lock_bh(&xfrm_state_lock); |
| 1353 | x = __xfrm_state_lookup(net, daddr, spi, proto, family); | 1378 | x = __xfrm_state_lookup(net, mark, daddr, spi, proto, family); |
| 1354 | spin_unlock_bh(&xfrm_state_lock); | 1379 | spin_unlock_bh(&xfrm_state_lock); |
| 1355 | return x; | 1380 | return x; |
| 1356 | } | 1381 | } |
| 1357 | EXPORT_SYMBOL(xfrm_state_lookup); | 1382 | EXPORT_SYMBOL(xfrm_state_lookup); |
| 1358 | 1383 | ||
| 1359 | struct xfrm_state * | 1384 | struct xfrm_state * |
| 1360 | xfrm_state_lookup_byaddr(struct net *net, | 1385 | xfrm_state_lookup_byaddr(struct net *net, u32 mark, |
| 1361 | xfrm_address_t *daddr, xfrm_address_t *saddr, | 1386 | xfrm_address_t *daddr, xfrm_address_t *saddr, |
| 1362 | u8 proto, unsigned short family) | 1387 | u8 proto, unsigned short family) |
| 1363 | { | 1388 | { |
| 1364 | struct xfrm_state *x; | 1389 | struct xfrm_state *x; |
| 1365 | 1390 | ||
| 1366 | spin_lock_bh(&xfrm_state_lock); | 1391 | spin_lock_bh(&xfrm_state_lock); |
| 1367 | x = __xfrm_state_lookup_byaddr(net, daddr, saddr, proto, family); | 1392 | x = __xfrm_state_lookup_byaddr(net, mark, daddr, saddr, proto, family); |
| 1368 | spin_unlock_bh(&xfrm_state_lock); | 1393 | spin_unlock_bh(&xfrm_state_lock); |
| 1369 | return x; | 1394 | return x; |
| 1370 | } | 1395 | } |
| 1371 | EXPORT_SYMBOL(xfrm_state_lookup_byaddr); | 1396 | EXPORT_SYMBOL(xfrm_state_lookup_byaddr); |
| 1372 | 1397 | ||
| 1373 | struct xfrm_state * | 1398 | struct xfrm_state * |
| 1374 | xfrm_find_acq(struct net *net, u8 mode, u32 reqid, u8 proto, | 1399 | xfrm_find_acq(struct net *net, struct xfrm_mark *mark, u8 mode, u32 reqid, u8 proto, |
| 1375 | xfrm_address_t *daddr, xfrm_address_t *saddr, | 1400 | xfrm_address_t *daddr, xfrm_address_t *saddr, |
| 1376 | int create, unsigned short family) | 1401 | int create, unsigned short family) |
| 1377 | { | 1402 | { |
| 1378 | struct xfrm_state *x; | 1403 | struct xfrm_state *x; |
| 1379 | 1404 | ||
| 1380 | spin_lock_bh(&xfrm_state_lock); | 1405 | spin_lock_bh(&xfrm_state_lock); |
| 1381 | x = __find_acq_core(net, family, mode, reqid, proto, daddr, saddr, create); | 1406 | x = __find_acq_core(net, mark, family, mode, reqid, proto, daddr, saddr, create); |
| 1382 | spin_unlock_bh(&xfrm_state_lock); | 1407 | spin_unlock_bh(&xfrm_state_lock); |
| 1383 | 1408 | ||
| 1384 | return x; | 1409 | return x; |
| @@ -1425,7 +1450,7 @@ EXPORT_SYMBOL(xfrm_state_sort); | |||
| 1425 | 1450 | ||
| 1426 | /* Silly enough, but I'm lazy to build resolution list */ | 1451 | /* Silly enough, but I'm lazy to build resolution list */ |
| 1427 | 1452 | ||
| 1428 | static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq) | 1453 | static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq) |
| 1429 | { | 1454 | { |
| 1430 | int i; | 1455 | int i; |
| 1431 | 1456 | ||
| @@ -1435,6 +1460,7 @@ static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq) | |||
| 1435 | 1460 | ||
| 1436 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+i, bydst) { | 1461 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+i, bydst) { |
| 1437 | if (x->km.seq == seq && | 1462 | if (x->km.seq == seq && |
| 1463 | (mark & x->mark.m) == x->mark.v && | ||
| 1438 | x->km.state == XFRM_STATE_ACQ) { | 1464 | x->km.state == XFRM_STATE_ACQ) { |
| 1439 | xfrm_state_hold(x); | 1465 | xfrm_state_hold(x); |
| 1440 | return x; | 1466 | return x; |
| @@ -1444,12 +1470,12 @@ static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq) | |||
| 1444 | return NULL; | 1470 | return NULL; |
| 1445 | } | 1471 | } |
| 1446 | 1472 | ||
| 1447 | struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 seq) | 1473 | struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq) |
| 1448 | { | 1474 | { |
| 1449 | struct xfrm_state *x; | 1475 | struct xfrm_state *x; |
| 1450 | 1476 | ||
| 1451 | spin_lock_bh(&xfrm_state_lock); | 1477 | spin_lock_bh(&xfrm_state_lock); |
| 1452 | x = __xfrm_find_acq_byseq(net, seq); | 1478 | x = __xfrm_find_acq_byseq(net, mark, seq); |
| 1453 | spin_unlock_bh(&xfrm_state_lock); | 1479 | spin_unlock_bh(&xfrm_state_lock); |
| 1454 | return x; | 1480 | return x; |
| 1455 | } | 1481 | } |
| @@ -1458,12 +1484,12 @@ EXPORT_SYMBOL(xfrm_find_acq_byseq); | |||
| 1458 | u32 xfrm_get_acqseq(void) | 1484 | u32 xfrm_get_acqseq(void) |
| 1459 | { | 1485 | { |
| 1460 | u32 res; | 1486 | u32 res; |
| 1461 | static u32 acqseq; | 1487 | static atomic_t acqseq; |
| 1462 | static DEFINE_SPINLOCK(acqseq_lock); | 1488 | |
| 1489 | do { | ||
| 1490 | res = atomic_inc_return(&acqseq); | ||
| 1491 | } while (!res); | ||
| 1463 | 1492 | ||
| 1464 | spin_lock_bh(&acqseq_lock); | ||
| 1465 | res = (++acqseq ? : ++acqseq); | ||
| 1466 | spin_unlock_bh(&acqseq_lock); | ||
| 1467 | return res; | 1493 | return res; |
| 1468 | } | 1494 | } |
| 1469 | EXPORT_SYMBOL(xfrm_get_acqseq); | 1495 | EXPORT_SYMBOL(xfrm_get_acqseq); |
| @@ -1476,6 +1502,7 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) | |||
| 1476 | int err = -ENOENT; | 1502 | int err = -ENOENT; |
| 1477 | __be32 minspi = htonl(low); | 1503 | __be32 minspi = htonl(low); |
| 1478 | __be32 maxspi = htonl(high); | 1504 | __be32 maxspi = htonl(high); |
| 1505 | u32 mark = x->mark.v & x->mark.m; | ||
| 1479 | 1506 | ||
| 1480 | spin_lock_bh(&x->lock); | 1507 | spin_lock_bh(&x->lock); |
| 1481 | if (x->km.state == XFRM_STATE_DEAD) | 1508 | if (x->km.state == XFRM_STATE_DEAD) |
| @@ -1488,7 +1515,7 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) | |||
| 1488 | err = -ENOENT; | 1515 | err = -ENOENT; |
| 1489 | 1516 | ||
| 1490 | if (minspi == maxspi) { | 1517 | if (minspi == maxspi) { |
| 1491 | x0 = xfrm_state_lookup(net, &x->id.daddr, minspi, x->id.proto, x->props.family); | 1518 | x0 = xfrm_state_lookup(net, mark, &x->id.daddr, minspi, x->id.proto, x->props.family); |
| 1492 | if (x0) { | 1519 | if (x0) { |
| 1493 | xfrm_state_put(x0); | 1520 | xfrm_state_put(x0); |
| 1494 | goto unlock; | 1521 | goto unlock; |
| @@ -1498,7 +1525,7 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) | |||
| 1498 | u32 spi = 0; | 1525 | u32 spi = 0; |
| 1499 | for (h=0; h<high-low+1; h++) { | 1526 | for (h=0; h<high-low+1; h++) { |
| 1500 | spi = low + net_random()%(high-low+1); | 1527 | spi = low + net_random()%(high-low+1); |
| 1501 | x0 = xfrm_state_lookup(net, &x->id.daddr, htonl(spi), x->id.proto, x->props.family); | 1528 | x0 = xfrm_state_lookup(net, mark, &x->id.daddr, htonl(spi), x->id.proto, x->props.family); |
| 1502 | if (x0 == NULL) { | 1529 | if (x0 == NULL) { |
| 1503 | x->id.spi = htonl(spi); | 1530 | x->id.spi = htonl(spi); |
| 1504 | break; | 1531 | break; |
