xref: /minix3/minix/servers/mib/remote.c (revision 6f3e0bcd3d3c17c74429db9d63eb808350d9a344)
1*6f3e0bcdSDavid van Moolenbroek /* MIB service - remote.c - remote service management and communication */
2*6f3e0bcdSDavid van Moolenbroek 
3*6f3e0bcdSDavid van Moolenbroek #include "mib.h"
4*6f3e0bcdSDavid van Moolenbroek 
5*6f3e0bcdSDavid van Moolenbroek /*
6*6f3e0bcdSDavid van Moolenbroek  * TODO: the main feature that is missing here is a more active way to
7*6f3e0bcdSDavid van Moolenbroek  * determine that a particular service has died, so that its mount points can
8*6f3e0bcdSDavid van Moolenbroek  * be removed proactively.  Without this, there is a (small) risk that we end
9*6f3e0bcdSDavid van Moolenbroek  * up talking to a recycled endpoint with a service that ignores our request,
10*6f3e0bcdSDavid van Moolenbroek  * resulting in a deadlock of the MIB service.  Right now, the problem is that
11*6f3e0bcdSDavid van Moolenbroek  * there is no proper DS API to subscribe to generic service-down events.
12*6f3e0bcdSDavid van Moolenbroek  *
13*6f3e0bcdSDavid van Moolenbroek  * In the long term, communication to other services should be made
14*6f3e0bcdSDavid van Moolenbroek  * asynchronous, so that the MIB service does not block if there are problems
15*6f3e0bcdSDavid van Moolenbroek  * with the other service.  The protocol should already support this, and some
16*6f3e0bcdSDavid van Moolenbroek  * simplifications are the result of preparing for future asynchrony support
17*6f3e0bcdSDavid van Moolenbroek  * (such as not dynamically querying the remote root node for its properties,
18*6f3e0bcdSDavid van Moolenbroek  * which would be very hard to implement in a nonblocking way).  However,
19*6f3e0bcdSDavid van Moolenbroek  * actual support is missing.  For now we assume that the remote service either
20*6f3e0bcdSDavid van Moolenbroek  * answers the request, or crashes (causing the sendrec to abort), which is
21*6f3e0bcdSDavid van Moolenbroek  * mostly good enough.
22*6f3e0bcdSDavid van Moolenbroek  */
23*6f3e0bcdSDavid van Moolenbroek 
24*6f3e0bcdSDavid van Moolenbroek /* This is the maximum number of remote services that may register subtrees. */
25*6f3e0bcdSDavid van Moolenbroek #define MIB_ENDPTS	(1U << MIB_EID_BITS)
26*6f3e0bcdSDavid van Moolenbroek 
27*6f3e0bcdSDavid van Moolenbroek /* This is the maximum service label size, including '\0'. */
28*6f3e0bcdSDavid van Moolenbroek #define MIB_LABEL_MAX	16
29*6f3e0bcdSDavid van Moolenbroek 
30*6f3e0bcdSDavid van Moolenbroek /* Table of remote endpoints, indexed by mount point nodes' node_eid fields. */
31*6f3e0bcdSDavid van Moolenbroek static struct {
32*6f3e0bcdSDavid van Moolenbroek 	endpoint_t endpt;		/* remote endpoint or NONE */
33*6f3e0bcdSDavid van Moolenbroek 	struct mib_node *nodes;		/* head of list of mount point nodes */
34*6f3e0bcdSDavid van Moolenbroek 	char label[MIB_LABEL_MAX];	/* label of the remote endpoint */
35*6f3e0bcdSDavid van Moolenbroek } endpts[MIB_ENDPTS];
36*6f3e0bcdSDavid van Moolenbroek 
37*6f3e0bcdSDavid van Moolenbroek /*
38*6f3e0bcdSDavid van Moolenbroek  * Initialize the table of remote endpoints.
39*6f3e0bcdSDavid van Moolenbroek  */
40*6f3e0bcdSDavid van Moolenbroek void
mib_remote_init(void)41*6f3e0bcdSDavid van Moolenbroek mib_remote_init(void)
42*6f3e0bcdSDavid van Moolenbroek {
43*6f3e0bcdSDavid van Moolenbroek 	unsigned int i;
44*6f3e0bcdSDavid van Moolenbroek 
45*6f3e0bcdSDavid van Moolenbroek 	for (i = 0; i < __arraycount(endpts); i++) {
46*6f3e0bcdSDavid van Moolenbroek 		endpts[i].endpt = NONE;
47*6f3e0bcdSDavid van Moolenbroek 		endpts[i].nodes = NULL;
48*6f3e0bcdSDavid van Moolenbroek 	}
49*6f3e0bcdSDavid van Moolenbroek }
50*6f3e0bcdSDavid van Moolenbroek 
51*6f3e0bcdSDavid van Moolenbroek /*
52*6f3e0bcdSDavid van Moolenbroek  * The remote endpoint with the given table index has been determined to have
53*6f3e0bcdSDavid van Moolenbroek  * died.  Clean up all its mount points.
54*6f3e0bcdSDavid van Moolenbroek  */
55*6f3e0bcdSDavid van Moolenbroek static void
mib_down(unsigned int eid)56*6f3e0bcdSDavid van Moolenbroek mib_down(unsigned int eid)
57*6f3e0bcdSDavid van Moolenbroek {
58*6f3e0bcdSDavid van Moolenbroek 	struct mib_node *node, *next_node;
59*6f3e0bcdSDavid van Moolenbroek 
60*6f3e0bcdSDavid van Moolenbroek 	assert(endpts[eid].endpt != NONE);
61*6f3e0bcdSDavid van Moolenbroek 	assert(endpts[eid].nodes != NULL);
62*6f3e0bcdSDavid van Moolenbroek 
63*6f3e0bcdSDavid van Moolenbroek 	/* Unmount each of the remote endpoint's mount points. */
64*6f3e0bcdSDavid van Moolenbroek 	for (node = endpts[eid].nodes; node != NULL; node = next_node) {
65*6f3e0bcdSDavid van Moolenbroek 		/* The unmount call may deallocate the node object. */
66*6f3e0bcdSDavid van Moolenbroek 		next_node = node->node_next;
67*6f3e0bcdSDavid van Moolenbroek 
68*6f3e0bcdSDavid van Moolenbroek 		mib_unmount(node);
69*6f3e0bcdSDavid van Moolenbroek 	}
70*6f3e0bcdSDavid van Moolenbroek 
71*6f3e0bcdSDavid van Moolenbroek 	/* Mark the entry itself as no longer in use. */
72*6f3e0bcdSDavid van Moolenbroek 	endpts[eid].endpt = NONE;
73*6f3e0bcdSDavid van Moolenbroek 	endpts[eid].nodes = NULL;
74*6f3e0bcdSDavid van Moolenbroek }
75*6f3e0bcdSDavid van Moolenbroek 
76*6f3e0bcdSDavid van Moolenbroek /*
77*6f3e0bcdSDavid van Moolenbroek  * Obtain the label for the given endpoint.  On success, return OK and store
78*6f3e0bcdSDavid van Moolenbroek  * the label in the given buffer.  If the label cannot be retrieved or does not
79*6f3e0bcdSDavid van Moolenbroek  * fit in the given buffer, return a negative error code.
80*6f3e0bcdSDavid van Moolenbroek  */
81*6f3e0bcdSDavid van Moolenbroek static int
mib_get_label(endpoint_t endpt,char * label,size_t labelsize)82*6f3e0bcdSDavid van Moolenbroek mib_get_label(endpoint_t endpt, char * label, size_t labelsize)
83*6f3e0bcdSDavid van Moolenbroek {
84*6f3e0bcdSDavid van Moolenbroek 	char key[DS_MAX_KEYLEN];
85*6f3e0bcdSDavid van Moolenbroek 	int r;
86*6f3e0bcdSDavid van Moolenbroek 
87*6f3e0bcdSDavid van Moolenbroek 	/* TODO: init has a label, so this is not a proper is-service test! */
88*6f3e0bcdSDavid van Moolenbroek 	if ((r = ds_retrieve_label_name(key, endpt)) != OK) {
89*6f3e0bcdSDavid van Moolenbroek 		printf("MIB: unable to obtain label for %d\n", endpt);
90*6f3e0bcdSDavid van Moolenbroek 
91*6f3e0bcdSDavid van Moolenbroek 		return r;
92*6f3e0bcdSDavid van Moolenbroek 	}
93*6f3e0bcdSDavid van Moolenbroek 
94*6f3e0bcdSDavid van Moolenbroek 	key[sizeof(key) - 1] = 0;
95*6f3e0bcdSDavid van Moolenbroek 	if (strlen(key) >= labelsize) {
96*6f3e0bcdSDavid van Moolenbroek 		/* This should really never happen. */
97*6f3e0bcdSDavid van Moolenbroek 		printf("MIB: service %d label '%s' is too long\n", endpt, key);
98*6f3e0bcdSDavid van Moolenbroek 
99*6f3e0bcdSDavid van Moolenbroek 		return ENAMETOOLONG;
100*6f3e0bcdSDavid van Moolenbroek 	}
101*6f3e0bcdSDavid van Moolenbroek 
102*6f3e0bcdSDavid van Moolenbroek 	strlcpy(label, key, labelsize);
103*6f3e0bcdSDavid van Moolenbroek 	return OK;
104*6f3e0bcdSDavid van Moolenbroek }
105*6f3e0bcdSDavid van Moolenbroek 
106*6f3e0bcdSDavid van Moolenbroek /*
107*6f3e0bcdSDavid van Moolenbroek  * Register a remote subtree, mounting it in the local tree as requested.
108*6f3e0bcdSDavid van Moolenbroek  */
109*6f3e0bcdSDavid van Moolenbroek static void
mib_do_register(endpoint_t endpt,const char * label,uint32_t rid,uint32_t flags,unsigned int csize,unsigned int clen,const int * mib,unsigned int miblen)110*6f3e0bcdSDavid van Moolenbroek mib_do_register(endpoint_t endpt, const char * label, uint32_t rid,
111*6f3e0bcdSDavid van Moolenbroek 	uint32_t flags, unsigned int csize, unsigned int clen, const int * mib,
112*6f3e0bcdSDavid van Moolenbroek 	unsigned int miblen)
113*6f3e0bcdSDavid van Moolenbroek {
114*6f3e0bcdSDavid van Moolenbroek 	struct mib_node *node;
115*6f3e0bcdSDavid van Moolenbroek 	unsigned int eid;
116*6f3e0bcdSDavid van Moolenbroek 	int r, free_eid;
117*6f3e0bcdSDavid van Moolenbroek 
118*6f3e0bcdSDavid van Moolenbroek 	/*
119*6f3e0bcdSDavid van Moolenbroek 	 * See if we already have a remote endpoint for the service's label.
120*6f3e0bcdSDavid van Moolenbroek 	 * If so, we can safely assume that the old endpoint has died and we
121*6f3e0bcdSDavid van Moolenbroek 	 * have to unmount any previous entries.  Also find a free entry for
122*6f3e0bcdSDavid van Moolenbroek 	 * the remote endpoint if it is new.
123*6f3e0bcdSDavid van Moolenbroek 	 */
124*6f3e0bcdSDavid van Moolenbroek 	free_eid = -1;
125*6f3e0bcdSDavid van Moolenbroek 	for (eid = 0; eid < __arraycount(endpts); eid++) {
126*6f3e0bcdSDavid van Moolenbroek 		if (endpts[eid].endpt == endpt)
127*6f3e0bcdSDavid van Moolenbroek 			break;
128*6f3e0bcdSDavid van Moolenbroek 		else if (endpts[eid].endpt != NONE &&
129*6f3e0bcdSDavid van Moolenbroek 		    !strcmp(endpts[eid].label, label)) {
130*6f3e0bcdSDavid van Moolenbroek 			mib_down(eid);
131*6f3e0bcdSDavid van Moolenbroek 
132*6f3e0bcdSDavid van Moolenbroek 			assert(endpts[eid].endpt == NONE);
133*6f3e0bcdSDavid van Moolenbroek 			assert(endpts[eid].nodes == NULL);
134*6f3e0bcdSDavid van Moolenbroek 
135*6f3e0bcdSDavid van Moolenbroek 			break;
136*6f3e0bcdSDavid van Moolenbroek 		} else if (endpts[eid].endpt == NONE && free_eid < 0)
137*6f3e0bcdSDavid van Moolenbroek 			free_eid = eid;
138*6f3e0bcdSDavid van Moolenbroek 	}
139*6f3e0bcdSDavid van Moolenbroek 
140*6f3e0bcdSDavid van Moolenbroek 	if (eid == __arraycount(endpts)) {
141*6f3e0bcdSDavid van Moolenbroek 		if (free_eid < 0) {
142*6f3e0bcdSDavid van Moolenbroek 			printf("MIB: remote endpoints table is full!\n");
143*6f3e0bcdSDavid van Moolenbroek 
144*6f3e0bcdSDavid van Moolenbroek 			return;
145*6f3e0bcdSDavid van Moolenbroek 		}
146*6f3e0bcdSDavid van Moolenbroek 
147*6f3e0bcdSDavid van Moolenbroek 		eid = free_eid;
148*6f3e0bcdSDavid van Moolenbroek 	}
149*6f3e0bcdSDavid van Moolenbroek 
150*6f3e0bcdSDavid van Moolenbroek 	/*
151*6f3e0bcdSDavid van Moolenbroek 	 * Make sure that the caller does not introduce two mount points with
152*6f3e0bcdSDavid van Moolenbroek 	 * the same ID.  Right now we refuse such requests; instead, we could
153*6f3e0bcdSDavid van Moolenbroek 	 * also choose to first deregister the old mount point with this ID.
154*6f3e0bcdSDavid van Moolenbroek 	 */
155*6f3e0bcdSDavid van Moolenbroek 	for (node = endpts[eid].nodes; node != NULL; node = node->node_next) {
156*6f3e0bcdSDavid van Moolenbroek 		if (node->node_rid == rid)
157*6f3e0bcdSDavid van Moolenbroek 			break;
158*6f3e0bcdSDavid van Moolenbroek 	}
159*6f3e0bcdSDavid van Moolenbroek 
160*6f3e0bcdSDavid van Moolenbroek 	if (node != NULL) {
161*6f3e0bcdSDavid van Moolenbroek 		MIB_DEBUG_MOUNT(("MIB: service %d tried to reuse ID %"PRIu32
162*6f3e0bcdSDavid van Moolenbroek 		    "\n", endpt, rid));
163*6f3e0bcdSDavid van Moolenbroek 
164*6f3e0bcdSDavid van Moolenbroek 		return;
165*6f3e0bcdSDavid van Moolenbroek 	}
166*6f3e0bcdSDavid van Moolenbroek 
167*6f3e0bcdSDavid van Moolenbroek 	/*
168*6f3e0bcdSDavid van Moolenbroek 	 * If we did not already have an entry for this endpoint, add one now,
169*6f3e0bcdSDavid van Moolenbroek 	 * because the mib_mount() call will expect it to be there.  If the
170*6f3e0bcdSDavid van Moolenbroek 	 * mount call fails, we may have to invalidate the entry again.
171*6f3e0bcdSDavid van Moolenbroek 	 */
172*6f3e0bcdSDavid van Moolenbroek 	if (endpts[eid].endpt == NONE) {
173*6f3e0bcdSDavid van Moolenbroek 		endpts[eid].endpt = endpt;
174*6f3e0bcdSDavid van Moolenbroek 		endpts[eid].nodes = NULL;
175*6f3e0bcdSDavid van Moolenbroek 		strlcpy(endpts[eid].label, label, sizeof(endpts[eid].label));
176*6f3e0bcdSDavid van Moolenbroek 	}
177*6f3e0bcdSDavid van Moolenbroek 
178*6f3e0bcdSDavid van Moolenbroek 	/* Attempt to mount the remote subtree in the tree. */
179*6f3e0bcdSDavid van Moolenbroek 	r = mib_mount(mib, miblen, eid, rid, flags, csize, clen, &node);
180*6f3e0bcdSDavid van Moolenbroek 
181*6f3e0bcdSDavid van Moolenbroek 	if (r != OK) {
182*6f3e0bcdSDavid van Moolenbroek 		/* If the entry has no other mount points, invalidate it. */
183*6f3e0bcdSDavid van Moolenbroek 		if (endpts[eid].nodes == NULL)
184*6f3e0bcdSDavid van Moolenbroek 			endpts[eid].endpt = NONE;
185*6f3e0bcdSDavid van Moolenbroek 
186*6f3e0bcdSDavid van Moolenbroek 		return;
187*6f3e0bcdSDavid van Moolenbroek 	}
188*6f3e0bcdSDavid van Moolenbroek 
189*6f3e0bcdSDavid van Moolenbroek 	/* Add the new node to the list of mount points of the endpoint. */
190*6f3e0bcdSDavid van Moolenbroek 	node->node_next = endpts[eid].nodes;
191*6f3e0bcdSDavid van Moolenbroek 	endpts[eid].nodes = node;
192*6f3e0bcdSDavid van Moolenbroek }
193*6f3e0bcdSDavid van Moolenbroek 
194*6f3e0bcdSDavid van Moolenbroek /*
195*6f3e0bcdSDavid van Moolenbroek  * Process a mount point registration request from another service.
196*6f3e0bcdSDavid van Moolenbroek  */
197*6f3e0bcdSDavid van Moolenbroek int
mib_register(const message * m_in,int ipc_status)198*6f3e0bcdSDavid van Moolenbroek mib_register(const message * m_in, int ipc_status)
199*6f3e0bcdSDavid van Moolenbroek {
200*6f3e0bcdSDavid van Moolenbroek 	char label[DS_MAX_KEYLEN];
201*6f3e0bcdSDavid van Moolenbroek 
202*6f3e0bcdSDavid van Moolenbroek 	/*
203*6f3e0bcdSDavid van Moolenbroek 	 * Registration messages must be one-way, or they may cause a deadlock
204*6f3e0bcdSDavid van Moolenbroek 	 * if crossed by a request coming from us.  This case also effectively
205*6f3e0bcdSDavid van Moolenbroek 	 * eliminates the possibility for userland to register nodes.  The
206*6f3e0bcdSDavid van Moolenbroek 	 * return value of ENOSYS effectively tells userland that this call
207*6f3e0bcdSDavid van Moolenbroek 	 * number is not in use, which allows us to repurpose call numbers
208*6f3e0bcdSDavid van Moolenbroek 	 * later.
209*6f3e0bcdSDavid van Moolenbroek 	 */
210*6f3e0bcdSDavid van Moolenbroek 	if (IPC_STATUS_CALL(ipc_status) == SENDREC)
211*6f3e0bcdSDavid van Moolenbroek 		return ENOSYS;
212*6f3e0bcdSDavid van Moolenbroek 
213*6f3e0bcdSDavid van Moolenbroek 	MIB_DEBUG_MOUNT(("MIB: got register request from %d\n",
214*6f3e0bcdSDavid van Moolenbroek 	    m_in->m_source));
215*6f3e0bcdSDavid van Moolenbroek 
216*6f3e0bcdSDavid van Moolenbroek 	/* Double-check if the caller is a service by obtaining its label. */
217*6f3e0bcdSDavid van Moolenbroek 	if (mib_get_label(m_in->m_source, label, sizeof(label)) != OK)
218*6f3e0bcdSDavid van Moolenbroek 		return EDONTREPLY;
219*6f3e0bcdSDavid van Moolenbroek 
220*6f3e0bcdSDavid van Moolenbroek 	/* Perform one message-level bounds check here. */
221*6f3e0bcdSDavid van Moolenbroek 	if (m_in->m_lsys_mib_register.miblen >
222*6f3e0bcdSDavid van Moolenbroek 	    __arraycount(m_in->m_lsys_mib_register.mib))
223*6f3e0bcdSDavid van Moolenbroek 		return EDONTREPLY;
224*6f3e0bcdSDavid van Moolenbroek 
225*6f3e0bcdSDavid van Moolenbroek 	/* The rest of the work is handled by a message-agnostic function. */
226*6f3e0bcdSDavid van Moolenbroek 	mib_do_register(m_in->m_source, label,
227*6f3e0bcdSDavid van Moolenbroek 	    m_in->m_lsys_mib_register.root_id, m_in->m_lsys_mib_register.flags,
228*6f3e0bcdSDavid van Moolenbroek 	    m_in->m_lsys_mib_register.csize, m_in->m_lsys_mib_register.clen,
229*6f3e0bcdSDavid van Moolenbroek 	    m_in->m_lsys_mib_register.mib, m_in->m_lsys_mib_register.miblen);
230*6f3e0bcdSDavid van Moolenbroek 
231*6f3e0bcdSDavid van Moolenbroek 	/* Never reply to this message. */
232*6f3e0bcdSDavid van Moolenbroek 	return EDONTREPLY;
233*6f3e0bcdSDavid van Moolenbroek }
234*6f3e0bcdSDavid van Moolenbroek 
235*6f3e0bcdSDavid van Moolenbroek /*
236*6f3e0bcdSDavid van Moolenbroek  * Deregister a previously registered remote subtree, unmounting it from the
237*6f3e0bcdSDavid van Moolenbroek  * local tree.
238*6f3e0bcdSDavid van Moolenbroek  */
239*6f3e0bcdSDavid van Moolenbroek static void
mib_do_deregister(endpoint_t endpt,uint32_t rid)240*6f3e0bcdSDavid van Moolenbroek mib_do_deregister(endpoint_t endpt, uint32_t rid)
241*6f3e0bcdSDavid van Moolenbroek {
242*6f3e0bcdSDavid van Moolenbroek 	struct mib_node *node, **nodep;
243*6f3e0bcdSDavid van Moolenbroek 	unsigned int eid;
244*6f3e0bcdSDavid van Moolenbroek 
245*6f3e0bcdSDavid van Moolenbroek 	for (eid = 0; eid < __arraycount(endpts); eid++) {
246*6f3e0bcdSDavid van Moolenbroek 		if (endpts[eid].endpt == endpt)
247*6f3e0bcdSDavid van Moolenbroek 			break;
248*6f3e0bcdSDavid van Moolenbroek 	}
249*6f3e0bcdSDavid van Moolenbroek 
250*6f3e0bcdSDavid van Moolenbroek 	if (eid == __arraycount(endpts)) {
251*6f3e0bcdSDavid van Moolenbroek 		MIB_DEBUG_MOUNT(("MIB: deregister request from unknown "
252*6f3e0bcdSDavid van Moolenbroek 		    "endpoint %d\n", endpt));
253*6f3e0bcdSDavid van Moolenbroek 
254*6f3e0bcdSDavid van Moolenbroek 		return;
255*6f3e0bcdSDavid van Moolenbroek 	}
256*6f3e0bcdSDavid van Moolenbroek 
257*6f3e0bcdSDavid van Moolenbroek 	for (nodep = &endpts[eid].nodes; *nodep != NULL;
258*6f3e0bcdSDavid van Moolenbroek 	    nodep = &node->node_next) {
259*6f3e0bcdSDavid van Moolenbroek 		node = *nodep;
260*6f3e0bcdSDavid van Moolenbroek 
261*6f3e0bcdSDavid van Moolenbroek 		if (node->node_rid == rid)
262*6f3e0bcdSDavid van Moolenbroek 			break;
263*6f3e0bcdSDavid van Moolenbroek 	}
264*6f3e0bcdSDavid van Moolenbroek 
265*6f3e0bcdSDavid van Moolenbroek 	if (*nodep == NULL) {
266*6f3e0bcdSDavid van Moolenbroek 		MIB_DEBUG_MOUNT(("MIB: deregister request from %d for unknown "
267*6f3e0bcdSDavid van Moolenbroek 		    "ID %"PRIu32"\n", endpt, rid));
268*6f3e0bcdSDavid van Moolenbroek 
269*6f3e0bcdSDavid van Moolenbroek 		return;
270*6f3e0bcdSDavid van Moolenbroek 	}
271*6f3e0bcdSDavid van Moolenbroek 
272*6f3e0bcdSDavid van Moolenbroek 	/*
273*6f3e0bcdSDavid van Moolenbroek 	 * The unmount function may or may not deallocate the node object, so
274*6f3e0bcdSDavid van Moolenbroek 	 * remove it from the linked list first.  If this leaves an empty
275*6f3e0bcdSDavid van Moolenbroek 	 * linked list, also mark the remote endpoint entry itself as free.
276*6f3e0bcdSDavid van Moolenbroek 	 */
277*6f3e0bcdSDavid van Moolenbroek 	*nodep = node->node_next;
278*6f3e0bcdSDavid van Moolenbroek 
279*6f3e0bcdSDavid van Moolenbroek 	if (endpts[eid].nodes == NULL) {
280*6f3e0bcdSDavid van Moolenbroek 		endpts[eid].endpt = NONE;
281*6f3e0bcdSDavid van Moolenbroek 		endpts[eid].nodes = NULL;
282*6f3e0bcdSDavid van Moolenbroek 	}
283*6f3e0bcdSDavid van Moolenbroek 
284*6f3e0bcdSDavid van Moolenbroek 	/* Finally, unmount the remote subtree. */
285*6f3e0bcdSDavid van Moolenbroek 	mib_unmount(node);
286*6f3e0bcdSDavid van Moolenbroek }
287*6f3e0bcdSDavid van Moolenbroek 
288*6f3e0bcdSDavid van Moolenbroek /*
289*6f3e0bcdSDavid van Moolenbroek  * Process a mount point deregistration request from another service.
290*6f3e0bcdSDavid van Moolenbroek  */
291*6f3e0bcdSDavid van Moolenbroek int
mib_deregister(const message * m_in,int ipc_status)292*6f3e0bcdSDavid van Moolenbroek mib_deregister(const message * m_in, int ipc_status)
293*6f3e0bcdSDavid van Moolenbroek {
294*6f3e0bcdSDavid van Moolenbroek 
295*6f3e0bcdSDavid van Moolenbroek 	/* Same as for registration messages. */
296*6f3e0bcdSDavid van Moolenbroek 	if (IPC_STATUS_CALL(ipc_status) == SENDREC)
297*6f3e0bcdSDavid van Moolenbroek 		return ENOSYS;
298*6f3e0bcdSDavid van Moolenbroek 
299*6f3e0bcdSDavid van Moolenbroek 	MIB_DEBUG_MOUNT(("MIB: got deregister request from %d\n",
300*6f3e0bcdSDavid van Moolenbroek 	    m_in->m_source));
301*6f3e0bcdSDavid van Moolenbroek 
302*6f3e0bcdSDavid van Moolenbroek 	/* The rest of the work is handled by a message-agnostic function. */
303*6f3e0bcdSDavid van Moolenbroek 	mib_do_deregister(m_in->m_source, m_in->m_lsys_mib_register.root_id);
304*6f3e0bcdSDavid van Moolenbroek 
305*6f3e0bcdSDavid van Moolenbroek 	/* Never reply to this message. */
306*6f3e0bcdSDavid van Moolenbroek 	return EDONTREPLY;
307*6f3e0bcdSDavid van Moolenbroek }
308*6f3e0bcdSDavid van Moolenbroek 
309*6f3e0bcdSDavid van Moolenbroek /*
310*6f3e0bcdSDavid van Moolenbroek  * Retrieve information about the root of a remote subtree, specifically its
311*6f3e0bcdSDavid van Moolenbroek  * name and description.  This is done only when there was no corresponding
312*6f3e0bcdSDavid van Moolenbroek  * local node and one has to be created temporarily.  On success, return OK
313*6f3e0bcdSDavid van Moolenbroek  * with the name and description stored in the given buffers.  Otherwise,
314*6f3e0bcdSDavid van Moolenbroek  * return a negative error code.
315*6f3e0bcdSDavid van Moolenbroek  */
316*6f3e0bcdSDavid van Moolenbroek int
mib_remote_info(unsigned int eid,uint32_t rid,char * name,size_t namesize,char * desc,size_t descsize)317*6f3e0bcdSDavid van Moolenbroek mib_remote_info(unsigned int eid, uint32_t rid, char * name, size_t namesize,
318*6f3e0bcdSDavid van Moolenbroek 	char * desc, size_t descsize)
319*6f3e0bcdSDavid van Moolenbroek {
320*6f3e0bcdSDavid van Moolenbroek 	endpoint_t endpt;
321*6f3e0bcdSDavid van Moolenbroek 	cp_grant_id_t name_grant, desc_grant;
322*6f3e0bcdSDavid van Moolenbroek 	message m;
323*6f3e0bcdSDavid van Moolenbroek 	int r;
324*6f3e0bcdSDavid van Moolenbroek 
325*6f3e0bcdSDavid van Moolenbroek 	if (eid >= __arraycount(endpts) || endpts[eid].endpt == NONE)
326*6f3e0bcdSDavid van Moolenbroek 		return EINVAL;
327*6f3e0bcdSDavid van Moolenbroek 
328*6f3e0bcdSDavid van Moolenbroek 	endpt = endpts[eid].endpt;
329*6f3e0bcdSDavid van Moolenbroek 
330*6f3e0bcdSDavid van Moolenbroek 	if ((name_grant = cpf_grant_direct(endpt, (vir_bytes)name, namesize,
331*6f3e0bcdSDavid van Moolenbroek 	    CPF_WRITE)) == GRANT_INVALID)
332*6f3e0bcdSDavid van Moolenbroek 		return EINVAL;
333*6f3e0bcdSDavid van Moolenbroek 
334*6f3e0bcdSDavid van Moolenbroek 	if ((desc_grant = cpf_grant_direct(endpt, (vir_bytes)desc, descsize,
335*6f3e0bcdSDavid van Moolenbroek 	    CPF_WRITE)) == GRANT_INVALID) {
336*6f3e0bcdSDavid van Moolenbroek 		cpf_revoke(name_grant);
337*6f3e0bcdSDavid van Moolenbroek 
338*6f3e0bcdSDavid van Moolenbroek 		return EINVAL;
339*6f3e0bcdSDavid van Moolenbroek 	}
340*6f3e0bcdSDavid van Moolenbroek 
341*6f3e0bcdSDavid van Moolenbroek 	memset(&m, 0, sizeof(m));
342*6f3e0bcdSDavid van Moolenbroek 
343*6f3e0bcdSDavid van Moolenbroek 	m.m_type = COMMON_MIB_INFO;
344*6f3e0bcdSDavid van Moolenbroek 	m.m_mib_lsys_info.req_id = 0; /* reserved for future async support */
345*6f3e0bcdSDavid van Moolenbroek 	m.m_mib_lsys_info.root_id = rid;
346*6f3e0bcdSDavid van Moolenbroek 	m.m_mib_lsys_info.name_grant = name_grant;
347*6f3e0bcdSDavid van Moolenbroek 	m.m_mib_lsys_info.name_size = namesize;
348*6f3e0bcdSDavid van Moolenbroek 	m.m_mib_lsys_info.desc_grant = desc_grant;
349*6f3e0bcdSDavid van Moolenbroek 	m.m_mib_lsys_info.desc_size = descsize;
350*6f3e0bcdSDavid van Moolenbroek 
351*6f3e0bcdSDavid van Moolenbroek 	r = ipc_sendrec(endpt, &m);
352*6f3e0bcdSDavid van Moolenbroek 
353*6f3e0bcdSDavid van Moolenbroek 	cpf_revoke(desc_grant);
354*6f3e0bcdSDavid van Moolenbroek 	cpf_revoke(name_grant);
355*6f3e0bcdSDavid van Moolenbroek 
356*6f3e0bcdSDavid van Moolenbroek 	if (r != OK)
357*6f3e0bcdSDavid van Moolenbroek 		return r;
358*6f3e0bcdSDavid van Moolenbroek 
359*6f3e0bcdSDavid van Moolenbroek 	if (m.m_type != COMMON_MIB_REPLY)
360*6f3e0bcdSDavid van Moolenbroek 		return EINVAL;
361*6f3e0bcdSDavid van Moolenbroek 	if (m.m_lsys_mib_reply.req_id != 0)
362*6f3e0bcdSDavid van Moolenbroek 		return EINVAL;
363*6f3e0bcdSDavid van Moolenbroek 
364*6f3e0bcdSDavid van Moolenbroek 	return m.m_lsys_mib_reply.status;
365*6f3e0bcdSDavid van Moolenbroek }
366*6f3e0bcdSDavid van Moolenbroek 
367*6f3e0bcdSDavid van Moolenbroek /*
368*6f3e0bcdSDavid van Moolenbroek  * Relay a sysctl(2) call from a user process to a remote service, because the
369*6f3e0bcdSDavid van Moolenbroek  * call reached a mount point into a remote subtree.  Return the result code
370*6f3e0bcdSDavid van Moolenbroek  * from the remote service.  Alternatively, return ERESTART if it has been
371*6f3e0bcdSDavid van Moolenbroek  * determined that the remote service is dead, in which case its mount points
372*6f3e0bcdSDavid van Moolenbroek  * will have been removed (possibly including the entire given node), and the
373*6f3e0bcdSDavid van Moolenbroek  * caller should continue the call on the underlying local subtree if there is
374*6f3e0bcdSDavid van Moolenbroek  * any.  Note that the remote service may also return ERESTART to indicate that
375*6f3e0bcdSDavid van Moolenbroek  * the remote subtree does not exist, either because it is being deregistered
376*6f3e0bcdSDavid van Moolenbroek  * or because the remote service was restarted with loss of state.
377*6f3e0bcdSDavid van Moolenbroek  */
378*6f3e0bcdSDavid van Moolenbroek ssize_t
mib_remote_call(struct mib_call * call,struct mib_node * node,struct mib_oldp * oldp,struct mib_newp * newp)379*6f3e0bcdSDavid van Moolenbroek mib_remote_call(struct mib_call * call, struct mib_node * node,
380*6f3e0bcdSDavid van Moolenbroek 	struct mib_oldp * oldp, struct mib_newp * newp)
381*6f3e0bcdSDavid van Moolenbroek {
382*6f3e0bcdSDavid van Moolenbroek 	cp_grant_id_t name_grant, oldp_grant, newp_grant;
383*6f3e0bcdSDavid van Moolenbroek 	size_t oldp_len, newp_len;
384*6f3e0bcdSDavid van Moolenbroek 	endpoint_t endpt;
385*6f3e0bcdSDavid van Moolenbroek 	message m;
386*6f3e0bcdSDavid van Moolenbroek 	int r;
387*6f3e0bcdSDavid van Moolenbroek 
388*6f3e0bcdSDavid van Moolenbroek 	endpt = endpts[node->node_eid].endpt;
389*6f3e0bcdSDavid van Moolenbroek 	assert(endpt != NONE);
390*6f3e0bcdSDavid van Moolenbroek 
391*6f3e0bcdSDavid van Moolenbroek 	/*
392*6f3e0bcdSDavid van Moolenbroek 	 * Allocate grants.  Since ENOMEM has a special meaning for sysctl(2),
393*6f3e0bcdSDavid van Moolenbroek 	 * never return that code even if it is the most appropriate one.
394*6f3e0bcdSDavid van Moolenbroek 	 * The remainder of the name may be empty; the callee should check.
395*6f3e0bcdSDavid van Moolenbroek 	 */
396*6f3e0bcdSDavid van Moolenbroek 	name_grant = cpf_grant_direct(endpt, (vir_bytes)call->call_name,
397*6f3e0bcdSDavid van Moolenbroek 	    call->call_namelen * sizeof(call->call_name[0]), CPF_READ);
398*6f3e0bcdSDavid van Moolenbroek 	if (!GRANT_VALID(name_grant))
399*6f3e0bcdSDavid van Moolenbroek 		return EINVAL;
400*6f3e0bcdSDavid van Moolenbroek 
401*6f3e0bcdSDavid van Moolenbroek 	if ((r = mib_relay_oldp(endpt, oldp, &oldp_grant, &oldp_len)) != OK) {
402*6f3e0bcdSDavid van Moolenbroek 		cpf_revoke(name_grant);
403*6f3e0bcdSDavid van Moolenbroek 
404*6f3e0bcdSDavid van Moolenbroek 		return r;
405*6f3e0bcdSDavid van Moolenbroek 	}
406*6f3e0bcdSDavid van Moolenbroek 
407*6f3e0bcdSDavid van Moolenbroek 	if ((r = mib_relay_newp(endpt, newp, &newp_grant, &newp_len)) != OK) {
408*6f3e0bcdSDavid van Moolenbroek 		if (GRANT_VALID(oldp_grant))
409*6f3e0bcdSDavid van Moolenbroek 			cpf_revoke(oldp_grant);
410*6f3e0bcdSDavid van Moolenbroek 		cpf_revoke(name_grant);
411*6f3e0bcdSDavid van Moolenbroek 
412*6f3e0bcdSDavid van Moolenbroek 		return r;
413*6f3e0bcdSDavid van Moolenbroek 	}
414*6f3e0bcdSDavid van Moolenbroek 
415*6f3e0bcdSDavid van Moolenbroek 	/*
416*6f3e0bcdSDavid van Moolenbroek 	 * Construct the request message.  We have not optimized this flow for
417*6f3e0bcdSDavid van Moolenbroek 	 * performance.  In particular, we never embed even short names in the
418*6f3e0bcdSDavid van Moolenbroek 	 * message, and we supply a flag indicating whether the caller is root
419*6f3e0bcdSDavid van Moolenbroek 	 * regardless of whether the callee is interested in this.  This is
420*6f3e0bcdSDavid van Moolenbroek 	 * more convenient for the callee, but also more costly.
421*6f3e0bcdSDavid van Moolenbroek 	 */
422*6f3e0bcdSDavid van Moolenbroek 	memset(&m, 0, sizeof(m));
423*6f3e0bcdSDavid van Moolenbroek 
424*6f3e0bcdSDavid van Moolenbroek 	m.m_type = COMMON_MIB_CALL;
425*6f3e0bcdSDavid van Moolenbroek 	m.m_mib_lsys_call.req_id = 0; /* reserved for future async support */
426*6f3e0bcdSDavid van Moolenbroek 	m.m_mib_lsys_call.root_id = node->node_rid;
427*6f3e0bcdSDavid van Moolenbroek 	m.m_mib_lsys_call.name_grant = name_grant;
428*6f3e0bcdSDavid van Moolenbroek 	m.m_mib_lsys_call.name_len = call->call_namelen;
429*6f3e0bcdSDavid van Moolenbroek 	m.m_mib_lsys_call.oldp_grant = oldp_grant;
430*6f3e0bcdSDavid van Moolenbroek 	m.m_mib_lsys_call.oldp_len = oldp_len;
431*6f3e0bcdSDavid van Moolenbroek 	m.m_mib_lsys_call.newp_grant = newp_grant;
432*6f3e0bcdSDavid van Moolenbroek 	m.m_mib_lsys_call.newp_len = newp_len;
433*6f3e0bcdSDavid van Moolenbroek 	m.m_mib_lsys_call.user_endpt = call->call_endpt;
434*6f3e0bcdSDavid van Moolenbroek 	m.m_mib_lsys_call.flags = !!mib_authed(call); /* TODO: define flags */
435*6f3e0bcdSDavid van Moolenbroek 	m.m_mib_lsys_call.root_ver = node->node_ver;
436*6f3e0bcdSDavid van Moolenbroek 	m.m_mib_lsys_call.tree_ver = mib_root.node_ver;
437*6f3e0bcdSDavid van Moolenbroek 
438*6f3e0bcdSDavid van Moolenbroek 	/* Issue a synchronous call to the remove service. */
439*6f3e0bcdSDavid van Moolenbroek 	r = ipc_sendrec(endpt, &m);
440*6f3e0bcdSDavid van Moolenbroek 
441*6f3e0bcdSDavid van Moolenbroek 	/* Then first clean up. */
442*6f3e0bcdSDavid van Moolenbroek 	if (GRANT_VALID(newp_grant))
443*6f3e0bcdSDavid van Moolenbroek 		cpf_revoke(newp_grant);
444*6f3e0bcdSDavid van Moolenbroek 	if (GRANT_VALID(oldp_grant))
445*6f3e0bcdSDavid van Moolenbroek 		cpf_revoke(oldp_grant);
446*6f3e0bcdSDavid van Moolenbroek 	cpf_revoke(name_grant);
447*6f3e0bcdSDavid van Moolenbroek 
448*6f3e0bcdSDavid van Moolenbroek 	/*
449*6f3e0bcdSDavid van Moolenbroek 	 * Treat any IPC-level error as an indication that there is a problem
450*6f3e0bcdSDavid van Moolenbroek 	 * with the remote service.  Declare it dead, remove all its mount
451*6f3e0bcdSDavid van Moolenbroek 	 * points, and return ERESTART to indicate to the caller that it should
452*6f3e0bcdSDavid van Moolenbroek 	 * (carefully) try to continue the request on a local subtree instead.
453*6f3e0bcdSDavid van Moolenbroek 	 * Again: mib_down() may actually deallocate the given 'node' object.
454*6f3e0bcdSDavid van Moolenbroek 	 */
455*6f3e0bcdSDavid van Moolenbroek 	if (r != OK) {
456*6f3e0bcdSDavid van Moolenbroek 		mib_down(node->node_eid);
457*6f3e0bcdSDavid van Moolenbroek 
458*6f3e0bcdSDavid van Moolenbroek 		return ERESTART;
459*6f3e0bcdSDavid van Moolenbroek 	}
460*6f3e0bcdSDavid van Moolenbroek 
461*6f3e0bcdSDavid van Moolenbroek 	if (m.m_type != COMMON_MIB_REPLY)
462*6f3e0bcdSDavid van Moolenbroek 		return EINVAL;
463*6f3e0bcdSDavid van Moolenbroek 	if (m.m_lsys_mib_reply.req_id != 0)
464*6f3e0bcdSDavid van Moolenbroek 		return EINVAL;
465*6f3e0bcdSDavid van Moolenbroek 
466*6f3e0bcdSDavid van Moolenbroek 	/*
467*6f3e0bcdSDavid van Moolenbroek 	 * If a deregister message from the service crosses our call, we'll get
468*6f3e0bcdSDavid van Moolenbroek 	 * the response before we get the deregister request.  In that case,
469*6f3e0bcdSDavid van Moolenbroek 	 * the remote service should return ERESTART to indicate that the mount
470*6f3e0bcdSDavid van Moolenbroek 	 * point does not exist as far as it is concerned, so that we can try
471*6f3e0bcdSDavid van Moolenbroek 	 * the local version of the tree instead.
472*6f3e0bcdSDavid van Moolenbroek 	 */
473*6f3e0bcdSDavid van Moolenbroek 	if (m.m_lsys_mib_reply.status == ERESTART)
474*6f3e0bcdSDavid van Moolenbroek 		mib_do_deregister(endpt, node->node_rid);
475*6f3e0bcdSDavid van Moolenbroek 
476*6f3e0bcdSDavid van Moolenbroek 	return m.m_lsys_mib_reply.status;
477*6f3e0bcdSDavid van Moolenbroek }
478