xref: /minix/minix/net/uds/stat.c (revision 08cbf5a0)
1 /* UNIX Domain Sockets - stat.c - network status */
2 
3 #include "uds.h"
4 #include <sys/socketvar.h>
5 #include <sys/unpcb.h>
6 
7 /*
8  * Fill the given 'ki' structure with information about the socket 'uds'.
9  */
10 static void
11 uds_get_info(struct kinfo_pcb * ki, const struct udssock * uds)
12 {
13 	struct udssock *peer;
14 	socklen_t len;
15 	int type;
16 
17 	type = uds_get_type(uds);
18 	peer = uds_get_peer(uds);
19 
20 	ki->ki_pcbaddr = (uint64_t)(uintptr_t)uds;
21 	ki->ki_ppcbaddr = (uint64_t)(uintptr_t)uds;
22 	ki->ki_sockaddr = (uint64_t)(uintptr_t)&uds->uds_sock;
23 	ki->ki_family = AF_UNIX;
24 	ki->ki_type = type;
25 	ki->ki_protocol = UDSPROTO_UDS;
26 	ki->ki_pflags = 0;
27 	if (uds->uds_flags & UDSF_CONNWAIT)
28 		ki->ki_pflags |= UNP_CONNWAIT;
29 	if (uds->uds_flags & UDSF_PASSCRED)
30 		ki->ki_pflags |= UNP_WANTCRED;
31 	if (type != SOCK_DGRAM && uds->uds_cred.unp_pid != -1) {
32 		if (uds_is_listening(uds))
33 			ki->ki_pflags |= UNP_EIDSBIND;
34 		else if (uds_is_connecting(uds) || uds_is_connected(uds))
35 			ki->ki_pflags |= UNP_EIDSVALID;
36 	}
37 	/* Not sure about NetBSD connection states.  First attempt here. */
38 	if (uds_is_connecting(uds))
39 		ki->ki_sostate = SS_ISCONNECTING;
40 	else if (uds_is_connected(uds))
41 		ki->ki_sostate = SS_ISCONNECTED;
42 	else if (uds_is_disconnected(uds))
43 		ki->ki_sostate = SS_ISDISCONNECTED;
44 	ki->ki_rcvq = uds->uds_len;
45 	/* We currently mirror the peer's receive queue size when connected. */
46 	if (uds_is_connected(uds))
47 		ki->ki_sndq = peer->uds_len;
48 	/* The source is not set for bound connection-type sockets here. */
49 	if (type == SOCK_DGRAM || uds_is_listening(uds))
50 		uds_make_addr(uds->uds_path, (size_t)uds->uds_pathlen,
51 		    &ki->ki_src, &len);
52 	if (peer != NULL)
53 		uds_make_addr(peer->uds_path, (size_t)peer->uds_pathlen,
54 		    &ki->ki_dst, &len);
55 	/* TODO: we should set ki_inode and ki_vnode, but to what? */
56 	ki->ki_conn = (uint64_t)(uintptr_t)peer;
57 	if (!TAILQ_EMPTY(&uds->uds_queue))
58 		ki->ki_refs =
59 		    (uint64_t)(uintptr_t)TAILQ_FIRST(&uds->uds_queue);
60 	if (uds_has_link(uds))
61 		ki->ki_nextref =
62 		    (uint64_t)(uintptr_t)TAILQ_NEXT(uds, uds_next);
63 }
64 
65 /*
66  * Remote MIB implementation of CTL_NET PF_LOCAL {SOCK_STREAM,SOCK_DGRAM,
67  * SOCK_SEQPACKET} 0.  This function handles all queries on the
68  * "net.local.{stream,dgram,seqpacket}.pcblist" sysctl(7) nodes.
69  *
70  * The 0 for "pcblist" is a MINIXism: we use it to keep our arrays small.
71  * NetBSD numbers these nodes dynamically and so they have numbers above
72  * CREATE_BASE.  That also means that no userland application can possibly
73  * hardcode their numbers, and must perform lookups by name.  In turn, that
74  * means that we can safely change the 0 to another number if NetBSD ever
75  * introduces statically numbered nodes in these subtrees.
76  */
77 static ssize_t
78 net_local_pcblist(struct rmib_call * call, struct rmib_node * node __unused,
79 	struct rmib_oldp * oldp, struct rmib_newp * newp __unused)
80 {
81 	struct udssock *uds;
82 	struct kinfo_pcb ki;
83 	ssize_t off;
84 	int r, type, size, max;
85 
86 	if (call->call_namelen != 4)
87 		return EINVAL;
88 
89 	/* The first two added name fields are not used. */
90 
91 	size = call->call_name[2];
92 	if (size < 0 || (size_t)size > sizeof(ki))
93 		return EINVAL;
94 	if (size == 0)
95 		size = sizeof(ki);
96 	max = call->call_name[3];
97 
98 	type = call->call_oname[2];
99 
100 	off = 0;
101 
102 	for (uds = uds_enum(NULL, type); uds != NULL;
103 	    uds = uds_enum(uds, type)) {
104 		if (rmib_inrange(oldp, off)) {
105 			memset(&ki, 0, sizeof(ki));
106 
107 			uds_get_info(&ki, uds);
108 
109 			if ((r = rmib_copyout(oldp, off, &ki, size)) < 0)
110 				return r;
111 		}
112 
113 		off += size;
114 		if (max > 0 && --max == 0)
115 			break;
116 	}
117 
118 	/*
119 	 * Margin to limit the possible effects of the inherent race condition
120 	 * between receiving just the data size and receiving the actual data.
121 	 */
122 	if (oldp == NULL)
123 		off += PCB_SLOP * size;
124 
125 	return off;
126 }
127 
128 /* The CTL_NET PF_LOCAL SOCK_STREAM subtree. */
129 static struct rmib_node net_local_stream_table[] = {
130 	[0]	= RMIB_FUNC(RMIB_RO | CTLTYPE_NODE, 0, net_local_pcblist,
131 		    "pcblist", "SOCK_STREAM protocol control block list"),
132 };
133 
134 /* The CTL_NET PF_LOCAL SOCK_DGRAM subtree. */
135 static struct rmib_node net_local_dgram_table[] = {
136 	[0]	= RMIB_FUNC(RMIB_RO | CTLTYPE_NODE, 0, net_local_pcblist,
137 		    "pcblist", "SOCK_DGRAM protocol control block list"),
138 };
139 
140 /* The CTL_NET PF_LOCAL SOCK_SEQPACKET subtree. */
141 static struct rmib_node net_local_seqpacket_table[] = {
142 	[0]	= RMIB_FUNC(RMIB_RO | CTLTYPE_NODE, 0, net_local_pcblist,
143 		    "pcblist", "SOCK_SEQPACKET protocol control block list"),
144 };
145 
146 /* The CTL_NET PF_LOCAL subtree. */
147 static struct rmib_node net_local_table[] = {
148 /* 1*/	[SOCK_STREAM]		= RMIB_NODE(RMIB_RO, net_local_stream_table,
149 				    "stream", "SOCK_STREAM settings"),
150 /* 2*/	[SOCK_DGRAM]		= RMIB_NODE(RMIB_RO, net_local_dgram_table,
151 				    "dgram", "SOCK_DGRAM settings"),
152 /* 5*/	[SOCK_SEQPACKET]	= RMIB_NODE(RMIB_RO, net_local_seqpacket_table,
153 				    "seqpacket", "SOCK_SEQPACKET settings"),
154 };
155 
156 static struct rmib_node net_local_node =
157     RMIB_NODE(RMIB_RO, net_local_table, "local", "PF_LOCAL related settings");
158 
159 /*
160  * Initialize the status module.
161  */
162 void
163 uds_stat_init(void)
164 {
165 	const int mib[] = { CTL_NET, PF_LOCAL };
166 	int r;
167 
168 	/*
169 	 * Register our own "net.local" subtree with the MIB service.
170 	 *
171 	 * This call only returns local failures.  Remote failures (in the MIB
172 	 * service) are silently ignored.  So, we can safely panic on failure.
173 	 */
174 	if ((r = rmib_register(mib, __arraycount(mib), &net_local_node)) != OK)
175 		panic("UDS: unable to register remote MIB tree: %d", r);
176 }
177 
178 /*
179  * Clean up the status module.
180  */
181 void
182 uds_stat_cleanup(void)
183 {
184 
185 	rmib_deregister(&net_local_node);
186 }
187