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