diff options
| -rw-r--r-- | include/net/xfrm.h | 26 | ||||
| -rw-r--r-- | net/ipv4/xfrm4_state.c | 3 | ||||
| -rw-r--r-- | net/ipv6/xfrm6_state.c | 3 | ||||
| -rw-r--r-- | net/xfrm/xfrm_state.c | 21 |
4 files changed, 51 insertions, 2 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index aa3be68041be..88145e3348d0 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
| @@ -95,6 +95,7 @@ struct xfrm_state | |||
| 95 | { | 95 | { |
| 96 | /* Note: bydst is re-used during gc */ | 96 | /* Note: bydst is re-used during gc */ |
| 97 | struct list_head bydst; | 97 | struct list_head bydst; |
| 98 | struct list_head bysrc; | ||
| 98 | struct list_head byspi; | 99 | struct list_head byspi; |
| 99 | 100 | ||
| 100 | atomic_t refcnt; | 101 | atomic_t refcnt; |
| @@ -236,6 +237,7 @@ extern int __xfrm_state_delete(struct xfrm_state *x); | |||
| 236 | struct xfrm_state_afinfo { | 237 | struct xfrm_state_afinfo { |
| 237 | unsigned short family; | 238 | unsigned short family; |
| 238 | struct list_head *state_bydst; | 239 | struct list_head *state_bydst; |
| 240 | struct list_head *state_bysrc; | ||
| 239 | struct list_head *state_byspi; | 241 | struct list_head *state_byspi; |
| 240 | int (*init_flags)(struct xfrm_state *x); | 242 | int (*init_flags)(struct xfrm_state *x); |
| 241 | void (*init_tempsel)(struct xfrm_state *x, struct flowi *fl, | 243 | void (*init_tempsel)(struct xfrm_state *x, struct flowi *fl, |
| @@ -421,6 +423,30 @@ unsigned xfrm_dst_hash(xfrm_address_t *addr, unsigned short family) | |||
| 421 | } | 423 | } |
| 422 | 424 | ||
| 423 | static __inline__ | 425 | static __inline__ |
| 426 | unsigned __xfrm4_src_hash(xfrm_address_t *addr) | ||
| 427 | { | ||
| 428 | return __xfrm4_dst_hash(addr); | ||
| 429 | } | ||
| 430 | |||
| 431 | static __inline__ | ||
| 432 | unsigned __xfrm6_src_hash(xfrm_address_t *addr) | ||
| 433 | { | ||
| 434 | return __xfrm6_dst_hash(addr); | ||
| 435 | } | ||
| 436 | |||
| 437 | static __inline__ | ||
| 438 | unsigned xfrm_src_hash(xfrm_address_t *addr, unsigned short family) | ||
| 439 | { | ||
| 440 | switch (family) { | ||
| 441 | case AF_INET: | ||
| 442 | return __xfrm4_src_hash(addr); | ||
| 443 | case AF_INET6: | ||
| 444 | return __xfrm6_src_hash(addr); | ||
| 445 | } | ||
| 446 | return 0; | ||
| 447 | } | ||
| 448 | |||
| 449 | static __inline__ | ||
| 424 | unsigned __xfrm4_spi_hash(xfrm_address_t *addr, u32 spi, u8 proto) | 450 | unsigned __xfrm4_spi_hash(xfrm_address_t *addr, u32 spi, u8 proto) |
| 425 | { | 451 | { |
| 426 | unsigned h; | 452 | unsigned h; |
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c index 97b0c7589711..c56b258fad73 100644 --- a/net/ipv4/xfrm4_state.c +++ b/net/ipv4/xfrm4_state.c | |||
| @@ -122,6 +122,9 @@ __xfrm4_find_acq(u8 mode, u32 reqid, u8 proto, | |||
| 122 | add_timer(&x0->timer); | 122 | add_timer(&x0->timer); |
| 123 | xfrm_state_hold(x0); | 123 | xfrm_state_hold(x0); |
| 124 | list_add_tail(&x0->bydst, xfrm4_state_afinfo.state_bydst+h); | 124 | list_add_tail(&x0->bydst, xfrm4_state_afinfo.state_bydst+h); |
| 125 | h = __xfrm4_src_hash(saddr); | ||
| 126 | xfrm_state_hold(x0); | ||
| 127 | list_add_tail(&x0->bysrc, xfrm4_state_afinfo.state_bysrc+h); | ||
| 125 | wake_up(&km_waitq); | 128 | wake_up(&km_waitq); |
| 126 | } | 129 | } |
| 127 | if (x0) | 130 | if (x0) |
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c index a1a1f5476442..2fb07850449f 100644 --- a/net/ipv6/xfrm6_state.c +++ b/net/ipv6/xfrm6_state.c | |||
| @@ -126,6 +126,9 @@ __xfrm6_find_acq(u8 mode, u32 reqid, u8 proto, | |||
| 126 | add_timer(&x0->timer); | 126 | add_timer(&x0->timer); |
| 127 | xfrm_state_hold(x0); | 127 | xfrm_state_hold(x0); |
| 128 | list_add_tail(&x0->bydst, xfrm6_state_afinfo.state_bydst+h); | 128 | list_add_tail(&x0->bydst, xfrm6_state_afinfo.state_bydst+h); |
| 129 | h = __xfrm6_src_hash(saddr); | ||
| 130 | xfrm_state_hold(x0); | ||
| 131 | list_add_tail(&x0->bysrc, xfrm6_state_afinfo.state_bysrc+h); | ||
| 129 | wake_up(&km_waitq); | 132 | wake_up(&km_waitq); |
| 130 | } | 133 | } |
| 131 | if (x0) | 134 | if (x0) |
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 34c038cbdf46..2a9992894e69 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
| @@ -45,6 +45,7 @@ static DEFINE_SPINLOCK(xfrm_state_lock); | |||
| 45 | * Also, it can be used by ah/esp icmp error handler to find offending SA. | 45 | * Also, it can be used by ah/esp icmp error handler to find offending SA. |
| 46 | */ | 46 | */ |
| 47 | static struct list_head xfrm_state_bydst[XFRM_DST_HSIZE]; | 47 | 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_byspi[XFRM_DST_HSIZE]; | 49 | static struct list_head xfrm_state_byspi[XFRM_DST_HSIZE]; |
| 49 | 50 | ||
| 50 | DECLARE_WAIT_QUEUE_HEAD(km_waitq); | 51 | DECLARE_WAIT_QUEUE_HEAD(km_waitq); |
| @@ -200,6 +201,7 @@ struct xfrm_state *xfrm_state_alloc(void) | |||
| 200 | atomic_set(&x->refcnt, 1); | 201 | atomic_set(&x->refcnt, 1); |
| 201 | atomic_set(&x->tunnel_users, 0); | 202 | atomic_set(&x->tunnel_users, 0); |
| 202 | INIT_LIST_HEAD(&x->bydst); | 203 | INIT_LIST_HEAD(&x->bydst); |
| 204 | INIT_LIST_HEAD(&x->bysrc); | ||
| 203 | INIT_LIST_HEAD(&x->byspi); | 205 | INIT_LIST_HEAD(&x->byspi); |
| 204 | init_timer(&x->timer); | 206 | init_timer(&x->timer); |
| 205 | x->timer.function = xfrm_timer_handler; | 207 | x->timer.function = xfrm_timer_handler; |
| @@ -240,6 +242,8 @@ int __xfrm_state_delete(struct xfrm_state *x) | |||
| 240 | spin_lock(&xfrm_state_lock); | 242 | spin_lock(&xfrm_state_lock); |
| 241 | list_del(&x->bydst); | 243 | list_del(&x->bydst); |
| 242 | __xfrm_state_put(x); | 244 | __xfrm_state_put(x); |
| 245 | list_del(&x->bysrc); | ||
| 246 | __xfrm_state_put(x); | ||
| 243 | if (x->id.spi) { | 247 | if (x->id.spi) { |
| 244 | list_del(&x->byspi); | 248 | list_del(&x->byspi); |
| 245 | __xfrm_state_put(x); | 249 | __xfrm_state_put(x); |
| @@ -415,6 +419,8 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
| 415 | x->km.state = XFRM_STATE_ACQ; | 419 | x->km.state = XFRM_STATE_ACQ; |
| 416 | list_add_tail(&x->bydst, xfrm_state_bydst+h); | 420 | list_add_tail(&x->bydst, xfrm_state_bydst+h); |
| 417 | xfrm_state_hold(x); | 421 | xfrm_state_hold(x); |
| 422 | list_add_tail(&x->bysrc, xfrm_state_bysrc+h); | ||
| 423 | xfrm_state_hold(x); | ||
| 418 | if (x->id.spi) { | 424 | if (x->id.spi) { |
| 419 | h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family); | 425 | h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family); |
| 420 | list_add(&x->byspi, xfrm_state_byspi+h); | 426 | list_add(&x->byspi, xfrm_state_byspi+h); |
| @@ -448,11 +454,19 @@ static void __xfrm_state_insert(struct xfrm_state *x) | |||
| 448 | list_add(&x->bydst, xfrm_state_bydst+h); | 454 | list_add(&x->bydst, xfrm_state_bydst+h); |
| 449 | xfrm_state_hold(x); | 455 | xfrm_state_hold(x); |
| 450 | 456 | ||
| 451 | h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family); | 457 | h = xfrm_src_hash(&x->props.saddr, x->props.family); |
| 452 | 458 | ||
| 453 | list_add(&x->byspi, xfrm_state_byspi+h); | 459 | list_add(&x->bysrc, xfrm_state_bysrc+h); |
| 454 | xfrm_state_hold(x); | 460 | xfrm_state_hold(x); |
| 455 | 461 | ||
| 462 | if (xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY)) { | ||
| 463 | h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, | ||
| 464 | x->props.family); | ||
| 465 | |||
| 466 | list_add(&x->byspi, xfrm_state_byspi+h); | ||
| 467 | xfrm_state_hold(x); | ||
| 468 | } | ||
| 469 | |||
| 456 | if (!mod_timer(&x->timer, jiffies + HZ)) | 470 | if (!mod_timer(&x->timer, jiffies + HZ)) |
| 457 | xfrm_state_hold(x); | 471 | xfrm_state_hold(x); |
| 458 | 472 | ||
| @@ -1075,6 +1089,7 @@ int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo) | |||
| 1075 | err = -ENOBUFS; | 1089 | err = -ENOBUFS; |
| 1076 | else { | 1090 | else { |
| 1077 | afinfo->state_bydst = xfrm_state_bydst; | 1091 | afinfo->state_bydst = xfrm_state_bydst; |
| 1092 | afinfo->state_bysrc = xfrm_state_bysrc; | ||
| 1078 | afinfo->state_byspi = xfrm_state_byspi; | 1093 | afinfo->state_byspi = xfrm_state_byspi; |
| 1079 | xfrm_state_afinfo[afinfo->family] = afinfo; | 1094 | xfrm_state_afinfo[afinfo->family] = afinfo; |
| 1080 | } | 1095 | } |
| @@ -1097,6 +1112,7 @@ int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo) | |||
| 1097 | else { | 1112 | else { |
| 1098 | xfrm_state_afinfo[afinfo->family] = NULL; | 1113 | xfrm_state_afinfo[afinfo->family] = NULL; |
| 1099 | afinfo->state_byspi = NULL; | 1114 | afinfo->state_byspi = NULL; |
| 1115 | afinfo->state_bysrc = NULL; | ||
| 1100 | afinfo->state_bydst = NULL; | 1116 | afinfo->state_bydst = NULL; |
| 1101 | } | 1117 | } |
| 1102 | } | 1118 | } |
| @@ -1218,6 +1234,7 @@ void __init xfrm_state_init(void) | |||
| 1218 | 1234 | ||
| 1219 | for (i=0; i<XFRM_DST_HSIZE; i++) { | 1235 | for (i=0; i<XFRM_DST_HSIZE; i++) { |
| 1220 | INIT_LIST_HEAD(&xfrm_state_bydst[i]); | 1236 | INIT_LIST_HEAD(&xfrm_state_bydst[i]); |
| 1237 | INIT_LIST_HEAD(&xfrm_state_bysrc[i]); | ||
| 1221 | INIT_LIST_HEAD(&xfrm_state_byspi[i]); | 1238 | INIT_LIST_HEAD(&xfrm_state_byspi[i]); |
| 1222 | } | 1239 | } |
| 1223 | INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task, NULL); | 1240 | INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task, NULL); |
