Commit b6d640c2 authored by Pavel Emelyanov's avatar Pavel Emelyanov Committed by David S. Miller

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: default avatarPavel Emelyanov <xemul@parallels.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a925aa00
...@@ -18,6 +18,17 @@ ...@@ -18,6 +18,17 @@
#include <linux/inet_diag.h> #include <linux/inet_diag.h>
#include <linux/sock_diag.h> #include <linux/sock_diag.h>
static int sk_diag_dump(struct sock *sk, struct sk_buff *skb,
struct netlink_callback *cb, struct inet_diag_req *req,
struct nlattr *bc)
{
if (!inet_diag_bc_sk(bc, sk))
return 0;
return inet_sk_diag_fill(sk, NULL, skb, req, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
}
static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb, static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb,
const struct nlmsghdr *nlh, struct inet_diag_req *req) const struct nlmsghdr *nlh, struct inet_diag_req *req)
{ {
...@@ -77,6 +88,49 @@ static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb, ...@@ -77,6 +88,49 @@ static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb,
static void udp_dump(struct udp_table *table, struct sk_buff *skb, struct netlink_callback *cb, static void udp_dump(struct udp_table *table, struct sk_buff *skb, struct netlink_callback *cb,
struct inet_diag_req *r, struct nlattr *bc) struct inet_diag_req *r, struct nlattr *bc)
{ {
int num, s_num, slot, s_slot;
s_slot = cb->args[0];
num = s_num = cb->args[1];
for (slot = s_slot; slot <= table->mask; num = s_num = 0, slot++) {
struct sock *sk;
struct hlist_nulls_node *node;
struct udp_hslot *hslot = &table->hash[slot];
if (hlist_nulls_empty(&hslot->head))
continue;
spin_lock_bh(&hslot->lock);
sk_nulls_for_each(sk, node, &hslot->head) {
struct inet_sock *inet = inet_sk(sk);
if (num < s_num)
goto next;
if (!(r->idiag_states & (1 << sk->sk_state)))
goto next;
if (r->sdiag_family != AF_UNSPEC &&
sk->sk_family != r->sdiag_family)
goto next;
if (r->id.idiag_sport != inet->inet_sport &&
r->id.idiag_sport)
goto next;
if (r->id.idiag_dport != inet->inet_dport &&
r->id.idiag_dport)
goto next;
if (sk_diag_dump(sk, skb, cb, r, bc) < 0) {
spin_unlock_bh(&hslot->lock);
goto done;
}
next:
num++;
}
spin_unlock_bh(&hslot->lock);
}
done:
cb->args[0] = slot;
cb->args[1] = num;
} }
static void udp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, static void udp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment