diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/key/af_key.c | 120 |
1 files changed, 91 insertions, 29 deletions
diff --git a/net/key/af_key.c b/net/key/af_key.c index 7cb6f1213360..50c442fc99ce 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c | |||
@@ -48,6 +48,17 @@ struct pfkey_sock { | |||
48 | struct sock sk; | 48 | struct sock sk; |
49 | int registered; | 49 | int registered; |
50 | int promisc; | 50 | int promisc; |
51 | |||
52 | struct { | ||
53 | uint8_t msg_version; | ||
54 | uint32_t msg_pid; | ||
55 | int (*dump)(struct pfkey_sock *sk); | ||
56 | void (*done)(struct pfkey_sock *sk); | ||
57 | union { | ||
58 | struct xfrm_policy_walk policy; | ||
59 | struct xfrm_state_walk state; | ||
60 | } u; | ||
61 | } dump; | ||
51 | }; | 62 | }; |
52 | 63 | ||
53 | static inline struct pfkey_sock *pfkey_sk(struct sock *sk) | 64 | static inline struct pfkey_sock *pfkey_sk(struct sock *sk) |
@@ -55,6 +66,27 @@ static inline struct pfkey_sock *pfkey_sk(struct sock *sk) | |||
55 | return (struct pfkey_sock *)sk; | 66 | return (struct pfkey_sock *)sk; |
56 | } | 67 | } |
57 | 68 | ||
69 | static int pfkey_can_dump(struct sock *sk) | ||
70 | { | ||
71 | if (3 * atomic_read(&sk->sk_rmem_alloc) <= 2 * sk->sk_rcvbuf) | ||
72 | return 1; | ||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | static int pfkey_do_dump(struct pfkey_sock *pfk) | ||
77 | { | ||
78 | int rc; | ||
79 | |||
80 | rc = pfk->dump.dump(pfk); | ||
81 | if (rc == -ENOBUFS) | ||
82 | return 0; | ||
83 | |||
84 | pfk->dump.done(pfk); | ||
85 | pfk->dump.dump = NULL; | ||
86 | pfk->dump.done = NULL; | ||
87 | return rc; | ||
88 | } | ||
89 | |||
58 | static void pfkey_sock_destruct(struct sock *sk) | 90 | static void pfkey_sock_destruct(struct sock *sk) |
59 | { | 91 | { |
60 | skb_queue_purge(&sk->sk_receive_queue); | 92 | skb_queue_purge(&sk->sk_receive_queue); |
@@ -1709,51 +1741,60 @@ static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hd | |||
1709 | return 0; | 1741 | return 0; |
1710 | } | 1742 | } |
1711 | 1743 | ||
1712 | struct pfkey_dump_data | ||
1713 | { | ||
1714 | struct sk_buff *skb; | ||
1715 | struct sadb_msg *hdr; | ||
1716 | struct sock *sk; | ||
1717 | }; | ||
1718 | |||
1719 | static int dump_sa(struct xfrm_state *x, int count, void *ptr) | 1744 | static int dump_sa(struct xfrm_state *x, int count, void *ptr) |
1720 | { | 1745 | { |
1721 | struct pfkey_dump_data *data = ptr; | 1746 | struct pfkey_sock *pfk = ptr; |
1722 | struct sk_buff *out_skb; | 1747 | struct sk_buff *out_skb; |
1723 | struct sadb_msg *out_hdr; | 1748 | struct sadb_msg *out_hdr; |
1724 | 1749 | ||
1750 | if (!pfkey_can_dump(&pfk->sk)) | ||
1751 | return -ENOBUFS; | ||
1752 | |||
1725 | out_skb = pfkey_xfrm_state2msg(x); | 1753 | out_skb = pfkey_xfrm_state2msg(x); |
1726 | if (IS_ERR(out_skb)) | 1754 | if (IS_ERR(out_skb)) |
1727 | return PTR_ERR(out_skb); | 1755 | return PTR_ERR(out_skb); |
1728 | 1756 | ||
1729 | out_hdr = (struct sadb_msg *) out_skb->data; | 1757 | out_hdr = (struct sadb_msg *) out_skb->data; |
1730 | out_hdr->sadb_msg_version = data->hdr->sadb_msg_version; | 1758 | out_hdr->sadb_msg_version = pfk->dump.msg_version; |
1731 | out_hdr->sadb_msg_type = SADB_DUMP; | 1759 | out_hdr->sadb_msg_type = SADB_DUMP; |
1732 | out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto); | 1760 | out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto); |
1733 | out_hdr->sadb_msg_errno = 0; | 1761 | out_hdr->sadb_msg_errno = 0; |
1734 | out_hdr->sadb_msg_reserved = 0; | 1762 | out_hdr->sadb_msg_reserved = 0; |
1735 | out_hdr->sadb_msg_seq = count; | 1763 | out_hdr->sadb_msg_seq = count; |
1736 | out_hdr->sadb_msg_pid = data->hdr->sadb_msg_pid; | 1764 | out_hdr->sadb_msg_pid = pfk->dump.msg_pid; |
1737 | pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, data->sk); | 1765 | pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, &pfk->sk); |
1738 | return 0; | 1766 | return 0; |
1739 | } | 1767 | } |
1740 | 1768 | ||
1769 | static int pfkey_dump_sa(struct pfkey_sock *pfk) | ||
1770 | { | ||
1771 | return xfrm_state_walk(&pfk->dump.u.state, dump_sa, (void *) pfk); | ||
1772 | } | ||
1773 | |||
1774 | static void pfkey_dump_sa_done(struct pfkey_sock *pfk) | ||
1775 | { | ||
1776 | xfrm_state_walk_done(&pfk->dump.u.state); | ||
1777 | } | ||
1778 | |||
1741 | static int pfkey_dump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) | 1779 | static int pfkey_dump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) |
1742 | { | 1780 | { |
1743 | u8 proto; | 1781 | u8 proto; |
1744 | struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk }; | 1782 | struct pfkey_sock *pfk = pfkey_sk(sk); |
1745 | struct xfrm_state_walk walk; | 1783 | |
1746 | int rc; | 1784 | if (pfk->dump.dump != NULL) |
1785 | return -EBUSY; | ||
1747 | 1786 | ||
1748 | proto = pfkey_satype2proto(hdr->sadb_msg_satype); | 1787 | proto = pfkey_satype2proto(hdr->sadb_msg_satype); |
1749 | if (proto == 0) | 1788 | if (proto == 0) |
1750 | return -EINVAL; | 1789 | return -EINVAL; |
1751 | 1790 | ||
1752 | xfrm_state_walk_init(&walk, proto); | 1791 | pfk->dump.msg_version = hdr->sadb_msg_version; |
1753 | rc = xfrm_state_walk(&walk, dump_sa, &data); | 1792 | pfk->dump.msg_pid = hdr->sadb_msg_pid; |
1754 | xfrm_state_walk_done(&walk); | 1793 | pfk->dump.dump = pfkey_dump_sa; |
1794 | pfk->dump.done = pfkey_dump_sa_done; | ||
1795 | xfrm_state_walk_init(&pfk->dump.u.state, proto); | ||
1755 | 1796 | ||
1756 | return rc; | 1797 | return pfkey_do_dump(pfk); |
1757 | } | 1798 | } |
1758 | 1799 | ||
1759 | static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) | 1800 | static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) |
@@ -2648,11 +2689,14 @@ out: | |||
2648 | 2689 | ||
2649 | static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr) | 2690 | static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr) |
2650 | { | 2691 | { |
2651 | struct pfkey_dump_data *data = ptr; | 2692 | struct pfkey_sock *pfk = ptr; |
2652 | struct sk_buff *out_skb; | 2693 | struct sk_buff *out_skb; |
2653 | struct sadb_msg *out_hdr; | 2694 | struct sadb_msg *out_hdr; |
2654 | int err; | 2695 | int err; |
2655 | 2696 | ||
2697 | if (!pfkey_can_dump(&pfk->sk)) | ||
2698 | return -ENOBUFS; | ||
2699 | |||
2656 | out_skb = pfkey_xfrm_policy2msg_prep(xp); | 2700 | out_skb = pfkey_xfrm_policy2msg_prep(xp); |
2657 | if (IS_ERR(out_skb)) | 2701 | if (IS_ERR(out_skb)) |
2658 | return PTR_ERR(out_skb); | 2702 | return PTR_ERR(out_skb); |
@@ -2662,27 +2706,40 @@ static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr) | |||
2662 | return err; | 2706 | return err; |
2663 | 2707 | ||
2664 | out_hdr = (struct sadb_msg *) out_skb->data; | 2708 | out_hdr = (struct sadb_msg *) out_skb->data; |
2665 | out_hdr->sadb_msg_version = data->hdr->sadb_msg_version; | 2709 | out_hdr->sadb_msg_version = pfk->dump.msg_version; |
2666 | out_hdr->sadb_msg_type = SADB_X_SPDDUMP; | 2710 | out_hdr->sadb_msg_type = SADB_X_SPDDUMP; |
2667 | out_hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC; | 2711 | out_hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC; |
2668 | out_hdr->sadb_msg_errno = 0; | 2712 | out_hdr->sadb_msg_errno = 0; |
2669 | out_hdr->sadb_msg_seq = count; | 2713 | out_hdr->sadb_msg_seq = count; |
2670 | out_hdr->sadb_msg_pid = data->hdr->sadb_msg_pid; | 2714 | out_hdr->sadb_msg_pid = pfk->dump.msg_pid; |
2671 | pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, data->sk); | 2715 | pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, &pfk->sk); |
2672 | return 0; | 2716 | return 0; |
2673 | } | 2717 | } |
2674 | 2718 | ||
2719 | static int pfkey_dump_sp(struct pfkey_sock *pfk) | ||
2720 | { | ||
2721 | return xfrm_policy_walk(&pfk->dump.u.policy, dump_sp, (void *) pfk); | ||
2722 | } | ||
2723 | |||
2724 | static void pfkey_dump_sp_done(struct pfkey_sock *pfk) | ||
2725 | { | ||
2726 | xfrm_policy_walk_done(&pfk->dump.u.policy); | ||
2727 | } | ||
2728 | |||
2675 | static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) | 2729 | static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) |
2676 | { | 2730 | { |
2677 | struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk }; | 2731 | struct pfkey_sock *pfk = pfkey_sk(sk); |
2678 | struct xfrm_policy_walk walk; | ||
2679 | int rc; | ||
2680 | 2732 | ||
2681 | xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN); | 2733 | if (pfk->dump.dump != NULL) |
2682 | rc = xfrm_policy_walk(&walk, dump_sp, &data); | 2734 | return -EBUSY; |
2683 | xfrm_policy_walk_done(&walk); | ||
2684 | 2735 | ||
2685 | return rc; | 2736 | pfk->dump.msg_version = hdr->sadb_msg_version; |
2737 | pfk->dump.msg_pid = hdr->sadb_msg_pid; | ||
2738 | pfk->dump.dump = pfkey_dump_sp; | ||
2739 | pfk->dump.done = pfkey_dump_sp_done; | ||
2740 | xfrm_policy_walk_init(&pfk->dump.u.policy, XFRM_POLICY_TYPE_MAIN); | ||
2741 | |||
2742 | return pfkey_do_dump(pfk); | ||
2686 | } | 2743 | } |
2687 | 2744 | ||
2688 | static int key_notify_policy_flush(struct km_event *c) | 2745 | static int key_notify_policy_flush(struct km_event *c) |
@@ -3687,6 +3744,7 @@ static int pfkey_recvmsg(struct kiocb *kiocb, | |||
3687 | int flags) | 3744 | int flags) |
3688 | { | 3745 | { |
3689 | struct sock *sk = sock->sk; | 3746 | struct sock *sk = sock->sk; |
3747 | struct pfkey_sock *pfk = pfkey_sk(sk); | ||
3690 | struct sk_buff *skb; | 3748 | struct sk_buff *skb; |
3691 | int copied, err; | 3749 | int copied, err; |
3692 | 3750 | ||
@@ -3714,6 +3772,10 @@ static int pfkey_recvmsg(struct kiocb *kiocb, | |||
3714 | 3772 | ||
3715 | err = (flags & MSG_TRUNC) ? skb->len : copied; | 3773 | err = (flags & MSG_TRUNC) ? skb->len : copied; |
3716 | 3774 | ||
3775 | if (pfk->dump.dump != NULL && | ||
3776 | 3 * atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) | ||
3777 | pfkey_do_dump(pfk); | ||
3778 | |||
3717 | out_free: | 3779 | out_free: |
3718 | skb_free_datagram(sk, skb); | 3780 | skb_free_datagram(sk, skb); |
3719 | out: | 3781 | out: |