Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+54 −0
Original line number Diff line number Diff line
@@ -18,6 +18,17 @@
#include <linux/inet_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,
		const struct nlmsghdr *nlh, struct inet_diag_req *req)
{
@@ -77,6 +88,49 @@ out_nosk:
static void udp_dump(struct udp_table *table, struct sk_buff *skb, struct netlink_callback *cb,
		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,