aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/key/af_key.c120
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
53static inline struct pfkey_sock *pfkey_sk(struct sock *sk) 64static 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
69static 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
76static 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
58static void pfkey_sock_destruct(struct sock *sk) 90static 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
1712struct pfkey_dump_data
1713{
1714 struct sk_buff *skb;
1715 struct sadb_msg *hdr;
1716 struct sock *sk;
1717};
1718
1719static int dump_sa(struct xfrm_state *x, int count, void *ptr) 1744static 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
1769static int pfkey_dump_sa(struct pfkey_sock *pfk)
1770{
1771 return xfrm_state_walk(&pfk->dump.u.state, dump_sa, (void *) pfk);
1772}
1773
1774static void pfkey_dump_sa_done(struct pfkey_sock *pfk)
1775{
1776 xfrm_state_walk_done(&pfk->dump.u.state);
1777}
1778
1741static int pfkey_dump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 1779static 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
1759static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 1800static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
@@ -2648,11 +2689,14 @@ out:
2648 2689
2649static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr) 2690static 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
2719static int pfkey_dump_sp(struct pfkey_sock *pfk)
2720{
2721 return xfrm_policy_walk(&pfk->dump.u.policy, dump_sp, (void *) pfk);
2722}
2723
2724static void pfkey_dump_sp_done(struct pfkey_sock *pfk)
2725{
2726 xfrm_policy_walk_done(&pfk->dump.u.policy);
2727}
2728
2675static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 2729static 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
2688static int key_notify_policy_flush(struct km_event *c) 2745static 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
3717out_free: 3779out_free:
3718 skb_free_datagram(sk, skb); 3780 skb_free_datagram(sk, skb);
3719out: 3781out: