aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm/xfrm_state.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2009-03-30 17:53:32 -0400
committerIngo Molnar <mingo@elte.hu>2009-03-30 17:53:32 -0400
commit65fb0d23fcddd8697c871047b700c78817bdaa43 (patch)
tree119e6e5f276622c4c862f6c9b6d795264ba1603a /net/xfrm/xfrm_state.c
parent8c083f081d0014057901c68a0a3e0f8ca7ac8d23 (diff)
parentdfbbe89e197a77f2c8046a51c74e33e35f878080 (diff)
Merge branch 'linus' into cpumask-for-linus
Conflicts: arch/x86/kernel/cpu/common.c
Diffstat (limited to 'net/xfrm/xfrm_state.c')
-rw-r--r--net/xfrm/xfrm_state.c92
1 files changed, 59 insertions, 33 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index e25ff62ab2a6..82271720d970 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -748,12 +748,51 @@ static void xfrm_hash_grow_check(struct net *net, int have_hash_collision)
748 schedule_work(&net->xfrm.state_hash_work); 748 schedule_work(&net->xfrm.state_hash_work);
749} 749}
750 750
751static void xfrm_state_look_at(struct xfrm_policy *pol, struct xfrm_state *x,
752 struct flowi *fl, unsigned short family,
753 xfrm_address_t *daddr, xfrm_address_t *saddr,
754 struct xfrm_state **best, int *acq_in_progress,
755 int *error)
756{
757 /* Resolution logic:
758 * 1. There is a valid state with matching selector. Done.
759 * 2. Valid state with inappropriate selector. Skip.
760 *
761 * Entering area of "sysdeps".
762 *
763 * 3. If state is not valid, selector is temporary, it selects
764 * only session which triggered previous resolution. Key
765 * manager will do something to install a state with proper
766 * selector.
767 */
768 if (x->km.state == XFRM_STATE_VALID) {
769 if ((x->sel.family &&
770 !xfrm_selector_match(&x->sel, fl, x->sel.family)) ||
771 !security_xfrm_state_pol_flow_match(x, pol, fl))
772 return;
773
774 if (!*best ||
775 (*best)->km.dying > x->km.dying ||
776 ((*best)->km.dying == x->km.dying &&
777 (*best)->curlft.add_time < x->curlft.add_time))
778 *best = x;
779 } else if (x->km.state == XFRM_STATE_ACQ) {
780 *acq_in_progress = 1;
781 } else if (x->km.state == XFRM_STATE_ERROR ||
782 x->km.state == XFRM_STATE_EXPIRED) {
783 if (xfrm_selector_match(&x->sel, fl, x->sel.family) &&
784 security_xfrm_state_pol_flow_match(x, pol, fl))
785 *error = -ESRCH;
786 }
787}
788
751struct xfrm_state * 789struct xfrm_state *
752xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, 790xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
753 struct flowi *fl, struct xfrm_tmpl *tmpl, 791 struct flowi *fl, struct xfrm_tmpl *tmpl,
754 struct xfrm_policy *pol, int *err, 792 struct xfrm_policy *pol, int *err,
755 unsigned short family) 793 unsigned short family)
756{ 794{
795 static xfrm_address_t saddr_wildcard = { };
757 struct net *net = xp_net(pol); 796 struct net *net = xp_net(pol);
758 unsigned int h; 797 unsigned int h;
759 struct hlist_node *entry; 798 struct hlist_node *entry;
@@ -773,40 +812,27 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
773 xfrm_state_addr_check(x, daddr, saddr, family) && 812 xfrm_state_addr_check(x, daddr, saddr, family) &&
774 tmpl->mode == x->props.mode && 813 tmpl->mode == x->props.mode &&
775 tmpl->id.proto == x->id.proto && 814 tmpl->id.proto == x->id.proto &&
776 (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) { 815 (tmpl->id.spi == x->id.spi || !tmpl->id.spi))
777 /* Resolution logic: 816 xfrm_state_look_at(pol, x, fl, family, daddr, saddr,
778 1. There is a valid state with matching selector. 817 &best, &acquire_in_progress, &error);
779 Done.
780 2. Valid state with inappropriate selector. Skip.
781
782 Entering area of "sysdeps".
783
784 3. If state is not valid, selector is temporary,
785 it selects only session which triggered
786 previous resolution. Key manager will do
787 something to install a state with proper
788 selector.
789 */
790 if (x->km.state == XFRM_STATE_VALID) {
791 if ((x->sel.family && !xfrm_selector_match(&x->sel, fl, x->sel.family)) ||
792 !security_xfrm_state_pol_flow_match(x, pol, fl))
793 continue;
794 if (!best ||
795 best->km.dying > x->km.dying ||
796 (best->km.dying == x->km.dying &&
797 best->curlft.add_time < x->curlft.add_time))
798 best = x;
799 } else if (x->km.state == XFRM_STATE_ACQ) {
800 acquire_in_progress = 1;
801 } else if (x->km.state == XFRM_STATE_ERROR ||
802 x->km.state == XFRM_STATE_EXPIRED) {
803 if (xfrm_selector_match(&x->sel, fl, x->sel.family) &&
804 security_xfrm_state_pol_flow_match(x, pol, fl))
805 error = -ESRCH;
806 }
807 }
808 } 818 }
819 if (best)
820 goto found;
809 821
822 h = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, family);
823 hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) {
824 if (x->props.family == family &&
825 x->props.reqid == tmpl->reqid &&
826 !(x->props.flags & XFRM_STATE_WILDRECV) &&
827 xfrm_state_addr_check(x, daddr, saddr, family) &&
828 tmpl->mode == x->props.mode &&
829 tmpl->id.proto == x->id.proto &&
830 (tmpl->id.spi == x->id.spi || !tmpl->id.spi))
831 xfrm_state_look_at(pol, x, fl, family, daddr, saddr,
832 &best, &acquire_in_progress, &error);
833 }
834
835found:
810 x = best; 836 x = best;
811 if (!x && !error && !acquire_in_progress) { 837 if (!x && !error && !acquire_in_progress) {
812 if (tmpl->id.spi && 838 if (tmpl->id.spi &&
@@ -1589,7 +1615,7 @@ void xfrm_state_walk_done(struct xfrm_state_walk *walk)
1589 1615
1590 spin_lock_bh(&xfrm_state_lock); 1616 spin_lock_bh(&xfrm_state_lock);
1591 list_del(&walk->all); 1617 list_del(&walk->all);
1592 spin_lock_bh(&xfrm_state_lock); 1618 spin_unlock_bh(&xfrm_state_lock);
1593} 1619}
1594EXPORT_SYMBOL(xfrm_state_walk_done); 1620EXPORT_SYMBOL(xfrm_state_walk_done);
1595 1621