]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/mach_node.c
xnu-6153.11.26.tar.gz
[apple/xnu.git] / osfmk / kern / mach_node.c
1 /*
2 * Copyright (c) 2015-2016 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /* File: kern/mach_node.h
29 * Author: Dean Reece
30 * Date: 2016
31 *
32 * Implementation of mach node support.
33 * This is the basis for flipc, which provides inter-node communication.
34 */
35
36
37 #include <mach/mach_types.h>
38 #include <mach/boolean.h>
39 #include <mach/kern_return.h>
40
41 #include <kern/kern_types.h>
42 #include <kern/assert.h>
43
44 #include <kern/host.h>
45 #include <kern/kalloc.h>
46 #include <kern/mach_node_link.h>
47 #include <kern/mach_node.h>
48 #include <kern/ipc_mig.h> // mach_msg_send_from_kernel_proper()
49
50 #include <ipc/port.h>
51 #include <ipc/ipc_types.h>
52 #include <ipc/ipc_init.h>
53 #include <ipc/ipc_kmsg.h>
54 #include <ipc/ipc_port.h>
55 #include <ipc/ipc_pset.h>
56 #include <ipc/ipc_table.h>
57 #include <ipc/ipc_entry.h>
58
59 #include <ipc/flipc.h>
60
61 #include <libkern/OSAtomic.h> // OSAddAtomic64(), OSCompareAndSwap()
62 #include <libkern/OSByteOrder.h> // OSHostByteOrder()
63
64 #pragma pack(4)
65
66 #define MNL_NAME_TABLE_SIZE (256) // Hash is evenly distributed, so ^2 is ok
67 #define MNL_NAME_HASH(name) (name % MNL_NAME_TABLE_SIZE)
68
69 /*** Visible outside mach_node layer ***/
70 mach_node_id_t localnode_id = -1; // This node's FLIPC id.
71 #if MACH_FLIPC
72 mach_node_t localnode; // This node's mach_node_t struct
73
74
75 /*** Private to mach_node layer ***/
76 static int mach_nodes_to_publish;
77 static mach_node_t mach_node_table[MACH_NODES_MAX];
78 static lck_spin_t mach_node_table_lock_data;
79 #define MACH_NODE_TABLE_LOCK() lck_spin_lock(&mach_node_table_lock_data)
80 #define MACH_NODE_TABLE_UNLOCK() lck_spin_unlock(&mach_node_table_lock_data)
81 #define MACH_NODE_TABLE_LOCK_INIT() lck_spin_init(&mach_node_table_lock_data, \
82 &ipc_lck_grp, &ipc_lck_attr)
83
84 static volatile SInt64 mnl_name_next;
85 static queue_head_t mnl_name_table[MNL_NAME_TABLE_SIZE];
86 static lck_spin_t mnl_name_table_lock_data;
87 #define MNL_NAME_TABLE_LOCK() lck_spin_lock(&mnl_name_table_lock_data)
88 #define MNL_NAME_TABLE_UNLOCK() lck_spin_unlock(&mnl_name_table_lock_data)
89 #define MNL_NAME_TABLE_LOCK_INIT() lck_spin_init(&mnl_name_table_lock_data, \
90 &ipc_lck_grp, &ipc_lck_attr)
91
92 static void mach_node_init(void);
93 static void mnl_name_table_init(void);
94 static void mach_node_table_init(void);
95 static void mach_node_publish(mach_node_t node);
96
97 static mach_node_t mach_node_alloc_init(mach_node_id_t node_id);
98 static kern_return_t mach_node_register(mach_node_t node);
99
100
101 /* mach_node_init() is run lazily when a node link driver registers
102 * or the node special port is set.
103 * The variable localnode_id is used to determine if init has already run.
104 */
105 void
106 mach_node_init(void)
107 {
108 mach_node_id_t node_id = 0; // TODO: Read from device tree?
109 if (OSCompareAndSwap((UInt32)(HOST_LOCAL_NODE),
110 (UInt32)node_id,
111 &localnode_id)) {
112 printf("mach_node_init(): localnode_id=%d of %d\n",
113 localnode_id, MACH_NODES_MAX);
114 mach_node_table_init();
115 mnl_name_table_init();
116 flipc_init();
117 } // TODO: else block until init is finished (init completion race)
118 }
119
120 void
121 mach_node_table_init(void)
122 {
123 MACH_NODE_TABLE_LOCK_INIT();
124 MACH_NODE_TABLE_LOCK();
125
126 /* Start with an enpty node table. */
127 bzero(mach_node_table, sizeof(mach_node_t) * MACH_NODES_MAX);
128 mach_nodes_to_publish = 0;
129
130 /* Allocate localnode's struct */
131 localnode = mach_node_for_id_locked(localnode_id, 1, 1);
132 assert(MACH_NODE_VALID(localnode));
133
134 MACH_NODE_TABLE_UNLOCK();
135
136 /* Set up localnode's struct */
137 bzero(localnode, sizeof(localnode));
138 localnode->info.datamodel = LOCAL_DATA_MODEL;
139 localnode->info.byteorder = OSHostByteOrder();
140 localnode->info.proto_vers_min = MNL_PROTOCOL_V1;
141 localnode->info.proto_vers_max = MNL_PROTOCOL_V1;
142 localnode->proto_vers = MNL_PROTOCOL_V1;
143 localnode->published = 0;
144 localnode->active = 1;
145
146 MACH_NODE_UNLOCK(localnode);
147 }
148
149 /* Sends a publication message to the local node's bootstrap server.
150 * This function is smart and will only send a notification if one as really
151 * needed - it can be called speculatively on any node at any time.
152 *
153 * Note: MUST be called with the node table lock held.
154 */
155
156 void
157 mach_node_publish(mach_node_t node)
158 {
159 kern_return_t kr;
160
161 if (!MACH_NODE_VALID(node) || (!node->active) || (node->published)) {
162 return; // node is invalid or not suitable for publication
163 }
164 ipc_port_t bs_port = localnode->bootstrap_port;
165 if (!IP_VALID(bs_port)) {
166 return; // No bootstrap server to notify!
167 }
168 /* Node is suitable and server is present, so make registration message */
169 struct mach_node_server_register_msg msg;
170
171 msg.node_header.header.msgh_remote_port = bs_port;
172 msg.node_header.header.msgh_size = sizeof(msg);
173 msg.node_header.header.msgh_local_port = MACH_PORT_NULL;
174 msg.node_header.header.msgh_voucher_port = MACH_PORT_NULL;
175 msg.node_header.header.msgh_id = MACH_NODE_SERVER_MSG_ID;
176 msg.node_header.node_id = node->info.node_id;
177 msg.node_header.options = 0;
178 msg.datamodel = node->info.datamodel;
179 msg.byteorder = node->info.byteorder;
180
181 if (node == localnode) {
182 msg.node_header.identifier = MACH_NODE_SM_REG_LOCAL;
183 msg.node_header.header.msgh_bits =
184 MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND, 0, 0, 0);
185 } else {
186 msg.node_header.identifier = MACH_NODE_SM_REG_REMOTE;
187 msg.node_header.header.msgh_local_port = node->bootstrap_port;
188 msg.node_header.header.msgh_bits = MACH_MSGH_BITS_SET
189 (MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND, 0, 0);
190 }
191
192 kr = mach_msg_send_from_kernel_proper(&msg.node_header.header,
193 sizeof(msg));
194 if (kr == KERN_SUCCESS) {
195 node->published = 1;
196 mach_nodes_to_publish--;
197 }
198 printf("mach_node_publish(%d)=%d\n", node->info.node_id, kr);
199 }
200
201 /* Called whenever the node special port changes */
202 void
203 mach_node_port_changed(void)
204 {
205 ipc_port_t bs_port;
206
207 mach_node_init(); // Lazy init of mach_node layer
208
209 /* Cleanup previous bootstrap port if necessary */
210 MACH_NODE_LOCK(localnode);
211 flipc_node_retire(localnode);
212 bs_port = localnode->bootstrap_port;
213 if (IP_VALID(bs_port)) {
214 localnode->bootstrap_port = IP_NULL;
215 // TODO: destroy send right to outgoing bs_port
216 }
217
218 kernel_get_special_port(host_priv_self(), HOST_NODE_PORT, &bs_port);
219 assert(IP_VALID(bs_port));
220 localnode->bootstrap_port = bs_port;
221 flipc_node_prepare(localnode);
222 MACH_NODE_UNLOCK(localnode);
223
224 /* Cleanup the publication state of all nodes in the table */
225 MACH_NODE_TABLE_LOCK();
226 // TODO: Signup for bootstrap port death notifications
227 localnode->active = 1;
228
229 mach_nodes_to_publish = 0;
230
231 int n;
232 for (n = 0; n < MACH_NODES_MAX; n++) {
233 mach_node_t np = mach_node_table[n];
234 // Publish all active nodes (except the local node)
235 if (!MACH_NODE_VALID(np)) {
236 continue;
237 }
238 np->published = 0;
239 if (np->active == 1) {
240 mach_nodes_to_publish++;
241 }
242 }
243
244 mach_node_publish(localnode); // Always publish local node first
245
246 for (n = 0; n < MACH_NODES_MAX; n++) {
247 mach_node_publish(mach_node_table[n]);
248 }
249
250 MACH_NODE_TABLE_UNLOCK();
251
252 // TODO: notify all active nodes we are bootstrapped
253 }
254
255 /* Allocate/init a mach_node struct and fill in the node_id field.
256 * This does NOT insert the node struct into the node table.
257 */
258 mach_node_t
259 mach_node_alloc_init(mach_node_id_t node_id)
260 {
261 mach_node_t node = MACH_NODE_ALLOC();
262 if (MACH_NODE_VALID(node)) {
263 bzero(node, sizeof(struct mach_node));
264 MACH_NODE_LOCK_INIT(node);
265 node->info.node_id = node_id;
266 }
267 return node;
268 }
269
270
271 /* This function takes a mach_node struct with a completed info field and
272 * registers it with the mach_node and flipc (if flipc is enabled) layers.
273 */
274 kern_return_t
275 mach_node_register(mach_node_t node)
276 {
277 assert(MACH_NODE_VALID(node));
278 mach_node_id_t nid = node->info.node_id;
279 assert(MACH_NODE_ID_VALID(nid));
280
281 kern_return_t kr;
282 ipc_space_t proxy_space = IS_NULL;
283 ipc_pset_t pp_set = IPS_NULL; // pset for proxy ports
284 ipc_port_t bs_port = MACH_PORT_NULL;
285 ipc_port_t ack_port = MACH_PORT_NULL;
286
287 printf("mach_node_register(%d)\n", nid);
288
289 /* TODO: Support non-native byte order and data models */
290 if ((node->info.byteorder != OSHostByteOrder()) ||
291 (node->info.datamodel != LOCAL_DATA_MODEL)) {
292 printf("mach_node_register: unsupported byte order (%d) or width (%d)",
293 node->info.byteorder, node->info.datamodel);
294 return KERN_INVALID_ARGUMENT;
295 }
296
297 /* Create the space that holds all local rights assigned to <nid> */
298 kr = ipc_space_create_special(&proxy_space);
299 if (kr != KERN_SUCCESS) {
300 goto out;
301 }
302 proxy_space->is_node_id = nid;
303
304 /* Create the bootstrap proxy port for this remote node */
305 bs_port = ipc_port_alloc_special(proxy_space);
306 if (bs_port == MACH_PORT_NULL) {
307 kr = KERN_RESOURCE_SHORTAGE;
308 goto out;
309 }
310
311 /* Create the control (ack) port for this remote node */
312 ack_port = ipc_port_alloc_special(proxy_space);
313 if (ack_port == MACH_PORT_NULL) {
314 kr = KERN_RESOURCE_SHORTAGE;
315 goto out;
316 }
317
318 /* Create the set that holds all proxy ports for this remote node */
319 pp_set = ipc_pset_alloc_special(proxy_space);
320 if (pp_set == IPS_NULL) {
321 kr = KERN_RESOURCE_SHORTAGE;
322 goto out;
323 }
324
325 waitq_set_lazy_init_link(pp_set);
326 /* Add the bootstrap port to the proxy port set */
327 uint64_t wq_link_id = waitq_link_reserve(NULL);
328 uint64_t wq_reserved_prepost = waitq_prepost_reserve(NULL, 10,
329 WAITQ_DONT_LOCK);
330 ips_lock(pp_set);
331 ip_lock(bs_port);
332 ipc_pset_add(pp_set,
333 bs_port,
334 &wq_link_id,
335 &wq_reserved_prepost);
336 ip_unlock(bs_port);
337 ips_unlock(pp_set);
338
339 waitq_link_release(wq_link_id);
340 waitq_prepost_release_reserve(wq_reserved_prepost);
341
342 /* Add the control port to the proxy port set */
343 wq_link_id = waitq_link_reserve(NULL);
344 wq_reserved_prepost = waitq_prepost_reserve(NULL, 10,
345 WAITQ_DONT_LOCK);
346 ips_lock(pp_set);
347 ip_lock(ack_port);
348 ipc_pset_add(pp_set,
349 ack_port,
350 &wq_link_id,
351 &wq_reserved_prepost);
352 ip_unlock(ack_port);
353 ips_unlock(pp_set);
354
355 waitq_link_release(wq_link_id);
356 waitq_prepost_release_reserve(wq_reserved_prepost);
357
358 // Setup mach_node struct
359 node->published = 0;
360 node->active = 1;
361 node->proxy_space = proxy_space;
362 node->proxy_port_set = pp_set;
363 node->bootstrap_port = bs_port;
364 node->proto_vers = node->info.proto_vers_max;
365 node->control_port = ack_port;
366
367 // Place new mach_node struct into node table
368 MACH_NODE_TABLE_LOCK();
369
370 mach_node_t old_node = mach_node_table[nid];
371 if (!MACH_NODE_VALID(old_node) || (old_node->dead)) {
372 node->antecedent = old_node;
373 flipc_node_prepare(node);
374 mach_node_table[nid] = node;
375 mach_nodes_to_publish++;
376 mach_node_publish(node);
377 kr = KERN_SUCCESS;
378 } else {
379 printf("mach_node_register: id %d already active!", nid);
380 kr = KERN_FAILURE;
381 }
382 MACH_NODE_TABLE_UNLOCK();
383
384 out:
385 if (kr != KERN_SUCCESS) { // Dispose of whatever we allocated
386 if (pp_set) {
387 ips_lock(pp_set);
388 ipc_pset_destroy(proxy_space, pp_set);
389 }
390
391 if (bs_port) {
392 ipc_port_dealloc_special(bs_port, proxy_space);
393 }
394
395 if (ack_port) {
396 ipc_port_dealloc_special(ack_port, proxy_space);
397 }
398
399 if (proxy_space) {
400 ipc_space_terminate(proxy_space);
401 }
402 }
403
404 return kr;
405 }
406
407
408 /* Gets or allocates a locked mach_node struct for the specified <node_id>.
409 * The current node is locked and returned if it is not dead, or if it is dead
410 * and <alloc_if_dead> is false. A new node struct is allocated, locked and
411 * returned if the node is dead and <alloc_if_dead> is true, or if the node
412 * is absent and <alloc_if_absent> is true. MACH_NODE_NULL is returned if
413 * the node is absent and <alloc_if_absent> is false. MACH_NODE_NULL is also
414 * returned if a new node structure was not able to be allocated.
415 *
416 * Note: This function must be called with the node table lock held!
417 */
418 mach_node_t
419 mach_node_for_id_locked(mach_node_id_t node_id,
420 boolean_t alloc_if_dead,
421 boolean_t alloc_if_absent)
422 {
423 if ((node_id < 0) || (node_id >= MACH_NODES_MAX)) {
424 return MACH_NODE_NULL;
425 }
426
427 mach_node_t node = mach_node_table[node_id];
428
429 if ((!MACH_NODE_VALID(node) && alloc_if_absent) ||
430 (MACH_NODE_VALID(node) && node->dead && alloc_if_dead)) {
431 node = mach_node_alloc_init(node_id);
432 if (MACH_NODE_VALID(node)) {
433 node->antecedent = mach_node_table[node_id];
434 mach_node_table[node_id] = node;
435 }
436 }
437
438 if (MACH_NODE_VALID(node)) {
439 MACH_NODE_LOCK(node);
440 }
441
442 return node;
443 }
444
445
446
447 /*** Mach Node Link Name and Hash Table Implementation ***/
448
449 /* Allocate a new unique name and return it.
450 * Dispose of this with mnl_name_free().
451 * Returns MNL_NAME_NULL on failure.
452 */
453 mnl_name_t
454 mnl_name_alloc(void)
455 {
456 return (mnl_name_t)OSAddAtomic64(MACH_NODES_MAX, &mnl_name_next);
457 }
458
459
460 /* Deallocate a unique name that was allocated via mnl_name_alloc().
461 */
462 void
463 mnl_name_free(mnl_name_t name __unused)
464 {
465 ; // Nothing to do for now since we don't recycle mnl names.
466 }
467
468
469 /* Called once from mach_node_init(), this sets up the hash table structures.
470 */
471 void
472 mnl_name_table_init(void)
473 {
474 MNL_NAME_TABLE_LOCK_INIT();
475 MNL_NAME_TABLE_LOCK();
476
477 // Set the first name to this node's bootstrap name
478 mnl_name_next = localnode_id + MACH_NODES_MAX;
479
480 for (int i = 0; i < MNL_NAME_TABLE_SIZE; i++) {
481 queue_head_init(mnl_name_table[i]);
482 }
483
484 MNL_NAME_TABLE_UNLOCK();
485 }
486
487
488 /* Initialize the data structures in the mnl_obj structure at the head of the
489 * provided object. This should be called on an object before it is passed to
490 * any other mnl_obj* routine.
491 */
492 void
493 mnl_obj_init(mnl_obj_t obj)
494 {
495 queue_chain_init(obj->links);
496 obj->name = MNL_NAME_NULL;
497 }
498
499
500 /* Search the local node's hash table for the object associated with a
501 * mnl_name_t and return it. Returns MNL_NAME_NULL on failure.
502 */
503 mnl_obj_t
504 mnl_obj_lookup(mnl_name_t name)
505 {
506 mnl_obj_t obj = MNL_OBJ_NULL;
507
508 if (name != MNL_NAME_NULL) {
509 qe_foreach_element(obj, &mnl_name_table[MNL_NAME_HASH(name)], links) {
510 if (obj->name == name) {
511 break;
512 }
513 }
514 }
515 return obj;
516 }
517
518
519 /* Search the local node's hash table for the object associated with a
520 * mnl_name_t and remove it. The pointer to the removed object is returned so
521 * that the caller can appropriately dispose of the object.
522 * Returns MNL_NAME_NULL on failure.
523 */
524 mnl_obj_t
525 mnl_obj_remove(mnl_name_t name)
526 {
527 mnl_obj_t obj = MNL_OBJ_NULL;
528
529 if (name != MNL_NAME_NULL) {
530 qe_foreach_element_safe(obj, &mnl_name_table[MNL_NAME_HASH(name)], links) {
531 if (obj->name == name) {
532 remqueue(&obj->links);
533 }
534 }
535 }
536 return obj;
537 }
538
539
540 /* Insert an object into the local node's hash table. If the name of the
541 * provided object is MNL_NAME_NULL then a new mnl_name is allocated and
542 * assigned to the object.
543 * Returns KERN_SUCCESS if obj was added to hash table
544 * Returns KERN_INVALID_ARGUMENT if obj is invalid
545 * Returns KERN_NAME_EXISTS if obj's name already exists in hash table
546 */
547 kern_return_t
548 mnl_obj_insert(mnl_obj_t obj)
549 {
550 if (!MNL_OBJ_VALID(obj)) {
551 return KERN_INVALID_ARGUMENT;
552 }
553
554 MNL_NAME_TABLE_LOCK();
555
556 if (!MNL_NAME_VALID(obj->name)) {
557 // obj is unnammed, so lets allocate a fresh one
558 obj->name = mnl_name_alloc();
559 }
560
561 enqueue(&mnl_name_table[MNL_NAME_HASH(obj->name)], &obj->links);
562 MNL_NAME_TABLE_UNLOCK();
563
564 if (obj->name >= (MACH_NODES_MAX << 1)) {
565 panic("Unexpected MNL_NAME %lld in obj %p", obj->name, obj);
566 }
567
568 return KERN_SUCCESS;
569 }
570
571
572 /*** Mach Node Link Driver Interface Implementation ***/
573
574 /* Allocate a mnl_msg struct plus additional payload. Link drivers are not
575 * required to use this to allocate messages; any wired and mapped kernel
576 * memory is acceptable.
577 *
578 * Arguments:
579 * payload Number of additional bytes to allocate for message payload
580 * flags Currently unused; 0 should be passed
581 *
582 * Return values:
583 * MNL_MSG_NULL: Allocation failed
584 * *: Pointer to new mnl_msg struct of requested size
585 */
586 mnl_msg_t
587 mnl_msg_alloc(int payload,
588 uint32_t flags __unused)
589 {
590 mnl_msg_t msg = kalloc(MNL_MSG_SIZE + payload);
591
592 if (MNL_MSG_VALID(msg)) {
593 bzero(msg, MNL_MSG_SIZE); // Only zero the header
594 msg->size = payload;
595 }
596
597 return msg;
598 }
599
600
601 /* Free a mnl_msg struct allocated by mnl_msg_alloc().
602 *
603 * Arguments:
604 * msg Pointer to the message buffer to be freed
605 * flags Currently unused; 0 should be passed
606 */
607 void
608 mnl_msg_free(mnl_msg_t msg,
609 uint32_t flags __unused)
610 {
611 if (MNL_MSG_VALID(msg)) {
612 kfree(msg, MNL_MSG_SIZE + msg->size);
613 }
614 }
615
616
617 /* The link driver calls this to setup a new (or restarted) node, and to get
618 * an mnl_node_info struct for use as a parameter to other mnl functions.
619 * If MNL_NODE_NULL is returned, the operation failed. Otherwise, a pointer
620 * to a new mnl_node struct is returned. The caller should set all fields
621 * in the structure, then call mnl_register() to complete node registration.
622 *
623 * Arguments:
624 * nid The id of the node to be instantiated
625 * flags Currently unused; 0 should be passed
626 *
627 * Return values:
628 * MNL_NODE_NULL: Operation failed
629 * *: Pointer to a new mnl_node struct
630 */
631 mnl_node_info_t
632 mnl_instantiate(mach_node_id_t nid,
633 uint32_t flags __unused)
634 {
635 mach_node_init(); // Lazy init of mach_node layer
636
637 if ((nid == localnode_id) || !MACH_NODE_ID_VALID(nid)) {
638 return MNL_NODE_NULL;
639 }
640
641 return (mnl_node_info_t)mach_node_alloc_init(nid);
642 }
643
644 /* The link driver calls mnl_register() to complete the node registration
645 * process. KERN_SUCCESS is returned if registration succeeded, otherwise
646 * an error is returned.
647 *
648 * Arguments:
649 * node Pointer to the node's mnl_node structure
650 * flags Currently unused; 0 should be passed
651 *
652 * Return values:
653 * KERN_SUCCESS: Registration succeeded
654 * KERN_INVALID_ARGUMENT: Field(s) in <node> contained unacceptable values
655 * KERN_*: Values returned from underlying functions
656 */
657 kern_return_t
658 mnl_register(mnl_node_info_t node,
659 uint32_t flags __unused)
660 {
661 if (MNL_NODE_VALID(node) && (node->node_id != localnode_id)) {
662 return mach_node_register((mach_node_t)node);
663 }
664
665 return KERN_INVALID_ARGUMENT;
666 }
667
668
669 /* The link driver calls this to report that the link has been raised in one
670 * or both directions. If the link is two uni-directional channels, each link
671 * driver will independently call this function, each only raising the link
672 * they are responsible for. The mach_node layer will not communicate with
673 * the remote node until both rx and tx links are up.
674 *
675 * Arguments:
676 * node Pointer to the node's mnl_node structure
677 * link Indicates which link(s) are up (see MNL_LINK_* defines)
678 * flags Currently unused; 0 should be passed
679 *
680 * Return values:
681 * KERN_SUCCESS: Link state changed successfully.
682 * KERN_INVALID_ARGUMENT: An argument value was not allowed.
683 * KERN_*: Values returned from underlying functions.
684 */
685 kern_return_t
686 mnl_set_link_state(mnl_node_info_t node,
687 int link,
688 uint32_t flags __unused)
689 {
690 kern_return_t kr;
691 mach_node_t mnode = (mach_node_t)node;
692
693 if (!MACH_NODE_VALID(mnode) || !(link & MNL_LINK_UP) || (link & mnode->link)) {
694 return KERN_INVALID_ARGUMENT; // bad node, or bad link argument
695 }
696 MACH_NODE_LOCK(mnode);
697
698 if (mnode->dead) {
699 kr = KERN_NODE_DOWN;
700 } else {
701 mnode->link |= link;
702 kr = KERN_SUCCESS;
703 }
704
705 MACH_NODE_UNLOCK(mnode);
706
707 return kr;
708 }
709
710 /* The link driver calls this to indicate a node has terminated and is no
711 * longer available for messaging. This may be due to a crash or an orderly
712 * shutdown, but either way the remote node no longer retains any state about
713 * the remaining nodes. References held on behalf of the terminated node
714 * will be cleaned up. After this is called, both the rx and tx links are
715 * marked as down. If the remote node restarts, the link driver can bring
716 * up the link using mnl_instantiate() again.
717 *
718 * Arguments:
719 * node Pointer to the node's mnl_node structure
720 * flags Currently unused; 0 should be passed
721 *
722 * Return values:
723 * KERN_SUCCESS: Node was terminated.
724 * KERN_INVALID_ARGUMENT: Node id was invalid or non-existant.
725 * KERN_*: Values returned from underlying functions.
726 */
727 kern_return_t
728 mnl_terminate(mnl_node_info_t node,
729 uint32_t flags __unused)
730 {
731 kern_return_t kr = KERN_SUCCESS;
732 mach_node_t mnode = (mach_node_t)node;
733
734 if (!MACH_NODE_VALID(mnode)) {
735 return KERN_INVALID_ARGUMENT; // bad node
736 }
737 MACH_NODE_LOCK(mnode);
738 if (mnode->dead) {
739 kr = KERN_NODE_DOWN; // node is already terminated
740 goto unlock;
741 }
742
743 mnode->link = MNL_LINK_DOWN;
744 mnode->active = 0;
745 mnode->suspended = 0;
746 mnode->dead = 1;
747
748 flipc_node_retire(mnode);
749
750 // Wake any threads sleeping on the proxy port set
751 if (mnode->proxy_port_set != IPS_NULL) {
752 ips_lock(mnode->proxy_port_set);
753 ipc_pset_destroy(mnode->proxy_space, mnode->proxy_port_set);
754 mnode->proxy_port_set = IPS_NULL;
755 }
756
757 // TODO: Inform node name server (if registered) of termination
758
759 unlock:
760 MACH_NODE_UNLOCK(mnode);
761 return kr;
762 }
763
764
765 /* The link driver calls this to deliver an incoming message. Note that the
766 * link driver must dispose of the memory pointed to by <msg> after the
767 * function call returns.
768 *
769 * Arguments:
770 * node Pointer to the node's mnl_node structure
771 * msg Pointer to the message buffer
772 * flags Currently unused; 0 should be passed
773 */
774 void
775 mnl_msg_from_node(mnl_node_info_t node __unused,
776 mnl_msg_t msg,
777 uint32_t flags __unused)
778 {
779 assert(MNL_MSG_VALID(msg));
780 assert(MACH_NODE_ID_VALID(msg->node_id));
781 assert(MNL_NODE_VALID(node));
782
783 /* If node message forwarding is supported, the from_node_id arg may not
784 * match fmsg->info.node_id. The former is the node from which we received
785 * the message; the latter is the node that generated the message originally.
786 * We always use fmsg->info.node_id, which is where the ack needs to go.
787 */
788
789 switch (msg->sub) {
790 case MACH_NODE_SUB_FLIPC:
791 flipc_msg_from_node((mach_node_t)node, msg, flags);
792 break;
793
794 default:
795 #if DEBUG
796 PE_enter_debugger("mnl_msg_from_node(): Invalid subsystem");
797 #endif
798 break;
799 }
800 }
801
802
803 /* The link driver calls this to fetch the next message to transmit.
804 * This function will block until a message is available, or will return
805 * FLIPC_MSG_NULL if the link is to be terminated. After the caller has
806 * completed the transmission and no longer needs the msg buffer, it should
807 * call mnl_msg_complete().
808 *
809 * Arguments:
810 * node Pointer to the node's mnl_node structure
811 * flags Currently unused; 0 should be passed
812 */
813 mnl_msg_t
814 mnl_msg_to_node(mnl_node_info_t node __unused,
815 uint32_t flags __unused)
816 {
817 assert(MNL_NODE_VALID(node));
818
819 #if DEBUG
820 thread_set_thread_name(current_thread(), "MNL_Link");
821 #endif
822
823 return flipc_msg_to_remote_node((mach_node_t)node, 0);
824 }
825
826
827 /* The link driver calls this to indicate that the specified msg buffer has
828 * been sent over the link and can be deallocated.
829 *
830 * Arguments:
831 * node Pointer to the node's mnl_node structure
832 * msg Pointer to the message buffer
833 * flags Currently unused; 0 should be passed
834 */
835 void
836 mnl_msg_complete(mnl_node_info_t node __unused,
837 mnl_msg_t msg,
838 uint32_t flags)
839 {
840 switch (msg->sub) {
841 case MACH_NODE_SUB_NODE:
842 mnl_msg_free(msg, flags);
843 break;
844
845 case MACH_NODE_SUB_FLIPC:
846 flipc_msg_free(msg, flags);
847 break;
848
849 default:
850 #if DEBUG
851 PE_enter_debugger("mnl_msg_complete(): Invalid subsystem");
852 #endif
853 break;
854 }
855 }
856
857 #else // MACH_FLIPC not configured, so provide KPI stubs
858
859 mnl_msg_t
860 mnl_msg_alloc(int payload __unused, uint32_t flags __unused)
861 {
862 return MNL_MSG_NULL;
863 }
864
865 void
866 mnl_msg_free(mnl_msg_t msg __unused, uint32_t flags __unused)
867 {
868 return;
869 }
870
871 mnl_node_info_t
872 mnl_instantiate(mach_node_id_t nid __unused, uint32_t flags __unused)
873 {
874 return MNL_NODE_NULL;
875 }
876
877 kern_return_t
878 mnl_register(mnl_node_info_t node __unused, uint32_t flags __unused)
879 {
880 return KERN_FAILURE;
881 }
882
883 kern_return_t
884 mnl_set_link_state(mnl_node_info_t node __unused,
885 int link __unused,
886 uint32_t flags __unused)
887 {
888 return KERN_FAILURE;
889 }
890
891 kern_return_t
892 mnl_terminate(mnl_node_info_t node __unused, uint32_t flags __unused)
893 {
894 return KERN_FAILURE;
895 }
896
897 void
898 mnl_msg_from_node(mnl_node_info_t node __unused,
899 mnl_msg_t msg __unused,
900 uint32_t flags __unused)
901 {
902 return;
903 }
904
905 mnl_msg_t
906 mnl_msg_to_node(mnl_node_info_t node __unused, uint32_t flags __unused)
907 {
908 return MNL_MSG_NULL;
909 }
910
911 void
912 mnl_msg_complete(mnl_node_info_t node __unused,
913 mnl_msg_t msg __unused,
914 uint32_t flags __unused)
915 {
916 return;
917 }
918
919 #endif // MACH_FLIPC