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