xref: /minix3/minix/servers/mib/main.c (revision 6f3e0bcd3d3c17c74429db9d63eb808350d9a344)
1e4e21ee1SDavid van Moolenbroek /* MIB service - main.c - request abstraction and first-level tree */
2e4e21ee1SDavid van Moolenbroek /*
3e4e21ee1SDavid van Moolenbroek  * This is the Management Information Base (MIB) service.  Its one and only
4e4e21ee1SDavid van Moolenbroek  * task is to implement the sysctl(2) system call, which plays a fairly
5e4e21ee1SDavid van Moolenbroek  * important role in parts of *BSD userland.
6e4e21ee1SDavid van Moolenbroek  *
7e4e21ee1SDavid van Moolenbroek  * The sysctl(2) interface is used to access a variety of information.  In
8e4e21ee1SDavid van Moolenbroek  * order to obtain that information, and possibly modify it, the MIB service
9e4e21ee1SDavid van Moolenbroek  * calls into many other services.  The MIB service must therefore not be
10e4e21ee1SDavid van Moolenbroek  * called directly from other services, with the exception of ProcFS.  In fact,
11e4e21ee1SDavid van Moolenbroek  * ProcFS is currently the only service that is modeled as logically higher in
12e4e21ee1SDavid van Moolenbroek  * the MINIX3 service stack than MIB, something that itself is possible only
13e4e21ee1SDavid van Moolenbroek  * due to the nonblocking nature of VFS.  MIB may issue blocking calls to VFS.
14e4e21ee1SDavid van Moolenbroek  *
15e4e21ee1SDavid van Moolenbroek  * The MIB service is in the boot image because even init(8) makes use of
16e4e21ee1SDavid van Moolenbroek  * sysctl(2) during its own startup, so launching the MIB service at any later
17e4e21ee1SDavid van Moolenbroek  * time would make a proper implementation of sysctl(2) impossible.  Also, the
18e4e21ee1SDavid van Moolenbroek  * service needs superuser privileges because it may need to issue privileged
19e4e21ee1SDavid van Moolenbroek  * calls and obtain privileged information from other services.
20e4e21ee1SDavid van Moolenbroek  *
21*6f3e0bcdSDavid van Moolenbroek  * While most of the sysctl tree is maintained locally, the MIB service also
22*6f3e0bcdSDavid van Moolenbroek  * allows other services to register "remote" subtrees which are then handled
23*6f3e0bcdSDavid van Moolenbroek  * entirely by those services.  This feature, which works much like file system
24*6f3e0bcdSDavid van Moolenbroek  * mounting, allows 1) sysctl handling code to stay local to its corresponding
25*6f3e0bcdSDavid van Moolenbroek  * service, and 2) parts of the sysctl tree to adapt and expand dynamically as
26*6f3e0bcdSDavid van Moolenbroek  * optional services are started and stopped.  Compared to the MIB service's
27*6f3e0bcdSDavid van Moolenbroek  * local handling, remotely handled subtrees are subject to several additional
28*6f3e0bcdSDavid van Moolenbroek  * practical restrictions, hoever.  In the current implementation, the MIB
29*6f3e0bcdSDavid van Moolenbroek  * service makes blocking calls to remote services as needed; in the future,
30*6f3e0bcdSDavid van Moolenbroek  * these interactions could be made (more) asynchronous.
31*6f3e0bcdSDavid van Moolenbroek  *
32e4e21ee1SDavid van Moolenbroek  * The MIB service was created by David van Moolenbroek <david@minix3.org>.
33e4e21ee1SDavid van Moolenbroek  */
34e4e21ee1SDavid van Moolenbroek 
35e4e21ee1SDavid van Moolenbroek #include "mib.h"
36e4e21ee1SDavid van Moolenbroek 
37e4e21ee1SDavid van Moolenbroek /*
38e4e21ee1SDavid van Moolenbroek  * Most of these initially empty nodes are filled in by their corresponding
39*6f3e0bcdSDavid van Moolenbroek  * modules' _init calls; see mib_init below.  However, some subtrees are not
40*6f3e0bcdSDavid van Moolenbroek  * populated by the MIB service itself.  CTL_NET is expected to be populated
41*6f3e0bcdSDavid van Moolenbroek  * through registration of remote subtrees.  The libc sysctl(3) wrapper code
42*6f3e0bcdSDavid van Moolenbroek  * takes care of the CTL_USER subtree.  It must have an entry here though, or
43*6f3e0bcdSDavid van Moolenbroek  * sysctl(8) will not list it.  CTL_VENDOR is also empty, but writable, so that
44*6f3e0bcdSDavid van Moolenbroek  * it may be used by third parties.
45e4e21ee1SDavid van Moolenbroek  */
46e4e21ee1SDavid van Moolenbroek static struct mib_node mib_table[] = {
47e4e21ee1SDavid van Moolenbroek /* 1*/	[CTL_KERN]	= MIB_ENODE(_P | _RO, "kern", "High kernel"),
4825d39513SDavid van Moolenbroek /* 2*/	[CTL_VM]	= MIB_ENODE(_P | _RO, "vm", "Virtual memory"),
49*6f3e0bcdSDavid van Moolenbroek /* 4*/	[CTL_NET]	= MIB_ENODE(_P | _RO, "net", "Networking"),
5025d39513SDavid van Moolenbroek /* 6*/	[CTL_HW]	= MIB_ENODE(_P | _RO, "hw", "Generic CPU, I/O"),
51e4e21ee1SDavid van Moolenbroek /* 8*/	[CTL_USER]	= MIB_ENODE(_P | _RO, "user", "User-level"),
52e4e21ee1SDavid van Moolenbroek /*11*/	[CTL_VENDOR]	= MIB_ENODE(_P | _RW, "vendor", "Vendor specific"),
53e4e21ee1SDavid van Moolenbroek /*32*/	[CTL_MINIX]	= MIB_ENODE(_P | _RO, "minix", "MINIX3 specific"),
54e4e21ee1SDavid van Moolenbroek };
55e4e21ee1SDavid van Moolenbroek 
56e4e21ee1SDavid van Moolenbroek /*
57e4e21ee1SDavid van Moolenbroek  * The root node of the tree.  The root node is used internally only--it is
58e4e21ee1SDavid van Moolenbroek  * impossible to access the root node itself from userland in any way.  The
59e4e21ee1SDavid van Moolenbroek  * node is writable by default, so that programs such as init(8) may create
60e4e21ee1SDavid van Moolenbroek  * their own top-level entries.
61e4e21ee1SDavid van Moolenbroek  */
62*6f3e0bcdSDavid van Moolenbroek struct mib_node mib_root = MIB_NODE(_RW, mib_table, "", "");
63e4e21ee1SDavid van Moolenbroek 
64e4e21ee1SDavid van Moolenbroek /*
65e4e21ee1SDavid van Moolenbroek  * Structures describing old and new data as provided by userland.  The primary
66e4e21ee1SDavid van Moolenbroek  * advantage of these opaque structures is that we could in principle use them
67e4e21ee1SDavid van Moolenbroek  * to implement storage of small data results in the sysctl reply message, so
68e4e21ee1SDavid van Moolenbroek  * as to avoid the kernel copy, without changing any of the handler code.
69e4e21ee1SDavid van Moolenbroek  */
70e4e21ee1SDavid van Moolenbroek struct mib_oldp {
71e4e21ee1SDavid van Moolenbroek 	endpoint_t oldp_endpt;
72e4e21ee1SDavid van Moolenbroek 	vir_bytes oldp_addr;
73e4e21ee1SDavid van Moolenbroek 	size_t oldp_len;
74e4e21ee1SDavid van Moolenbroek };
75e4e21ee1SDavid van Moolenbroek /*
76e4e21ee1SDavid van Moolenbroek  * Same structure, different type: prevent accidental mixups, and avoid the
77e4e21ee1SDavid van Moolenbroek  * need to use __restrict everywhere.
78e4e21ee1SDavid van Moolenbroek  */
79e4e21ee1SDavid van Moolenbroek struct mib_newp {
80e4e21ee1SDavid van Moolenbroek 	endpoint_t newp_endpt;
81e4e21ee1SDavid van Moolenbroek 	vir_bytes newp_addr;
82e4e21ee1SDavid van Moolenbroek 	size_t newp_len;
83e4e21ee1SDavid van Moolenbroek };
84e4e21ee1SDavid van Moolenbroek 
85e4e21ee1SDavid van Moolenbroek /*
86e4e21ee1SDavid van Moolenbroek  * Return TRUE or FALSE indicating whether the given offset is within the range
87e4e21ee1SDavid van Moolenbroek  * of data that is to be copied out.  This call can be used to test whether
88e4e21ee1SDavid van Moolenbroek  * certain bits of data need to be prepared for copying at all.
89e4e21ee1SDavid van Moolenbroek  */
90e4e21ee1SDavid van Moolenbroek int
mib_inrange(struct mib_oldp * oldp,size_t off)91e4e21ee1SDavid van Moolenbroek mib_inrange(struct mib_oldp * oldp, size_t off)
92e4e21ee1SDavid van Moolenbroek {
93e4e21ee1SDavid van Moolenbroek 
94e4e21ee1SDavid van Moolenbroek 	if (oldp == NULL)
95e4e21ee1SDavid van Moolenbroek 		return FALSE;
96e4e21ee1SDavid van Moolenbroek 
97e4e21ee1SDavid van Moolenbroek 	return (off < oldp->oldp_len);
98e4e21ee1SDavid van Moolenbroek }
99e4e21ee1SDavid van Moolenbroek 
100e4e21ee1SDavid van Moolenbroek /*
101e4e21ee1SDavid van Moolenbroek  * Return the total length of the requested data.  This should not be used
102e4e21ee1SDavid van Moolenbroek  * directly except in highly unusual cases, such as particular node requests
103e4e21ee1SDavid van Moolenbroek  * where the request semantics blatantly violate overall sysctl(2) semantics.
104e4e21ee1SDavid van Moolenbroek  */
105e4e21ee1SDavid van Moolenbroek size_t
mib_getoldlen(struct mib_oldp * oldp)106e4e21ee1SDavid van Moolenbroek mib_getoldlen(struct mib_oldp * oldp)
107e4e21ee1SDavid van Moolenbroek {
108e4e21ee1SDavid van Moolenbroek 
109e4e21ee1SDavid van Moolenbroek 	if (oldp == NULL)
110e4e21ee1SDavid van Moolenbroek 		return 0;
111e4e21ee1SDavid van Moolenbroek 
112e4e21ee1SDavid van Moolenbroek 	return oldp->oldp_len;
113e4e21ee1SDavid van Moolenbroek }
114e4e21ee1SDavid van Moolenbroek 
115e4e21ee1SDavid van Moolenbroek /*
116e4e21ee1SDavid van Moolenbroek  * Copy out (partial) data to the user.  The copy is automatically limited to
117e4e21ee1SDavid van Moolenbroek  * the range of data requested by the user.  Return the requested length on
118e4e21ee1SDavid van Moolenbroek  * success (for the caller's convenience) or an error code on failure.
119e4e21ee1SDavid van Moolenbroek  */
120e4e21ee1SDavid van Moolenbroek ssize_t
mib_copyout(struct mib_oldp * __restrict oldp,size_t off,const void * __restrict buf,size_t size)121e4e21ee1SDavid van Moolenbroek mib_copyout(struct mib_oldp * __restrict oldp, size_t off,
122e4e21ee1SDavid van Moolenbroek 	const void * __restrict buf, size_t size)
123e4e21ee1SDavid van Moolenbroek {
124e4e21ee1SDavid van Moolenbroek 	size_t len;
125e4e21ee1SDavid van Moolenbroek 	int r;
126e4e21ee1SDavid van Moolenbroek 
127e4e21ee1SDavid van Moolenbroek 	len = size;
128e4e21ee1SDavid van Moolenbroek 	assert(len <= SSIZE_MAX);
129e4e21ee1SDavid van Moolenbroek 
130e4e21ee1SDavid van Moolenbroek 	if (oldp == NULL || off >= oldp->oldp_len)
131e4e21ee1SDavid van Moolenbroek 		return size; /* nothing to do */
132e4e21ee1SDavid van Moolenbroek 
133e4e21ee1SDavid van Moolenbroek 	if (len > oldp->oldp_len - off)
134e4e21ee1SDavid van Moolenbroek 		len = oldp->oldp_len - off;
135e4e21ee1SDavid van Moolenbroek 
136e4e21ee1SDavid van Moolenbroek 	if ((r = sys_datacopy(SELF, (vir_bytes)buf, oldp->oldp_endpt,
137e4e21ee1SDavid van Moolenbroek 	    oldp->oldp_addr + off, len)) != OK)
138e4e21ee1SDavid van Moolenbroek 		return r;
139e4e21ee1SDavid van Moolenbroek 
140e4e21ee1SDavid van Moolenbroek 	return size;
141e4e21ee1SDavid van Moolenbroek }
142e4e21ee1SDavid van Moolenbroek 
143e4e21ee1SDavid van Moolenbroek /*
144e4e21ee1SDavid van Moolenbroek  * Override the oldlen value returned from the call, in situations where an
145e4e21ee1SDavid van Moolenbroek  * error is thrown as well.
146e4e21ee1SDavid van Moolenbroek  */
147e4e21ee1SDavid van Moolenbroek void
mib_setoldlen(struct mib_call * call,size_t oldlen)148e4e21ee1SDavid van Moolenbroek mib_setoldlen(struct mib_call * call, size_t oldlen)
149e4e21ee1SDavid van Moolenbroek {
150e4e21ee1SDavid van Moolenbroek 
151e4e21ee1SDavid van Moolenbroek 	call->call_reslen = oldlen;
152e4e21ee1SDavid van Moolenbroek }
153e4e21ee1SDavid van Moolenbroek 
154e4e21ee1SDavid van Moolenbroek /*
155e4e21ee1SDavid van Moolenbroek  * Return the new data length as provided by the user, or 0 if the user did not
156e4e21ee1SDavid van Moolenbroek  * supply new data.
157e4e21ee1SDavid van Moolenbroek  */
158e4e21ee1SDavid van Moolenbroek size_t
mib_getnewlen(struct mib_newp * newp)159e4e21ee1SDavid van Moolenbroek mib_getnewlen(struct mib_newp * newp)
160e4e21ee1SDavid van Moolenbroek {
161e4e21ee1SDavid van Moolenbroek 
162e4e21ee1SDavid van Moolenbroek 	if (newp == NULL)
163e4e21ee1SDavid van Moolenbroek 		return 0;
164e4e21ee1SDavid van Moolenbroek 
165e4e21ee1SDavid van Moolenbroek 	return newp->newp_len;
166e4e21ee1SDavid van Moolenbroek }
167e4e21ee1SDavid van Moolenbroek 
168e4e21ee1SDavid van Moolenbroek /*
169e4e21ee1SDavid van Moolenbroek  * Copy in data from the user.  The given length must match exactly the length
170e4e21ee1SDavid van Moolenbroek  * given by the user.  Return OK or an error code.
171e4e21ee1SDavid van Moolenbroek  */
172e4e21ee1SDavid van Moolenbroek int
mib_copyin(struct mib_newp * __restrict newp,void * __restrict buf,size_t len)173e4e21ee1SDavid van Moolenbroek mib_copyin(struct mib_newp * __restrict newp, void * __restrict buf,
174e4e21ee1SDavid van Moolenbroek 	size_t len)
175e4e21ee1SDavid van Moolenbroek {
176e4e21ee1SDavid van Moolenbroek 
177e4e21ee1SDavid van Moolenbroek 	if (newp == NULL || len != newp->newp_len)
178e4e21ee1SDavid van Moolenbroek 		return EINVAL;
179e4e21ee1SDavid van Moolenbroek 
180e4e21ee1SDavid van Moolenbroek 	if (len == 0)
181e4e21ee1SDavid van Moolenbroek 		return OK;
182e4e21ee1SDavid van Moolenbroek 
183e4e21ee1SDavid van Moolenbroek 	return sys_datacopy(newp->newp_endpt, newp->newp_addr, SELF,
184e4e21ee1SDavid van Moolenbroek 	    (vir_bytes)buf, len);
185e4e21ee1SDavid van Moolenbroek }
186e4e21ee1SDavid van Moolenbroek 
187e4e21ee1SDavid van Moolenbroek /*
188e4e21ee1SDavid van Moolenbroek  * Copy in auxiliary data from the user, based on a user pointer obtained from
189e4e21ee1SDavid van Moolenbroek  * data copied in earlier through mib_copyin().
190e4e21ee1SDavid van Moolenbroek  */
191e4e21ee1SDavid van Moolenbroek int
mib_copyin_aux(struct mib_newp * __restrict newp,vir_bytes addr,void * __restrict buf,size_t len)192e4e21ee1SDavid van Moolenbroek mib_copyin_aux(struct mib_newp * __restrict newp, vir_bytes addr,
193e4e21ee1SDavid van Moolenbroek 	void * __restrict buf, size_t len)
194e4e21ee1SDavid van Moolenbroek {
195e4e21ee1SDavid van Moolenbroek 
196e4e21ee1SDavid van Moolenbroek 	assert(newp != NULL);
197e4e21ee1SDavid van Moolenbroek 
198e4e21ee1SDavid van Moolenbroek 	if (len == 0)
199e4e21ee1SDavid van Moolenbroek 		return OK;
200e4e21ee1SDavid van Moolenbroek 
201e4e21ee1SDavid van Moolenbroek 	return sys_datacopy(newp->newp_endpt, addr, SELF, (vir_bytes)buf, len);
202e4e21ee1SDavid van Moolenbroek }
203e4e21ee1SDavid van Moolenbroek 
204e4e21ee1SDavid van Moolenbroek /*
205*6f3e0bcdSDavid van Moolenbroek  * Create a grant for a call's old data region, if not NULL, for the given
206*6f3e0bcdSDavid van Moolenbroek  * endpoint.  On success, store the grant (or GRANT_INVALID) in grantp and the
207*6f3e0bcdSDavid van Moolenbroek  * length in lenp, and return OK.  On error, return an error code that must not
208*6f3e0bcdSDavid van Moolenbroek  * be ENOMEM.
209*6f3e0bcdSDavid van Moolenbroek  */
210*6f3e0bcdSDavid van Moolenbroek int
mib_relay_oldp(endpoint_t endpt,struct mib_oldp * __restrict oldp,cp_grant_id_t * grantp,size_t * __restrict lenp)211*6f3e0bcdSDavid van Moolenbroek mib_relay_oldp(endpoint_t endpt, struct mib_oldp * __restrict oldp,
212*6f3e0bcdSDavid van Moolenbroek 	cp_grant_id_t * grantp, size_t * __restrict lenp)
213*6f3e0bcdSDavid van Moolenbroek {
214*6f3e0bcdSDavid van Moolenbroek 
215*6f3e0bcdSDavid van Moolenbroek 	if (oldp != NULL) {
216*6f3e0bcdSDavid van Moolenbroek 		*grantp = cpf_grant_magic(endpt, oldp->oldp_endpt,
217*6f3e0bcdSDavid van Moolenbroek 		    oldp->oldp_addr, oldp->oldp_len, CPF_WRITE);
218*6f3e0bcdSDavid van Moolenbroek 		if (!GRANT_VALID(*grantp))
219*6f3e0bcdSDavid van Moolenbroek 			return EINVAL;
220*6f3e0bcdSDavid van Moolenbroek 		*lenp = oldp->oldp_len;
221*6f3e0bcdSDavid van Moolenbroek 	} else {
222*6f3e0bcdSDavid van Moolenbroek 		*grantp = GRANT_INVALID;
223*6f3e0bcdSDavid van Moolenbroek 		*lenp = 0;
224*6f3e0bcdSDavid van Moolenbroek 	}
225*6f3e0bcdSDavid van Moolenbroek 
226*6f3e0bcdSDavid van Moolenbroek 	return OK;
227*6f3e0bcdSDavid van Moolenbroek }
228*6f3e0bcdSDavid van Moolenbroek 
229*6f3e0bcdSDavid van Moolenbroek /*
230*6f3e0bcdSDavid van Moolenbroek  * Create a grant for a call's new data region, if not NULL, for the given
231*6f3e0bcdSDavid van Moolenbroek  * endpoint.  On success, store the grant (or GRANT_INVALID) in grantp and the
232*6f3e0bcdSDavid van Moolenbroek  * length in lenp, and return OK.  On error, return an error code that must not
233*6f3e0bcdSDavid van Moolenbroek  * be ENOMEM.
234*6f3e0bcdSDavid van Moolenbroek  */
235*6f3e0bcdSDavid van Moolenbroek int
mib_relay_newp(endpoint_t endpt,struct mib_newp * __restrict newp,cp_grant_id_t * grantp,size_t * __restrict lenp)236*6f3e0bcdSDavid van Moolenbroek mib_relay_newp(endpoint_t endpt, struct mib_newp * __restrict newp,
237*6f3e0bcdSDavid van Moolenbroek 	cp_grant_id_t * grantp, size_t * __restrict lenp)
238*6f3e0bcdSDavid van Moolenbroek {
239*6f3e0bcdSDavid van Moolenbroek 
240*6f3e0bcdSDavid van Moolenbroek 	if (newp != NULL) {
241*6f3e0bcdSDavid van Moolenbroek 		*grantp = cpf_grant_magic(endpt, newp->newp_endpt,
242*6f3e0bcdSDavid van Moolenbroek 		    newp->newp_addr, newp->newp_len, CPF_READ);
243*6f3e0bcdSDavid van Moolenbroek 		if (!GRANT_VALID(*grantp))
244*6f3e0bcdSDavid van Moolenbroek 			return EINVAL;
245*6f3e0bcdSDavid van Moolenbroek 		*lenp = newp->newp_len;
246*6f3e0bcdSDavid van Moolenbroek 	} else {
247*6f3e0bcdSDavid van Moolenbroek 		*grantp = GRANT_INVALID;
248*6f3e0bcdSDavid van Moolenbroek 		*lenp = 0;
249*6f3e0bcdSDavid van Moolenbroek 	}
250*6f3e0bcdSDavid van Moolenbroek 
251*6f3e0bcdSDavid van Moolenbroek 	return OK;
252*6f3e0bcdSDavid van Moolenbroek }
253*6f3e0bcdSDavid van Moolenbroek 
254*6f3e0bcdSDavid van Moolenbroek /*
255e4e21ee1SDavid van Moolenbroek  * Check whether the user is allowed to perform privileged operations.  The
256e4e21ee1SDavid van Moolenbroek  * function returns a nonzero value if this is the case, and zero otherwise.
257e4e21ee1SDavid van Moolenbroek  * Authorization is performed only once per call.
258e4e21ee1SDavid van Moolenbroek  */
259e4e21ee1SDavid van Moolenbroek int
mib_authed(struct mib_call * call)260e4e21ee1SDavid van Moolenbroek mib_authed(struct mib_call * call)
261e4e21ee1SDavid van Moolenbroek {
262e4e21ee1SDavid van Moolenbroek 
263e4e21ee1SDavid van Moolenbroek 	if ((call->call_flags & (MIB_FLAG_AUTH | MIB_FLAG_NOAUTH)) == 0) {
264e4e21ee1SDavid van Moolenbroek 		/* Ask PM if this endpoint has superuser privileges. */
265e4e21ee1SDavid van Moolenbroek 		if (getnuid(call->call_endpt) == SUPER_USER)
266e4e21ee1SDavid van Moolenbroek 			call->call_flags |= MIB_FLAG_AUTH;
267e4e21ee1SDavid van Moolenbroek 		else
268e4e21ee1SDavid van Moolenbroek 			call->call_flags |= MIB_FLAG_NOAUTH;
269e4e21ee1SDavid van Moolenbroek 	}
270e4e21ee1SDavid van Moolenbroek 
271e4e21ee1SDavid van Moolenbroek 	return (call->call_flags & MIB_FLAG_AUTH);
272e4e21ee1SDavid van Moolenbroek }
273e4e21ee1SDavid van Moolenbroek 
274e4e21ee1SDavid van Moolenbroek /*
275e4e21ee1SDavid van Moolenbroek  * Implement the sysctl(2) system call.
276e4e21ee1SDavid van Moolenbroek  */
277e4e21ee1SDavid van Moolenbroek static int
mib_sysctl(message * __restrict m_in,int ipc_status,message * __restrict m_out)278*6f3e0bcdSDavid van Moolenbroek mib_sysctl(message * __restrict m_in, int ipc_status,
279*6f3e0bcdSDavid van Moolenbroek 	message * __restrict m_out)
280e4e21ee1SDavid van Moolenbroek {
281e4e21ee1SDavid van Moolenbroek 	vir_bytes oldaddr, newaddr;
282e4e21ee1SDavid van Moolenbroek 	size_t oldlen, newlen;
283e4e21ee1SDavid van Moolenbroek 	unsigned int namelen;
284e4e21ee1SDavid van Moolenbroek 	int s, name[CTL_MAXNAME];
285e4e21ee1SDavid van Moolenbroek 	endpoint_t endpt;
286e4e21ee1SDavid van Moolenbroek 	struct mib_oldp oldp, *oldpp;
287e4e21ee1SDavid van Moolenbroek 	struct mib_newp newp, *newpp;
288e4e21ee1SDavid van Moolenbroek 	struct mib_call call;
289e4e21ee1SDavid van Moolenbroek 	ssize_t r;
290e4e21ee1SDavid van Moolenbroek 
291*6f3e0bcdSDavid van Moolenbroek 	/* Only handle blocking calls.  Ignore everything else. */
292*6f3e0bcdSDavid van Moolenbroek 	if (IPC_STATUS_CALL(ipc_status) != SENDREC)
293*6f3e0bcdSDavid van Moolenbroek 		return EDONTREPLY;
294*6f3e0bcdSDavid van Moolenbroek 
295e4e21ee1SDavid van Moolenbroek 	endpt = m_in->m_source;
296e4e21ee1SDavid van Moolenbroek 	oldaddr = m_in->m_lc_mib_sysctl.oldp;
297e4e21ee1SDavid van Moolenbroek 	oldlen = m_in->m_lc_mib_sysctl.oldlen;
298e4e21ee1SDavid van Moolenbroek 	newaddr = m_in->m_lc_mib_sysctl.newp;
299e4e21ee1SDavid van Moolenbroek 	newlen = m_in->m_lc_mib_sysctl.newlen;
300e4e21ee1SDavid van Moolenbroek 	namelen = m_in->m_lc_mib_sysctl.namelen;
301e4e21ee1SDavid van Moolenbroek 
302e4e21ee1SDavid van Moolenbroek 	if (namelen == 0 || namelen > CTL_MAXNAME)
303e4e21ee1SDavid van Moolenbroek 		return EINVAL;
304e4e21ee1SDavid van Moolenbroek 
305e4e21ee1SDavid van Moolenbroek 	/*
306e4e21ee1SDavid van Moolenbroek 	 * In most cases, the entire name fits in the request message, so we
307e4e21ee1SDavid van Moolenbroek 	 * can avoid a kernel copy.
308e4e21ee1SDavid van Moolenbroek 	 */
309e4e21ee1SDavid van Moolenbroek 	if (namelen > CTL_SHORTNAME) {
310e4e21ee1SDavid van Moolenbroek 		if ((s = sys_datacopy(endpt, m_in->m_lc_mib_sysctl.namep, SELF,
311e4e21ee1SDavid van Moolenbroek 		    (vir_bytes)&name, sizeof(name[0]) * namelen)) != OK)
312e4e21ee1SDavid van Moolenbroek 			return s;
313e4e21ee1SDavid van Moolenbroek 	} else
314e4e21ee1SDavid van Moolenbroek 		memcpy(name, m_in->m_lc_mib_sysctl.name,
315e4e21ee1SDavid van Moolenbroek 		    sizeof(name[0]) * namelen);
316e4e21ee1SDavid van Moolenbroek 
317e4e21ee1SDavid van Moolenbroek 	/*
318e4e21ee1SDavid van Moolenbroek 	 * Set up a structure for the old data, if any.  When no old address is
319e4e21ee1SDavid van Moolenbroek 	 * given, be forgiving if oldlen is not zero, as the user may simply
320e4e21ee1SDavid van Moolenbroek 	 * not have initialized the variable before passing a pointer to it.
321e4e21ee1SDavid van Moolenbroek 	 */
322e4e21ee1SDavid van Moolenbroek 	if (oldaddr != 0) {
323e4e21ee1SDavid van Moolenbroek 		oldp.oldp_endpt = endpt;
324e4e21ee1SDavid van Moolenbroek 		oldp.oldp_addr = oldaddr;
325e4e21ee1SDavid van Moolenbroek 		oldp.oldp_len = oldlen;
326e4e21ee1SDavid van Moolenbroek 		oldpp = &oldp;
327e4e21ee1SDavid van Moolenbroek 	} else
328e4e21ee1SDavid van Moolenbroek 		oldpp = NULL;
329e4e21ee1SDavid van Moolenbroek 
330e4e21ee1SDavid van Moolenbroek 	/*
331e4e21ee1SDavid van Moolenbroek 	 * Set up a structure for the new data, if any.  If one of newaddr and
332e4e21ee1SDavid van Moolenbroek 	 * newlen is zero but not the other, we (like NetBSD) disregard both.
333e4e21ee1SDavid van Moolenbroek 	 */
334e4e21ee1SDavid van Moolenbroek 	if (newaddr != 0 && newlen != 0) {
335e4e21ee1SDavid van Moolenbroek 		newp.newp_endpt = endpt;
336e4e21ee1SDavid van Moolenbroek 		newp.newp_addr = newaddr;
337e4e21ee1SDavid van Moolenbroek 		newp.newp_len = newlen;
338e4e21ee1SDavid van Moolenbroek 		newpp = &newp;
339e4e21ee1SDavid van Moolenbroek 	} else
340e4e21ee1SDavid van Moolenbroek 		newpp = NULL;
341e4e21ee1SDavid van Moolenbroek 
342e4e21ee1SDavid van Moolenbroek 	/*
343e4e21ee1SDavid van Moolenbroek 	 * Set up a structure for other call parameters.  Most of these should
344e4e21ee1SDavid van Moolenbroek 	 * be used rarely, and we may want to add more later, so do not pass
345e4e21ee1SDavid van Moolenbroek 	 * all of them around as actual function parameters all the time.
346e4e21ee1SDavid van Moolenbroek 	 */
347e4e21ee1SDavid van Moolenbroek 	call.call_endpt = endpt;
348e4e21ee1SDavid van Moolenbroek 	call.call_name = name;
349e4e21ee1SDavid van Moolenbroek 	call.call_namelen = namelen;
350e4e21ee1SDavid van Moolenbroek 	call.call_flags = 0;
351e4e21ee1SDavid van Moolenbroek 	call.call_reslen = 0;
352e4e21ee1SDavid van Moolenbroek 
353*6f3e0bcdSDavid van Moolenbroek 	r = mib_dispatch(&call, oldpp, newpp);
354e4e21ee1SDavid van Moolenbroek 
355e4e21ee1SDavid van Moolenbroek 	/*
356e4e21ee1SDavid van Moolenbroek 	 * From NetBSD: we copy out as much as we can from the old data, while
357e4e21ee1SDavid van Moolenbroek 	 * at the same time computing the full data length.  Then, here at the
358e4e21ee1SDavid van Moolenbroek 	 * end, if the entire result did not fit in the destination buffer, we
359e4e21ee1SDavid van Moolenbroek 	 * return ENOMEM instead of success, thus also returning a partial
360e4e21ee1SDavid van Moolenbroek 	 * result and the full data length.
361e4e21ee1SDavid van Moolenbroek 	 *
362e4e21ee1SDavid van Moolenbroek 	 * It is also possible that data are copied out along with a "real"
363e4e21ee1SDavid van Moolenbroek 	 * error.  In that case, we must report a nonzero resulting length
364e4e21ee1SDavid van Moolenbroek 	 * along with that error code.  This is currently the case when node
365e4e21ee1SDavid van Moolenbroek 	 * creation resulted in a collision, in which case the error code is
366e4e21ee1SDavid van Moolenbroek 	 * EEXIST while the existing node is copied out as well.
367e4e21ee1SDavid van Moolenbroek 	 */
368e4e21ee1SDavid van Moolenbroek 	if (r >= 0) {
369e4e21ee1SDavid van Moolenbroek 		m_out->m_mib_lc_sysctl.oldlen = (size_t)r;
370e4e21ee1SDavid van Moolenbroek 
371e4e21ee1SDavid van Moolenbroek 		if (oldaddr != 0 && oldlen < (size_t)r)
372e4e21ee1SDavid van Moolenbroek 			r = ENOMEM;
373e4e21ee1SDavid van Moolenbroek 		else
374e4e21ee1SDavid van Moolenbroek 			r = OK;
375e4e21ee1SDavid van Moolenbroek 	} else
376e4e21ee1SDavid van Moolenbroek 		m_out->m_mib_lc_sysctl.oldlen = call.call_reslen;
377e4e21ee1SDavid van Moolenbroek 
378e4e21ee1SDavid van Moolenbroek 	return r;
379e4e21ee1SDavid van Moolenbroek }
380e4e21ee1SDavid van Moolenbroek 
381e4e21ee1SDavid van Moolenbroek /*
382e4e21ee1SDavid van Moolenbroek  * Initialize the service.
383e4e21ee1SDavid van Moolenbroek  */
384e4e21ee1SDavid van Moolenbroek static int
mib_init(int type __unused,sef_init_info_t * info __unused)385e4e21ee1SDavid van Moolenbroek mib_init(int type __unused, sef_init_info_t * info __unused)
386e4e21ee1SDavid van Moolenbroek {
387e4e21ee1SDavid van Moolenbroek 
388e4e21ee1SDavid van Moolenbroek 	/*
389e4e21ee1SDavid van Moolenbroek 	 * Initialize pointers and sizes of subtrees in different modules.
390e4e21ee1SDavid van Moolenbroek 	 * This is needed because we cannot use sizeof on external arrays.
391e4e21ee1SDavid van Moolenbroek 	 * We do initialize the node entry (including any other fields)
392e4e21ee1SDavid van Moolenbroek 	 * statically through MIB_ENODE because that forces the array to be
393e4e21ee1SDavid van Moolenbroek 	 * large enough to store the entry.
394e4e21ee1SDavid van Moolenbroek 	 */
395e4e21ee1SDavid van Moolenbroek 	mib_kern_init(&mib_table[CTL_KERN]);
39625d39513SDavid van Moolenbroek 	mib_vm_init(&mib_table[CTL_VM]);
39725d39513SDavid van Moolenbroek 	mib_hw_init(&mib_table[CTL_HW]);
398e4e21ee1SDavid van Moolenbroek 	mib_minix_init(&mib_table[CTL_MINIX]);
399e4e21ee1SDavid van Moolenbroek 
400e4e21ee1SDavid van Moolenbroek 	/*
401e4e21ee1SDavid van Moolenbroek 	 * Now that the static tree is complete, go through the entire tree,
402e4e21ee1SDavid van Moolenbroek 	 * initializing miscellaneous fields.
403e4e21ee1SDavid van Moolenbroek 	 */
404*6f3e0bcdSDavid van Moolenbroek 	mib_tree_init();
405*6f3e0bcdSDavid van Moolenbroek 
406*6f3e0bcdSDavid van Moolenbroek 	/* Prepare for requests to mount remote subtrees. */
407*6f3e0bcdSDavid van Moolenbroek 	mib_remote_init();
408e4e21ee1SDavid van Moolenbroek 
409e4e21ee1SDavid van Moolenbroek 	return OK;
410e4e21ee1SDavid van Moolenbroek }
411e4e21ee1SDavid van Moolenbroek 
412e4e21ee1SDavid van Moolenbroek /*
413e4e21ee1SDavid van Moolenbroek  * Perform SEF startup.
414e4e21ee1SDavid van Moolenbroek  */
415e4e21ee1SDavid van Moolenbroek static void
mib_startup(void)416e4e21ee1SDavid van Moolenbroek mib_startup(void)
417e4e21ee1SDavid van Moolenbroek {
418e4e21ee1SDavid van Moolenbroek 
419e4e21ee1SDavid van Moolenbroek 	sef_setcb_init_fresh(mib_init);
420e4e21ee1SDavid van Moolenbroek 	/*
421e4e21ee1SDavid van Moolenbroek 	 * If we restart we lose all dynamic state, which means we lose all
422e4e21ee1SDavid van Moolenbroek 	 * nodes that have been created at run time.  However, running with
423e4e21ee1SDavid van Moolenbroek 	 * only the static node tree is still better than not running at all.
424e4e21ee1SDavid van Moolenbroek 	 */
425e4e21ee1SDavid van Moolenbroek 	sef_setcb_init_restart(mib_init);
426e4e21ee1SDavid van Moolenbroek 
427e4e21ee1SDavid van Moolenbroek 	sef_startup();
428e4e21ee1SDavid van Moolenbroek }
429e4e21ee1SDavid van Moolenbroek 
430e4e21ee1SDavid van Moolenbroek /*
431e4e21ee1SDavid van Moolenbroek  * The Management Information Base (MIB) service.
432e4e21ee1SDavid van Moolenbroek  */
433e4e21ee1SDavid van Moolenbroek int
main(void)434e4e21ee1SDavid van Moolenbroek main(void)
435e4e21ee1SDavid van Moolenbroek {
436e4e21ee1SDavid van Moolenbroek 	message m_in, m_out;
437e4e21ee1SDavid van Moolenbroek 	int r, ipc_status;
438e4e21ee1SDavid van Moolenbroek 
439e4e21ee1SDavid van Moolenbroek 	/* Perform initialization. */
440e4e21ee1SDavid van Moolenbroek 	mib_startup();
441e4e21ee1SDavid van Moolenbroek 
442e4e21ee1SDavid van Moolenbroek 	/* The main message loop. */
443e4e21ee1SDavid van Moolenbroek 	for (;;) {
444e4e21ee1SDavid van Moolenbroek 		/* Receive a request. */
445e4e21ee1SDavid van Moolenbroek 		if ((r = sef_receive_status(ANY, &m_in, &ipc_status)) != OK)
446e4e21ee1SDavid van Moolenbroek 			panic("sef_receive failed: %d", r);
447e4e21ee1SDavid van Moolenbroek 
448e4e21ee1SDavid van Moolenbroek 		/* Process the request. */
449e4e21ee1SDavid van Moolenbroek 		if (is_ipc_notify(ipc_status)) {
450e4e21ee1SDavid van Moolenbroek 			/* We are not expecting any notifications. */
451e4e21ee1SDavid van Moolenbroek 			printf("MIB: notification from %d\n", m_in.m_source);
452e4e21ee1SDavid van Moolenbroek 
453e4e21ee1SDavid van Moolenbroek 			continue;
454e4e21ee1SDavid van Moolenbroek 		}
455e4e21ee1SDavid van Moolenbroek 
456e4e21ee1SDavid van Moolenbroek 		memset(&m_out, 0, sizeof(m_out));
457e4e21ee1SDavid van Moolenbroek 
458e4e21ee1SDavid van Moolenbroek 		switch (m_in.m_type) {
459e4e21ee1SDavid van Moolenbroek 		case MIB_SYSCTL:
460*6f3e0bcdSDavid van Moolenbroek 			r = mib_sysctl(&m_in, ipc_status, &m_out);
461*6f3e0bcdSDavid van Moolenbroek 
462*6f3e0bcdSDavid van Moolenbroek 			break;
463*6f3e0bcdSDavid van Moolenbroek 
464*6f3e0bcdSDavid van Moolenbroek 		case MIB_REGISTER:
465*6f3e0bcdSDavid van Moolenbroek 			r = mib_register(&m_in, ipc_status);
466*6f3e0bcdSDavid van Moolenbroek 
467*6f3e0bcdSDavid van Moolenbroek 			break;
468*6f3e0bcdSDavid van Moolenbroek 
469*6f3e0bcdSDavid van Moolenbroek 		case MIB_DEREGISTER:
470*6f3e0bcdSDavid van Moolenbroek 			r = mib_deregister(&m_in, ipc_status);
471e4e21ee1SDavid van Moolenbroek 
472e4e21ee1SDavid van Moolenbroek 			break;
473e4e21ee1SDavid van Moolenbroek 
474e4e21ee1SDavid van Moolenbroek 		default:
475*6f3e0bcdSDavid van Moolenbroek 			if (IPC_STATUS_CALL(ipc_status) == SENDREC)
476e4e21ee1SDavid van Moolenbroek 				r = ENOSYS;
477*6f3e0bcdSDavid van Moolenbroek 			else
478*6f3e0bcdSDavid van Moolenbroek 				r = EDONTREPLY;
479e4e21ee1SDavid van Moolenbroek 		}
480e4e21ee1SDavid van Moolenbroek 
481*6f3e0bcdSDavid van Moolenbroek 		/* Send a reply, if applicable. */
482*6f3e0bcdSDavid van Moolenbroek 		if (r != EDONTREPLY) {
483e4e21ee1SDavid van Moolenbroek 			m_out.m_type = r;
484e4e21ee1SDavid van Moolenbroek 
485e4e21ee1SDavid van Moolenbroek 			if ((r = ipc_sendnb(m_in.m_source, &m_out)) != OK)
486e4e21ee1SDavid van Moolenbroek 				printf("MIB: ipc_sendnb failed (%d)\n", r);
487e4e21ee1SDavid van Moolenbroek 		}
488*6f3e0bcdSDavid van Moolenbroek 	}
489e4e21ee1SDavid van Moolenbroek 
490e4e21ee1SDavid van Moolenbroek 	/* NOTREACHED */
491e4e21ee1SDavid van Moolenbroek 	return 0;
492e4e21ee1SDavid van Moolenbroek }
493