diff options
author | Pavel Emelyanov <xemul@parallels.com> | 2011-12-15 03:44:52 +0100 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-12-16 19:48:28 +0100 |
commit | 45a96b9be6ec1b7d248642d17ceee59ff5f64451 (patch) | |
tree | 9623dc58bd01b23a70b3ef261e69b533b717ec46 /net/unix | |
parent | unix_diag: Basic module skeleton (diff) | |
download | linux-45a96b9be6ec1b7d248642d17ceee59ff5f64451.tar.xz linux-45a96b9be6ec1b7d248642d17ceee59ff5f64451.zip |
unix_diag: Dumping all sockets core
Walk the unix sockets table and fill the core response structure,
which includes type, state and inode.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/unix')
-rw-r--r-- | net/unix/diag.c | 76 |
1 files changed, 75 insertions, 1 deletions
diff --git a/net/unix/diag.c b/net/unix/diag.c index 6be16c0ad38f..86d85abf90c6 100644 --- a/net/unix/diag.c +++ b/net/unix/diag.c @@ -10,9 +10,83 @@ #define UNIX_DIAG_PUT(skb, attrtype, attrlen) \ RTA_DATA(__RTA_PUT(skb, attrtype, attrlen)) +static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_req *req, + u32 pid, u32 seq, u32 flags, int sk_ino) +{ + unsigned char *b = skb_tail_pointer(skb); + struct nlmsghdr *nlh; + struct unix_diag_msg *rep; + + nlh = NLMSG_PUT(skb, pid, seq, SOCK_DIAG_BY_FAMILY, sizeof(*rep)); + nlh->nlmsg_flags = flags; + + rep = NLMSG_DATA(nlh); + + rep->udiag_family = AF_UNIX; + rep->udiag_type = sk->sk_type; + rep->udiag_state = sk->sk_state; + rep->udiag_ino = sk_ino; + sock_diag_save_cookie(sk, rep->udiag_cookie); + + nlh->nlmsg_len = skb_tail_pointer(skb) - b; + return skb->len; + +nlmsg_failure: + nlmsg_trim(skb, b); + return -EMSGSIZE; +} + +static int sk_diag_dump(struct sock *sk, struct sk_buff *skb, struct unix_diag_req *req, + u32 pid, u32 seq, u32 flags) +{ + int sk_ino; + + unix_state_lock(sk); + sk_ino = sock_i_ino(sk); + unix_state_unlock(sk); + + if (!sk_ino) + return 0; + + return sk_diag_fill(sk, skb, req, pid, seq, flags, sk_ino); +} + static int unix_diag_dump(struct sk_buff *skb, struct netlink_callback *cb) { - return 0; + struct unix_diag_req *req; + int num, s_num, slot, s_slot; + + req = NLMSG_DATA(cb->nlh); + + s_slot = cb->args[0]; + num = s_num = cb->args[1]; + + spin_lock(&unix_table_lock); + for (slot = s_slot; slot <= UNIX_HASH_SIZE; s_num = 0, slot++) { + struct sock *sk; + struct hlist_node *node; + + num = 0; + sk_for_each(sk, node, &unix_socket_table[slot]) { + if (num < s_num) + goto next; + if (!(req->udiag_states & (1 << sk->sk_state))) + goto next; + if (sk_diag_dump(sk, skb, req, + NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, + NLM_F_MULTI) < 0) + goto done; +next: + num++; + } + } +done: + spin_unlock(&unix_table_lock); + cb->args[0] = slot; + cb->args[1] = num; + + return skb->len; } static int unix_diag_get_exact(struct sk_buff *in_skb, |