diff options
Diffstat (limited to 'net/xfrm/xfrm_state.c')
-rw-r--r-- | net/xfrm/xfrm_state.c | 100 |
1 files changed, 60 insertions, 40 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index b36cc344474b..17d5b96f2fc8 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -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); |
@@ -665,7 +669,7 @@ xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl, | |||
665 | return 0; | 669 | return 0; |
666 | } | 670 | } |
667 | 671 | ||
668 | static struct xfrm_state *__xfrm_state_lookup(struct net *net, xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family) | 672 | static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark, xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family) |
669 | { | 673 | { |
670 | unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family); | 674 | unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family); |
671 | struct xfrm_state *x; | 675 | struct xfrm_state *x; |
@@ -678,6 +682,8 @@ static struct xfrm_state *__xfrm_state_lookup(struct net *net, xfrm_address_t *d | |||
678 | xfrm_addr_cmp(&x->id.daddr, daddr, family)) | 682 | xfrm_addr_cmp(&x->id.daddr, daddr, family)) |
679 | continue; | 683 | continue; |
680 | 684 | ||
685 | if ((mark & x->mark.m) != x->mark.v) | ||
686 | continue; | ||
681 | xfrm_state_hold(x); | 687 | xfrm_state_hold(x); |
682 | return x; | 688 | return x; |
683 | } | 689 | } |
@@ -685,7 +691,7 @@ static struct xfrm_state *__xfrm_state_lookup(struct net *net, xfrm_address_t *d | |||
685 | return NULL; | 691 | return NULL; |
686 | } | 692 | } |
687 | 693 | ||
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) | 694 | 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 | { | 695 | { |
690 | unsigned int h = xfrm_src_hash(net, daddr, saddr, family); | 696 | unsigned int h = xfrm_src_hash(net, daddr, saddr, family); |
691 | struct xfrm_state *x; | 697 | struct xfrm_state *x; |
@@ -698,6 +704,8 @@ static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, xfrm_addre | |||
698 | xfrm_addr_cmp(&x->props.saddr, saddr, family)) | 704 | xfrm_addr_cmp(&x->props.saddr, saddr, family)) |
699 | continue; | 705 | continue; |
700 | 706 | ||
707 | if ((mark & x->mark.m) != x->mark.v) | ||
708 | continue; | ||
701 | xfrm_state_hold(x); | 709 | xfrm_state_hold(x); |
702 | return x; | 710 | return x; |
703 | } | 711 | } |
@@ -709,12 +717,14 @@ static inline struct xfrm_state * | |||
709 | __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family) | 717 | __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family) |
710 | { | 718 | { |
711 | struct net *net = xs_net(x); | 719 | struct net *net = xs_net(x); |
720 | u32 mark = x->mark.v & x->mark.m; | ||
712 | 721 | ||
713 | if (use_spi) | 722 | if (use_spi) |
714 | return __xfrm_state_lookup(net, &x->id.daddr, x->id.spi, | 723 | return __xfrm_state_lookup(net, mark, &x->id.daddr, |
715 | x->id.proto, family); | 724 | x->id.spi, x->id.proto, family); |
716 | else | 725 | else |
717 | return __xfrm_state_lookup_byaddr(net, &x->id.daddr, | 726 | return __xfrm_state_lookup_byaddr(net, mark, |
727 | &x->id.daddr, | ||
718 | &x->props.saddr, | 728 | &x->props.saddr, |
719 | x->id.proto, family); | 729 | x->id.proto, family); |
720 | } | 730 | } |
@@ -779,6 +789,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
779 | int acquire_in_progress = 0; | 789 | int acquire_in_progress = 0; |
780 | int error = 0; | 790 | int error = 0; |
781 | struct xfrm_state *best = NULL; | 791 | struct xfrm_state *best = NULL; |
792 | u32 mark = pol->mark.v & pol->mark.m; | ||
782 | 793 | ||
783 | to_put = NULL; | 794 | to_put = NULL; |
784 | 795 | ||
@@ -787,6 +798,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
787 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { | 798 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { |
788 | if (x->props.family == family && | 799 | if (x->props.family == family && |
789 | x->props.reqid == tmpl->reqid && | 800 | x->props.reqid == tmpl->reqid && |
801 | (mark & x->mark.m) == x->mark.v && | ||
790 | !(x->props.flags & XFRM_STATE_WILDRECV) && | 802 | !(x->props.flags & XFRM_STATE_WILDRECV) && |
791 | xfrm_state_addr_check(x, daddr, saddr, family) && | 803 | xfrm_state_addr_check(x, daddr, saddr, family) && |
792 | tmpl->mode == x->props.mode && | 804 | tmpl->mode == x->props.mode && |
@@ -802,6 +814,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
802 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h_wildcard, bydst) { | 814 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h_wildcard, bydst) { |
803 | if (x->props.family == family && | 815 | if (x->props.family == family && |
804 | x->props.reqid == tmpl->reqid && | 816 | x->props.reqid == tmpl->reqid && |
817 | (mark & x->mark.m) == x->mark.v && | ||
805 | !(x->props.flags & XFRM_STATE_WILDRECV) && | 818 | !(x->props.flags & XFRM_STATE_WILDRECV) && |
806 | xfrm_state_addr_check(x, daddr, saddr, family) && | 819 | xfrm_state_addr_check(x, daddr, saddr, family) && |
807 | tmpl->mode == x->props.mode && | 820 | tmpl->mode == x->props.mode && |
@@ -815,7 +828,7 @@ found: | |||
815 | x = best; | 828 | x = best; |
816 | if (!x && !error && !acquire_in_progress) { | 829 | if (!x && !error && !acquire_in_progress) { |
817 | if (tmpl->id.spi && | 830 | if (tmpl->id.spi && |
818 | (x0 = __xfrm_state_lookup(net, daddr, tmpl->id.spi, | 831 | (x0 = __xfrm_state_lookup(net, mark, daddr, tmpl->id.spi, |
819 | tmpl->id.proto, family)) != NULL) { | 832 | tmpl->id.proto, family)) != NULL) { |
820 | to_put = x0; | 833 | to_put = x0; |
821 | error = -EEXIST; | 834 | error = -EEXIST; |
@@ -829,6 +842,7 @@ found: | |||
829 | /* Initialize temporary selector matching only | 842 | /* Initialize temporary selector matching only |
830 | * to current session. */ | 843 | * to current session. */ |
831 | xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family); | 844 | xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family); |
845 | memcpy(&x->mark, &pol->mark, sizeof(x->mark)); | ||
832 | 846 | ||
833 | error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid); | 847 | error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid); |
834 | if (error) { | 848 | if (error) { |
@@ -871,7 +885,7 @@ out: | |||
871 | } | 885 | } |
872 | 886 | ||
873 | struct xfrm_state * | 887 | struct xfrm_state * |
874 | xfrm_stateonly_find(struct net *net, | 888 | xfrm_stateonly_find(struct net *net, u32 mark, |
875 | xfrm_address_t *daddr, xfrm_address_t *saddr, | 889 | xfrm_address_t *daddr, xfrm_address_t *saddr, |
876 | unsigned short family, u8 mode, u8 proto, u32 reqid) | 890 | unsigned short family, u8 mode, u8 proto, u32 reqid) |
877 | { | 891 | { |
@@ -884,6 +898,7 @@ xfrm_stateonly_find(struct net *net, | |||
884 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { | 898 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { |
885 | if (x->props.family == family && | 899 | if (x->props.family == family && |
886 | x->props.reqid == reqid && | 900 | x->props.reqid == reqid && |
901 | (mark & x->mark.m) == x->mark.v && | ||
887 | !(x->props.flags & XFRM_STATE_WILDRECV) && | 902 | !(x->props.flags & XFRM_STATE_WILDRECV) && |
888 | xfrm_state_addr_check(x, daddr, saddr, family) && | 903 | xfrm_state_addr_check(x, daddr, saddr, family) && |
889 | mode == x->props.mode && | 904 | mode == x->props.mode && |
@@ -946,11 +961,13 @@ static void __xfrm_state_bump_genids(struct xfrm_state *xnew) | |||
946 | struct xfrm_state *x; | 961 | struct xfrm_state *x; |
947 | struct hlist_node *entry; | 962 | struct hlist_node *entry; |
948 | unsigned int h; | 963 | unsigned int h; |
964 | u32 mark = xnew->mark.v & xnew->mark.m; | ||
949 | 965 | ||
950 | h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family); | 966 | 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) { | 967 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { |
952 | if (x->props.family == family && | 968 | if (x->props.family == family && |
953 | x->props.reqid == reqid && | 969 | x->props.reqid == reqid && |
970 | (mark & x->mark.m) == x->mark.v && | ||
954 | !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) && | 971 | !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) && |
955 | !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family)) | 972 | !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family)) |
956 | x->genid = xfrm_state_genid; | 973 | x->genid = xfrm_state_genid; |
@@ -967,11 +984,12 @@ void xfrm_state_insert(struct xfrm_state *x) | |||
967 | EXPORT_SYMBOL(xfrm_state_insert); | 984 | EXPORT_SYMBOL(xfrm_state_insert); |
968 | 985 | ||
969 | /* xfrm_state_lock is held */ | 986 | /* 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) | 987 | 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 | { | 988 | { |
972 | unsigned int h = xfrm_dst_hash(net, daddr, saddr, reqid, family); | 989 | unsigned int h = xfrm_dst_hash(net, daddr, saddr, reqid, family); |
973 | struct hlist_node *entry; | 990 | struct hlist_node *entry; |
974 | struct xfrm_state *x; | 991 | struct xfrm_state *x; |
992 | u32 mark = m->v & m->m; | ||
975 | 993 | ||
976 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { | 994 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { |
977 | if (x->props.reqid != reqid || | 995 | if (x->props.reqid != reqid || |
@@ -980,6 +998,7 @@ static struct xfrm_state *__find_acq_core(struct net *net, unsigned short family | |||
980 | x->km.state != XFRM_STATE_ACQ || | 998 | x->km.state != XFRM_STATE_ACQ || |
981 | x->id.spi != 0 || | 999 | x->id.spi != 0 || |
982 | x->id.proto != proto || | 1000 | x->id.proto != proto || |
1001 | (mark & x->mark.m) != x->mark.v || | ||
983 | xfrm_addr_cmp(&x->id.daddr, daddr, family) || | 1002 | xfrm_addr_cmp(&x->id.daddr, daddr, family) || |
984 | xfrm_addr_cmp(&x->props.saddr, saddr, family)) | 1003 | xfrm_addr_cmp(&x->props.saddr, saddr, family)) |
985 | continue; | 1004 | continue; |
@@ -1022,6 +1041,8 @@ static struct xfrm_state *__find_acq_core(struct net *net, unsigned short family | |||
1022 | x->props.family = family; | 1041 | x->props.family = family; |
1023 | x->props.mode = mode; | 1042 | x->props.mode = mode; |
1024 | x->props.reqid = reqid; | 1043 | x->props.reqid = reqid; |
1044 | x->mark.v = m->v; | ||
1045 | x->mark.m = m->m; | ||
1025 | x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; | 1046 | x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; |
1026 | xfrm_state_hold(x); | 1047 | xfrm_state_hold(x); |
1027 | tasklet_hrtimer_start(&x->mtimer, ktime_set(net->xfrm.sysctl_acq_expires, 0), HRTIMER_MODE_REL); | 1048 | tasklet_hrtimer_start(&x->mtimer, ktime_set(net->xfrm.sysctl_acq_expires, 0), HRTIMER_MODE_REL); |
@@ -1038,7 +1059,7 @@ static struct xfrm_state *__find_acq_core(struct net *net, unsigned short family | |||
1038 | return x; | 1059 | return x; |
1039 | } | 1060 | } |
1040 | 1061 | ||
1041 | static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq); | 1062 | static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq); |
1042 | 1063 | ||
1043 | int xfrm_state_add(struct xfrm_state *x) | 1064 | int xfrm_state_add(struct xfrm_state *x) |
1044 | { | 1065 | { |
@@ -1046,6 +1067,7 @@ int xfrm_state_add(struct xfrm_state *x) | |||
1046 | struct xfrm_state *x1, *to_put; | 1067 | struct xfrm_state *x1, *to_put; |
1047 | int family; | 1068 | int family; |
1048 | int err; | 1069 | int err; |
1070 | u32 mark = x->mark.v & x->mark.m; | ||
1049 | int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); | 1071 | int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); |
1050 | 1072 | ||
1051 | family = x->props.family; | 1073 | family = x->props.family; |
@@ -1063,7 +1085,7 @@ int xfrm_state_add(struct xfrm_state *x) | |||
1063 | } | 1085 | } |
1064 | 1086 | ||
1065 | if (use_spi && x->km.seq) { | 1087 | if (use_spi && x->km.seq) { |
1066 | x1 = __xfrm_find_acq_byseq(net, x->km.seq); | 1088 | x1 = __xfrm_find_acq_byseq(net, mark, x->km.seq); |
1067 | if (x1 && ((x1->id.proto != x->id.proto) || | 1089 | if (x1 && ((x1->id.proto != x->id.proto) || |
1068 | xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) { | 1090 | xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) { |
1069 | to_put = x1; | 1091 | to_put = x1; |
@@ -1072,8 +1094,8 @@ int xfrm_state_add(struct xfrm_state *x) | |||
1072 | } | 1094 | } |
1073 | 1095 | ||
1074 | if (use_spi && !x1) | 1096 | if (use_spi && !x1) |
1075 | x1 = __find_acq_core(net, family, x->props.mode, x->props.reqid, | 1097 | x1 = __find_acq_core(net, &x->mark, family, x->props.mode, |
1076 | x->id.proto, | 1098 | x->props.reqid, x->id.proto, |
1077 | &x->id.daddr, &x->props.saddr, 0); | 1099 | &x->id.daddr, &x->props.saddr, 0); |
1078 | 1100 | ||
1079 | __xfrm_state_bump_genids(x); | 1101 | __xfrm_state_bump_genids(x); |
@@ -1102,7 +1124,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) | |||
1102 | int err = -ENOMEM; | 1124 | int err = -ENOMEM; |
1103 | struct xfrm_state *x = xfrm_state_alloc(net); | 1125 | struct xfrm_state *x = xfrm_state_alloc(net); |
1104 | if (!x) | 1126 | if (!x) |
1105 | goto error; | 1127 | goto out; |
1106 | 1128 | ||
1107 | memcpy(&x->id, &orig->id, sizeof(x->id)); | 1129 | memcpy(&x->id, &orig->id, sizeof(x->id)); |
1108 | memcpy(&x->sel, &orig->sel, sizeof(x->sel)); | 1130 | memcpy(&x->sel, &orig->sel, sizeof(x->sel)); |
@@ -1147,6 +1169,8 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) | |||
1147 | goto error; | 1169 | goto error; |
1148 | } | 1170 | } |
1149 | 1171 | ||
1172 | memcpy(&x->mark, &orig->mark, sizeof(x->mark)); | ||
1173 | |||
1150 | err = xfrm_init_state(x); | 1174 | err = xfrm_init_state(x); |
1151 | if (err) | 1175 | if (err) |
1152 | goto error; | 1176 | goto error; |
@@ -1160,16 +1184,10 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) | |||
1160 | return x; | 1184 | return x; |
1161 | 1185 | ||
1162 | error: | 1186 | error: |
1187 | xfrm_state_put(x); | ||
1188 | out: | ||
1163 | if (errp) | 1189 | if (errp) |
1164 | *errp = err; | 1190 | *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; | 1191 | return NULL; |
1174 | } | 1192 | } |
1175 | 1193 | ||
@@ -1344,41 +1362,41 @@ int xfrm_state_check_expire(struct xfrm_state *x) | |||
1344 | EXPORT_SYMBOL(xfrm_state_check_expire); | 1362 | EXPORT_SYMBOL(xfrm_state_check_expire); |
1345 | 1363 | ||
1346 | struct xfrm_state * | 1364 | struct xfrm_state * |
1347 | xfrm_state_lookup(struct net *net, xfrm_address_t *daddr, __be32 spi, u8 proto, | 1365 | xfrm_state_lookup(struct net *net, u32 mark, xfrm_address_t *daddr, __be32 spi, |
1348 | unsigned short family) | 1366 | u8 proto, unsigned short family) |
1349 | { | 1367 | { |
1350 | struct xfrm_state *x; | 1368 | struct xfrm_state *x; |
1351 | 1369 | ||
1352 | spin_lock_bh(&xfrm_state_lock); | 1370 | spin_lock_bh(&xfrm_state_lock); |
1353 | x = __xfrm_state_lookup(net, daddr, spi, proto, family); | 1371 | x = __xfrm_state_lookup(net, mark, daddr, spi, proto, family); |
1354 | spin_unlock_bh(&xfrm_state_lock); | 1372 | spin_unlock_bh(&xfrm_state_lock); |
1355 | return x; | 1373 | return x; |
1356 | } | 1374 | } |
1357 | EXPORT_SYMBOL(xfrm_state_lookup); | 1375 | EXPORT_SYMBOL(xfrm_state_lookup); |
1358 | 1376 | ||
1359 | struct xfrm_state * | 1377 | struct xfrm_state * |
1360 | xfrm_state_lookup_byaddr(struct net *net, | 1378 | xfrm_state_lookup_byaddr(struct net *net, u32 mark, |
1361 | xfrm_address_t *daddr, xfrm_address_t *saddr, | 1379 | xfrm_address_t *daddr, xfrm_address_t *saddr, |
1362 | u8 proto, unsigned short family) | 1380 | u8 proto, unsigned short family) |
1363 | { | 1381 | { |
1364 | struct xfrm_state *x; | 1382 | struct xfrm_state *x; |
1365 | 1383 | ||
1366 | spin_lock_bh(&xfrm_state_lock); | 1384 | spin_lock_bh(&xfrm_state_lock); |
1367 | x = __xfrm_state_lookup_byaddr(net, daddr, saddr, proto, family); | 1385 | x = __xfrm_state_lookup_byaddr(net, mark, daddr, saddr, proto, family); |
1368 | spin_unlock_bh(&xfrm_state_lock); | 1386 | spin_unlock_bh(&xfrm_state_lock); |
1369 | return x; | 1387 | return x; |
1370 | } | 1388 | } |
1371 | EXPORT_SYMBOL(xfrm_state_lookup_byaddr); | 1389 | EXPORT_SYMBOL(xfrm_state_lookup_byaddr); |
1372 | 1390 | ||
1373 | struct xfrm_state * | 1391 | struct xfrm_state * |
1374 | xfrm_find_acq(struct net *net, u8 mode, u32 reqid, u8 proto, | 1392 | 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, | 1393 | xfrm_address_t *daddr, xfrm_address_t *saddr, |
1376 | int create, unsigned short family) | 1394 | int create, unsigned short family) |
1377 | { | 1395 | { |
1378 | struct xfrm_state *x; | 1396 | struct xfrm_state *x; |
1379 | 1397 | ||
1380 | spin_lock_bh(&xfrm_state_lock); | 1398 | spin_lock_bh(&xfrm_state_lock); |
1381 | x = __find_acq_core(net, family, mode, reqid, proto, daddr, saddr, create); | 1399 | x = __find_acq_core(net, mark, family, mode, reqid, proto, daddr, saddr, create); |
1382 | spin_unlock_bh(&xfrm_state_lock); | 1400 | spin_unlock_bh(&xfrm_state_lock); |
1383 | 1401 | ||
1384 | return x; | 1402 | return x; |
@@ -1425,7 +1443,7 @@ EXPORT_SYMBOL(xfrm_state_sort); | |||
1425 | 1443 | ||
1426 | /* Silly enough, but I'm lazy to build resolution list */ | 1444 | /* Silly enough, but I'm lazy to build resolution list */ |
1427 | 1445 | ||
1428 | static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq) | 1446 | static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq) |
1429 | { | 1447 | { |
1430 | int i; | 1448 | int i; |
1431 | 1449 | ||
@@ -1435,6 +1453,7 @@ static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq) | |||
1435 | 1453 | ||
1436 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+i, bydst) { | 1454 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+i, bydst) { |
1437 | if (x->km.seq == seq && | 1455 | if (x->km.seq == seq && |
1456 | (mark & x->mark.m) == x->mark.v && | ||
1438 | x->km.state == XFRM_STATE_ACQ) { | 1457 | x->km.state == XFRM_STATE_ACQ) { |
1439 | xfrm_state_hold(x); | 1458 | xfrm_state_hold(x); |
1440 | return x; | 1459 | return x; |
@@ -1444,12 +1463,12 @@ static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq) | |||
1444 | return NULL; | 1463 | return NULL; |
1445 | } | 1464 | } |
1446 | 1465 | ||
1447 | struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 seq) | 1466 | struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq) |
1448 | { | 1467 | { |
1449 | struct xfrm_state *x; | 1468 | struct xfrm_state *x; |
1450 | 1469 | ||
1451 | spin_lock_bh(&xfrm_state_lock); | 1470 | spin_lock_bh(&xfrm_state_lock); |
1452 | x = __xfrm_find_acq_byseq(net, seq); | 1471 | x = __xfrm_find_acq_byseq(net, mark, seq); |
1453 | spin_unlock_bh(&xfrm_state_lock); | 1472 | spin_unlock_bh(&xfrm_state_lock); |
1454 | return x; | 1473 | return x; |
1455 | } | 1474 | } |
@@ -1458,12 +1477,12 @@ EXPORT_SYMBOL(xfrm_find_acq_byseq); | |||
1458 | u32 xfrm_get_acqseq(void) | 1477 | u32 xfrm_get_acqseq(void) |
1459 | { | 1478 | { |
1460 | u32 res; | 1479 | u32 res; |
1461 | static u32 acqseq; | 1480 | static atomic_t acqseq; |
1462 | static DEFINE_SPINLOCK(acqseq_lock); | 1481 | |
1482 | do { | ||
1483 | res = atomic_inc_return(&acqseq); | ||
1484 | } while (!res); | ||
1463 | 1485 | ||
1464 | spin_lock_bh(&acqseq_lock); | ||
1465 | res = (++acqseq ? : ++acqseq); | ||
1466 | spin_unlock_bh(&acqseq_lock); | ||
1467 | return res; | 1486 | return res; |
1468 | } | 1487 | } |
1469 | EXPORT_SYMBOL(xfrm_get_acqseq); | 1488 | EXPORT_SYMBOL(xfrm_get_acqseq); |
@@ -1476,6 +1495,7 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) | |||
1476 | int err = -ENOENT; | 1495 | int err = -ENOENT; |
1477 | __be32 minspi = htonl(low); | 1496 | __be32 minspi = htonl(low); |
1478 | __be32 maxspi = htonl(high); | 1497 | __be32 maxspi = htonl(high); |
1498 | u32 mark = x->mark.v & x->mark.m; | ||
1479 | 1499 | ||
1480 | spin_lock_bh(&x->lock); | 1500 | spin_lock_bh(&x->lock); |
1481 | if (x->km.state == XFRM_STATE_DEAD) | 1501 | if (x->km.state == XFRM_STATE_DEAD) |
@@ -1488,7 +1508,7 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) | |||
1488 | err = -ENOENT; | 1508 | err = -ENOENT; |
1489 | 1509 | ||
1490 | if (minspi == maxspi) { | 1510 | if (minspi == maxspi) { |
1491 | x0 = xfrm_state_lookup(net, &x->id.daddr, minspi, x->id.proto, x->props.family); | 1511 | x0 = xfrm_state_lookup(net, mark, &x->id.daddr, minspi, x->id.proto, x->props.family); |
1492 | if (x0) { | 1512 | if (x0) { |
1493 | xfrm_state_put(x0); | 1513 | xfrm_state_put(x0); |
1494 | goto unlock; | 1514 | goto unlock; |
@@ -1498,7 +1518,7 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) | |||
1498 | u32 spi = 0; | 1518 | u32 spi = 0; |
1499 | for (h=0; h<high-low+1; h++) { | 1519 | for (h=0; h<high-low+1; h++) { |
1500 | spi = low + net_random()%(high-low+1); | 1520 | spi = low + net_random()%(high-low+1); |
1501 | x0 = xfrm_state_lookup(net, &x->id.daddr, htonl(spi), x->id.proto, x->props.family); | 1521 | x0 = xfrm_state_lookup(net, mark, &x->id.daddr, htonl(spi), x->id.proto, x->props.family); |
1502 | if (x0 == NULL) { | 1522 | if (x0 == NULL) { |
1503 | x->id.spi = htonl(spi); | 1523 | x->id.spi = htonl(spi); |
1504 | break; | 1524 | break; |