]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - net/vmw_vsock/diag.c
vsock/virtio: reset connected sockets on device removal
[mirror_ubuntu-bionic-kernel.git] / net / vmw_vsock / diag.c
CommitLineData
413a4317
SH
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 */);