aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm/xfrm_state.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/xfrm/xfrm_state.c')
-rw-r--r--net/xfrm/xfrm_state.c210
1 files changed, 159 insertions, 51 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 80f5f9dc2b9e..4a3832f81c37 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -38,6 +38,8 @@ EXPORT_SYMBOL(sysctl_xfrm_aevent_rseqth);
38 38
39static DEFINE_SPINLOCK(xfrm_state_lock); 39static DEFINE_SPINLOCK(xfrm_state_lock);
40 40
41#define XFRM_DST_HSIZE 1024
42
41/* Hash table to find appropriate SA towards given target (endpoint 43/* Hash table to find appropriate SA towards given target (endpoint
42 * of tunnel or destination of transport mode) allowed by selector. 44 * of tunnel or destination of transport mode) allowed by selector.
43 * 45 *
@@ -49,6 +51,48 @@ static struct list_head xfrm_state_bysrc[XFRM_DST_HSIZE];
49static struct list_head xfrm_state_byspi[XFRM_DST_HSIZE]; 51static struct list_head xfrm_state_byspi[XFRM_DST_HSIZE];
50 52
51static __inline__ 53static __inline__
54unsigned __xfrm4_dst_hash(xfrm_address_t *addr)
55{
56 unsigned h;
57 h = ntohl(addr->a4);
58 h = (h ^ (h>>16)) % XFRM_DST_HSIZE;
59 return h;
60}
61
62static __inline__
63unsigned __xfrm6_dst_hash(xfrm_address_t *addr)
64{
65 unsigned h;
66 h = ntohl(addr->a6[2]^addr->a6[3]);
67 h = (h ^ (h>>16)) % XFRM_DST_HSIZE;
68 return h;
69}
70
71static __inline__
72unsigned __xfrm4_src_hash(xfrm_address_t *addr)
73{
74 return __xfrm4_dst_hash(addr);
75}
76
77static __inline__
78unsigned __xfrm6_src_hash(xfrm_address_t *addr)
79{
80 return __xfrm6_dst_hash(addr);
81}
82
83static __inline__
84unsigned xfrm_src_hash(xfrm_address_t *addr, unsigned short family)
85{
86 switch (family) {
87 case AF_INET:
88 return __xfrm4_src_hash(addr);
89 case AF_INET6:
90 return __xfrm6_src_hash(addr);
91 }
92 return 0;
93}
94
95static __inline__
52unsigned xfrm_dst_hash(xfrm_address_t *addr, unsigned short family) 96unsigned xfrm_dst_hash(xfrm_address_t *addr, unsigned short family)
53{ 97{
54 switch (family) { 98 switch (family) {
@@ -60,6 +104,36 @@ unsigned xfrm_dst_hash(xfrm_address_t *addr, unsigned short family)
60 return 0; 104 return 0;
61} 105}
62 106
107static __inline__
108unsigned __xfrm4_spi_hash(xfrm_address_t *addr, u32 spi, u8 proto)
109{
110 unsigned h;
111 h = ntohl(addr->a4^spi^proto);
112 h = (h ^ (h>>10) ^ (h>>20)) % XFRM_DST_HSIZE;
113 return h;
114}
115
116static __inline__
117unsigned __xfrm6_spi_hash(xfrm_address_t *addr, u32 spi, u8 proto)
118{
119 unsigned h;
120 h = ntohl(addr->a6[2]^addr->a6[3]^spi^proto);
121 h = (h ^ (h>>10) ^ (h>>20)) % XFRM_DST_HSIZE;
122 return h;
123}
124
125static __inline__
126unsigned xfrm_spi_hash(xfrm_address_t *addr, u32 spi, u8 proto, unsigned short family)
127{
128 switch (family) {
129 case AF_INET:
130 return __xfrm4_spi_hash(addr, spi, proto);
131 case AF_INET6:
132 return __xfrm6_spi_hash(addr, spi, proto);
133 }
134 return 0; /*XXX*/
135}
136
63DECLARE_WAIT_QUEUE_HEAD(km_waitq); 137DECLARE_WAIT_QUEUE_HEAD(km_waitq);
64EXPORT_SYMBOL(km_waitq); 138EXPORT_SYMBOL(km_waitq);
65 139
@@ -342,6 +416,83 @@ xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl,
342 return 0; 416 return 0;
343} 417}
344 418
419static struct xfrm_state *__xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family)
420{
421 unsigned int h = xfrm_spi_hash(daddr, spi, proto, family);
422 struct xfrm_state *x;
423
424 list_for_each_entry(x, xfrm_state_byspi+h, byspi) {
425 if (x->props.family != family ||
426 x->id.spi != spi ||
427 x->id.proto != proto)
428 continue;
429
430 switch (family) {
431 case AF_INET:
432 if (x->id.daddr.a4 != daddr->a4)
433 continue;
434 break;
435 case AF_INET6:
436 if (!ipv6_addr_equal((struct in6_addr *)daddr,
437 (struct in6_addr *)
438 x->id.daddr.a6))
439 continue;
440 break;
441 };
442
443 xfrm_state_hold(x);
444 return x;
445 }
446
447 return NULL;
448}
449
450static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family)
451{
452 unsigned int h = xfrm_src_hash(saddr, family);
453 struct xfrm_state *x;
454
455 list_for_each_entry(x, xfrm_state_bysrc+h, bysrc) {
456 if (x->props.family != family ||
457 x->id.proto != proto)
458 continue;
459
460 switch (family) {
461 case AF_INET:
462 if (x->id.daddr.a4 != daddr->a4 ||
463 x->props.saddr.a4 != saddr->a4)
464 continue;
465 break;
466 case AF_INET6:
467 if (!ipv6_addr_equal((struct in6_addr *)daddr,
468 (struct in6_addr *)
469 x->id.daddr.a6) ||
470 !ipv6_addr_equal((struct in6_addr *)saddr,
471 (struct in6_addr *)
472 x->props.saddr.a6))
473 continue;
474 break;
475 };
476
477 xfrm_state_hold(x);
478 return x;
479 }
480
481 return NULL;
482}
483
484static inline struct xfrm_state *
485__xfrm_state_locate(struct xfrm_state *x, int use_spi, int family)
486{
487 if (use_spi)
488 return __xfrm_state_lookup(&x->id.daddr, x->id.spi,
489 x->id.proto, family);
490 else
491 return __xfrm_state_lookup_byaddr(&x->id.daddr,
492 &x->props.saddr,
493 x->id.proto, family);
494}
495
345struct xfrm_state * 496struct xfrm_state *
346xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, 497xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
347 struct flowi *fl, struct xfrm_tmpl *tmpl, 498 struct flowi *fl, struct xfrm_tmpl *tmpl,
@@ -353,14 +504,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
353 int acquire_in_progress = 0; 504 int acquire_in_progress = 0;
354 int error = 0; 505 int error = 0;
355 struct xfrm_state *best = NULL; 506 struct xfrm_state *best = NULL;
356 struct xfrm_state_afinfo *afinfo;
357 507
358 afinfo = xfrm_state_get_afinfo(family);
359 if (afinfo == NULL) {
360 *err = -EAFNOSUPPORT;
361 return NULL;
362 }
363
364 spin_lock_bh(&xfrm_state_lock); 508 spin_lock_bh(&xfrm_state_lock);
365 list_for_each_entry(x, xfrm_state_bydst+h, bydst) { 509 list_for_each_entry(x, xfrm_state_bydst+h, bydst) {
366 if (x->props.family == family && 510 if (x->props.family == family &&
@@ -406,8 +550,8 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
406 x = best; 550 x = best;
407 if (!x && !error && !acquire_in_progress) { 551 if (!x && !error && !acquire_in_progress) {
408 if (tmpl->id.spi && 552 if (tmpl->id.spi &&
409 (x0 = afinfo->state_lookup(daddr, tmpl->id.spi, 553 (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi,
410 tmpl->id.proto)) != NULL) { 554 tmpl->id.proto, family)) != NULL) {
411 xfrm_state_put(x0); 555 xfrm_state_put(x0);
412 error = -EEXIST; 556 error = -EEXIST;
413 goto out; 557 goto out;
@@ -457,7 +601,6 @@ out:
457 else 601 else
458 *err = acquire_in_progress ? -EAGAIN : error; 602 *err = acquire_in_progress ? -EAGAIN : error;
459 spin_unlock_bh(&xfrm_state_lock); 603 spin_unlock_bh(&xfrm_state_lock);
460 xfrm_state_put_afinfo(afinfo);
461 return x; 604 return x;
462} 605}
463 606
@@ -584,34 +727,20 @@ static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 re
584 return x; 727 return x;
585} 728}
586 729
587static inline struct xfrm_state *
588__xfrm_state_locate(struct xfrm_state_afinfo *afinfo, struct xfrm_state *x,
589 int use_spi)
590{
591 if (use_spi)
592 return afinfo->state_lookup(&x->id.daddr, x->id.spi, x->id.proto);
593 else
594 return afinfo->state_lookup_byaddr(&x->id.daddr, &x->props.saddr, x->id.proto);
595}
596
597static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq); 730static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq);
598 731
599int xfrm_state_add(struct xfrm_state *x) 732int xfrm_state_add(struct xfrm_state *x)
600{ 733{
601 struct xfrm_state_afinfo *afinfo;
602 struct xfrm_state *x1; 734 struct xfrm_state *x1;
603 int family; 735 int family;
604 int err; 736 int err;
605 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); 737 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
606 738
607 family = x->props.family; 739 family = x->props.family;
608 afinfo = xfrm_state_get_afinfo(family);
609 if (unlikely(afinfo == NULL))
610 return -EAFNOSUPPORT;
611 740
612 spin_lock_bh(&xfrm_state_lock); 741 spin_lock_bh(&xfrm_state_lock);
613 742
614 x1 = __xfrm_state_locate(afinfo, x, use_spi); 743 x1 = __xfrm_state_locate(x, use_spi, family);
615 if (x1) { 744 if (x1) {
616 xfrm_state_put(x1); 745 xfrm_state_put(x1);
617 x1 = NULL; 746 x1 = NULL;
@@ -637,7 +766,6 @@ int xfrm_state_add(struct xfrm_state *x)
637 766
638out: 767out:
639 spin_unlock_bh(&xfrm_state_lock); 768 spin_unlock_bh(&xfrm_state_lock);
640 xfrm_state_put_afinfo(afinfo);
641 769
642 if (!err) 770 if (!err)
643 xfrm_flush_all_bundles(); 771 xfrm_flush_all_bundles();
@@ -653,17 +781,12 @@ EXPORT_SYMBOL(xfrm_state_add);
653 781
654int xfrm_state_update(struct xfrm_state *x) 782int xfrm_state_update(struct xfrm_state *x)
655{ 783{
656 struct xfrm_state_afinfo *afinfo;
657 struct xfrm_state *x1; 784 struct xfrm_state *x1;
658 int err; 785 int err;
659 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); 786 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
660 787
661 afinfo = xfrm_state_get_afinfo(x->props.family);
662 if (unlikely(afinfo == NULL))
663 return -EAFNOSUPPORT;
664
665 spin_lock_bh(&xfrm_state_lock); 788 spin_lock_bh(&xfrm_state_lock);
666 x1 = __xfrm_state_locate(afinfo, x, use_spi); 789 x1 = __xfrm_state_locate(x, use_spi, x->props.family);
667 790
668 err = -ESRCH; 791 err = -ESRCH;
669 if (!x1) 792 if (!x1)
@@ -683,7 +806,6 @@ int xfrm_state_update(struct xfrm_state *x)
683 806
684out: 807out:
685 spin_unlock_bh(&xfrm_state_lock); 808 spin_unlock_bh(&xfrm_state_lock);
686 xfrm_state_put_afinfo(afinfo);
687 809
688 if (err) 810 if (err)
689 return err; 811 return err;
@@ -776,14 +898,10 @@ xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto,
776 unsigned short family) 898 unsigned short family)
777{ 899{
778 struct xfrm_state *x; 900 struct xfrm_state *x;
779 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
780 if (!afinfo)
781 return NULL;
782 901
783 spin_lock_bh(&xfrm_state_lock); 902 spin_lock_bh(&xfrm_state_lock);
784 x = afinfo->state_lookup(daddr, spi, proto); 903 x = __xfrm_state_lookup(daddr, spi, proto, family);
785 spin_unlock_bh(&xfrm_state_lock); 904 spin_unlock_bh(&xfrm_state_lock);
786 xfrm_state_put_afinfo(afinfo);
787 return x; 905 return x;
788} 906}
789EXPORT_SYMBOL(xfrm_state_lookup); 907EXPORT_SYMBOL(xfrm_state_lookup);
@@ -793,14 +911,10 @@ xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr,
793 u8 proto, unsigned short family) 911 u8 proto, unsigned short family)
794{ 912{
795 struct xfrm_state *x; 913 struct xfrm_state *x;
796 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
797 if (!afinfo)
798 return NULL;
799 914
800 spin_lock_bh(&xfrm_state_lock); 915 spin_lock_bh(&xfrm_state_lock);
801 x = afinfo->state_lookup_byaddr(daddr, saddr, proto); 916 x = __xfrm_state_lookup_byaddr(daddr, saddr, proto, family);
802 spin_unlock_bh(&xfrm_state_lock); 917 spin_unlock_bh(&xfrm_state_lock);
803 xfrm_state_put_afinfo(afinfo);
804 return x; 918 return x;
805} 919}
806EXPORT_SYMBOL(xfrm_state_lookup_byaddr); 920EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
@@ -1272,11 +1386,8 @@ int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo)
1272 write_lock_bh(&xfrm_state_afinfo_lock); 1386 write_lock_bh(&xfrm_state_afinfo_lock);
1273 if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL)) 1387 if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL))
1274 err = -ENOBUFS; 1388 err = -ENOBUFS;
1275 else { 1389 else
1276 afinfo->state_bysrc = xfrm_state_bysrc;
1277 afinfo->state_byspi = xfrm_state_byspi;
1278 xfrm_state_afinfo[afinfo->family] = afinfo; 1390 xfrm_state_afinfo[afinfo->family] = afinfo;
1279 }
1280 write_unlock_bh(&xfrm_state_afinfo_lock); 1391 write_unlock_bh(&xfrm_state_afinfo_lock);
1281 return err; 1392 return err;
1282} 1393}
@@ -1293,11 +1404,8 @@ int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo)
1293 if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) { 1404 if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) {
1294 if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo)) 1405 if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo))
1295 err = -EINVAL; 1406 err = -EINVAL;
1296 else { 1407 else
1297 xfrm_state_afinfo[afinfo->family] = NULL; 1408 xfrm_state_afinfo[afinfo->family] = NULL;
1298 afinfo->state_byspi = NULL;
1299 afinfo->state_bysrc = NULL;
1300 }
1301 } 1409 }
1302 write_unlock_bh(&xfrm_state_afinfo_lock); 1410 write_unlock_bh(&xfrm_state_afinfo_lock);
1303 return err; 1411 return err;