+/*
+ * Routine: mach_port_guard_with_flags [kernel call]
+ * Purpose:
+ * Guard a mach port with specified guard value and guard flags.
+ * The context field of the port is used as the guard.
+ * Conditions:
+ * Should hold receive right for that port
+ * Returns:
+ * KERN_SUCCESS The name is destroyed.
+ * KERN_INVALID_TASK The space is null.
+ * KERN_INVALID_TASK The space is dead.
+ * KERN_INVALID_NAME The name doesn't denote a right.
+ * KERN_INVALID_RIGHT The right isn't correct.
+ * KERN_INVALID_ARGUMENT Port already contains a context/guard.
+ * KERN_INVALID_CAPABILITY Cannot set MPG_IMMOVABLE_RECEIVE flag for a port with
+ * a movable port-destroyed notification port
+ */
+kern_return_t
+mach_port_guard_with_flags(
+ ipc_space_t space,
+ mach_port_name_t name,
+ uint64_t guard,
+ uint64_t flags)
+{
+ kern_return_t kr;
+ ipc_port_t port;
+
+ if (space == IS_NULL) {
+ return KERN_INVALID_TASK;
+ }
+
+ if (!MACH_PORT_VALID(name)) {
+ return KERN_INVALID_NAME;
+ }
+
+ kr = ipc_port_translate_receive(space, name, &port);
+ if (kr != KERN_SUCCESS) {
+ mach_port_guard_exception(name, 0, 0,
+ ((KERN_INVALID_NAME == kr) ?
+ kGUARD_EXC_INVALID_NAME :
+ kGUARD_EXC_INVALID_RIGHT));
+ return kr;
+ }
+
+ /* Port locked and active */
+ kr = mach_port_guard_locked(port, guard, flags);
+ ip_unlock(port);
+
+ if (KERN_INVALID_ARGUMENT == kr) {
+ mach_port_guard_exception(name, 0, 0, kGUARD_EXC_INVALID_ARGUMENT);
+ }
+
+ return kr;
+}
+
+/*
+ * Routine: mach_port_swap_guard [kernel call]
+ * Purpose:
+ * Swap guard value.
+ * Conditions:
+ * Port should already be guarded.
+ * Returns:
+ * KERN_SUCCESS The name is destroyed.
+ * KERN_INVALID_TASK The space is null.
+ * KERN_INVALID_TASK The space is dead.
+ * KERN_INVALID_NAME The name doesn't denote a right.
+ * KERN_INVALID_RIGHT The right isn't correct.
+ * KERN_INVALID_ARGUMENT Port doesn't contain a guard; is strictly guarded
+ * or the old_guard doesnt match the context
+ */
+kern_return_t
+mach_port_swap_guard(
+ ipc_space_t space,
+ mach_port_name_t name,
+ uint64_t old_guard,
+ uint64_t new_guard)
+{
+ kern_return_t kr;
+ ipc_port_t port;
+
+ if (space == IS_NULL) {
+ return KERN_INVALID_TASK;
+ }
+
+ if (!MACH_PORT_VALID(name)) {
+ return KERN_INVALID_NAME;
+ }
+
+ kr = ipc_port_translate_receive(space, name, &port);
+ if (kr != KERN_SUCCESS) {
+ mach_port_guard_exception(name, 0, 0,
+ ((KERN_INVALID_NAME == kr) ?
+ kGUARD_EXC_INVALID_NAME :
+ kGUARD_EXC_INVALID_RIGHT));
+ return kr;
+ }
+
+ /* Port locked and active */
+ if (!port->ip_guarded) {
+ ip_unlock(port);
+ mach_port_guard_exception(name, old_guard, 0, kGUARD_EXC_UNGUARDED);
+ return KERN_INVALID_ARGUMENT;
+ }
+
+ if (port->ip_strict_guard) {
+ uint64_t portguard = port->ip_context;
+ ip_unlock(port);
+ /* For strictly guarded ports, disallow overwriting context; Raise Exception */
+ mach_port_guard_exception(name, old_guard, portguard, kGUARD_EXC_SET_CONTEXT);
+ return KERN_INVALID_ARGUMENT;
+ }
+
+ if (port->ip_context != old_guard) {
+ uint64_t portguard = port->ip_context;
+ ip_unlock(port);
+ mach_port_guard_exception(name, old_guard, portguard, kGUARD_EXC_INCORRECT_GUARD);
+ return KERN_INVALID_ARGUMENT;
+ }
+
+ imq_lock(&port->ip_messages);
+ port->ip_context = new_guard;
+ imq_unlock(&port->ip_messages);
+
+ ip_unlock(port);
+
+ return KERN_SUCCESS;
+}