File Index
Files and directories
Sign in
FILE

diag.c

File preview with syntax highlighting.

linux-6.19.14/net/vmw_vsock/diag.c C
  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	.owner = THIS_MODULE,
161	.family = AF_VSOCK,
162	.dump = vsock_diag_handler_dump,
163};
164
165static int __init vsock_diag_init(void)
166{
167	return sock_diag_register(&vsock_diag_handler);
168}
169
170static void __exit vsock_diag_exit(void)
171{
172	sock_diag_unregister(&vsock_diag_handler);
173}
174
175module_init(vsock_diag_init);
176module_exit(vsock_diag_exit);
177MODULE_LICENSE("GPL");
178MODULE_DESCRIPTION("VMware Virtual Sockets monitoring via SOCK_DIAG");
179MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG,
180			       40 /* AF_VSOCK */);
~/ Read-only file preview.