|
@@ -89,11 +89,76 @@ done:
|
|
|
return skb->len;
|
|
|
}
|
|
|
|
|
|
+static struct sock *unix_lookup_by_ino(int ino)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ struct sock *sk;
|
|
|
+
|
|
|
+ spin_lock(&unix_table_lock);
|
|
|
+ for (i = 0; i <= UNIX_HASH_SIZE; i++) {
|
|
|
+ struct hlist_node *node;
|
|
|
+
|
|
|
+ sk_for_each(sk, node, &unix_socket_table[i])
|
|
|
+ if (ino == sock_i_ino(sk)) {
|
|
|
+ sock_hold(sk);
|
|
|
+ spin_unlock(&unix_table_lock);
|
|
|
+
|
|
|
+ return sk;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ spin_unlock(&unix_table_lock);
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
static int unix_diag_get_exact(struct sk_buff *in_skb,
|
|
|
const struct nlmsghdr *nlh,
|
|
|
struct unix_diag_req *req)
|
|
|
{
|
|
|
- return -EAFNOSUPPORT;
|
|
|
+ int err = -EINVAL;
|
|
|
+ struct sock *sk;
|
|
|
+ struct sk_buff *rep;
|
|
|
+ unsigned int extra_len;
|
|
|
+
|
|
|
+ if (req->udiag_ino == 0)
|
|
|
+ goto out_nosk;
|
|
|
+
|
|
|
+ sk = unix_lookup_by_ino(req->udiag_ino);
|
|
|
+ err = -ENOENT;
|
|
|
+ if (sk == NULL)
|
|
|
+ goto out_nosk;
|
|
|
+
|
|
|
+ err = sock_diag_check_cookie(sk, req->udiag_cookie);
|
|
|
+ if (err)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ extra_len = 256;
|
|
|
+again:
|
|
|
+ err = -ENOMEM;
|
|
|
+ rep = alloc_skb(NLMSG_SPACE((sizeof(struct unix_diag_msg) + extra_len)),
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!rep)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ err = sk_diag_fill(sk, rep, req, NETLINK_CB(in_skb).pid,
|
|
|
+ nlh->nlmsg_seq, 0, req->udiag_ino);
|
|
|
+ if (err < 0) {
|
|
|
+ kfree_skb(rep);
|
|
|
+ extra_len += 256;
|
|
|
+ if (extra_len >= PAGE_SIZE)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ goto again;
|
|
|
+ }
|
|
|
+ err = netlink_unicast(sock_diag_nlsk, rep, NETLINK_CB(in_skb).pid,
|
|
|
+ MSG_DONTWAIT);
|
|
|
+ if (err > 0)
|
|
|
+ err = 0;
|
|
|
+out:
|
|
|
+ if (sk)
|
|
|
+ sock_put(sk);
|
|
|
+out_nosk:
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
static int unix_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
|