linux/net/vmw_vsock/diag.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * vsock sock_diag(7) module
   4 *
   5 * Copyright (C) 2017 Red Hat, Inc.
   6 * Author: Stefan Hajnoczi <stefanha@redhat.com>
   7 */
   8
   9#include <linux/module.h>
  10#include <linux/sock_diag.h>
  11#include <linux/vm_sockets_diag.h>
  12#include <net/af_vsock.h>
  13
  14static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
  15                        u32 portid, u32 seq, u32 flags)
  16{
  17        struct vsock_sock *vsk = vsock_sk(sk);
  18        struct vsock_diag_msg *rep;
  19        struct nlmsghdr *nlh;
  20
  21        nlh = nlmsg_put(skb, portid, seq, SOCK_DIAG_BY_FAMILY, sizeof(*rep),
  22                        flags);
  23        if (!nlh)
  24                return -EMSGSIZE;
  25
  26        rep = nlmsg_data(nlh);
  27        rep->vdiag_family = AF_VSOCK;
  28
  29        /* Lock order dictates that sk_lock is acquired before
  30         * vsock_table_lock, so we cannot lock here.  Simply don't take
  31         * sk_lock; sk is guaranteed to stay alive since vsock_table_lock is
  32         * held.
  33         */
  34        rep->vdiag_type = sk->sk_type;
  35        rep->vdiag_state = sk->sk_state;
  36        rep->vdiag_shutdown = sk->sk_shutdown;
  37        rep->vdiag_src_cid = vsk->local_addr.svm_cid;
  38        rep->vdiag_src_port = vsk->local_addr.svm_port;
  39        rep->vdiag_dst_cid = vsk->remote_addr.svm_cid;
  40        rep->vdiag_dst_port = vsk->remote_addr.svm_port;
  41        rep->vdiag_ino = sock_i_ino(sk);
  42
  43        sock_diag_save_cookie(sk, rep->vdiag_cookie);
  44
  45        return 0;
  46}
  47
  48static int vsock_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
  49{
  50        struct vsock_diag_req *req;
  51        struct vsock_sock *vsk;
  52        unsigned int bucket;
  53        unsigned int last_i;
  54        unsigned int table;
  55        struct net *net;
  56        unsigned int i;
  57
  58        req = nlmsg_data(cb->nlh);
  59        net = sock_net(skb->sk);
  60
  61        /* State saved between calls: */
  62        table = cb->args[0];
  63        bucket = cb->args[1];
  64        i = last_i = cb->args[2];
  65
  66        /* TODO VMCI pending sockets? */
  67
  68        spin_lock_bh(&vsock_table_lock);
  69
  70        /* Bind table (locally created sockets) */
  71        if (table == 0) {
  72                while (bucket < ARRAY_SIZE(vsock_bind_table)) {
  73                        struct list_head *head = &vsock_bind_table[bucket];
  74
  75                        i = 0;
  76                        list_for_each_entry(vsk, head, bound_table) {
  77                                struct sock *sk = sk_vsock(vsk);
  78
  79                                if (!net_eq(sock_net(sk), net))
  80                                        continue;
  81                                if (i < last_i)
  82                                        goto next_bind;
  83                                if (!(req->vdiag_states & (1 << sk->sk_state)))
  84                                        goto next_bind;
  85                                if (sk_diag_fill(sk, skb,
  86                                                 NETLINK_CB(cb->skb).portid,
  87                                                 cb->nlh->nlmsg_seq,
  88                                                 NLM_F_MULTI) < 0)
  89                                        goto done;
  90next_bind:
  91                                i++;
  92                        }
  93                        last_i = 0;
  94                        bucket++;
  95                }
  96
  97                table++;
  98                bucket = 0;
  99        }
 100
 101        /* Connected table (accepted connections) */
 102        while (bucket < ARRAY_SIZE(vsock_connected_table)) {
 103                struct list_head *head = &vsock_connected_table[bucket];
 104
 105                i = 0;
 106                list_for_each_entry(vsk, head, connected_table) {
 107                        struct sock *sk = sk_vsock(vsk);
 108
 109                        /* Skip sockets we've already seen above */
 110                        if (__vsock_in_bound_table(vsk))
 111                                continue;
 112
 113                        if (!net_eq(sock_net(sk), net))
 114                                continue;
 115                        if (i < last_i)
 116                                goto next_connected;
 117                        if (!(req->vdiag_states & (1 << sk->sk_state)))
 118                                goto next_connected;
 119                        if (sk_diag_fill(sk, skb,
 120                                         NETLINK_CB(cb->skb).portid,
 121                                         cb->nlh->nlmsg_seq,
 122                                         NLM_F_MULTI) < 0)
 123                                goto done;
 124next_connected:
 125                        i++;
 126                }
 127                last_i = 0;
 128                bucket++;
 129        }
 130
 131done:
 132        spin_unlock_bh(&vsock_table_lock);
 133
 134        cb->args[0] = table;
 135        cb->args[1] = bucket;
 136        cb->args[2] = i;
 137
 138        return skb->len;
 139}
 140
 141static int vsock_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
 142{
 143        int hdrlen = sizeof(struct vsock_diag_req);
 144        struct net *net = sock_net(skb->sk);
 145
 146        if (nlmsg_len(h) < hdrlen)
 147                return -EINVAL;
 148
 149        if (h->nlmsg_flags & NLM_F_DUMP) {
 150                struct netlink_dump_control c = {
 151                        .dump = vsock_diag_dump,
 152                };
 153                return netlink_dump_start(net->diag_nlsk, skb, h, &c);
 154        }
 155
 156        return -EOPNOTSUPP;
 157}
 158
 159static const struct sock_diag_handler vsock_diag_handler = {
 160        .family = AF_VSOCK,
 161        .dump = vsock_diag_handler_dump,
 162};
 163
 164static int __init vsock_diag_init(void)
 165{
 166        return sock_diag_register(&vsock_diag_handler);
 167}
 168
 169static void __exit vsock_diag_exit(void)
 170{
 171        sock_diag_unregister(&vsock_diag_handler);
 172}
 173
 174module_init(vsock_diag_init);
 175module_exit(vsock_diag_exit);
 176MODULE_LICENSE("GPL");
 177MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG,
 178                               40 /* AF_VSOCK */);
 179