diff options
-rw-r--r-- | include/linux/xfrm.h | 7 | ||||
-rw-r--r-- | include/net/xfrm.h | 45 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 252 |
3 files changed, 260 insertions, 44 deletions
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index 4009f4445fa9..492fb9818747 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h | |||
@@ -104,6 +104,13 @@ struct xfrm_stats { | |||
104 | 104 | ||
105 | enum | 105 | enum |
106 | { | 106 | { |
107 | XFRM_POLICY_TYPE_MAIN = 0, | ||
108 | XFRM_POLICY_TYPE_SUB = 1, | ||
109 | XFRM_POLICY_TYPE_MAX = 2 | ||
110 | }; | ||
111 | |||
112 | enum | ||
113 | { | ||
107 | XFRM_POLICY_IN = 0, | 114 | XFRM_POLICY_IN = 0, |
108 | XFRM_POLICY_OUT = 1, | 115 | XFRM_POLICY_OUT = 1, |
109 | XFRM_POLICY_FWD = 2, | 116 | XFRM_POLICY_FWD = 2, |
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 0b223eed4c9b..4655ca25f808 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -341,6 +341,7 @@ struct xfrm_policy | |||
341 | atomic_t refcnt; | 341 | atomic_t refcnt; |
342 | struct timer_list timer; | 342 | struct timer_list timer; |
343 | 343 | ||
344 | u8 type; | ||
344 | u32 priority; | 345 | u32 priority; |
345 | u32 index; | 346 | u32 index; |
346 | struct xfrm_selector selector; | 347 | struct xfrm_selector selector; |
@@ -389,6 +390,19 @@ extern int xfrm_unregister_km(struct xfrm_mgr *km); | |||
389 | 390 | ||
390 | 391 | ||
391 | extern struct xfrm_policy *xfrm_policy_list[XFRM_POLICY_MAX*2]; | 392 | extern struct xfrm_policy *xfrm_policy_list[XFRM_POLICY_MAX*2]; |
393 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
394 | extern struct xfrm_policy *xfrm_policy_list_sub[XFRM_POLICY_MAX*2]; | ||
395 | |||
396 | static inline int xfrm_policy_lists_empty(int dir) | ||
397 | { | ||
398 | return (!xfrm_policy_list[dir] && !xfrm_policy_list_sub[dir]); | ||
399 | } | ||
400 | #else | ||
401 | static inline int xfrm_policy_lists_empty(int dir) | ||
402 | { | ||
403 | return (!xfrm_policy_list[dir]); | ||
404 | } | ||
405 | #endif | ||
392 | 406 | ||
393 | static inline void xfrm_pol_hold(struct xfrm_policy *policy) | 407 | static inline void xfrm_pol_hold(struct xfrm_policy *policy) |
394 | { | 408 | { |
@@ -404,6 +418,20 @@ static inline void xfrm_pol_put(struct xfrm_policy *policy) | |||
404 | __xfrm_policy_destroy(policy); | 418 | __xfrm_policy_destroy(policy); |
405 | } | 419 | } |
406 | 420 | ||
421 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
422 | static inline void xfrm_pols_put(struct xfrm_policy **pols, int npols) | ||
423 | { | ||
424 | int i; | ||
425 | for (i = npols - 1; i >= 0; --i) | ||
426 | xfrm_pol_put(pols[i]); | ||
427 | } | ||
428 | #else | ||
429 | static inline void xfrm_pols_put(struct xfrm_policy **pols, int npols) | ||
430 | { | ||
431 | xfrm_pol_put(pols[0]); | ||
432 | } | ||
433 | #endif | ||
434 | |||
407 | #define XFRM_DST_HSIZE 1024 | 435 | #define XFRM_DST_HSIZE 1024 |
408 | 436 | ||
409 | static __inline__ | 437 | static __inline__ |
@@ -737,8 +765,8 @@ static inline int xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *sk | |||
737 | { | 765 | { |
738 | if (sk && sk->sk_policy[XFRM_POLICY_IN]) | 766 | if (sk && sk->sk_policy[XFRM_POLICY_IN]) |
739 | return __xfrm_policy_check(sk, dir, skb, family); | 767 | return __xfrm_policy_check(sk, dir, skb, family); |
740 | 768 | ||
741 | return (!xfrm_policy_list[dir] && !skb->sp) || | 769 | return (xfrm_policy_lists_empty(dir) && !skb->sp) || |
742 | (skb->dst->flags & DST_NOPOLICY) || | 770 | (skb->dst->flags & DST_NOPOLICY) || |
743 | __xfrm_policy_check(sk, dir, skb, family); | 771 | __xfrm_policy_check(sk, dir, skb, family); |
744 | } | 772 | } |
@@ -758,7 +786,7 @@ extern int __xfrm_route_forward(struct sk_buff *skb, unsigned short family); | |||
758 | 786 | ||
759 | static inline int xfrm_route_forward(struct sk_buff *skb, unsigned short family) | 787 | static inline int xfrm_route_forward(struct sk_buff *skb, unsigned short family) |
760 | { | 788 | { |
761 | return !xfrm_policy_list[XFRM_POLICY_OUT] || | 789 | return xfrm_policy_lists_empty(XFRM_POLICY_OUT) || |
762 | (skb->dst->flags & DST_NOXFRM) || | 790 | (skb->dst->flags & DST_NOXFRM) || |
763 | __xfrm_route_forward(skb, family); | 791 | __xfrm_route_forward(skb, family); |
764 | } | 792 | } |
@@ -1023,18 +1051,19 @@ static inline int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, unsig | |||
1023 | #endif | 1051 | #endif |
1024 | 1052 | ||
1025 | struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp); | 1053 | struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp); |
1026 | extern int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), void *); | 1054 | extern int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), void *); |
1027 | int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); | 1055 | int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); |
1028 | struct xfrm_policy *xfrm_policy_bysel_ctx(int dir, struct xfrm_selector *sel, | 1056 | struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir, |
1057 | struct xfrm_selector *sel, | ||
1029 | struct xfrm_sec_ctx *ctx, int delete); | 1058 | struct xfrm_sec_ctx *ctx, int delete); |
1030 | struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete); | 1059 | struct xfrm_policy *xfrm_policy_byid(u8, int dir, u32 id, int delete); |
1031 | void xfrm_policy_flush(void); | 1060 | void xfrm_policy_flush(u8 type); |
1032 | u32 xfrm_get_acqseq(void); | 1061 | u32 xfrm_get_acqseq(void); |
1033 | void xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi); | 1062 | void xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi); |
1034 | struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto, | 1063 | struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto, |
1035 | xfrm_address_t *daddr, xfrm_address_t *saddr, | 1064 | xfrm_address_t *daddr, xfrm_address_t *saddr, |
1036 | int create, unsigned short family); | 1065 | int create, unsigned short family); |
1037 | extern void xfrm_policy_flush(void); | 1066 | extern void xfrm_policy_flush(u8 type); |
1038 | extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol); | 1067 | extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol); |
1039 | extern int xfrm_flush_bundles(void); | 1068 | extern int xfrm_flush_bundles(void); |
1040 | extern void xfrm_flush_all_bundles(void); | 1069 | extern void xfrm_flush_all_bundles(void); |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index d125a2649037..96de6c76ed57 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -32,6 +32,24 @@ static DEFINE_RWLOCK(xfrm_policy_lock); | |||
32 | 32 | ||
33 | struct xfrm_policy *xfrm_policy_list[XFRM_POLICY_MAX*2]; | 33 | struct xfrm_policy *xfrm_policy_list[XFRM_POLICY_MAX*2]; |
34 | EXPORT_SYMBOL(xfrm_policy_list); | 34 | EXPORT_SYMBOL(xfrm_policy_list); |
35 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
36 | struct xfrm_policy *xfrm_policy_list_sub[XFRM_POLICY_MAX*2]; | ||
37 | EXPORT_SYMBOL(xfrm_policy_list_sub); | ||
38 | |||
39 | #define XFRM_POLICY_LISTS(type) \ | ||
40 | ((type == XFRM_POLICY_TYPE_SUB) ? xfrm_policy_list_sub : \ | ||
41 | xfrm_policy_list) | ||
42 | #define XFRM_POLICY_LISTHEAD(type, dir) \ | ||
43 | ((type == XFRM_POLICY_TYPE_SUB) ? xfrm_policy_list_sub[dir] : \ | ||
44 | xfrm_policy_list[dir]) | ||
45 | #define XFRM_POLICY_LISTHEADP(type, dir) \ | ||
46 | ((type == XFRM_POLICY_TYPE_SUB) ? &xfrm_policy_list_sub[dir] : \ | ||
47 | &xfrm_policy_list[dir]) | ||
48 | #else | ||
49 | #define XFRM_POLICY_LISTS(type) xfrm_policy_list | ||
50 | #define XFRM_POLICY_LISTHEAD(type, dif) xfrm_policy_list[dir] | ||
51 | #define XFRM_POLICY_LISTHEADP(type, dif) &xfrm_policy_list[dir] | ||
52 | #endif | ||
35 | 53 | ||
36 | static DEFINE_RWLOCK(xfrm_policy_afinfo_lock); | 54 | static DEFINE_RWLOCK(xfrm_policy_afinfo_lock); |
37 | static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO]; | 55 | static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO]; |
@@ -397,7 +415,7 @@ static void xfrm_policy_kill(struct xfrm_policy *policy) | |||
397 | 415 | ||
398 | /* Generate new index... KAME seems to generate them ordered by cost | 416 | /* Generate new index... KAME seems to generate them ordered by cost |
399 | * of an absolute inpredictability of ordering of rules. This will not pass. */ | 417 | * of an absolute inpredictability of ordering of rules. This will not pass. */ |
400 | static u32 xfrm_gen_index(int dir) | 418 | static u32 xfrm_gen_index(u8 type, int dir) |
401 | { | 419 | { |
402 | u32 idx; | 420 | u32 idx; |
403 | struct xfrm_policy *p; | 421 | struct xfrm_policy *p; |
@@ -408,7 +426,7 @@ static u32 xfrm_gen_index(int dir) | |||
408 | idx_generator += 8; | 426 | idx_generator += 8; |
409 | if (idx == 0) | 427 | if (idx == 0) |
410 | idx = 8; | 428 | idx = 8; |
411 | for (p = xfrm_policy_list[dir]; p; p = p->next) { | 429 | for (p = XFRM_POLICY_LISTHEAD(type, dir); p; p = p->next) { |
412 | if (p->index == idx) | 430 | if (p->index == idx) |
413 | break; | 431 | break; |
414 | } | 432 | } |
@@ -425,7 +443,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
425 | struct dst_entry *gc_list; | 443 | struct dst_entry *gc_list; |
426 | 444 | ||
427 | write_lock_bh(&xfrm_policy_lock); | 445 | write_lock_bh(&xfrm_policy_lock); |
428 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL;) { | 446 | for (p = XFRM_POLICY_LISTHEADP(policy->type, dir); (pol=*p)!=NULL;) { |
429 | if (!delpol && memcmp(&policy->selector, &pol->selector, sizeof(pol->selector)) == 0 && | 447 | if (!delpol && memcmp(&policy->selector, &pol->selector, sizeof(pol->selector)) == 0 && |
430 | xfrm_sec_ctx_match(pol->security, policy->security)) { | 448 | xfrm_sec_ctx_match(pol->security, policy->security)) { |
431 | if (excl) { | 449 | if (excl) { |
@@ -452,7 +470,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
452 | policy->next = *p; | 470 | policy->next = *p; |
453 | *p = policy; | 471 | *p = policy; |
454 | atomic_inc(&flow_cache_genid); | 472 | atomic_inc(&flow_cache_genid); |
455 | policy->index = delpol ? delpol->index : xfrm_gen_index(dir); | 473 | policy->index = delpol ? delpol->index : xfrm_gen_index(policy->type, dir); |
456 | policy->curlft.add_time = (unsigned long)xtime.tv_sec; | 474 | policy->curlft.add_time = (unsigned long)xtime.tv_sec; |
457 | policy->curlft.use_time = 0; | 475 | policy->curlft.use_time = 0; |
458 | if (!mod_timer(&policy->timer, jiffies + HZ)) | 476 | if (!mod_timer(&policy->timer, jiffies + HZ)) |
@@ -493,13 +511,14 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
493 | } | 511 | } |
494 | EXPORT_SYMBOL(xfrm_policy_insert); | 512 | EXPORT_SYMBOL(xfrm_policy_insert); |
495 | 513 | ||
496 | struct xfrm_policy *xfrm_policy_bysel_ctx(int dir, struct xfrm_selector *sel, | 514 | struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir, |
515 | struct xfrm_selector *sel, | ||
497 | struct xfrm_sec_ctx *ctx, int delete) | 516 | struct xfrm_sec_ctx *ctx, int delete) |
498 | { | 517 | { |
499 | struct xfrm_policy *pol, **p; | 518 | struct xfrm_policy *pol, **p; |
500 | 519 | ||
501 | write_lock_bh(&xfrm_policy_lock); | 520 | write_lock_bh(&xfrm_policy_lock); |
502 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) { | 521 | for (p = XFRM_POLICY_LISTHEADP(type, dir); (pol=*p)!=NULL; p = &pol->next) { |
503 | if ((memcmp(sel, &pol->selector, sizeof(*sel)) == 0) && | 522 | if ((memcmp(sel, &pol->selector, sizeof(*sel)) == 0) && |
504 | (xfrm_sec_ctx_match(ctx, pol->security))) { | 523 | (xfrm_sec_ctx_match(ctx, pol->security))) { |
505 | xfrm_pol_hold(pol); | 524 | xfrm_pol_hold(pol); |
@@ -518,12 +537,12 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(int dir, struct xfrm_selector *sel, | |||
518 | } | 537 | } |
519 | EXPORT_SYMBOL(xfrm_policy_bysel_ctx); | 538 | EXPORT_SYMBOL(xfrm_policy_bysel_ctx); |
520 | 539 | ||
521 | struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete) | 540 | struct xfrm_policy *xfrm_policy_byid(u8 type, int dir, u32 id, int delete) |
522 | { | 541 | { |
523 | struct xfrm_policy *pol, **p; | 542 | struct xfrm_policy *pol, **p; |
524 | 543 | ||
525 | write_lock_bh(&xfrm_policy_lock); | 544 | write_lock_bh(&xfrm_policy_lock); |
526 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) { | 545 | for (p = XFRM_POLICY_LISTHEADP(type, dir); (pol=*p)!=NULL; p = &pol->next) { |
527 | if (pol->index == id) { | 546 | if (pol->index == id) { |
528 | xfrm_pol_hold(pol); | 547 | xfrm_pol_hold(pol); |
529 | if (delete) | 548 | if (delete) |
@@ -541,15 +560,16 @@ struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete) | |||
541 | } | 560 | } |
542 | EXPORT_SYMBOL(xfrm_policy_byid); | 561 | EXPORT_SYMBOL(xfrm_policy_byid); |
543 | 562 | ||
544 | void xfrm_policy_flush(void) | 563 | void xfrm_policy_flush(u8 type) |
545 | { | 564 | { |
546 | struct xfrm_policy *xp; | 565 | struct xfrm_policy *xp; |
566 | struct xfrm_policy **p_list = XFRM_POLICY_LISTS(type); | ||
547 | int dir; | 567 | int dir; |
548 | 568 | ||
549 | write_lock_bh(&xfrm_policy_lock); | 569 | write_lock_bh(&xfrm_policy_lock); |
550 | for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { | 570 | for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { |
551 | while ((xp = xfrm_policy_list[dir]) != NULL) { | 571 | while ((xp = p_list[dir]) != NULL) { |
552 | xfrm_policy_list[dir] = xp->next; | 572 | p_list[dir] = xp->next; |
553 | write_unlock_bh(&xfrm_policy_lock); | 573 | write_unlock_bh(&xfrm_policy_lock); |
554 | 574 | ||
555 | xfrm_policy_kill(xp); | 575 | xfrm_policy_kill(xp); |
@@ -562,7 +582,7 @@ void xfrm_policy_flush(void) | |||
562 | } | 582 | } |
563 | EXPORT_SYMBOL(xfrm_policy_flush); | 583 | EXPORT_SYMBOL(xfrm_policy_flush); |
564 | 584 | ||
565 | int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), | 585 | int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), |
566 | void *data) | 586 | void *data) |
567 | { | 587 | { |
568 | struct xfrm_policy *xp; | 588 | struct xfrm_policy *xp; |
@@ -572,7 +592,7 @@ int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), | |||
572 | 592 | ||
573 | read_lock_bh(&xfrm_policy_lock); | 593 | read_lock_bh(&xfrm_policy_lock); |
574 | for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { | 594 | for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { |
575 | for (xp = xfrm_policy_list[dir]; xp; xp = xp->next) | 595 | for (xp = XFRM_POLICY_LISTHEAD(type, dir); xp; xp = xp->next) |
576 | count++; | 596 | count++; |
577 | } | 597 | } |
578 | 598 | ||
@@ -582,7 +602,7 @@ int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), | |||
582 | } | 602 | } |
583 | 603 | ||
584 | for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { | 604 | for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { |
585 | for (xp = xfrm_policy_list[dir]; xp; xp = xp->next) { | 605 | for (xp = XFRM_POLICY_LISTHEAD(type, dir); xp; xp = xp->next) { |
586 | error = func(xp, dir%XFRM_POLICY_MAX, --count, data); | 606 | error = func(xp, dir%XFRM_POLICY_MAX, --count, data); |
587 | if (error) | 607 | if (error) |
588 | goto out; | 608 | goto out; |
@@ -597,13 +617,13 @@ EXPORT_SYMBOL(xfrm_policy_walk); | |||
597 | 617 | ||
598 | /* Find policy to apply to this flow. */ | 618 | /* Find policy to apply to this flow. */ |
599 | 619 | ||
600 | static void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, | 620 | static struct xfrm_policy *xfrm_policy_lookup_bytype(u8 type, struct flowi *fl, |
601 | void **objp, atomic_t **obj_refp) | 621 | u16 family, u8 dir) |
602 | { | 622 | { |
603 | struct xfrm_policy *pol; | 623 | struct xfrm_policy *pol; |
604 | 624 | ||
605 | read_lock_bh(&xfrm_policy_lock); | 625 | read_lock_bh(&xfrm_policy_lock); |
606 | for (pol = xfrm_policy_list[dir]; pol; pol = pol->next) { | 626 | for (pol = XFRM_POLICY_LISTHEAD(type, dir); pol; pol = pol->next) { |
607 | struct xfrm_selector *sel = &pol->selector; | 627 | struct xfrm_selector *sel = &pol->selector; |
608 | int match; | 628 | int match; |
609 | 629 | ||
@@ -620,6 +640,25 @@ static void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, | |||
620 | } | 640 | } |
621 | } | 641 | } |
622 | read_unlock_bh(&xfrm_policy_lock); | 642 | read_unlock_bh(&xfrm_policy_lock); |
643 | |||
644 | return pol; | ||
645 | } | ||
646 | |||
647 | static void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, | ||
648 | void **objp, atomic_t **obj_refp) | ||
649 | { | ||
650 | struct xfrm_policy *pol; | ||
651 | |||
652 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
653 | pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_SUB, fl, family, dir); | ||
654 | if (pol) | ||
655 | goto end; | ||
656 | #endif | ||
657 | pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, fl, family, dir); | ||
658 | |||
659 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
660 | end: | ||
661 | #endif | ||
623 | if ((*objp = (void *) pol) != NULL) | 662 | if ((*objp = (void *) pol) != NULL) |
624 | *obj_refp = &pol->refcnt; | 663 | *obj_refp = &pol->refcnt; |
625 | } | 664 | } |
@@ -665,8 +704,10 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struc | |||
665 | 704 | ||
666 | static void __xfrm_policy_link(struct xfrm_policy *pol, int dir) | 705 | static void __xfrm_policy_link(struct xfrm_policy *pol, int dir) |
667 | { | 706 | { |
668 | pol->next = xfrm_policy_list[dir]; | 707 | struct xfrm_policy **p_list = XFRM_POLICY_LISTS(pol->type); |
669 | xfrm_policy_list[dir] = pol; | 708 | |
709 | pol->next = p_list[dir]; | ||
710 | p_list[dir] = pol; | ||
670 | xfrm_pol_hold(pol); | 711 | xfrm_pol_hold(pol); |
671 | } | 712 | } |
672 | 713 | ||
@@ -675,7 +716,7 @@ static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, | |||
675 | { | 716 | { |
676 | struct xfrm_policy **polp; | 717 | struct xfrm_policy **polp; |
677 | 718 | ||
678 | for (polp = &xfrm_policy_list[dir]; | 719 | for (polp = XFRM_POLICY_LISTHEADP(pol->type, dir); |
679 | *polp != NULL; polp = &(*polp)->next) { | 720 | *polp != NULL; polp = &(*polp)->next) { |
680 | if (*polp == pol) { | 721 | if (*polp == pol) { |
681 | *polp = pol->next; | 722 | *polp = pol->next; |
@@ -704,12 +745,17 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) | |||
704 | { | 745 | { |
705 | struct xfrm_policy *old_pol; | 746 | struct xfrm_policy *old_pol; |
706 | 747 | ||
748 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
749 | if (pol && pol->type != XFRM_POLICY_TYPE_MAIN) | ||
750 | return -EINVAL; | ||
751 | #endif | ||
752 | |||
707 | write_lock_bh(&xfrm_policy_lock); | 753 | write_lock_bh(&xfrm_policy_lock); |
708 | old_pol = sk->sk_policy[dir]; | 754 | old_pol = sk->sk_policy[dir]; |
709 | sk->sk_policy[dir] = pol; | 755 | sk->sk_policy[dir] = pol; |
710 | if (pol) { | 756 | if (pol) { |
711 | pol->curlft.add_time = (unsigned long)xtime.tv_sec; | 757 | pol->curlft.add_time = (unsigned long)xtime.tv_sec; |
712 | pol->index = xfrm_gen_index(XFRM_POLICY_MAX+dir); | 758 | pol->index = xfrm_gen_index(pol->type, XFRM_POLICY_MAX+dir); |
713 | __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir); | 759 | __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir); |
714 | } | 760 | } |
715 | if (old_pol) | 761 | if (old_pol) |
@@ -738,6 +784,7 @@ static struct xfrm_policy *clone_policy(struct xfrm_policy *old, int dir) | |||
738 | newp->flags = old->flags; | 784 | newp->flags = old->flags; |
739 | newp->xfrm_nr = old->xfrm_nr; | 785 | newp->xfrm_nr = old->xfrm_nr; |
740 | newp->index = old->index; | 786 | newp->index = old->index; |
787 | newp->type = old->type; | ||
741 | memcpy(newp->xfrm_vec, old->xfrm_vec, | 788 | memcpy(newp->xfrm_vec, old->xfrm_vec, |
742 | newp->xfrm_nr*sizeof(struct xfrm_tmpl)); | 789 | newp->xfrm_nr*sizeof(struct xfrm_tmpl)); |
743 | write_lock_bh(&xfrm_policy_lock); | 790 | write_lock_bh(&xfrm_policy_lock); |
@@ -764,9 +811,9 @@ int __xfrm_sk_clone_policy(struct sock *sk) | |||
764 | /* Resolve list of templates for the flow, given policy. */ | 811 | /* Resolve list of templates for the flow, given policy. */ |
765 | 812 | ||
766 | static int | 813 | static int |
767 | xfrm_tmpl_resolve(struct xfrm_policy *policy, struct flowi *fl, | 814 | xfrm_tmpl_resolve_one(struct xfrm_policy *policy, struct flowi *fl, |
768 | struct xfrm_state **xfrm, | 815 | struct xfrm_state **xfrm, |
769 | unsigned short family) | 816 | unsigned short family) |
770 | { | 817 | { |
771 | int nx; | 818 | int nx; |
772 | int i, error; | 819 | int i, error; |
@@ -809,6 +856,38 @@ fail: | |||
809 | return error; | 856 | return error; |
810 | } | 857 | } |
811 | 858 | ||
859 | static int | ||
860 | xfrm_tmpl_resolve(struct xfrm_policy **pols, int npols, struct flowi *fl, | ||
861 | struct xfrm_state **xfrm, | ||
862 | unsigned short family) | ||
863 | { | ||
864 | int cnx = 0; | ||
865 | int error; | ||
866 | int ret; | ||
867 | int i; | ||
868 | |||
869 | for (i = 0; i < npols; i++) { | ||
870 | if (cnx + pols[i]->xfrm_nr >= XFRM_MAX_DEPTH) { | ||
871 | error = -ENOBUFS; | ||
872 | goto fail; | ||
873 | } | ||
874 | ret = xfrm_tmpl_resolve_one(pols[i], fl, &xfrm[cnx], family); | ||
875 | if (ret < 0) { | ||
876 | error = ret; | ||
877 | goto fail; | ||
878 | } else | ||
879 | cnx += ret; | ||
880 | } | ||
881 | |||
882 | return cnx; | ||
883 | |||
884 | fail: | ||
885 | for (cnx--; cnx>=0; cnx--) | ||
886 | xfrm_state_put(xfrm[cnx]); | ||
887 | return error; | ||
888 | |||
889 | } | ||
890 | |||
812 | /* Check that the bundle accepts the flow and its components are | 891 | /* Check that the bundle accepts the flow and its components are |
813 | * still valid. | 892 | * still valid. |
814 | */ | 893 | */ |
@@ -855,6 +934,11 @@ int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, | |||
855 | struct sock *sk, int flags) | 934 | struct sock *sk, int flags) |
856 | { | 935 | { |
857 | struct xfrm_policy *policy; | 936 | struct xfrm_policy *policy; |
937 | struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; | ||
938 | int npols; | ||
939 | int pol_dead; | ||
940 | int xfrm_nr; | ||
941 | int pi; | ||
858 | struct xfrm_state *xfrm[XFRM_MAX_DEPTH]; | 942 | struct xfrm_state *xfrm[XFRM_MAX_DEPTH]; |
859 | struct dst_entry *dst, *dst_orig = *dst_p; | 943 | struct dst_entry *dst, *dst_orig = *dst_p; |
860 | int nx = 0; | 944 | int nx = 0; |
@@ -866,12 +950,18 @@ int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, | |||
866 | restart: | 950 | restart: |
867 | genid = atomic_read(&flow_cache_genid); | 951 | genid = atomic_read(&flow_cache_genid); |
868 | policy = NULL; | 952 | policy = NULL; |
953 | for (pi = 0; pi < ARRAY_SIZE(pols); pi++) | ||
954 | pols[pi] = NULL; | ||
955 | npols = 0; | ||
956 | pol_dead = 0; | ||
957 | xfrm_nr = 0; | ||
958 | |||
869 | if (sk && sk->sk_policy[1]) | 959 | if (sk && sk->sk_policy[1]) |
870 | policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl); | 960 | policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl); |
871 | 961 | ||
872 | if (!policy) { | 962 | if (!policy) { |
873 | /* To accelerate a bit... */ | 963 | /* To accelerate a bit... */ |
874 | if ((dst_orig->flags & DST_NOXFRM) || !xfrm_policy_list[XFRM_POLICY_OUT]) | 964 | if ((dst_orig->flags & DST_NOXFRM) || xfrm_policy_lists_empty(XFRM_POLICY_OUT)) |
875 | return 0; | 965 | return 0; |
876 | 966 | ||
877 | policy = flow_cache_lookup(fl, dst_orig->ops->family, | 967 | policy = flow_cache_lookup(fl, dst_orig->ops->family, |
@@ -883,6 +973,9 @@ restart: | |||
883 | 973 | ||
884 | family = dst_orig->ops->family; | 974 | family = dst_orig->ops->family; |
885 | policy->curlft.use_time = (unsigned long)xtime.tv_sec; | 975 | policy->curlft.use_time = (unsigned long)xtime.tv_sec; |
976 | pols[0] = policy; | ||
977 | npols ++; | ||
978 | xfrm_nr += pols[0]->xfrm_nr; | ||
886 | 979 | ||
887 | switch (policy->action) { | 980 | switch (policy->action) { |
888 | case XFRM_POLICY_BLOCK: | 981 | case XFRM_POLICY_BLOCK: |
@@ -891,11 +984,13 @@ restart: | |||
891 | goto error; | 984 | goto error; |
892 | 985 | ||
893 | case XFRM_POLICY_ALLOW: | 986 | case XFRM_POLICY_ALLOW: |
987 | #ifndef CONFIG_XFRM_SUB_POLICY | ||
894 | if (policy->xfrm_nr == 0) { | 988 | if (policy->xfrm_nr == 0) { |
895 | /* Flow passes not transformed. */ | 989 | /* Flow passes not transformed. */ |
896 | xfrm_pol_put(policy); | 990 | xfrm_pol_put(policy); |
897 | return 0; | 991 | return 0; |
898 | } | 992 | } |
993 | #endif | ||
899 | 994 | ||
900 | /* Try to find matching bundle. | 995 | /* Try to find matching bundle. |
901 | * | 996 | * |
@@ -911,7 +1006,36 @@ restart: | |||
911 | if (dst) | 1006 | if (dst) |
912 | break; | 1007 | break; |
913 | 1008 | ||
914 | nx = xfrm_tmpl_resolve(policy, fl, xfrm, family); | 1009 | #ifdef CONFIG_XFRM_SUB_POLICY |
1010 | if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) { | ||
1011 | pols[1] = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, | ||
1012 | fl, family, | ||
1013 | XFRM_POLICY_OUT); | ||
1014 | if (pols[1]) { | ||
1015 | if (pols[1]->action == XFRM_POLICY_BLOCK) { | ||
1016 | err = -EPERM; | ||
1017 | goto error; | ||
1018 | } | ||
1019 | npols ++; | ||
1020 | xfrm_nr += pols[1]->xfrm_nr; | ||
1021 | } | ||
1022 | } | ||
1023 | |||
1024 | /* | ||
1025 | * Because neither flowi nor bundle information knows about | ||
1026 | * transformation template size. On more than one policy usage | ||
1027 | * we can realize whether all of them is bypass or not after | ||
1028 | * they are searched. See above not-transformed bypass | ||
1029 | * is surrounded by non-sub policy configuration, too. | ||
1030 | */ | ||
1031 | if (xfrm_nr == 0) { | ||
1032 | /* Flow passes not transformed. */ | ||
1033 | xfrm_pols_put(pols, npols); | ||
1034 | return 0; | ||
1035 | } | ||
1036 | |||
1037 | #endif | ||
1038 | nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family); | ||
915 | 1039 | ||
916 | if (unlikely(nx<0)) { | 1040 | if (unlikely(nx<0)) { |
917 | err = nx; | 1041 | err = nx; |
@@ -924,7 +1048,7 @@ restart: | |||
924 | set_current_state(TASK_RUNNING); | 1048 | set_current_state(TASK_RUNNING); |
925 | remove_wait_queue(&km_waitq, &wait); | 1049 | remove_wait_queue(&km_waitq, &wait); |
926 | 1050 | ||
927 | nx = xfrm_tmpl_resolve(policy, fl, xfrm, family); | 1051 | nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family); |
928 | 1052 | ||
929 | if (nx == -EAGAIN && signal_pending(current)) { | 1053 | if (nx == -EAGAIN && signal_pending(current)) { |
930 | err = -ERESTART; | 1054 | err = -ERESTART; |
@@ -932,7 +1056,7 @@ restart: | |||
932 | } | 1056 | } |
933 | if (nx == -EAGAIN || | 1057 | if (nx == -EAGAIN || |
934 | genid != atomic_read(&flow_cache_genid)) { | 1058 | genid != atomic_read(&flow_cache_genid)) { |
935 | xfrm_pol_put(policy); | 1059 | xfrm_pols_put(pols, npols); |
936 | goto restart; | 1060 | goto restart; |
937 | } | 1061 | } |
938 | err = nx; | 1062 | err = nx; |
@@ -942,7 +1066,7 @@ restart: | |||
942 | } | 1066 | } |
943 | if (nx == 0) { | 1067 | if (nx == 0) { |
944 | /* Flow passes not transformed. */ | 1068 | /* Flow passes not transformed. */ |
945 | xfrm_pol_put(policy); | 1069 | xfrm_pols_put(pols, npols); |
946 | return 0; | 1070 | return 0; |
947 | } | 1071 | } |
948 | 1072 | ||
@@ -956,8 +1080,14 @@ restart: | |||
956 | goto error; | 1080 | goto error; |
957 | } | 1081 | } |
958 | 1082 | ||
1083 | for (pi = 0; pi < npols; pi++) { | ||
1084 | read_lock_bh(&pols[pi]->lock); | ||
1085 | pol_dead |= pols[pi]->dead; | ||
1086 | read_unlock_bh(&pols[pi]->lock); | ||
1087 | } | ||
1088 | |||
959 | write_lock_bh(&policy->lock); | 1089 | write_lock_bh(&policy->lock); |
960 | if (unlikely(policy->dead || stale_bundle(dst))) { | 1090 | if (unlikely(pol_dead || stale_bundle(dst))) { |
961 | /* Wow! While we worked on resolving, this | 1091 | /* Wow! While we worked on resolving, this |
962 | * policy has gone. Retry. It is not paranoia, | 1092 | * policy has gone. Retry. It is not paranoia, |
963 | * we just cannot enlist new bundle to dead object. | 1093 | * we just cannot enlist new bundle to dead object. |
@@ -977,12 +1107,12 @@ restart: | |||
977 | } | 1107 | } |
978 | *dst_p = dst; | 1108 | *dst_p = dst; |
979 | dst_release(dst_orig); | 1109 | dst_release(dst_orig); |
980 | xfrm_pol_put(policy); | 1110 | xfrm_pols_put(pols, npols); |
981 | return 0; | 1111 | return 0; |
982 | 1112 | ||
983 | error: | 1113 | error: |
984 | dst_release(dst_orig); | 1114 | dst_release(dst_orig); |
985 | xfrm_pol_put(policy); | 1115 | xfrm_pols_put(pols, npols); |
986 | *dst_p = NULL; | 1116 | *dst_p = NULL; |
987 | return err; | 1117 | return err; |
988 | } | 1118 | } |
@@ -1090,6 +1220,10 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1090 | unsigned short family) | 1220 | unsigned short family) |
1091 | { | 1221 | { |
1092 | struct xfrm_policy *pol; | 1222 | struct xfrm_policy *pol; |
1223 | struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; | ||
1224 | int npols = 0; | ||
1225 | int xfrm_nr; | ||
1226 | int pi; | ||
1093 | struct flowi fl; | 1227 | struct flowi fl; |
1094 | u8 fl_dir = policy_to_flow_dir(dir); | 1228 | u8 fl_dir = policy_to_flow_dir(dir); |
1095 | int xerr_idx = -1; | 1229 | int xerr_idx = -1; |
@@ -1128,22 +1262,50 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1128 | 1262 | ||
1129 | pol->curlft.use_time = (unsigned long)xtime.tv_sec; | 1263 | pol->curlft.use_time = (unsigned long)xtime.tv_sec; |
1130 | 1264 | ||
1265 | pols[0] = pol; | ||
1266 | npols ++; | ||
1267 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
1268 | if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) { | ||
1269 | pols[1] = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, | ||
1270 | &fl, family, | ||
1271 | XFRM_POLICY_IN); | ||
1272 | if (pols[1]) { | ||
1273 | pols[1]->curlft.use_time = (unsigned long)xtime.tv_sec; | ||
1274 | npols ++; | ||
1275 | } | ||
1276 | } | ||
1277 | #endif | ||
1278 | |||
1131 | if (pol->action == XFRM_POLICY_ALLOW) { | 1279 | if (pol->action == XFRM_POLICY_ALLOW) { |
1132 | struct sec_path *sp; | 1280 | struct sec_path *sp; |
1133 | static struct sec_path dummy; | 1281 | static struct sec_path dummy; |
1282 | struct xfrm_tmpl *tp[XFRM_MAX_DEPTH]; | ||
1283 | struct xfrm_tmpl **tpp = tp; | ||
1284 | int ti = 0; | ||
1134 | int i, k; | 1285 | int i, k; |
1135 | 1286 | ||
1136 | if ((sp = skb->sp) == NULL) | 1287 | if ((sp = skb->sp) == NULL) |
1137 | sp = &dummy; | 1288 | sp = &dummy; |
1138 | 1289 | ||
1290 | for (pi = 0; pi < npols; pi++) { | ||
1291 | if (pols[pi] != pol && | ||
1292 | pols[pi]->action != XFRM_POLICY_ALLOW) | ||
1293 | goto reject; | ||
1294 | if (ti + pols[pi]->xfrm_nr >= XFRM_MAX_DEPTH) | ||
1295 | goto reject_error; | ||
1296 | for (i = 0; i < pols[pi]->xfrm_nr; i++) | ||
1297 | tpp[ti++] = &pols[pi]->xfrm_vec[i]; | ||
1298 | } | ||
1299 | xfrm_nr = ti; | ||
1300 | |||
1139 | /* For each tunnel xfrm, find the first matching tmpl. | 1301 | /* For each tunnel xfrm, find the first matching tmpl. |
1140 | * For each tmpl before that, find corresponding xfrm. | 1302 | * For each tmpl before that, find corresponding xfrm. |
1141 | * Order is _important_. Later we will implement | 1303 | * Order is _important_. Later we will implement |
1142 | * some barriers, but at the moment barriers | 1304 | * some barriers, but at the moment barriers |
1143 | * are implied between each two transformations. | 1305 | * are implied between each two transformations. |
1144 | */ | 1306 | */ |
1145 | for (i = pol->xfrm_nr-1, k = 0; i >= 0; i--) { | 1307 | for (i = xfrm_nr-1, k = 0; i >= 0; i--) { |
1146 | k = xfrm_policy_ok(pol->xfrm_vec+i, sp, k, family); | 1308 | k = xfrm_policy_ok(tpp[i], sp, k, family); |
1147 | if (k < 0) { | 1309 | if (k < 0) { |
1148 | if (k < -1 && xerr_idxp) | 1310 | if (k < -1 && xerr_idxp) |
1149 | *xerr_idxp = -(2+k); | 1311 | *xerr_idxp = -(2+k); |
@@ -1154,13 +1316,14 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1154 | if (secpath_has_nontransport(sp, k, xerr_idxp)) | 1316 | if (secpath_has_nontransport(sp, k, xerr_idxp)) |
1155 | goto reject; | 1317 | goto reject; |
1156 | 1318 | ||
1157 | xfrm_pol_put(pol); | 1319 | xfrm_pols_put(pols, npols); |
1158 | return 1; | 1320 | return 1; |
1159 | } | 1321 | } |
1160 | 1322 | ||
1161 | reject: | 1323 | reject: |
1162 | xfrm_secpath_reject(xerr_idx, skb, &fl); | 1324 | xfrm_secpath_reject(xerr_idx, skb, &fl); |
1163 | xfrm_pol_put(pol); | 1325 | reject_error: |
1326 | xfrm_pols_put(pols, npols); | ||
1164 | return 0; | 1327 | return 0; |
1165 | } | 1328 | } |
1166 | EXPORT_SYMBOL(__xfrm_policy_check); | 1329 | EXPORT_SYMBOL(__xfrm_policy_check); |
@@ -1246,6 +1409,23 @@ static void xfrm_prune_bundles(int (*func)(struct dst_entry *)) | |||
1246 | 1409 | ||
1247 | read_lock_bh(&xfrm_policy_lock); | 1410 | read_lock_bh(&xfrm_policy_lock); |
1248 | for (i=0; i<2*XFRM_POLICY_MAX; i++) { | 1411 | for (i=0; i<2*XFRM_POLICY_MAX; i++) { |
1412 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
1413 | for (pol = xfrm_policy_list_sub[i]; pol; pol = pol->next) { | ||
1414 | write_lock(&pol->lock); | ||
1415 | dstp = &pol->bundles; | ||
1416 | while ((dst=*dstp) != NULL) { | ||
1417 | if (func(dst)) { | ||
1418 | *dstp = dst->next; | ||
1419 | dst->next = gc_list; | ||
1420 | gc_list = dst; | ||
1421 | } else { | ||
1422 | dstp = &dst->next; | ||
1423 | } | ||
1424 | } | ||
1425 | write_unlock(&pol->lock); | ||
1426 | } | ||
1427 | |||
1428 | #endif | ||
1249 | for (pol = xfrm_policy_list[i]; pol; pol = pol->next) { | 1429 | for (pol = xfrm_policy_list[i]; pol; pol = pol->next) { |
1250 | write_lock(&pol->lock); | 1430 | write_lock(&pol->lock); |
1251 | dstp = &pol->bundles; | 1431 | dstp = &pol->bundles; |