aboutsummaryrefslogtreecommitdiffstats
path: root/net/key/af_key.c
diff options
context:
space:
mode:
authorTimo Teras <timo.teras@iki.fi>2008-03-04 02:40:12 -0500
committerDavid S. Miller <davem@davemloft.net>2008-03-04 02:40:12 -0500
commit83321d6b9872b94604e481a79dc2c8acbe4ece31 (patch)
tree7ea6bad51b21b2dd5abaaab75df2fc546f623441 /net/key/af_key.c
parent26bad2c05eef400d9af16979bd96e301902ebd13 (diff)
[AF_KEY]: Dump SA/SP entries non-atomically
Stop dumping of entries when af_key socket receive queue is getting full and continue it later when there is more room again. This fixes dumping of large databases. Currently the entries not fitting into the receive queue are just dropped (including the end-of-dump message) which can confuse applications. Signed-off-by: Timo Teras <timo.teras@iki.fi> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/key/af_key.c')
-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: