diff options
author | Pavel Emelyanov <xemul@parallels.com> | 2011-12-09 01:24:21 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-12-09 14:15:00 -0500 |
commit | b6d640c2286d16b15a21a4475c896cdce6a0bbe0 (patch) | |
tree | 01f55007bfb8c680a4689d6e6f312f22f28adec3 /net/ipv4/udp_diag.c | |
parent | a925aa00a55e3b72bd38bfdd3d6f97c0d900c949 (diff) |
udp_diag: Implement the dump-all functionality
Do the same as TCP does -- iterate the given udp_table, filter
sockets with bytecode and dump sockets into reply message.
The same filtering as for TCP applies, though only some of the
state bits really matter.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/udp_diag.c')
-rw-r--r-- | net/ipv4/udp_diag.c | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/net/ipv4/udp_diag.c b/net/ipv4/udp_diag.c index caa164dcd30f..65063444a119 100644 --- a/net/ipv4/udp_diag.c +++ b/net/ipv4/udp_diag.c | |||
@@ -18,6 +18,17 @@ | |||
18 | #include <linux/inet_diag.h> | 18 | #include <linux/inet_diag.h> |
19 | #include <linux/sock_diag.h> | 19 | #include <linux/sock_diag.h> |
20 | 20 | ||
21 | static int sk_diag_dump(struct sock *sk, struct sk_buff *skb, | ||
22 | struct netlink_callback *cb, struct inet_diag_req *req, | ||
23 | struct nlattr *bc) | ||
24 | { | ||
25 | if (!inet_diag_bc_sk(bc, sk)) | ||
26 | return 0; | ||
27 | |||
28 | return inet_sk_diag_fill(sk, NULL, skb, req, NETLINK_CB(cb->skb).pid, | ||
29 | cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh); | ||
30 | } | ||
31 | |||
21 | static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb, | 32 | static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb, |
22 | const struct nlmsghdr *nlh, struct inet_diag_req *req) | 33 | const struct nlmsghdr *nlh, struct inet_diag_req *req) |
23 | { | 34 | { |
@@ -77,6 +88,49 @@ out_nosk: | |||
77 | static void udp_dump(struct udp_table *table, struct sk_buff *skb, struct netlink_callback *cb, | 88 | static void udp_dump(struct udp_table *table, struct sk_buff *skb, struct netlink_callback *cb, |
78 | struct inet_diag_req *r, struct nlattr *bc) | 89 | struct inet_diag_req *r, struct nlattr *bc) |
79 | { | 90 | { |
91 | int num, s_num, slot, s_slot; | ||
92 | |||
93 | s_slot = cb->args[0]; | ||
94 | num = s_num = cb->args[1]; | ||
95 | |||
96 | for (slot = s_slot; slot <= table->mask; num = s_num = 0, slot++) { | ||
97 | struct sock *sk; | ||
98 | struct hlist_nulls_node *node; | ||
99 | struct udp_hslot *hslot = &table->hash[slot]; | ||
100 | |||
101 | if (hlist_nulls_empty(&hslot->head)) | ||
102 | continue; | ||
103 | |||
104 | spin_lock_bh(&hslot->lock); | ||
105 | sk_nulls_for_each(sk, node, &hslot->head) { | ||
106 | struct inet_sock *inet = inet_sk(sk); | ||
107 | |||
108 | if (num < s_num) | ||
109 | goto next; | ||
110 | if (!(r->idiag_states & (1 << sk->sk_state))) | ||
111 | goto next; | ||
112 | if (r->sdiag_family != AF_UNSPEC && | ||
113 | sk->sk_family != r->sdiag_family) | ||
114 | goto next; | ||
115 | if (r->id.idiag_sport != inet->inet_sport && | ||
116 | r->id.idiag_sport) | ||
117 | goto next; | ||
118 | if (r->id.idiag_dport != inet->inet_dport && | ||
119 | r->id.idiag_dport) | ||
120 | goto next; | ||
121 | |||
122 | if (sk_diag_dump(sk, skb, cb, r, bc) < 0) { | ||
123 | spin_unlock_bh(&hslot->lock); | ||
124 | goto done; | ||
125 | } | ||
126 | next: | ||
127 | num++; | ||
128 | } | ||
129 | spin_unlock_bh(&hslot->lock); | ||
130 | } | ||
131 | done: | ||
132 | cb->args[0] = slot; | ||
133 | cb->args[1] = num; | ||
80 | } | 134 | } |
81 | 135 | ||
82 | static void udp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, | 136 | static void udp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, |