aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/xfrm4_state.c53
-rw-r--r--net/ipv6/xfrm6_state.c56
-rw-r--r--net/xfrm/xfrm_state.c110
3 files changed, 100 insertions, 119 deletions
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c
index 616be131b4e3..9dc1afc17b6d 100644
--- a/net/ipv4/xfrm4_state.c
+++ b/net/ipv4/xfrm4_state.c
@@ -88,65 +88,12 @@ __xfrm4_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr,
88 return NULL; 88 return NULL;
89} 89}
90 90
91static struct xfrm_state *
92__xfrm4_find_acq(u8 mode, u32 reqid, u8 proto,
93 xfrm_address_t *daddr, xfrm_address_t *saddr,
94 int create)
95{
96 struct xfrm_state *x, *x0;
97 unsigned h = __xfrm4_dst_hash(daddr);
98
99 x0 = NULL;
100
101 list_for_each_entry(x, xfrm4_state_afinfo.state_bydst+h, bydst) {
102 if (x->props.family == AF_INET &&
103 daddr->a4 == x->id.daddr.a4 &&
104 mode == x->props.mode &&
105 proto == x->id.proto &&
106 saddr->a4 == x->props.saddr.a4 &&
107 reqid == x->props.reqid &&
108 x->km.state == XFRM_STATE_ACQ &&
109 !x->id.spi) {
110 x0 = x;
111 break;
112 }
113 }
114 if (!x0 && create && (x0 = xfrm_state_alloc()) != NULL) {
115 x0->sel.daddr.a4 = daddr->a4;
116 x0->sel.saddr.a4 = saddr->a4;
117 x0->sel.prefixlen_d = 32;
118 x0->sel.prefixlen_s = 32;
119 x0->props.saddr.a4 = saddr->a4;
120 x0->km.state = XFRM_STATE_ACQ;
121 x0->id.daddr.a4 = daddr->a4;
122 x0->id.proto = proto;
123 x0->props.family = AF_INET;
124 x0->props.mode = mode;
125 x0->props.reqid = reqid;
126 x0->props.family = AF_INET;
127 x0->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES;
128 xfrm_state_hold(x0);
129 x0->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ;
130 add_timer(&x0->timer);
131 xfrm_state_hold(x0);
132 list_add_tail(&x0->bydst, xfrm4_state_afinfo.state_bydst+h);
133 h = __xfrm4_src_hash(saddr);
134 xfrm_state_hold(x0);
135 list_add_tail(&x0->bysrc, xfrm4_state_afinfo.state_bysrc+h);
136 wake_up(&km_waitq);
137 }
138 if (x0)
139 xfrm_state_hold(x0);
140 return x0;
141}
142
143static struct xfrm_state_afinfo xfrm4_state_afinfo = { 91static struct xfrm_state_afinfo xfrm4_state_afinfo = {
144 .family = AF_INET, 92 .family = AF_INET,
145 .init_flags = xfrm4_init_flags, 93 .init_flags = xfrm4_init_flags,
146 .init_tempsel = __xfrm4_init_tempsel, 94 .init_tempsel = __xfrm4_init_tempsel,
147 .state_lookup = __xfrm4_state_lookup, 95 .state_lookup = __xfrm4_state_lookup,
148 .state_lookup_byaddr = __xfrm4_state_lookup_byaddr, 96 .state_lookup_byaddr = __xfrm4_state_lookup_byaddr,
149 .find_acq = __xfrm4_find_acq,
150}; 97};
151 98
152void __init xfrm4_state_init(void) 99void __init xfrm4_state_init(void)
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index 6269584e610e..40fcaab7e028 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -101,61 +101,6 @@ __xfrm6_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto)
101 return NULL; 101 return NULL;
102} 102}
103 103
104static struct xfrm_state *
105__xfrm6_find_acq(u8 mode, u32 reqid, u8 proto,
106 xfrm_address_t *daddr, xfrm_address_t *saddr,
107 int create)
108{
109 struct xfrm_state *x, *x0;
110 unsigned h = __xfrm6_dst_hash(daddr);
111
112 x0 = NULL;
113
114 list_for_each_entry(x, xfrm6_state_afinfo.state_bydst+h, bydst) {
115 if (x->props.family == AF_INET6 &&
116 ipv6_addr_equal((struct in6_addr *)daddr, (struct in6_addr *)x->id.daddr.a6) &&
117 mode == x->props.mode &&
118 proto == x->id.proto &&
119 ipv6_addr_equal((struct in6_addr *)saddr, (struct in6_addr *)x->props.saddr.a6) &&
120 reqid == x->props.reqid &&
121 x->km.state == XFRM_STATE_ACQ &&
122 !x->id.spi) {
123 x0 = x;
124 break;
125 }
126 }
127 if (!x0 && create && (x0 = xfrm_state_alloc()) != NULL) {
128 ipv6_addr_copy((struct in6_addr *)x0->sel.daddr.a6,
129 (struct in6_addr *)daddr);
130 ipv6_addr_copy((struct in6_addr *)x0->sel.saddr.a6,
131 (struct in6_addr *)saddr);
132 x0->sel.prefixlen_d = 128;
133 x0->sel.prefixlen_s = 128;
134 ipv6_addr_copy((struct in6_addr *)x0->props.saddr.a6,
135 (struct in6_addr *)saddr);
136 x0->km.state = XFRM_STATE_ACQ;
137 ipv6_addr_copy((struct in6_addr *)x0->id.daddr.a6,
138 (struct in6_addr *)daddr);
139 x0->id.proto = proto;
140 x0->props.family = AF_INET6;
141 x0->props.mode = mode;
142 x0->props.reqid = reqid;
143 x0->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES;
144 xfrm_state_hold(x0);
145 x0->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ;
146 add_timer(&x0->timer);
147 xfrm_state_hold(x0);
148 list_add_tail(&x0->bydst, xfrm6_state_afinfo.state_bydst+h);
149 h = __xfrm6_src_hash(saddr);
150 xfrm_state_hold(x0);
151 list_add_tail(&x0->bysrc, xfrm6_state_afinfo.state_bysrc+h);
152 wake_up(&km_waitq);
153 }
154 if (x0)
155 xfrm_state_hold(x0);
156 return x0;
157}
158
159static int 104static int
160__xfrm6_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n) 105__xfrm6_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n)
161{ 106{
@@ -280,7 +225,6 @@ static struct xfrm_state_afinfo xfrm6_state_afinfo = {
280 .init_tempsel = __xfrm6_init_tempsel, 225 .init_tempsel = __xfrm6_init_tempsel,
281 .state_lookup = __xfrm6_state_lookup, 226 .state_lookup = __xfrm6_state_lookup,
282 .state_lookup_byaddr = __xfrm6_state_lookup_byaddr, 227 .state_lookup_byaddr = __xfrm6_state_lookup_byaddr,
283 .find_acq = __xfrm6_find_acq,
284 .tmpl_sort = __xfrm6_tmpl_sort, 228 .tmpl_sort = __xfrm6_tmpl_sort,
285 .state_sort = __xfrm6_state_sort, 229 .state_sort = __xfrm6_state_sort,
286}; 230};
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 622e92a08d0b..80f5f9dc2b9e 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -48,6 +48,18 @@ static struct list_head xfrm_state_bydst[XFRM_DST_HSIZE];
48static struct list_head xfrm_state_bysrc[XFRM_DST_HSIZE]; 48static struct list_head xfrm_state_bysrc[XFRM_DST_HSIZE];
49static struct list_head xfrm_state_byspi[XFRM_DST_HSIZE]; 49static struct list_head xfrm_state_byspi[XFRM_DST_HSIZE];
50 50
51static __inline__
52unsigned xfrm_dst_hash(xfrm_address_t *addr, unsigned short family)
53{
54 switch (family) {
55 case AF_INET:
56 return __xfrm4_dst_hash(addr);
57 case AF_INET6:
58 return __xfrm6_dst_hash(addr);
59 }
60 return 0;
61}
62
51DECLARE_WAIT_QUEUE_HEAD(km_waitq); 63DECLARE_WAIT_QUEUE_HEAD(km_waitq);
52EXPORT_SYMBOL(km_waitq); 64EXPORT_SYMBOL(km_waitq);
53 65
@@ -489,6 +501,89 @@ void xfrm_state_insert(struct xfrm_state *x)
489} 501}
490EXPORT_SYMBOL(xfrm_state_insert); 502EXPORT_SYMBOL(xfrm_state_insert);
491 503
504/* xfrm_state_lock is held */
505static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create)
506{
507 unsigned int h = xfrm_dst_hash(daddr, family);
508 struct xfrm_state *x;
509
510 list_for_each_entry(x, xfrm_state_bydst+h, bydst) {
511 if (x->props.reqid != reqid ||
512 x->props.mode != mode ||
513 x->props.family != family ||
514 x->km.state != XFRM_STATE_ACQ ||
515 x->id.spi != 0)
516 continue;
517
518 switch (family) {
519 case AF_INET:
520 if (x->id.daddr.a4 != daddr->a4 ||
521 x->props.saddr.a4 != saddr->a4)
522 continue;
523 break;
524 case AF_INET6:
525 if (!ipv6_addr_equal((struct in6_addr *)x->id.daddr.a6,
526 (struct in6_addr *)daddr) ||
527 !ipv6_addr_equal((struct in6_addr *)
528 x->props.saddr.a6,
529 (struct in6_addr *)saddr))
530 continue;
531 break;
532 };
533
534 xfrm_state_hold(x);
535 return x;
536 }
537
538 if (!create)
539 return NULL;
540
541 x = xfrm_state_alloc();
542 if (likely(x)) {
543 switch (family) {
544 case AF_INET:
545 x->sel.daddr.a4 = daddr->a4;
546 x->sel.saddr.a4 = saddr->a4;
547 x->sel.prefixlen_d = 32;
548 x->sel.prefixlen_s = 32;
549 x->props.saddr.a4 = saddr->a4;
550 x->id.daddr.a4 = daddr->a4;
551 break;
552
553 case AF_INET6:
554 ipv6_addr_copy((struct in6_addr *)x->sel.daddr.a6,
555 (struct in6_addr *)daddr);
556 ipv6_addr_copy((struct in6_addr *)x->sel.saddr.a6,
557 (struct in6_addr *)saddr);
558 x->sel.prefixlen_d = 128;
559 x->sel.prefixlen_s = 128;
560 ipv6_addr_copy((struct in6_addr *)x->props.saddr.a6,
561 (struct in6_addr *)saddr);
562 ipv6_addr_copy((struct in6_addr *)x->id.daddr.a6,
563 (struct in6_addr *)daddr);
564 break;
565 };
566
567 x->km.state = XFRM_STATE_ACQ;
568 x->id.proto = proto;
569 x->props.family = family;
570 x->props.mode = mode;
571 x->props.reqid = reqid;
572 x->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES;
573 xfrm_state_hold(x);
574 x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ;
575 add_timer(&x->timer);
576 xfrm_state_hold(x);
577 list_add_tail(&x->bydst, xfrm_state_bydst+h);
578 h = xfrm_src_hash(saddr, family);
579 xfrm_state_hold(x);
580 list_add_tail(&x->bysrc, xfrm_state_bysrc+h);
581 wake_up(&km_waitq);
582 }
583
584 return x;
585}
586
492static inline struct xfrm_state * 587static inline struct xfrm_state *
493__xfrm_state_locate(struct xfrm_state_afinfo *afinfo, struct xfrm_state *x, 588__xfrm_state_locate(struct xfrm_state_afinfo *afinfo, struct xfrm_state *x,
494 int use_spi) 589 int use_spi)
@@ -533,9 +628,9 @@ int xfrm_state_add(struct xfrm_state *x)
533 } 628 }
534 629
535 if (use_spi && !x1) 630 if (use_spi && !x1)
536 x1 = afinfo->find_acq( 631 x1 = __find_acq_core(family, x->props.mode, x->props.reqid,
537 x->props.mode, x->props.reqid, x->id.proto, 632 x->id.proto,
538 &x->id.daddr, &x->props.saddr, 0); 633 &x->id.daddr, &x->props.saddr, 0);
539 634
540 __xfrm_state_insert(x); 635 __xfrm_state_insert(x);
541 err = 0; 636 err = 0;
@@ -716,14 +811,11 @@ xfrm_find_acq(u8 mode, u32 reqid, u8 proto,
716 int create, unsigned short family) 811 int create, unsigned short family)
717{ 812{
718 struct xfrm_state *x; 813 struct xfrm_state *x;
719 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
720 if (!afinfo)
721 return NULL;
722 814
723 spin_lock_bh(&xfrm_state_lock); 815 spin_lock_bh(&xfrm_state_lock);
724 x = afinfo->find_acq(mode, reqid, proto, daddr, saddr, create); 816 x = __find_acq_core(family, mode, reqid, proto, daddr, saddr, create);
725 spin_unlock_bh(&xfrm_state_lock); 817 spin_unlock_bh(&xfrm_state_lock);
726 xfrm_state_put_afinfo(afinfo); 818
727 return x; 819 return x;
728} 820}
729EXPORT_SYMBOL(xfrm_find_acq); 821EXPORT_SYMBOL(xfrm_find_acq);
@@ -1181,7 +1273,6 @@ int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo)
1181 if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL)) 1273 if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL))
1182 err = -ENOBUFS; 1274 err = -ENOBUFS;
1183 else { 1275 else {
1184 afinfo->state_bydst = xfrm_state_bydst;
1185 afinfo->state_bysrc = xfrm_state_bysrc; 1276 afinfo->state_bysrc = xfrm_state_bysrc;
1186 afinfo->state_byspi = xfrm_state_byspi; 1277 afinfo->state_byspi = xfrm_state_byspi;
1187 xfrm_state_afinfo[afinfo->family] = afinfo; 1278 xfrm_state_afinfo[afinfo->family] = afinfo;
@@ -1206,7 +1297,6 @@ int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo)
1206 xfrm_state_afinfo[afinfo->family] = NULL; 1297 xfrm_state_afinfo[afinfo->family] = NULL;
1207 afinfo->state_byspi = NULL; 1298 afinfo->state_byspi = NULL;
1208 afinfo->state_bysrc = NULL; 1299 afinfo->state_bysrc = NULL;
1209 afinfo->state_bydst = NULL;
1210 } 1300 }
1211 } 1301 }
1212 write_unlock_bh(&xfrm_state_afinfo_lock); 1302 write_unlock_bh(&xfrm_state_afinfo_lock);