diff options
-rw-r--r-- | include/linux/xfrm.h | 1 | ||||
-rw-r--r-- | include/net/xfrm.h | 2 | ||||
-rw-r--r-- | net/ipv4/xfrm4_state.c | 9 | ||||
-rw-r--r-- | net/ipv6/xfrm6_state.c | 21 | ||||
-rw-r--r-- | net/xfrm/xfrm_state.c | 37 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 59 |
6 files changed, 119 insertions, 10 deletions
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index 5154064b6d95..66343d3d4b91 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h | |||
@@ -234,6 +234,7 @@ enum xfrm_attr_type_t { | |||
234 | XFRMA_REPLAY_VAL, | 234 | XFRMA_REPLAY_VAL, |
235 | XFRMA_REPLAY_THRESH, | 235 | XFRMA_REPLAY_THRESH, |
236 | XFRMA_ETIMER_THRESH, | 236 | XFRMA_ETIMER_THRESH, |
237 | XFRMA_SRCADDR, /* xfrm_address_t */ | ||
237 | __XFRMA_MAX | 238 | __XFRMA_MAX |
238 | 239 | ||
239 | #define XFRMA_MAX (__XFRMA_MAX - 1) | 240 | #define XFRMA_MAX (__XFRMA_MAX - 1) |
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 88145e3348d0..d9c40e713184 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -244,6 +244,7 @@ struct xfrm_state_afinfo { | |||
244 | struct xfrm_tmpl *tmpl, | 244 | struct xfrm_tmpl *tmpl, |
245 | xfrm_address_t *daddr, xfrm_address_t *saddr); | 245 | xfrm_address_t *daddr, xfrm_address_t *saddr); |
246 | struct xfrm_state *(*state_lookup)(xfrm_address_t *daddr, u32 spi, u8 proto); | 246 | struct xfrm_state *(*state_lookup)(xfrm_address_t *daddr, u32 spi, u8 proto); |
247 | struct xfrm_state *(*state_lookup_byaddr)(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto); | ||
247 | struct xfrm_state *(*find_acq)(u8 mode, u32 reqid, u8 proto, | 248 | struct xfrm_state *(*find_acq)(u8 mode, u32 reqid, u8 proto, |
248 | xfrm_address_t *daddr, xfrm_address_t *saddr, | 249 | xfrm_address_t *daddr, xfrm_address_t *saddr, |
249 | int create); | 250 | int create); |
@@ -937,6 +938,7 @@ extern void xfrm_state_insert(struct xfrm_state *x); | |||
937 | extern int xfrm_state_add(struct xfrm_state *x); | 938 | extern int xfrm_state_add(struct xfrm_state *x); |
938 | extern int xfrm_state_update(struct xfrm_state *x); | 939 | extern int xfrm_state_update(struct xfrm_state *x); |
939 | extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family); | 940 | extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family); |
941 | extern struct xfrm_state *xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family); | ||
940 | extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq); | 942 | extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq); |
941 | extern int xfrm_state_delete(struct xfrm_state *x); | 943 | extern int xfrm_state_delete(struct xfrm_state *x); |
942 | extern void xfrm_state_flush(u8 proto); | 944 | extern void xfrm_state_flush(u8 proto); |
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c index c56b258fad73..616be131b4e3 100644 --- a/net/ipv4/xfrm4_state.c +++ b/net/ipv4/xfrm4_state.c | |||
@@ -80,6 +80,14 @@ __xfrm4_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto) | |||
80 | return NULL; | 80 | return NULL; |
81 | } | 81 | } |
82 | 82 | ||
83 | /* placeholder until ipv4's code is written */ | ||
84 | static struct xfrm_state * | ||
85 | __xfrm4_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, | ||
86 | u8 proto) | ||
87 | { | ||
88 | return NULL; | ||
89 | } | ||
90 | |||
83 | static struct xfrm_state * | 91 | static struct xfrm_state * |
84 | __xfrm4_find_acq(u8 mode, u32 reqid, u8 proto, | 92 | __xfrm4_find_acq(u8 mode, u32 reqid, u8 proto, |
85 | xfrm_address_t *daddr, xfrm_address_t *saddr, | 93 | xfrm_address_t *daddr, xfrm_address_t *saddr, |
@@ -137,6 +145,7 @@ static struct xfrm_state_afinfo xfrm4_state_afinfo = { | |||
137 | .init_flags = xfrm4_init_flags, | 145 | .init_flags = xfrm4_init_flags, |
138 | .init_tempsel = __xfrm4_init_tempsel, | 146 | .init_tempsel = __xfrm4_init_tempsel, |
139 | .state_lookup = __xfrm4_state_lookup, | 147 | .state_lookup = __xfrm4_state_lookup, |
148 | .state_lookup_byaddr = __xfrm4_state_lookup_byaddr, | ||
140 | .find_acq = __xfrm4_find_acq, | 149 | .find_acq = __xfrm4_find_acq, |
141 | }; | 150 | }; |
142 | 151 | ||
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c index 2fb07850449f..9c95b9d3e110 100644 --- a/net/ipv6/xfrm6_state.c +++ b/net/ipv6/xfrm6_state.c | |||
@@ -64,6 +64,26 @@ __xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl, | |||
64 | } | 64 | } |
65 | 65 | ||
66 | static struct xfrm_state * | 66 | static struct xfrm_state * |
67 | __xfrm6_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, | ||
68 | u8 proto) | ||
69 | { | ||
70 | struct xfrm_state *x = NULL; | ||
71 | unsigned h; | ||
72 | |||
73 | h = __xfrm6_src_hash(saddr); | ||
74 | list_for_each_entry(x, xfrm6_state_afinfo.state_bysrc+h, bysrc) { | ||
75 | if (x->props.family == AF_INET6 && | ||
76 | ipv6_addr_equal((struct in6_addr *)daddr, (struct in6_addr *)x->id.daddr.a6) && | ||
77 | ipv6_addr_equal((struct in6_addr *)saddr, (struct in6_addr *)x->props.saddr.a6) && | ||
78 | proto == x->id.proto) { | ||
79 | xfrm_state_hold(x); | ||
80 | return x; | ||
81 | } | ||
82 | } | ||
83 | return NULL; | ||
84 | } | ||
85 | |||
86 | static struct xfrm_state * | ||
67 | __xfrm6_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto) | 87 | __xfrm6_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto) |
68 | { | 88 | { |
69 | unsigned h = __xfrm6_spi_hash(daddr, spi, proto); | 89 | unsigned h = __xfrm6_spi_hash(daddr, spi, proto); |
@@ -140,6 +160,7 @@ static struct xfrm_state_afinfo xfrm6_state_afinfo = { | |||
140 | .family = AF_INET6, | 160 | .family = AF_INET6, |
141 | .init_tempsel = __xfrm6_init_tempsel, | 161 | .init_tempsel = __xfrm6_init_tempsel, |
142 | .state_lookup = __xfrm6_state_lookup, | 162 | .state_lookup = __xfrm6_state_lookup, |
163 | .state_lookup_byaddr = __xfrm6_state_lookup_byaddr, | ||
143 | .find_acq = __xfrm6_find_acq, | 164 | .find_acq = __xfrm6_find_acq, |
144 | }; | 165 | }; |
145 | 166 | ||
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 2a9992894e69..11f480b12952 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -487,6 +487,16 @@ void xfrm_state_insert(struct xfrm_state *x) | |||
487 | } | 487 | } |
488 | EXPORT_SYMBOL(xfrm_state_insert); | 488 | EXPORT_SYMBOL(xfrm_state_insert); |
489 | 489 | ||
490 | static inline struct xfrm_state * | ||
491 | __xfrm_state_locate(struct xfrm_state_afinfo *afinfo, struct xfrm_state *x, | ||
492 | int use_spi) | ||
493 | { | ||
494 | if (use_spi) | ||
495 | return afinfo->state_lookup(&x->id.daddr, x->id.spi, x->id.proto); | ||
496 | else | ||
497 | return afinfo->state_lookup_byaddr(&x->id.daddr, &x->props.saddr, x->id.proto); | ||
498 | } | ||
499 | |||
490 | static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq); | 500 | static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq); |
491 | 501 | ||
492 | int xfrm_state_add(struct xfrm_state *x) | 502 | int xfrm_state_add(struct xfrm_state *x) |
@@ -495,6 +505,7 @@ int xfrm_state_add(struct xfrm_state *x) | |||
495 | struct xfrm_state *x1; | 505 | struct xfrm_state *x1; |
496 | int family; | 506 | int family; |
497 | int err; | 507 | int err; |
508 | int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); | ||
498 | 509 | ||
499 | family = x->props.family; | 510 | family = x->props.family; |
500 | afinfo = xfrm_state_get_afinfo(family); | 511 | afinfo = xfrm_state_get_afinfo(family); |
@@ -503,7 +514,7 @@ int xfrm_state_add(struct xfrm_state *x) | |||
503 | 514 | ||
504 | spin_lock_bh(&xfrm_state_lock); | 515 | spin_lock_bh(&xfrm_state_lock); |
505 | 516 | ||
506 | x1 = afinfo->state_lookup(&x->id.daddr, x->id.spi, x->id.proto); | 517 | x1 = __xfrm_state_locate(afinfo, x, use_spi); |
507 | if (x1) { | 518 | if (x1) { |
508 | xfrm_state_put(x1); | 519 | xfrm_state_put(x1); |
509 | x1 = NULL; | 520 | x1 = NULL; |
@@ -511,7 +522,7 @@ int xfrm_state_add(struct xfrm_state *x) | |||
511 | goto out; | 522 | goto out; |
512 | } | 523 | } |
513 | 524 | ||
514 | if (x->km.seq) { | 525 | if (use_spi && x->km.seq) { |
515 | x1 = __xfrm_find_acq_byseq(x->km.seq); | 526 | x1 = __xfrm_find_acq_byseq(x->km.seq); |
516 | if (x1 && xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family)) { | 527 | if (x1 && xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family)) { |
517 | xfrm_state_put(x1); | 528 | xfrm_state_put(x1); |
@@ -519,7 +530,7 @@ int xfrm_state_add(struct xfrm_state *x) | |||
519 | } | 530 | } |
520 | } | 531 | } |
521 | 532 | ||
522 | if (!x1) | 533 | if (use_spi && !x1) |
523 | x1 = afinfo->find_acq( | 534 | x1 = afinfo->find_acq( |
524 | x->props.mode, x->props.reqid, x->id.proto, | 535 | x->props.mode, x->props.reqid, x->id.proto, |
525 | &x->id.daddr, &x->props.saddr, 0); | 536 | &x->id.daddr, &x->props.saddr, 0); |
@@ -548,13 +559,14 @@ int xfrm_state_update(struct xfrm_state *x) | |||
548 | struct xfrm_state_afinfo *afinfo; | 559 | struct xfrm_state_afinfo *afinfo; |
549 | struct xfrm_state *x1; | 560 | struct xfrm_state *x1; |
550 | int err; | 561 | int err; |
562 | int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); | ||
551 | 563 | ||
552 | afinfo = xfrm_state_get_afinfo(x->props.family); | 564 | afinfo = xfrm_state_get_afinfo(x->props.family); |
553 | if (unlikely(afinfo == NULL)) | 565 | if (unlikely(afinfo == NULL)) |
554 | return -EAFNOSUPPORT; | 566 | return -EAFNOSUPPORT; |
555 | 567 | ||
556 | spin_lock_bh(&xfrm_state_lock); | 568 | spin_lock_bh(&xfrm_state_lock); |
557 | x1 = afinfo->state_lookup(&x->id.daddr, x->id.spi, x->id.proto); | 569 | x1 = __xfrm_state_locate(afinfo, x, use_spi); |
558 | 570 | ||
559 | err = -ESRCH; | 571 | err = -ESRCH; |
560 | if (!x1) | 572 | if (!x1) |
@@ -675,6 +687,23 @@ xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, | |||
675 | EXPORT_SYMBOL(xfrm_state_lookup); | 687 | EXPORT_SYMBOL(xfrm_state_lookup); |
676 | 688 | ||
677 | struct xfrm_state * | 689 | struct xfrm_state * |
690 | xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, | ||
691 | u8 proto, unsigned short family) | ||
692 | { | ||
693 | struct xfrm_state *x; | ||
694 | struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); | ||
695 | if (!afinfo) | ||
696 | return NULL; | ||
697 | |||
698 | spin_lock_bh(&xfrm_state_lock); | ||
699 | x = afinfo->state_lookup_byaddr(daddr, saddr, proto); | ||
700 | spin_unlock_bh(&xfrm_state_lock); | ||
701 | xfrm_state_put_afinfo(afinfo); | ||
702 | return x; | ||
703 | } | ||
704 | EXPORT_SYMBOL(xfrm_state_lookup_byaddr); | ||
705 | |||
706 | struct xfrm_state * | ||
678 | xfrm_find_acq(u8 mode, u32 reqid, u8 proto, | 707 | xfrm_find_acq(u8 mode, u32 reqid, u8 proto, |
679 | xfrm_address_t *daddr, xfrm_address_t *saddr, | 708 | xfrm_address_t *daddr, xfrm_address_t *saddr, |
680 | int create, unsigned short family) | 709 | int create, unsigned short family) |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 41f3d51ffc33..b5f8ab71aa54 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -87,6 +87,22 @@ static int verify_encap_tmpl(struct rtattr **xfrma) | |||
87 | return 0; | 87 | return 0; |
88 | } | 88 | } |
89 | 89 | ||
90 | static int verify_one_addr(struct rtattr **xfrma, enum xfrm_attr_type_t type, | ||
91 | xfrm_address_t **addrp) | ||
92 | { | ||
93 | struct rtattr *rt = xfrma[type - 1]; | ||
94 | |||
95 | if (!rt) | ||
96 | return 0; | ||
97 | |||
98 | if ((rt->rta_len - sizeof(*rt)) < sizeof(**addrp)) | ||
99 | return -EINVAL; | ||
100 | |||
101 | if (addrp) | ||
102 | *addrp = RTA_DATA(rt); | ||
103 | |||
104 | return 0; | ||
105 | } | ||
90 | 106 | ||
91 | static inline int verify_sec_ctx_len(struct rtattr **xfrma) | 107 | static inline int verify_sec_ctx_len(struct rtattr **xfrma) |
92 | { | 108 | { |
@@ -418,16 +434,48 @@ out: | |||
418 | return err; | 434 | return err; |
419 | } | 435 | } |
420 | 436 | ||
437 | static struct xfrm_state *xfrm_user_state_lookup(struct xfrm_usersa_id *p, | ||
438 | struct rtattr **xfrma, | ||
439 | int *errp) | ||
440 | { | ||
441 | struct xfrm_state *x = NULL; | ||
442 | int err; | ||
443 | |||
444 | if (xfrm_id_proto_match(p->proto, IPSEC_PROTO_ANY)) { | ||
445 | err = -ESRCH; | ||
446 | x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family); | ||
447 | } else { | ||
448 | xfrm_address_t *saddr = NULL; | ||
449 | |||
450 | err = verify_one_addr(xfrma, XFRMA_SRCADDR, &saddr); | ||
451 | if (err) | ||
452 | goto out; | ||
453 | |||
454 | if (!saddr) { | ||
455 | err = -EINVAL; | ||
456 | goto out; | ||
457 | } | ||
458 | |||
459 | x = xfrm_state_lookup_byaddr(&p->daddr, saddr, p->proto, | ||
460 | p->family); | ||
461 | } | ||
462 | |||
463 | out: | ||
464 | if (!x && errp) | ||
465 | *errp = err; | ||
466 | return x; | ||
467 | } | ||
468 | |||
421 | static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 469 | static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) |
422 | { | 470 | { |
423 | struct xfrm_state *x; | 471 | struct xfrm_state *x; |
424 | int err; | 472 | int err = -ESRCH; |
425 | struct km_event c; | 473 | struct km_event c; |
426 | struct xfrm_usersa_id *p = NLMSG_DATA(nlh); | 474 | struct xfrm_usersa_id *p = NLMSG_DATA(nlh); |
427 | 475 | ||
428 | x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family); | 476 | x = xfrm_user_state_lookup(p, (struct rtattr **)xfrma, &err); |
429 | if (x == NULL) | 477 | if (x == NULL) |
430 | return -ESRCH; | 478 | return err; |
431 | 479 | ||
432 | if ((err = security_xfrm_state_delete(x)) != 0) | 480 | if ((err = security_xfrm_state_delete(x)) != 0) |
433 | goto out; | 481 | goto out; |
@@ -578,10 +626,9 @@ static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | |||
578 | struct xfrm_usersa_id *p = NLMSG_DATA(nlh); | 626 | struct xfrm_usersa_id *p = NLMSG_DATA(nlh); |
579 | struct xfrm_state *x; | 627 | struct xfrm_state *x; |
580 | struct sk_buff *resp_skb; | 628 | struct sk_buff *resp_skb; |
581 | int err; | 629 | int err = -ESRCH; |
582 | 630 | ||
583 | x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family); | 631 | x = xfrm_user_state_lookup(p, (struct rtattr **)xfrma, &err); |
584 | err = -ESRCH; | ||
585 | if (x == NULL) | 632 | if (x == NULL) |
586 | goto out_noput; | 633 | goto out_noput; |
587 | 634 | ||