2 * Copyright (c) 2015-2016 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 /* File: kern/mach_node.h
32 * Implementation of mach node support.
33 * This is the basis for flipc, which provides inter-node communication.
37 #include <mach/mach_types.h>
38 #include <mach/boolean.h>
39 #include <mach/kern_return.h>
41 #include <kern/kern_types.h>
42 #include <kern/assert.h>
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()
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>
59 #include <ipc/flipc.h>
61 #include <libkern/OSAtomic.h> // OSAddAtomic64(), OSCompareAndSwap()
62 #include <libkern/OSByteOrder.h> // OSHostByteOrder()
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)
69 /*** Visible outside mach_node layer ***/
70 mach_node_id_t localnode_id
= -1; // This node's FLIPC id.
72 mach_node_t localnode
; // This node's mach_node_t struct
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)
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)
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
);
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
);
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.
108 mach_node_id_t node_id
= 0; // TODO: Read from device tree?
109 if (OSCompareAndSwap((UInt32
)(HOST_LOCAL_NODE
),
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();
117 } // TODO: else block until init is finished (init completion race)
121 mach_node_table_init(void)
123 MACH_NODE_TABLE_LOCK_INIT();
124 MACH_NODE_TABLE_LOCK();
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;
130 /* Allocate localnode's struct */
131 localnode
= mach_node_for_id_locked(localnode_id
, 1, 1);
132 assert(MACH_NODE_VALID(localnode
));
134 MACH_NODE_TABLE_UNLOCK();
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;
146 MACH_NODE_UNLOCK(localnode
);
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.
153 * Note: MUST be called with the node table lock held.
157 mach_node_publish(mach_node_t node
)
161 if (!MACH_NODE_VALID(node
) || (!node
->active
) || (node
->published
)) {
162 return; // node is invalid or not suitable for publication
164 ipc_port_t bs_port
= localnode
->bootstrap_port
;
165 if (!IP_VALID(bs_port
)) {
166 return; // No bootstrap server to notify!
168 /* Node is suitable and server is present, so make registration message */
169 struct mach_node_server_register_msg msg
;
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
;
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);
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);
192 kr
= mach_msg_send_from_kernel_proper(&msg
.node_header
.header
,
194 if (kr
== KERN_SUCCESS
) {
196 mach_nodes_to_publish
--;
198 printf("mach_node_publish(%d)=%d\n", node
->info
.node_id
, kr
);
201 /* Called whenever the node special port changes */
203 mach_node_port_changed(void)
207 mach_node_init(); // Lazy init of mach_node layer
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
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
);
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;
229 mach_nodes_to_publish
= 0;
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
)) {
239 if (np
->active
== 1) {
240 mach_nodes_to_publish
++;
244 mach_node_publish(localnode
); // Always publish local node first
246 for (n
= 0; n
< MACH_NODES_MAX
; n
++) {
247 mach_node_publish(mach_node_table
[n
]);
250 MACH_NODE_TABLE_UNLOCK();
252 // TODO: notify all active nodes we are bootstrapped
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.
259 mach_node_alloc_init(mach_node_id_t node_id
)
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
;
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.
275 mach_node_register(mach_node_t node
)
277 assert(MACH_NODE_VALID(node
));
278 mach_node_id_t nid
= node
->info
.node_id
;
279 assert(MACH_NODE_ID_VALID(nid
));
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
;
287 printf("mach_node_register(%d)\n", nid
);
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
;
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
) {
302 proxy_space
->is_node_id
= nid
;
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
;
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
;
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
;
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,
335 &wq_reserved_prepost
);
339 waitq_link_release(wq_link_id
);
340 waitq_prepost_release_reserve(wq_reserved_prepost
);
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,
351 &wq_reserved_prepost
);
355 waitq_link_release(wq_link_id
);
356 waitq_prepost_release_reserve(wq_reserved_prepost
);
358 // Setup mach_node struct
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
;
367 // Place new mach_node struct into node table
368 MACH_NODE_TABLE_LOCK();
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
);
379 printf("mach_node_register: id %d already active!", nid
);
382 MACH_NODE_TABLE_UNLOCK();
385 if (kr
!= KERN_SUCCESS
) { // Dispose of whatever we allocated
388 ipc_pset_destroy(proxy_space
, pp_set
);
392 ipc_port_dealloc_special(bs_port
, proxy_space
);
396 ipc_port_dealloc_special(ack_port
, proxy_space
);
400 ipc_space_terminate(proxy_space
);
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.
416 * Note: This function must be called with the node table lock held!
419 mach_node_for_id_locked(mach_node_id_t node_id
,
420 boolean_t alloc_if_dead
,
421 boolean_t alloc_if_absent
)
423 if ((node_id
< 0) || (node_id
>= MACH_NODES_MAX
)) {
424 return MACH_NODE_NULL
;
427 mach_node_t node
= mach_node_table
[node_id
];
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
;
438 if (MACH_NODE_VALID(node
)) {
439 MACH_NODE_LOCK(node
);
447 /*** Mach Node Link Name and Hash Table Implementation ***/
449 /* Allocate a new unique name and return it.
450 * Dispose of this with mnl_name_free().
451 * Returns MNL_NAME_NULL on failure.
456 return (mnl_name_t
)OSAddAtomic64(MACH_NODES_MAX
, &mnl_name_next
);
460 /* Deallocate a unique name that was allocated via mnl_name_alloc().
463 mnl_name_free(mnl_name_t name __unused
)
465 ; // Nothing to do for now since we don't recycle mnl names.
469 /* Called once from mach_node_init(), this sets up the hash table structures.
472 mnl_name_table_init(void)
474 MNL_NAME_TABLE_LOCK_INIT();
475 MNL_NAME_TABLE_LOCK();
477 // Set the first name to this node's bootstrap name
478 mnl_name_next
= localnode_id
+ MACH_NODES_MAX
;
480 for (int i
= 0; i
< MNL_NAME_TABLE_SIZE
; i
++) {
481 queue_head_init(mnl_name_table
[i
]);
484 MNL_NAME_TABLE_UNLOCK();
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.
493 mnl_obj_init(mnl_obj_t obj
)
495 queue_chain_init(obj
->links
);
496 obj
->name
= MNL_NAME_NULL
;
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.
504 mnl_obj_lookup(mnl_name_t name
)
506 mnl_obj_t obj
= MNL_OBJ_NULL
;
508 if (name
!= MNL_NAME_NULL
) {
509 qe_foreach_element(obj
, &mnl_name_table
[MNL_NAME_HASH(name
)], links
) {
510 if (obj
->name
== name
) {
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.
525 mnl_obj_remove(mnl_name_t name
)
527 mnl_obj_t obj
= MNL_OBJ_NULL
;
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
);
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
548 mnl_obj_insert(mnl_obj_t obj
)
550 if (!MNL_OBJ_VALID(obj
)) {
551 return KERN_INVALID_ARGUMENT
;
554 MNL_NAME_TABLE_LOCK();
556 if (!MNL_NAME_VALID(obj
->name
)) {
557 // obj is unnammed, so lets allocate a fresh one
558 obj
->name
= mnl_name_alloc();
561 enqueue(&mnl_name_table
[MNL_NAME_HASH(obj
->name
)], &obj
->links
);
562 MNL_NAME_TABLE_UNLOCK();
564 if (obj
->name
>= (MACH_NODES_MAX
<< 1)) {
565 panic("Unexpected MNL_NAME %lld in obj %p", obj
->name
, obj
);
572 /*** Mach Node Link Driver Interface Implementation ***/
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.
579 * payload Number of additional bytes to allocate for message payload
580 * flags Currently unused; 0 should be passed
583 * MNL_MSG_NULL: Allocation failed
584 * *: Pointer to new mnl_msg struct of requested size
587 mnl_msg_alloc(int payload
,
588 uint32_t flags __unused
)
590 mnl_msg_t msg
= kalloc(MNL_MSG_SIZE
+ payload
);
592 if (MNL_MSG_VALID(msg
)) {
593 bzero(msg
, MNL_MSG_SIZE
); // Only zero the header
601 /* Free a mnl_msg struct allocated by mnl_msg_alloc().
604 * msg Pointer to the message buffer to be freed
605 * flags Currently unused; 0 should be passed
608 mnl_msg_free(mnl_msg_t msg
,
609 uint32_t flags __unused
)
611 if (MNL_MSG_VALID(msg
)) {
612 kfree(msg
, MNL_MSG_SIZE
+ msg
->size
);
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.
624 * nid The id of the node to be instantiated
625 * flags Currently unused; 0 should be passed
628 * MNL_NODE_NULL: Operation failed
629 * *: Pointer to a new mnl_node struct
632 mnl_instantiate(mach_node_id_t nid
,
633 uint32_t flags __unused
)
635 mach_node_init(); // Lazy init of mach_node layer
637 if ((nid
== localnode_id
) || !MACH_NODE_ID_VALID(nid
)) {
638 return MNL_NODE_NULL
;
641 return (mnl_node_info_t
)mach_node_alloc_init(nid
);
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.
649 * node Pointer to the node's mnl_node structure
650 * flags Currently unused; 0 should be passed
653 * KERN_SUCCESS: Registration succeeded
654 * KERN_INVALID_ARGUMENT: Field(s) in <node> contained unacceptable values
655 * KERN_*: Values returned from underlying functions
658 mnl_register(mnl_node_info_t node
,
659 uint32_t flags __unused
)
661 if (MNL_NODE_VALID(node
) && (node
->node_id
!= localnode_id
)) {
662 return mach_node_register((mach_node_t
)node
);
665 return KERN_INVALID_ARGUMENT
;
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.
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
681 * KERN_SUCCESS: Link state changed successfully.
682 * KERN_INVALID_ARGUMENT: An argument value was not allowed.
683 * KERN_*: Values returned from underlying functions.
686 mnl_set_link_state(mnl_node_info_t node
,
688 uint32_t flags __unused
)
691 mach_node_t mnode
= (mach_node_t
)node
;
693 if (!MACH_NODE_VALID(mnode
) || !(link
& MNL_LINK_UP
) || (link
& mnode
->link
)) {
694 return KERN_INVALID_ARGUMENT
; // bad node, or bad link argument
696 MACH_NODE_LOCK(mnode
);
705 MACH_NODE_UNLOCK(mnode
);
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.
719 * node Pointer to the node's mnl_node structure
720 * flags Currently unused; 0 should be passed
723 * KERN_SUCCESS: Node was terminated.
724 * KERN_INVALID_ARGUMENT: Node id was invalid or non-existant.
725 * KERN_*: Values returned from underlying functions.
728 mnl_terminate(mnl_node_info_t node
,
729 uint32_t flags __unused
)
731 kern_return_t kr
= KERN_SUCCESS
;
732 mach_node_t mnode
= (mach_node_t
)node
;
734 if (!MACH_NODE_VALID(mnode
)) {
735 return KERN_INVALID_ARGUMENT
; // bad node
737 MACH_NODE_LOCK(mnode
);
739 kr
= KERN_NODE_DOWN
; // node is already terminated
743 mnode
->link
= MNL_LINK_DOWN
;
745 mnode
->suspended
= 0;
748 flipc_node_retire(mnode
);
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
;
757 // TODO: Inform node name server (if registered) of termination
760 MACH_NODE_UNLOCK(mnode
);
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.
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
775 mnl_msg_from_node(mnl_node_info_t node __unused
,
777 uint32_t flags __unused
)
779 assert(MNL_MSG_VALID(msg
));
780 assert(MACH_NODE_ID_VALID(msg
->node_id
));
781 assert(MNL_NODE_VALID(node
));
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.
790 case MACH_NODE_SUB_FLIPC
:
791 flipc_msg_from_node((mach_node_t
)node
, msg
, flags
);
796 PE_enter_debugger("mnl_msg_from_node(): Invalid subsystem");
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().
810 * node Pointer to the node's mnl_node structure
811 * flags Currently unused; 0 should be passed
814 mnl_msg_to_node(mnl_node_info_t node __unused
,
815 uint32_t flags __unused
)
817 assert(MNL_NODE_VALID(node
));
820 thread_set_thread_name(current_thread(), "MNL_Link");
823 return flipc_msg_to_remote_node((mach_node_t
)node
, 0);
827 /* The link driver calls this to indicate that the specified msg buffer has
828 * been sent over the link and can be deallocated.
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
836 mnl_msg_complete(mnl_node_info_t node __unused
,
841 case MACH_NODE_SUB_NODE
:
842 mnl_msg_free(msg
, flags
);
845 case MACH_NODE_SUB_FLIPC
:
846 flipc_msg_free(msg
, flags
);
851 PE_enter_debugger("mnl_msg_complete(): Invalid subsystem");
857 #else // MACH_FLIPC not configured, so provide KPI stubs
860 mnl_msg_alloc(int payload __unused
, uint32_t flags __unused
)
866 mnl_msg_free(mnl_msg_t msg __unused
, uint32_t flags __unused
)
872 mnl_instantiate(mach_node_id_t nid __unused
, uint32_t flags __unused
)
874 return MNL_NODE_NULL
;
878 mnl_register(mnl_node_info_t node __unused
, uint32_t flags __unused
)
884 mnl_set_link_state(mnl_node_info_t node __unused
,
886 uint32_t flags __unused
)
892 mnl_terminate(mnl_node_info_t node __unused
, uint32_t flags __unused
)
898 mnl_msg_from_node(mnl_node_info_t node __unused
,
899 mnl_msg_t msg __unused
,
900 uint32_t flags __unused
)
906 mnl_msg_to_node(mnl_node_info_t node __unused
, uint32_t flags __unused
)
912 mnl_msg_complete(mnl_node_info_t node __unused
,
913 mnl_msg_t msg __unused
,
914 uint32_t flags __unused
)