diff options
Diffstat (limited to 'net/xfrm/xfrm_state.c')
| -rw-r--r-- | net/xfrm/xfrm_state.c | 139 |
1 files changed, 82 insertions, 57 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index f2f7c638083e..add77ecb8ac4 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
| @@ -21,6 +21,10 @@ | |||
| 21 | #include <linux/cache.h> | 21 | #include <linux/cache.h> |
| 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> | ||
| 25 | #include <linux/slab.h> | ||
| 26 | #include <linux/interrupt.h> | ||
| 27 | #include <linux/kernel.h> | ||
| 24 | 28 | ||
| 25 | #include "xfrm_hash.h" | 29 | #include "xfrm_hash.h" |
| 26 | 30 | ||
| @@ -352,7 +356,7 @@ static void xfrm_put_mode(struct xfrm_mode *mode) | |||
| 352 | 356 | ||
| 353 | static void xfrm_state_gc_destroy(struct xfrm_state *x) | 357 | static void xfrm_state_gc_destroy(struct xfrm_state *x) |
| 354 | { | 358 | { |
| 355 | del_timer_sync(&x->timer); | 359 | tasklet_hrtimer_cancel(&x->mtimer); |
| 356 | del_timer_sync(&x->rtimer); | 360 | del_timer_sync(&x->rtimer); |
| 357 | kfree(x->aalg); | 361 | kfree(x->aalg); |
| 358 | kfree(x->ealg); | 362 | kfree(x->ealg); |
| @@ -398,9 +402,10 @@ static inline unsigned long make_jiffies(long secs) | |||
| 398 | return secs*HZ; | 402 | return secs*HZ; |
| 399 | } | 403 | } |
| 400 | 404 | ||
| 401 | static void xfrm_timer_handler(unsigned long data) | 405 | static enum hrtimer_restart xfrm_timer_handler(struct hrtimer * me) |
| 402 | { | 406 | { |
| 403 | struct xfrm_state *x = (struct xfrm_state*)data; | 407 | struct tasklet_hrtimer *thr = container_of(me, struct tasklet_hrtimer, timer); |
| 408 | struct xfrm_state *x = container_of(thr, struct xfrm_state, mtimer); | ||
| 404 | struct net *net = xs_net(x); | 409 | struct net *net = xs_net(x); |
| 405 | unsigned long now = get_seconds(); | 410 | unsigned long now = get_seconds(); |
| 406 | long next = LONG_MAX; | 411 | long next = LONG_MAX; |
| @@ -451,8 +456,9 @@ static void xfrm_timer_handler(unsigned long data) | |||
| 451 | if (warn) | 456 | if (warn) |
| 452 | km_state_expired(x, 0, 0); | 457 | km_state_expired(x, 0, 0); |
| 453 | resched: | 458 | resched: |
| 454 | if (next != LONG_MAX) | 459 | if (next != LONG_MAX){ |
| 455 | mod_timer(&x->timer, jiffies + make_jiffies(next)); | 460 | tasklet_hrtimer_start(&x->mtimer, ktime_set(next, 0), HRTIMER_MODE_REL); |
| 461 | } | ||
| 456 | 462 | ||
| 457 | goto out; | 463 | goto out; |
| 458 | 464 | ||
| @@ -474,6 +480,7 @@ expired: | |||
| 474 | 480 | ||
| 475 | out: | 481 | out: |
| 476 | spin_unlock(&x->lock); | 482 | spin_unlock(&x->lock); |
| 483 | return HRTIMER_NORESTART; | ||
| 477 | } | 484 | } |
| 478 | 485 | ||
| 479 | static void xfrm_replay_timer_handler(unsigned long data); | 486 | static void xfrm_replay_timer_handler(unsigned long data); |
| @@ -492,7 +499,7 @@ struct xfrm_state *xfrm_state_alloc(struct net *net) | |||
| 492 | INIT_HLIST_NODE(&x->bydst); | 499 | INIT_HLIST_NODE(&x->bydst); |
| 493 | INIT_HLIST_NODE(&x->bysrc); | 500 | INIT_HLIST_NODE(&x->bysrc); |
| 494 | INIT_HLIST_NODE(&x->byspi); | 501 | INIT_HLIST_NODE(&x->byspi); |
| 495 | setup_timer(&x->timer, xfrm_timer_handler, (unsigned long)x); | 502 | tasklet_hrtimer_init(&x->mtimer, xfrm_timer_handler, CLOCK_REALTIME, HRTIMER_MODE_ABS); |
| 496 | setup_timer(&x->rtimer, xfrm_replay_timer_handler, | 503 | setup_timer(&x->rtimer, xfrm_replay_timer_handler, |
| 497 | (unsigned long)x); | 504 | (unsigned long)x); |
| 498 | x->curlft.add_time = get_seconds(); | 505 | x->curlft.add_time = get_seconds(); |
| @@ -597,13 +604,14 @@ xfrm_state_flush_secctx_check(struct net *net, u8 proto, struct xfrm_audit *audi | |||
| 597 | 604 | ||
| 598 | int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info) | 605 | int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info) |
| 599 | { | 606 | { |
| 600 | int i, err = 0; | 607 | int i, err = 0, cnt = 0; |
| 601 | 608 | ||
| 602 | spin_lock_bh(&xfrm_state_lock); | 609 | spin_lock_bh(&xfrm_state_lock); |
| 603 | err = xfrm_state_flush_secctx_check(net, proto, audit_info); | 610 | err = xfrm_state_flush_secctx_check(net, proto, audit_info); |
| 604 | if (err) | 611 | if (err) |
| 605 | goto out; | 612 | goto out; |
| 606 | 613 | ||
| 614 | err = -ESRCH; | ||
| 607 | for (i = 0; i <= net->xfrm.state_hmask; i++) { | 615 | for (i = 0; i <= net->xfrm.state_hmask; i++) { |
| 608 | struct hlist_node *entry; | 616 | struct hlist_node *entry; |
| 609 | struct xfrm_state *x; | 617 | struct xfrm_state *x; |
| @@ -620,13 +628,16 @@ restart: | |||
| 620 | audit_info->sessionid, | 628 | audit_info->sessionid, |
| 621 | audit_info->secid); | 629 | audit_info->secid); |
| 622 | xfrm_state_put(x); | 630 | xfrm_state_put(x); |
| 631 | if (!err) | ||
| 632 | cnt++; | ||
| 623 | 633 | ||
| 624 | spin_lock_bh(&xfrm_state_lock); | 634 | spin_lock_bh(&xfrm_state_lock); |
| 625 | goto restart; | 635 | goto restart; |
| 626 | } | 636 | } |
| 627 | } | 637 | } |
| 628 | } | 638 | } |
| 629 | err = 0; | 639 | if (cnt) |
| 640 | err = 0; | ||
| 630 | 641 | ||
| 631 | out: | 642 | out: |
| 632 | spin_unlock_bh(&xfrm_state_lock); | 643 | spin_unlock_bh(&xfrm_state_lock); |
| @@ -635,11 +646,11 @@ out: | |||
| 635 | } | 646 | } |
| 636 | EXPORT_SYMBOL(xfrm_state_flush); | 647 | EXPORT_SYMBOL(xfrm_state_flush); |
| 637 | 648 | ||
| 638 | void xfrm_sad_getinfo(struct xfrmk_sadinfo *si) | 649 | void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si) |
| 639 | { | 650 | { |
| 640 | spin_lock_bh(&xfrm_state_lock); | 651 | spin_lock_bh(&xfrm_state_lock); |
| 641 | si->sadcnt = init_net.xfrm.state_num; | 652 | si->sadcnt = net->xfrm.state_num; |
| 642 | si->sadhcnt = init_net.xfrm.state_hmask; | 653 | si->sadhcnt = net->xfrm.state_hmask; |
| 643 | si->sadhmcnt = xfrm_state_hashmax; | 654 | si->sadhmcnt = xfrm_state_hashmax; |
| 644 | spin_unlock_bh(&xfrm_state_lock); | 655 | spin_unlock_bh(&xfrm_state_lock); |
| 645 | } | 656 | } |
| @@ -659,7 +670,7 @@ xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl, | |||
| 659 | return 0; | 670 | return 0; |
| 660 | } | 671 | } |
| 661 | 672 | ||
| 662 | static struct xfrm_state *__xfrm_state_lookup(struct net *net, xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family) | 673 | static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark, xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family) |
| 663 | { | 674 | { |
| 664 | unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family); | 675 | unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family); |
| 665 | struct xfrm_state *x; | 676 | struct xfrm_state *x; |
| @@ -672,6 +683,8 @@ static struct xfrm_state *__xfrm_state_lookup(struct net *net, xfrm_address_t *d | |||
| 672 | xfrm_addr_cmp(&x->id.daddr, daddr, family)) | 683 | xfrm_addr_cmp(&x->id.daddr, daddr, family)) |
| 673 | continue; | 684 | continue; |
| 674 | 685 | ||
| 686 | if ((mark & x->mark.m) != x->mark.v) | ||
| 687 | continue; | ||
| 675 | xfrm_state_hold(x); | 688 | xfrm_state_hold(x); |
| 676 | return x; | 689 | return x; |
| 677 | } | 690 | } |
| @@ -679,7 +692,7 @@ static struct xfrm_state *__xfrm_state_lookup(struct net *net, xfrm_address_t *d | |||
| 679 | return NULL; | 692 | return NULL; |
| 680 | } | 693 | } |
| 681 | 694 | ||
| 682 | static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family) | 695 | 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) |
| 683 | { | 696 | { |
| 684 | unsigned int h = xfrm_src_hash(net, daddr, saddr, family); | 697 | unsigned int h = xfrm_src_hash(net, daddr, saddr, family); |
| 685 | struct xfrm_state *x; | 698 | struct xfrm_state *x; |
| @@ -692,6 +705,8 @@ static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, xfrm_addre | |||
| 692 | xfrm_addr_cmp(&x->props.saddr, saddr, family)) | 705 | xfrm_addr_cmp(&x->props.saddr, saddr, family)) |
| 693 | continue; | 706 | continue; |
| 694 | 707 | ||
| 708 | if ((mark & x->mark.m) != x->mark.v) | ||
| 709 | continue; | ||
| 695 | xfrm_state_hold(x); | 710 | xfrm_state_hold(x); |
| 696 | return x; | 711 | return x; |
| 697 | } | 712 | } |
| @@ -703,12 +718,14 @@ static inline struct xfrm_state * | |||
| 703 | __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family) | 718 | __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family) |
| 704 | { | 719 | { |
| 705 | struct net *net = xs_net(x); | 720 | struct net *net = xs_net(x); |
| 721 | u32 mark = x->mark.v & x->mark.m; | ||
| 706 | 722 | ||
| 707 | if (use_spi) | 723 | if (use_spi) |
| 708 | return __xfrm_state_lookup(net, &x->id.daddr, x->id.spi, | 724 | return __xfrm_state_lookup(net, mark, &x->id.daddr, |
| 709 | x->id.proto, family); | 725 | x->id.spi, x->id.proto, family); |
| 710 | else | 726 | else |
| 711 | return __xfrm_state_lookup_byaddr(net, &x->id.daddr, | 727 | return __xfrm_state_lookup_byaddr(net, mark, |
| 728 | &x->id.daddr, | ||
| 712 | &x->props.saddr, | 729 | &x->props.saddr, |
| 713 | x->id.proto, family); | 730 | x->id.proto, family); |
| 714 | } | 731 | } |
| @@ -773,6 +790,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
| 773 | int acquire_in_progress = 0; | 790 | int acquire_in_progress = 0; |
| 774 | int error = 0; | 791 | int error = 0; |
| 775 | struct xfrm_state *best = NULL; | 792 | struct xfrm_state *best = NULL; |
| 793 | u32 mark = pol->mark.v & pol->mark.m; | ||
| 776 | 794 | ||
| 777 | to_put = NULL; | 795 | to_put = NULL; |
| 778 | 796 | ||
| @@ -781,6 +799,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
| 781 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { | 799 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { |
| 782 | if (x->props.family == family && | 800 | if (x->props.family == family && |
| 783 | x->props.reqid == tmpl->reqid && | 801 | x->props.reqid == tmpl->reqid && |
| 802 | (mark & x->mark.m) == x->mark.v && | ||
| 784 | !(x->props.flags & XFRM_STATE_WILDRECV) && | 803 | !(x->props.flags & XFRM_STATE_WILDRECV) && |
| 785 | xfrm_state_addr_check(x, daddr, saddr, family) && | 804 | xfrm_state_addr_check(x, daddr, saddr, family) && |
| 786 | tmpl->mode == x->props.mode && | 805 | tmpl->mode == x->props.mode && |
| @@ -796,6 +815,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
| 796 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h_wildcard, bydst) { | 815 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h_wildcard, bydst) { |
| 797 | if (x->props.family == family && | 816 | if (x->props.family == family && |
| 798 | x->props.reqid == tmpl->reqid && | 817 | x->props.reqid == tmpl->reqid && |
| 818 | (mark & x->mark.m) == x->mark.v && | ||
| 799 | !(x->props.flags & XFRM_STATE_WILDRECV) && | 819 | !(x->props.flags & XFRM_STATE_WILDRECV) && |
| 800 | xfrm_state_addr_check(x, daddr, saddr, family) && | 820 | xfrm_state_addr_check(x, daddr, saddr, family) && |
| 801 | tmpl->mode == x->props.mode && | 821 | tmpl->mode == x->props.mode && |
| @@ -809,7 +829,7 @@ found: | |||
| 809 | x = best; | 829 | x = best; |
| 810 | if (!x && !error && !acquire_in_progress) { | 830 | if (!x && !error && !acquire_in_progress) { |
| 811 | if (tmpl->id.spi && | 831 | if (tmpl->id.spi && |
| 812 | (x0 = __xfrm_state_lookup(net, daddr, tmpl->id.spi, | 832 | (x0 = __xfrm_state_lookup(net, mark, daddr, tmpl->id.spi, |
| 813 | tmpl->id.proto, family)) != NULL) { | 833 | tmpl->id.proto, family)) != NULL) { |
| 814 | to_put = x0; | 834 | to_put = x0; |
| 815 | error = -EEXIST; | 835 | error = -EEXIST; |
| @@ -823,6 +843,7 @@ found: | |||
| 823 | /* Initialize temporary selector matching only | 843 | /* Initialize temporary selector matching only |
| 824 | * to current session. */ | 844 | * to current session. */ |
| 825 | xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family); | 845 | xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family); |
| 846 | memcpy(&x->mark, &pol->mark, sizeof(x->mark)); | ||
| 826 | 847 | ||
| 827 | error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid); | 848 | error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid); |
| 828 | if (error) { | 849 | if (error) { |
| @@ -843,8 +864,7 @@ found: | |||
| 843 | hlist_add_head(&x->byspi, net->xfrm.state_byspi+h); | 864 | hlist_add_head(&x->byspi, net->xfrm.state_byspi+h); |
| 844 | } | 865 | } |
| 845 | x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; | 866 | x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; |
| 846 | x->timer.expires = jiffies + net->xfrm.sysctl_acq_expires*HZ; | 867 | tasklet_hrtimer_start(&x->mtimer, ktime_set(net->xfrm.sysctl_acq_expires, 0), HRTIMER_MODE_REL); |
| 847 | add_timer(&x->timer); | ||
| 848 | net->xfrm.state_num++; | 868 | net->xfrm.state_num++; |
| 849 | xfrm_hash_grow_check(net, x->bydst.next != NULL); | 869 | xfrm_hash_grow_check(net, x->bydst.next != NULL); |
| 850 | } else { | 870 | } else { |
| @@ -866,7 +886,7 @@ out: | |||
| 866 | } | 886 | } |
| 867 | 887 | ||
| 868 | struct xfrm_state * | 888 | struct xfrm_state * |
| 869 | xfrm_stateonly_find(struct net *net, | 889 | xfrm_stateonly_find(struct net *net, u32 mark, |
| 870 | xfrm_address_t *daddr, xfrm_address_t *saddr, | 890 | xfrm_address_t *daddr, xfrm_address_t *saddr, |
| 871 | unsigned short family, u8 mode, u8 proto, u32 reqid) | 891 | unsigned short family, u8 mode, u8 proto, u32 reqid) |
| 872 | { | 892 | { |
| @@ -879,6 +899,7 @@ xfrm_stateonly_find(struct net *net, | |||
| 879 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { | 899 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { |
| 880 | if (x->props.family == family && | 900 | if (x->props.family == family && |
| 881 | x->props.reqid == reqid && | 901 | x->props.reqid == reqid && |
| 902 | (mark & x->mark.m) == x->mark.v && | ||
| 882 | !(x->props.flags & XFRM_STATE_WILDRECV) && | 903 | !(x->props.flags & XFRM_STATE_WILDRECV) && |
| 883 | xfrm_state_addr_check(x, daddr, saddr, family) && | 904 | xfrm_state_addr_check(x, daddr, saddr, family) && |
| 884 | mode == x->props.mode && | 905 | mode == x->props.mode && |
| @@ -921,7 +942,7 @@ static void __xfrm_state_insert(struct xfrm_state *x) | |||
| 921 | hlist_add_head(&x->byspi, net->xfrm.state_byspi+h); | 942 | hlist_add_head(&x->byspi, net->xfrm.state_byspi+h); |
| 922 | } | 943 | } |
| 923 | 944 | ||
| 924 | mod_timer(&x->timer, jiffies + HZ); | 945 | tasklet_hrtimer_start(&x->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL); |
| 925 | if (x->replay_maxage) | 946 | if (x->replay_maxage) |
| 926 | mod_timer(&x->rtimer, jiffies + x->replay_maxage); | 947 | mod_timer(&x->rtimer, jiffies + x->replay_maxage); |
| 927 | 948 | ||
| @@ -941,11 +962,13 @@ static void __xfrm_state_bump_genids(struct xfrm_state *xnew) | |||
| 941 | struct xfrm_state *x; | 962 | struct xfrm_state *x; |
| 942 | struct hlist_node *entry; | 963 | struct hlist_node *entry; |
| 943 | unsigned int h; | 964 | unsigned int h; |
| 965 | u32 mark = xnew->mark.v & xnew->mark.m; | ||
| 944 | 966 | ||
| 945 | h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family); | 967 | h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family); |
| 946 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { | 968 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { |
| 947 | if (x->props.family == family && | 969 | if (x->props.family == family && |
| 948 | x->props.reqid == reqid && | 970 | x->props.reqid == reqid && |
| 971 | (mark & x->mark.m) == x->mark.v && | ||
| 949 | !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) && | 972 | !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) && |
| 950 | !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family)) | 973 | !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family)) |
| 951 | x->genid = xfrm_state_genid; | 974 | x->genid = xfrm_state_genid; |
| @@ -962,11 +985,12 @@ void xfrm_state_insert(struct xfrm_state *x) | |||
| 962 | EXPORT_SYMBOL(xfrm_state_insert); | 985 | EXPORT_SYMBOL(xfrm_state_insert); |
| 963 | 986 | ||
| 964 | /* xfrm_state_lock is held */ | 987 | /* xfrm_state_lock is held */ |
| 965 | 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) | 988 | 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) |
| 966 | { | 989 | { |
| 967 | unsigned int h = xfrm_dst_hash(net, daddr, saddr, reqid, family); | 990 | unsigned int h = xfrm_dst_hash(net, daddr, saddr, reqid, family); |
| 968 | struct hlist_node *entry; | 991 | struct hlist_node *entry; |
| 969 | struct xfrm_state *x; | 992 | struct xfrm_state *x; |
| 993 | u32 mark = m->v & m->m; | ||
| 970 | 994 | ||
| 971 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { | 995 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { |
| 972 | if (x->props.reqid != reqid || | 996 | if (x->props.reqid != reqid || |
| @@ -975,6 +999,7 @@ static struct xfrm_state *__find_acq_core(struct net *net, unsigned short family | |||
| 975 | x->km.state != XFRM_STATE_ACQ || | 999 | x->km.state != XFRM_STATE_ACQ || |
| 976 | x->id.spi != 0 || | 1000 | x->id.spi != 0 || |
| 977 | x->id.proto != proto || | 1001 | x->id.proto != proto || |
| 1002 | (mark & x->mark.m) != x->mark.v || | ||
| 978 | xfrm_addr_cmp(&x->id.daddr, daddr, family) || | 1003 | xfrm_addr_cmp(&x->id.daddr, daddr, family) || |
| 979 | xfrm_addr_cmp(&x->props.saddr, saddr, family)) | 1004 | xfrm_addr_cmp(&x->props.saddr, saddr, family)) |
| 980 | continue; | 1005 | continue; |
| @@ -1017,10 +1042,11 @@ static struct xfrm_state *__find_acq_core(struct net *net, unsigned short family | |||
| 1017 | x->props.family = family; | 1042 | x->props.family = family; |
| 1018 | x->props.mode = mode; | 1043 | x->props.mode = mode; |
| 1019 | x->props.reqid = reqid; | 1044 | x->props.reqid = reqid; |
| 1045 | x->mark.v = m->v; | ||
| 1046 | x->mark.m = m->m; | ||
| 1020 | x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; | 1047 | x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; |
| 1021 | xfrm_state_hold(x); | 1048 | xfrm_state_hold(x); |
| 1022 | x->timer.expires = jiffies + net->xfrm.sysctl_acq_expires*HZ; | 1049 | tasklet_hrtimer_start(&x->mtimer, ktime_set(net->xfrm.sysctl_acq_expires, 0), HRTIMER_MODE_REL); |
| 1023 | add_timer(&x->timer); | ||
| 1024 | list_add(&x->km.all, &net->xfrm.state_all); | 1050 | list_add(&x->km.all, &net->xfrm.state_all); |
| 1025 | hlist_add_head(&x->bydst, net->xfrm.state_bydst+h); | 1051 | hlist_add_head(&x->bydst, net->xfrm.state_bydst+h); |
| 1026 | h = xfrm_src_hash(net, daddr, saddr, family); | 1052 | h = xfrm_src_hash(net, daddr, saddr, family); |
| @@ -1034,7 +1060,7 @@ static struct xfrm_state *__find_acq_core(struct net *net, unsigned short family | |||
| 1034 | return x; | 1060 | return x; |
| 1035 | } | 1061 | } |
| 1036 | 1062 | ||
| 1037 | static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq); | 1063 | static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq); |
| 1038 | 1064 | ||
| 1039 | int xfrm_state_add(struct xfrm_state *x) | 1065 | int xfrm_state_add(struct xfrm_state *x) |
| 1040 | { | 1066 | { |
| @@ -1042,6 +1068,7 @@ int xfrm_state_add(struct xfrm_state *x) | |||
| 1042 | struct xfrm_state *x1, *to_put; | 1068 | struct xfrm_state *x1, *to_put; |
| 1043 | int family; | 1069 | int family; |
| 1044 | int err; | 1070 | int err; |
| 1071 | u32 mark = x->mark.v & x->mark.m; | ||
| 1045 | int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); | 1072 | int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); |
| 1046 | 1073 | ||
| 1047 | family = x->props.family; | 1074 | family = x->props.family; |
| @@ -1059,7 +1086,7 @@ int xfrm_state_add(struct xfrm_state *x) | |||
| 1059 | } | 1086 | } |
| 1060 | 1087 | ||
| 1061 | if (use_spi && x->km.seq) { | 1088 | if (use_spi && x->km.seq) { |
| 1062 | x1 = __xfrm_find_acq_byseq(net, x->km.seq); | 1089 | x1 = __xfrm_find_acq_byseq(net, mark, x->km.seq); |
| 1063 | if (x1 && ((x1->id.proto != x->id.proto) || | 1090 | if (x1 && ((x1->id.proto != x->id.proto) || |
| 1064 | xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) { | 1091 | xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) { |
| 1065 | to_put = x1; | 1092 | to_put = x1; |
| @@ -1068,8 +1095,8 @@ int xfrm_state_add(struct xfrm_state *x) | |||
| 1068 | } | 1095 | } |
| 1069 | 1096 | ||
| 1070 | if (use_spi && !x1) | 1097 | if (use_spi && !x1) |
| 1071 | x1 = __find_acq_core(net, family, x->props.mode, x->props.reqid, | 1098 | x1 = __find_acq_core(net, &x->mark, family, x->props.mode, |
| 1072 | x->id.proto, | 1099 | x->props.reqid, x->id.proto, |
| 1073 | &x->id.daddr, &x->props.saddr, 0); | 1100 | &x->id.daddr, &x->props.saddr, 0); |
| 1074 | 1101 | ||
| 1075 | __xfrm_state_bump_genids(x); | 1102 | __xfrm_state_bump_genids(x); |
| @@ -1098,7 +1125,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) | |||
| 1098 | int err = -ENOMEM; | 1125 | int err = -ENOMEM; |
| 1099 | struct xfrm_state *x = xfrm_state_alloc(net); | 1126 | struct xfrm_state *x = xfrm_state_alloc(net); |
| 1100 | if (!x) | 1127 | if (!x) |
| 1101 | goto error; | 1128 | goto out; |
| 1102 | 1129 | ||
| 1103 | memcpy(&x->id, &orig->id, sizeof(x->id)); | 1130 | memcpy(&x->id, &orig->id, sizeof(x->id)); |
| 1104 | memcpy(&x->sel, &orig->sel, sizeof(x->sel)); | 1131 | memcpy(&x->sel, &orig->sel, sizeof(x->sel)); |
| @@ -1110,7 +1137,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) | |||
| 1110 | x->props.saddr = orig->props.saddr; | 1137 | x->props.saddr = orig->props.saddr; |
| 1111 | 1138 | ||
| 1112 | if (orig->aalg) { | 1139 | if (orig->aalg) { |
| 1113 | x->aalg = xfrm_algo_clone(orig->aalg); | 1140 | x->aalg = xfrm_algo_auth_clone(orig->aalg); |
| 1114 | if (!x->aalg) | 1141 | if (!x->aalg) |
| 1115 | goto error; | 1142 | goto error; |
| 1116 | } | 1143 | } |
| @@ -1143,6 +1170,8 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) | |||
| 1143 | goto error; | 1170 | goto error; |
| 1144 | } | 1171 | } |
| 1145 | 1172 | ||
| 1173 | memcpy(&x->mark, &orig->mark, sizeof(x->mark)); | ||
| 1174 | |||
| 1146 | err = xfrm_init_state(x); | 1175 | err = xfrm_init_state(x); |
| 1147 | if (err) | 1176 | if (err) |
| 1148 | goto error; | 1177 | goto error; |
| @@ -1156,16 +1185,10 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) | |||
| 1156 | return x; | 1185 | return x; |
| 1157 | 1186 | ||
| 1158 | error: | 1187 | error: |
| 1188 | xfrm_state_put(x); | ||
| 1189 | out: | ||
| 1159 | if (errp) | 1190 | if (errp) |
| 1160 | *errp = err; | 1191 | *errp = err; |
| 1161 | if (x) { | ||
| 1162 | kfree(x->aalg); | ||
| 1163 | kfree(x->ealg); | ||
| 1164 | kfree(x->calg); | ||
| 1165 | kfree(x->encap); | ||
| 1166 | kfree(x->coaddr); | ||
| 1167 | } | ||
| 1168 | kfree(x); | ||
| 1169 | return NULL; | 1192 | return NULL; |
| 1170 | } | 1193 | } |
| 1171 | 1194 | ||
| @@ -1300,7 +1323,7 @@ out: | |||
| 1300 | memcpy(&x1->lft, &x->lft, sizeof(x1->lft)); | 1323 | memcpy(&x1->lft, &x->lft, sizeof(x1->lft)); |
| 1301 | x1->km.dying = 0; | 1324 | x1->km.dying = 0; |
| 1302 | 1325 | ||
| 1303 | mod_timer(&x1->timer, jiffies + HZ); | 1326 | tasklet_hrtimer_start(&x1->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL); |
| 1304 | if (x1->curlft.use_time) | 1327 | if (x1->curlft.use_time) |
| 1305 | xfrm_state_check_expire(x1); | 1328 | xfrm_state_check_expire(x1); |
| 1306 | 1329 | ||
| @@ -1325,7 +1348,7 @@ int xfrm_state_check_expire(struct xfrm_state *x) | |||
| 1325 | if (x->curlft.bytes >= x->lft.hard_byte_limit || | 1348 | if (x->curlft.bytes >= x->lft.hard_byte_limit || |
| 1326 | x->curlft.packets >= x->lft.hard_packet_limit) { | 1349 | x->curlft.packets >= x->lft.hard_packet_limit) { |
| 1327 | x->km.state = XFRM_STATE_EXPIRED; | 1350 | x->km.state = XFRM_STATE_EXPIRED; |
| 1328 | mod_timer(&x->timer, jiffies); | 1351 | tasklet_hrtimer_start(&x->mtimer, ktime_set(0,0), HRTIMER_MODE_REL); |
| 1329 | return -EINVAL; | 1352 | return -EINVAL; |
| 1330 | } | 1353 | } |
| 1331 | 1354 | ||
| @@ -1340,41 +1363,41 @@ int xfrm_state_check_expire(struct xfrm_state *x) | |||
| 1340 | EXPORT_SYMBOL(xfrm_state_check_expire); | 1363 | EXPORT_SYMBOL(xfrm_state_check_expire); |
| 1341 | 1364 | ||
| 1342 | struct xfrm_state * | 1365 | struct xfrm_state * |
| 1343 | xfrm_state_lookup(struct net *net, xfrm_address_t *daddr, __be32 spi, u8 proto, | 1366 | xfrm_state_lookup(struct net *net, u32 mark, xfrm_address_t *daddr, __be32 spi, |
| 1344 | unsigned short family) | 1367 | u8 proto, unsigned short family) |
| 1345 | { | 1368 | { |
| 1346 | struct xfrm_state *x; | 1369 | struct xfrm_state *x; |
| 1347 | 1370 | ||
| 1348 | spin_lock_bh(&xfrm_state_lock); | 1371 | spin_lock_bh(&xfrm_state_lock); |
| 1349 | x = __xfrm_state_lookup(net, daddr, spi, proto, family); | 1372 | x = __xfrm_state_lookup(net, mark, daddr, spi, proto, family); |
| 1350 | spin_unlock_bh(&xfrm_state_lock); | 1373 | spin_unlock_bh(&xfrm_state_lock); |
| 1351 | return x; | 1374 | return x; |
| 1352 | } | 1375 | } |
| 1353 | EXPORT_SYMBOL(xfrm_state_lookup); | 1376 | EXPORT_SYMBOL(xfrm_state_lookup); |
| 1354 | 1377 | ||
| 1355 | struct xfrm_state * | 1378 | struct xfrm_state * |
| 1356 | xfrm_state_lookup_byaddr(struct net *net, | 1379 | xfrm_state_lookup_byaddr(struct net *net, u32 mark, |
| 1357 | xfrm_address_t *daddr, xfrm_address_t *saddr, | 1380 | xfrm_address_t *daddr, xfrm_address_t *saddr, |
| 1358 | u8 proto, unsigned short family) | 1381 | u8 proto, unsigned short family) |
| 1359 | { | 1382 | { |
| 1360 | struct xfrm_state *x; | 1383 | struct xfrm_state *x; |
| 1361 | 1384 | ||
| 1362 | spin_lock_bh(&xfrm_state_lock); | 1385 | spin_lock_bh(&xfrm_state_lock); |
| 1363 | x = __xfrm_state_lookup_byaddr(net, daddr, saddr, proto, family); | 1386 | x = __xfrm_state_lookup_byaddr(net, mark, daddr, saddr, proto, family); |
| 1364 | spin_unlock_bh(&xfrm_state_lock); | 1387 | spin_unlock_bh(&xfrm_state_lock); |
| 1365 | return x; | 1388 | return x; |
| 1366 | } | 1389 | } |
| 1367 | EXPORT_SYMBOL(xfrm_state_lookup_byaddr); | 1390 | EXPORT_SYMBOL(xfrm_state_lookup_byaddr); |
| 1368 | 1391 | ||
| 1369 | struct xfrm_state * | 1392 | struct xfrm_state * |
| 1370 | xfrm_find_acq(struct net *net, u8 mode, u32 reqid, u8 proto, | 1393 | xfrm_find_acq(struct net *net, struct xfrm_mark *mark, u8 mode, u32 reqid, u8 proto, |
| 1371 | xfrm_address_t *daddr, xfrm_address_t *saddr, | 1394 | xfrm_address_t *daddr, xfrm_address_t *saddr, |
| 1372 | int create, unsigned short family) | 1395 | int create, unsigned short family) |
| 1373 | { | 1396 | { |
| 1374 | struct xfrm_state *x; | 1397 | struct xfrm_state *x; |
| 1375 | 1398 | ||
| 1376 | spin_lock_bh(&xfrm_state_lock); | 1399 | spin_lock_bh(&xfrm_state_lock); |
| 1377 | x = __find_acq_core(net, family, mode, reqid, proto, daddr, saddr, create); | 1400 | x = __find_acq_core(net, mark, family, mode, reqid, proto, daddr, saddr, create); |
| 1378 | spin_unlock_bh(&xfrm_state_lock); | 1401 | spin_unlock_bh(&xfrm_state_lock); |
| 1379 | 1402 | ||
| 1380 | return x; | 1403 | return x; |
| @@ -1421,7 +1444,7 @@ EXPORT_SYMBOL(xfrm_state_sort); | |||
| 1421 | 1444 | ||
| 1422 | /* Silly enough, but I'm lazy to build resolution list */ | 1445 | /* Silly enough, but I'm lazy to build resolution list */ |
| 1423 | 1446 | ||
| 1424 | static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq) | 1447 | static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq) |
| 1425 | { | 1448 | { |
| 1426 | int i; | 1449 | int i; |
| 1427 | 1450 | ||
| @@ -1431,6 +1454,7 @@ static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq) | |||
| 1431 | 1454 | ||
| 1432 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+i, bydst) { | 1455 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+i, bydst) { |
| 1433 | if (x->km.seq == seq && | 1456 | if (x->km.seq == seq && |
| 1457 | (mark & x->mark.m) == x->mark.v && | ||
| 1434 | x->km.state == XFRM_STATE_ACQ) { | 1458 | x->km.state == XFRM_STATE_ACQ) { |
| 1435 | xfrm_state_hold(x); | 1459 | xfrm_state_hold(x); |
| 1436 | return x; | 1460 | return x; |
| @@ -1440,12 +1464,12 @@ static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq) | |||
| 1440 | return NULL; | 1464 | return NULL; |
| 1441 | } | 1465 | } |
| 1442 | 1466 | ||
| 1443 | struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 seq) | 1467 | struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq) |
| 1444 | { | 1468 | { |
| 1445 | struct xfrm_state *x; | 1469 | struct xfrm_state *x; |
| 1446 | 1470 | ||
| 1447 | spin_lock_bh(&xfrm_state_lock); | 1471 | spin_lock_bh(&xfrm_state_lock); |
| 1448 | x = __xfrm_find_acq_byseq(net, seq); | 1472 | x = __xfrm_find_acq_byseq(net, mark, seq); |
| 1449 | spin_unlock_bh(&xfrm_state_lock); | 1473 | spin_unlock_bh(&xfrm_state_lock); |
| 1450 | return x; | 1474 | return x; |
| 1451 | } | 1475 | } |
| @@ -1454,12 +1478,12 @@ EXPORT_SYMBOL(xfrm_find_acq_byseq); | |||
| 1454 | u32 xfrm_get_acqseq(void) | 1478 | u32 xfrm_get_acqseq(void) |
| 1455 | { | 1479 | { |
| 1456 | u32 res; | 1480 | u32 res; |
| 1457 | static u32 acqseq; | 1481 | static atomic_t acqseq; |
| 1458 | static DEFINE_SPINLOCK(acqseq_lock); | 1482 | |
| 1483 | do { | ||
| 1484 | res = atomic_inc_return(&acqseq); | ||
| 1485 | } while (!res); | ||
| 1459 | 1486 | ||
| 1460 | spin_lock_bh(&acqseq_lock); | ||
| 1461 | res = (++acqseq ? : ++acqseq); | ||
| 1462 | spin_unlock_bh(&acqseq_lock); | ||
| 1463 | return res; | 1487 | return res; |
| 1464 | } | 1488 | } |
| 1465 | EXPORT_SYMBOL(xfrm_get_acqseq); | 1489 | EXPORT_SYMBOL(xfrm_get_acqseq); |
| @@ -1472,6 +1496,7 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) | |||
| 1472 | int err = -ENOENT; | 1496 | int err = -ENOENT; |
| 1473 | __be32 minspi = htonl(low); | 1497 | __be32 minspi = htonl(low); |
| 1474 | __be32 maxspi = htonl(high); | 1498 | __be32 maxspi = htonl(high); |
| 1499 | u32 mark = x->mark.v & x->mark.m; | ||
| 1475 | 1500 | ||
| 1476 | spin_lock_bh(&x->lock); | 1501 | spin_lock_bh(&x->lock); |
| 1477 | if (x->km.state == XFRM_STATE_DEAD) | 1502 | if (x->km.state == XFRM_STATE_DEAD) |
| @@ -1484,7 +1509,7 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) | |||
| 1484 | err = -ENOENT; | 1509 | err = -ENOENT; |
| 1485 | 1510 | ||
| 1486 | if (minspi == maxspi) { | 1511 | if (minspi == maxspi) { |
| 1487 | x0 = xfrm_state_lookup(net, &x->id.daddr, minspi, x->id.proto, x->props.family); | 1512 | x0 = xfrm_state_lookup(net, mark, &x->id.daddr, minspi, x->id.proto, x->props.family); |
| 1488 | if (x0) { | 1513 | if (x0) { |
| 1489 | xfrm_state_put(x0); | 1514 | xfrm_state_put(x0); |
| 1490 | goto unlock; | 1515 | goto unlock; |
| @@ -1494,7 +1519,7 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) | |||
| 1494 | u32 spi = 0; | 1519 | u32 spi = 0; |
| 1495 | for (h=0; h<high-low+1; h++) { | 1520 | for (h=0; h<high-low+1; h++) { |
| 1496 | spi = low + net_random()%(high-low+1); | 1521 | spi = low + net_random()%(high-low+1); |
| 1497 | x0 = xfrm_state_lookup(net, &x->id.daddr, htonl(spi), x->id.proto, x->props.family); | 1522 | x0 = xfrm_state_lookup(net, mark, &x->id.daddr, htonl(spi), x->id.proto, x->props.family); |
| 1498 | if (x0 == NULL) { | 1523 | if (x0 == NULL) { |
| 1499 | x->id.spi = htonl(spi); | 1524 | x->id.spi = htonl(spi); |
| 1500 | break; | 1525 | break; |
