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; |