diff options
Diffstat (limited to 'net/xfrm/xfrm_state.c')
-rw-r--r-- | net/xfrm/xfrm_state.c | 110 |
1 files changed, 100 insertions, 10 deletions
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]; | |||
48 | static struct list_head xfrm_state_bysrc[XFRM_DST_HSIZE]; | 48 | static struct list_head xfrm_state_bysrc[XFRM_DST_HSIZE]; |
49 | static struct list_head xfrm_state_byspi[XFRM_DST_HSIZE]; | 49 | static struct list_head xfrm_state_byspi[XFRM_DST_HSIZE]; |
50 | 50 | ||
51 | static __inline__ | ||
52 | unsigned 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 | |||
51 | DECLARE_WAIT_QUEUE_HEAD(km_waitq); | 63 | DECLARE_WAIT_QUEUE_HEAD(km_waitq); |
52 | EXPORT_SYMBOL(km_waitq); | 64 | EXPORT_SYMBOL(km_waitq); |
53 | 65 | ||
@@ -489,6 +501,89 @@ void xfrm_state_insert(struct xfrm_state *x) | |||
489 | } | 501 | } |
490 | EXPORT_SYMBOL(xfrm_state_insert); | 502 | EXPORT_SYMBOL(xfrm_state_insert); |
491 | 503 | ||
504 | /* xfrm_state_lock is held */ | ||
505 | static 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 | |||
492 | static inline struct xfrm_state * | 587 | static 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 | } |
729 | EXPORT_SYMBOL(xfrm_find_acq); | 821 | EXPORT_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); |