diff options
Diffstat (limited to 'net/key/af_key.c')
-rw-r--r-- | net/key/af_key.c | 120 |
1 files changed, 99 insertions, 21 deletions
diff --git a/net/key/af_key.c b/net/key/af_key.c index e9ef9af4a53b..6db58924368a 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,45 +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); |
1783 | |||
1784 | if (pfk->dump.dump != NULL) | ||
1785 | return -EBUSY; | ||
1745 | 1786 | ||
1746 | proto = pfkey_satype2proto(hdr->sadb_msg_satype); | 1787 | proto = pfkey_satype2proto(hdr->sadb_msg_satype); |
1747 | if (proto == 0) | 1788 | if (proto == 0) |
1748 | return -EINVAL; | 1789 | return -EINVAL; |
1749 | 1790 | ||
1750 | return xfrm_state_walk(proto, dump_sa, &data); | 1791 | pfk->dump.msg_version = hdr->sadb_msg_version; |
1792 | pfk->dump.msg_pid = hdr->sadb_msg_pid; | ||
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); | ||
1796 | |||
1797 | return pfkey_do_dump(pfk); | ||
1751 | } | 1798 | } |
1752 | 1799 | ||
1753 | 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) |
@@ -1780,7 +1827,9 @@ static int check_reqid(struct xfrm_policy *xp, int dir, int count, void *ptr) | |||
1780 | 1827 | ||
1781 | static u32 gen_reqid(void) | 1828 | static u32 gen_reqid(void) |
1782 | { | 1829 | { |
1830 | struct xfrm_policy_walk walk; | ||
1783 | u32 start; | 1831 | u32 start; |
1832 | int rc; | ||
1784 | static u32 reqid = IPSEC_MANUAL_REQID_MAX; | 1833 | static u32 reqid = IPSEC_MANUAL_REQID_MAX; |
1785 | 1834 | ||
1786 | start = reqid; | 1835 | start = reqid; |
@@ -1788,8 +1837,10 @@ static u32 gen_reqid(void) | |||
1788 | ++reqid; | 1837 | ++reqid; |
1789 | if (reqid == 0) | 1838 | if (reqid == 0) |
1790 | reqid = IPSEC_MANUAL_REQID_MAX+1; | 1839 | reqid = IPSEC_MANUAL_REQID_MAX+1; |
1791 | if (xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, check_reqid, | 1840 | xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN); |
1792 | (void*)&reqid) != -EEXIST) | 1841 | rc = xfrm_policy_walk(&walk, check_reqid, (void*)&reqid); |
1842 | xfrm_policy_walk_done(&walk); | ||
1843 | if (rc != -EEXIST) | ||
1793 | return reqid; | 1844 | return reqid; |
1794 | } while (reqid != start); | 1845 | } while (reqid != start); |
1795 | return 0; | 1846 | return 0; |
@@ -2638,11 +2689,14 @@ out: | |||
2638 | 2689 | ||
2639 | 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) |
2640 | { | 2691 | { |
2641 | struct pfkey_dump_data *data = ptr; | 2692 | struct pfkey_sock *pfk = ptr; |
2642 | struct sk_buff *out_skb; | 2693 | struct sk_buff *out_skb; |
2643 | struct sadb_msg *out_hdr; | 2694 | struct sadb_msg *out_hdr; |
2644 | int err; | 2695 | int err; |
2645 | 2696 | ||
2697 | if (!pfkey_can_dump(&pfk->sk)) | ||
2698 | return -ENOBUFS; | ||
2699 | |||
2646 | out_skb = pfkey_xfrm_policy2msg_prep(xp); | 2700 | out_skb = pfkey_xfrm_policy2msg_prep(xp); |
2647 | if (IS_ERR(out_skb)) | 2701 | if (IS_ERR(out_skb)) |
2648 | return PTR_ERR(out_skb); | 2702 | return PTR_ERR(out_skb); |
@@ -2652,21 +2706,40 @@ static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr) | |||
2652 | return err; | 2706 | return err; |
2653 | 2707 | ||
2654 | out_hdr = (struct sadb_msg *) out_skb->data; | 2708 | out_hdr = (struct sadb_msg *) out_skb->data; |
2655 | out_hdr->sadb_msg_version = data->hdr->sadb_msg_version; | 2709 | out_hdr->sadb_msg_version = pfk->dump.msg_version; |
2656 | out_hdr->sadb_msg_type = SADB_X_SPDDUMP; | 2710 | out_hdr->sadb_msg_type = SADB_X_SPDDUMP; |
2657 | out_hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC; | 2711 | out_hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC; |
2658 | out_hdr->sadb_msg_errno = 0; | 2712 | out_hdr->sadb_msg_errno = 0; |
2659 | out_hdr->sadb_msg_seq = count; | 2713 | out_hdr->sadb_msg_seq = count; |
2660 | out_hdr->sadb_msg_pid = data->hdr->sadb_msg_pid; | 2714 | out_hdr->sadb_msg_pid = pfk->dump.msg_pid; |
2661 | pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, data->sk); | 2715 | pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, &pfk->sk); |
2662 | return 0; | 2716 | return 0; |
2663 | } | 2717 | } |
2664 | 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 | |||
2665 | 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) |
2666 | { | 2730 | { |
2667 | struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk }; | 2731 | struct pfkey_sock *pfk = pfkey_sk(sk); |
2732 | |||
2733 | if (pfk->dump.dump != NULL) | ||
2734 | return -EBUSY; | ||
2735 | |||
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); | ||
2668 | 2741 | ||
2669 | return xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_sp, &data); | 2742 | return pfkey_do_dump(pfk); |
2670 | } | 2743 | } |
2671 | 2744 | ||
2672 | static int key_notify_policy_flush(struct km_event *c) | 2745 | static int key_notify_policy_flush(struct km_event *c) |
@@ -3671,6 +3744,7 @@ static int pfkey_recvmsg(struct kiocb *kiocb, | |||
3671 | int flags) | 3744 | int flags) |
3672 | { | 3745 | { |
3673 | struct sock *sk = sock->sk; | 3746 | struct sock *sk = sock->sk; |
3747 | struct pfkey_sock *pfk = pfkey_sk(sk); | ||
3674 | struct sk_buff *skb; | 3748 | struct sk_buff *skb; |
3675 | int copied, err; | 3749 | int copied, err; |
3676 | 3750 | ||
@@ -3698,6 +3772,10 @@ static int pfkey_recvmsg(struct kiocb *kiocb, | |||
3698 | 3772 | ||
3699 | err = (flags & MSG_TRUNC) ? skb->len : copied; | 3773 | err = (flags & MSG_TRUNC) ? skb->len : copied; |
3700 | 3774 | ||
3775 | if (pfk->dump.dump != NULL && | ||
3776 | 3 * atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) | ||
3777 | pfkey_do_dump(pfk); | ||
3778 | |||
3701 | out_free: | 3779 | out_free: |
3702 | skb_free_datagram(sk, skb); | 3780 | skb_free_datagram(sk, skb); |
3703 | out: | 3781 | out: |