xref: /xnu-11215/iokit/Kernel/IOUserServer.cpp (revision 33de042d)
1 /*
2  * Copyright (c) 1998-2021 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 
29 #include <IOKit/IORPC.h>
30 #include <IOKit/IOKitServer.h>
31 #include <IOKit/IOKitKeysPrivate.h>
32 #include <IOKit/IOKernelReportStructs.h>
33 #include <IOKit/IOUserClient.h>
34 #include <IOKit/IOService.h>
35 #include <IOKit/IORegistryEntry.h>
36 #include <IOKit/IOCatalogue.h>
37 #include <IOKit/IOMemoryDescriptor.h>
38 #include <IOKit/IOBufferMemoryDescriptor.h>
39 #include <IOKit/IOSubMemoryDescriptor.h>
40 #include <IOKit/IOMultiMemoryDescriptor.h>
41 #include <IOKit/IOMapper.h>
42 #include <IOKit/IOLib.h>
43 #include <IOKit/IOHibernatePrivate.h>
44 #include <IOKit/IOBSD.h>
45 #include <IOKit/system.h>
46 #include "IOServicePrivate.h"
47 #include <IOKit/IOUserServer.h>
48 #include <IOKit/IOInterruptEventSource.h>
49 #include <IOKit/IOTimerEventSource.h>
50 #include <IOKit/pwr_mgt/RootDomain.h>
51 #include <IOKit/pwr_mgt/IOPowerConnection.h>
52 #include <libkern/c++/OSAllocation.h>
53 #include <libkern/c++/OSKext.h>
54 #include <libkern/c++/OSSharedPtr.h>
55 #include <libkern/OSDebug.h>
56 #include <libkern/Block.h>
57 #include <kern/cs_blobs.h>
58 #include <kern/thread_call.h>
59 #include <os/atomic_private.h>
60 #include <sys/proc.h>
61 #include <sys/reboot.h>
62 #include <sys/codesign.h>
63 #include "IOKitKernelInternal.h"
64 
65 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
66 
67 #include <DriverKit/IODispatchQueue.h>
68 #include <DriverKit/OSObject.h>
69 #include <DriverKit/OSAction.h>
70 #include <DriverKit/IODispatchSource.h>
71 #include <DriverKit/IOInterruptDispatchSource.h>
72 #include <DriverKit/IOService.h>
73 #include <DriverKit/IOMemoryDescriptor.h>
74 #include <DriverKit/IOBufferMemoryDescriptor.h>
75 #include <DriverKit/IOMemoryMap.h>
76 #include <DriverKit/IODataQueueDispatchSource.h>
77 #include <DriverKit/IOServiceNotificationDispatchSource.h>
78 #include <DriverKit/IOServiceStateNotificationDispatchSource.h>
79 #include <DriverKit/IOEventLink.h>
80 #include <DriverKit/IOWorkGroup.h>
81 #include <DriverKit/IOUserServer.h>
82 
83 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
84 
85 #include <System/IODataQueueDispatchSourceShared.h>
86 
87 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
88 
89 TUNABLE(SInt64, gIODKDebug, "dk", kIODKEnable);
90 
91 #if DEBUG || DEVELOPMENT
92 TUNABLE(bool, disable_dext_crash_reboot, "disable_dext_crash_reboot", 0);
93 #endif /* DEBUG || DEVELOPMENT */
94 
95 extern bool restore_boot;
96 
97 static OSString       * gIOSystemStateSleepDescriptionKey;
98 static const OSSymbol * gIOSystemStateSleepDescriptionReasonKey;
99 static const OSSymbol * gIOSystemStateSleepDescriptionHibernateStateKey;
100 
101 static OSString       * gIOSystemStateWakeDescriptionKey;
102 static const OSSymbol * gIOSystemStateWakeDescriptionWakeReasonKey;
103 static const OSSymbol * gIOSystemStateWakeDescriptionContinuousTimeOffsetKey;
104 
105 static OSString       * gIOSystemStateHaltDescriptionKey;
106 static const OSSymbol * gIOSystemStateHaltDescriptionHaltStateKey;
107 
108 static OSString       * gIOSystemStatePowerSourceDescriptionKey;
109 static const OSSymbol * gIOSystemStatePowerSourceDescriptionACAttachedKey;
110 
111 extern bool gInUserspaceReboot;
112 
113 extern void iokit_clear_registered_ports(task_t task);
114 
115 static IORPCMessage *
116 IORPCMessageFromMachReply(IORPCMessageMach * msg);
117 
118 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
119 
120 struct IOPStrings;
121 
122 class OSUserMetaClass : public OSObject
123 {
124 	OSDeclareDefaultStructors(OSUserMetaClass);
125 public:
126 	const OSSymbol    * name;
127 	const OSMetaClass * meta;
128 	OSUserMetaClass   * superMeta;
129 
130 	queue_chain_t       link;
131 
132 	OSClassDescription * description;
133 	IOPStrings * queueNames;
134 	uint32_t     methodCount;
135 	uint64_t   * methods;
136 
137 	virtual void free() override;
138 	virtual kern_return_t Dispatch(const IORPC rpc) APPLE_KEXT_OVERRIDE;
139 };
140 OSDefineMetaClassAndStructors(OSUserMetaClass, OSObject);
141 
142 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
143 
144 class IOUserService : public IOService
145 {
146 	friend class IOService;
147 
148 	OSDeclareDefaultStructors(IOUserService)
149 
150 	virtual bool
151 	start(IOService * provider) APPLE_KEXT_OVERRIDE;
152 };
153 
154 OSDefineMetaClassAndStructors(IOUserService, IOService)
155 
156 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
157 
158 class IOUserUserClient : public IOUserClient
159 {
160 	OSDeclareDefaultStructors(IOUserUserClient);
161 public:
162 	task_t          fTask;
163 	OSDictionary  * fWorkGroups;
164 	OSDictionary  * fEventLinks;
165 	IOLock        * fLock;
166 
167 	IOReturn                   setTask(task_t task);
168 	IOReturn                   eventlinkConfigurationTrap(void * p1, void * p2, void * p3, void * p4, void * p5, void * p6);
169 	IOReturn                   workgroupConfigurationTrap(void * p1, void * p2, void * p3, void * p4, void * p5, void * p6);
170 
171 	virtual bool           init( OSDictionary * dictionary ) APPLE_KEXT_OVERRIDE;
172 	virtual void           free() APPLE_KEXT_OVERRIDE;
173 	virtual void           stop(IOService * provider) APPLE_KEXT_OVERRIDE;
174 	virtual IOReturn       clientClose(void) APPLE_KEXT_OVERRIDE;
175 	virtual IOReturn       setProperties(OSObject * properties) APPLE_KEXT_OVERRIDE;
176 	virtual IOReturn       externalMethod(uint32_t selector, IOExternalMethodArguments * args,
177 	    IOExternalMethodDispatch * dispatch, OSObject * target, void * reference) APPLE_KEXT_OVERRIDE;
178 	virtual IOReturn           clientMemoryForType(UInt32 type,
179 	    IOOptionBits * options,
180 	    IOMemoryDescriptor ** memory) APPLE_KEXT_OVERRIDE;
181 	virtual IOExternalTrap * getTargetAndTrapForIndex( IOService **targetP, UInt32 index ) APPLE_KEXT_OVERRIDE;
182 };
183 
184 OSDefineMetaClassAndStructors(IOUserServerCheckInToken, OSObject);
185 OSDefineMetaClassAndStructors(_IOUserServerCheckInCancellationHandler, OSObject);
186 
187 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
188 
189 
190 bool
191 IOUserService::start(IOService * provider)
192 {
193 	bool     ok = true;
194 	IOReturn ret;
195 
196 	ret = Start(provider);
197 	if (kIOReturnSuccess != ret) {
198 		return false;
199 	}
200 
201 	return ok;
202 }
203 
204 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
205 
206 #undef super
207 
208 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
209 
210 struct IODispatchQueue_IVars {
211 	IOUserServer * userServer;
212 	IODispatchQueue   * queue;
213 	queue_chain_t  link;
214 	uint64_t       tid;
215 
216 	mach_port_t    serverPort;
217 };
218 
219 struct OSAction_IVars {
220 	OSObject             * target;
221 	uint64_t               targetmsgid;
222 	uint64_t               msgid;
223 	IOUserServer         * userServer;
224 	OSActionAbortedHandler abortedHandler;
225 	OSString             * typeName;
226 	void                 * reference;
227 	size_t                 referenceSize;
228 	bool                   aborted;
229 };
230 
231 struct IOWorkGroup_IVars {
232 	IOUserServer * userServer;
233 	OSString * name;
234 	IOUserUserClient * userClient;
235 };
236 
237 struct IOEventLink_IVars {
238 	IOUserServer * userServer;
239 	OSString * name;
240 	IOUserUserClient * userClient;
241 };
242 
243 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
244 
245 kern_return_t
246 IOService::GetRegistryEntryID_Impl(
247 	uint64_t * registryEntryID)
248 {
249 	IOReturn ret = kIOReturnSuccess;
250 
251 	*registryEntryID = getRegistryEntryID();
252 
253 	return ret;
254 }
255 
256 kern_return_t
257 IOService::SetName_Impl(
258 	const char * name)
259 {
260 	IOReturn ret = kIOReturnSuccess;
261 
262 	setName(name);
263 
264 	return ret;
265 }
266 
267 kern_return_t
268 IOService::CopyName_Impl(
269 	OSString ** name)
270 {
271 	const OSString * str = copyName();
272 	*name = __DECONST(OSString *, str);
273 	return str ? kIOReturnSuccess : kIOReturnError;
274 }
275 
276 
277 kern_return_t
278 IOService::Start_Impl(
279 	IOService * provider)
280 {
281 	IOReturn ret = kIOReturnSuccess;
282 	return ret;
283 }
284 
285 
286 IOReturn
287 IOService::UpdateReport_Impl(OSData *channels, uint32_t action,
288     uint32_t *outElementCount,
289     uint64_t offset, uint64_t capacity,
290     IOMemoryDescriptor *buffer)
291 {
292 	return kIOReturnUnsupported;
293 }
294 
295 IOReturn
296 IOService::ConfigureReport_Impl(OSData *channels, uint32_t action, uint32_t *outCount)
297 {
298 	return kIOReturnUnsupported;
299 }
300 
301 // adapt old signature of configureReport to the iig-friendly signature of ConfigureReport
302 IOReturn
303 IOService::_ConfigureReport(IOReportChannelList    *channelList,
304     IOReportConfigureAction action,
305     void                   *result,
306     void                   *destination)
307 {
308 	if (action != kIOReportEnable && action != kIOReportGetDimensions && action != kIOReportDisable) {
309 		return kIOReturnUnsupported;
310 	}
311 	static_assert(sizeof(IOReportChannelList) == 8);
312 	static_assert(sizeof(IOReportChannel) == 16);
313 	unsigned int size_of_channels;
314 	bool overflow = os_mul_and_add_overflow(channelList->nchannels, sizeof(IOReportChannel), sizeof(IOReportChannelList), &size_of_channels);
315 	if (overflow) {
316 		return kIOReturnOverrun;
317 	}
318 	OSSharedPtr<OSData> sp_channels(OSData::withBytesNoCopy(channelList, size_of_channels), libkern::no_retain);
319 	if (!sp_channels) {
320 		return kIOReturnNoMemory;
321 	}
322 	int *resultp = (int*) result;
323 	uint32_t count = 0;
324 	IOReturn r = ConfigureReport(sp_channels.get(), action, &count);
325 	int new_result;
326 	overflow = os_add_overflow(*resultp, count, &new_result);
327 	if (overflow) {
328 		return kIOReturnOverrun;
329 	}
330 	*resultp = new_result;
331 	return r;
332 }
333 
334 // adapt old signature of updateReport to the iig-friendly signature of UpdateReport
335 IOReturn
336 IOService::_UpdateReport(IOReportChannelList      *channelList,
337     IOReportUpdateAction      action,
338     void                     *result,
339     void                     *destination)
340 {
341 	if (action != kIOReportCopyChannelData) {
342 		return kIOReturnUnsupported;
343 	}
344 	unsigned int size_of_channels;
345 	bool overflow = os_mul_and_add_overflow(channelList->nchannels, sizeof(IOReportChannel), sizeof(IOReportChannelList), &size_of_channels);
346 	if (overflow) {
347 		return kIOReturnOverrun;
348 	}
349 	OSSharedPtr<OSData> sp_channels(OSData::withBytesNoCopy(channelList, size_of_channels), libkern::no_retain);
350 	if (!sp_channels) {
351 		return kIOReturnNoMemory;
352 	}
353 	int *resultp = (int*) result;
354 	uint32_t count = 0;
355 	auto buffer = (IOBufferMemoryDescriptor*) destination;
356 	uint64_t length = buffer->getLength();
357 	buffer->setLength(buffer->getCapacity());
358 	IOReturn r = UpdateReport(sp_channels.get(), action, &count, length, buffer->getCapacity() - length, buffer);
359 	int new_result;
360 	overflow = os_add_overflow(*resultp, count, &new_result);
361 	size_t new_length;
362 	overflow = overflow || os_mul_and_add_overflow(count, sizeof(IOReportElement), length, &new_length);
363 	if (overflow || new_length > buffer->getCapacity()) {
364 		buffer->setLength(length);
365 		return kIOReturnOverrun;
366 	}
367 	*resultp = new_result;
368 	buffer->setLength(new_length);
369 	return r;
370 }
371 
372 
373 IOReturn
374 IOService::SetLegend_Impl(OSArray *legend, bool is_public)
375 {
376 	bool ok = setProperty(kIOReportLegendKey, legend);
377 	ok = ok && setProperty(kIOReportLegendPublicKey, is_public);
378 	return ok ? kIOReturnSuccess : kIOReturnError;
379 }
380 
381 
382 kern_return_t
383 IOService::RegisterService_Impl()
384 {
385 	IOReturn ret = kIOReturnSuccess;
386 	bool started;
387 
388 	IOUserServer *us = (typeof(us))thread_iokit_tls_get(0);
389 	if (reserved != NULL && reserved->uvars != NULL && reserved->uvars->userServer == us) {
390 		started = reserved->uvars->started;
391 	} else {
392 		// assume started
393 		started = true;
394 	}
395 
396 	if (OSDynamicCast(IOUserServer, this) != NULL || started) {
397 		registerService(kIOServiceAsynchronous);
398 	} else {
399 		assert(reserved != NULL && reserved->uvars != NULL);
400 		reserved->uvars->deferredRegisterService = true;
401 	}
402 
403 	return ret;
404 }
405 
406 kern_return_t
407 IOService::CopyDispatchQueue_Impl(
408 	const char * name,
409 	IODispatchQueue ** queue)
410 {
411 	IODispatchQueue * result;
412 	IOService  * service;
413 	IOReturn     ret;
414 	uint32_t index;
415 
416 	if (!reserved->uvars) {
417 		return kIOReturnError;
418 	}
419 
420 	if (!reserved->uvars->queueArray) {
421 		// CopyDispatchQueue should not be called after the service has stopped
422 		return kIOReturnError;
423 	}
424 
425 	ret = kIOReturnNotFound;
426 	index = -1U;
427 	if (!strcmp("Default", name)) {
428 		index = 0;
429 	} else if (reserved->uvars->userMeta
430 	    && reserved->uvars->userMeta->queueNames) {
431 		index = reserved->uvars->userServer->stringArrayIndex(reserved->uvars->userMeta->queueNames, name);
432 		if (index != -1U) {
433 			index++;
434 		}
435 	}
436 	if (index == -1U) {
437 		if ((service = getProvider())) {
438 			ret = service->CopyDispatchQueue(name, queue);
439 		}
440 	} else {
441 		result = reserved->uvars->queueArray[index];
442 		if (result) {
443 			result->retain();
444 			*queue = result;
445 			ret = kIOReturnSuccess;
446 		}
447 	}
448 
449 	return ret;
450 }
451 
452 kern_return_t
453 IOService::CreateDefaultDispatchQueue_Impl(
454 	IODispatchQueue ** queue)
455 {
456 	return kIOReturnError;
457 }
458 
459 kern_return_t
460 IOService::CoreAnalyticsSendEvent_Impl(
461 	uint64_t       options,
462 	OSString     * eventName,
463 	OSDictionary * eventPayload)
464 {
465 	kern_return_t ret;
466 
467 	if (NULL == gIOCoreAnalyticsSendEventProc) {
468 		// perhaps save for later?
469 		return kIOReturnNotReady;
470 	}
471 
472 	ret = (*gIOCoreAnalyticsSendEventProc)(options, eventName, eventPayload);
473 
474 	return ret;
475 }
476 
477 kern_return_t
478 IOService::SetDispatchQueue_Impl(
479 	const char * name,
480 	IODispatchQueue * queue)
481 {
482 	IOReturn ret = kIOReturnSuccess;
483 	uint32_t index;
484 
485 	if (!reserved->uvars) {
486 		return kIOReturnError;
487 	}
488 
489 	if (kIODKLogSetup & gIODKDebug) {
490 		DKLOG(DKS "::SetDispatchQueue(%s)\n", DKN(this), name);
491 	}
492 	queue->ivars->userServer = reserved->uvars->userServer;
493 	index = -1U;
494 	if (!strcmp("Default", name)) {
495 		index = 0;
496 	} else if (reserved->uvars->userMeta
497 	    && reserved->uvars->userMeta->queueNames) {
498 		index = reserved->uvars->userServer->stringArrayIndex(reserved->uvars->userMeta->queueNames, name);
499 		if (index != -1U) {
500 			index++;
501 		}
502 	}
503 	if (index == -1U) {
504 		ret = kIOReturnBadArgument;
505 	} else {
506 		reserved->uvars->queueArray[index] = queue;
507 		queue->retain();
508 	}
509 
510 	return ret;
511 }
512 
513 IOService *
514 IOService::GetProvider() const
515 {
516 	return getProvider();
517 }
518 
519 kern_return_t
520 IOService::SetProperties_Impl(
521 	OSDictionary * properties)
522 {
523 	IOUserServer   * us;
524 	OSDictionary   * dict;
525 	IOReturn         ret;
526 
527 	us = (typeof(us))thread_iokit_tls_get(0);
528 	dict = OSDynamicCast(OSDictionary, properties);
529 	if (NULL == us) {
530 		if (!dict) {
531 			return kIOReturnBadArgument;
532 		}
533 		bool ok __block = true;
534 		dict->iterateObjects(^bool (const OSSymbol * key, OSObject * value) {
535 			ok = setProperty(key, value);
536 			return !ok;
537 		});
538 		ret = ok ? kIOReturnSuccess : kIOReturnNotWritable;
539 		return ret;
540 	}
541 
542 	ret = setProperties(properties);
543 
544 	if (kIOReturnUnsupported == ret) {
545 		if (dict && reserved->uvars && (reserved->uvars->userServer == us)) {
546 			ret = runPropertyActionBlock(^IOReturn (void) {
547 				OSDictionary   * userProps;
548 				IOReturn         ret;
549 
550 				userProps = OSDynamicCast(OSDictionary, getProperty(gIOUserServicePropertiesKey));
551 				if (userProps) {
552 				        userProps = (typeof(userProps))userProps->copyCollection();
553 				} else {
554 				        userProps = OSDictionary::withCapacity(4);
555 				}
556 				if (!userProps) {
557 				        ret = kIOReturnNoMemory;
558 				} else {
559 				        bool ok = userProps->merge(dict);
560 				        if (ok) {
561 				                ok = setProperty(gIOUserServicePropertiesKey, userProps);
562 					}
563 				        OSSafeReleaseNULL(userProps);
564 				        ret = ok ? kIOReturnSuccess : kIOReturnNotWritable;
565 				}
566 				return ret;
567 			});
568 		}
569 	}
570 
571 	return ret;
572 }
573 
574 kern_return_t
575 IOService::RemoveProperty_Impl(OSString * propertyName)
576 {
577 	IOUserServer * us  = (IOUserServer *)thread_iokit_tls_get(0);
578 	IOReturn       ret = kIOReturnUnsupported;
579 
580 	if (NULL == propertyName) {
581 		return kIOReturnUnsupported;
582 	}
583 	if (NULL == us) {
584 		removeProperty(propertyName);
585 		return kIOReturnSuccess;
586 	}
587 	if (reserved && reserved->uvars && reserved->uvars->userServer == us) {
588 		ret = runPropertyActionBlock(^IOReturn (void) {
589 			OSDictionary * userProps;
590 			userProps = OSDynamicCast(OSDictionary, getProperty(gIOUserServicePropertiesKey));
591 			if (userProps) {
592 			        userProps = (OSDictionary *)userProps->copyCollection();
593 			        if (!userProps) {
594 			                return kIOReturnNoMemory;
595 				}
596 			        userProps->removeObject(propertyName);
597 			        bool ok = setProperty(gIOUserServicePropertiesKey, userProps);
598 			        OSSafeReleaseNULL(userProps);
599 			        return ok ? kIOReturnSuccess : kIOReturnNotWritable;
600 			} else {
601 			        return kIOReturnNotFound;
602 			}
603 		});
604 	}
605 	return ret;
606 }
607 
608 kern_return_t
609 IOService::CopyProperties_Local(
610 	OSDictionary ** properties)
611 {
612 	OSDictionary * props;
613 	OSDictionary * userProps;
614 
615 	props = dictionaryWithProperties();
616 	userProps = OSDynamicCast(OSDictionary, props->getObject(gIOUserServicePropertiesKey));
617 	if (userProps) {
618 		props->merge(userProps);
619 		props->removeObject(gIOUserServicePropertiesKey);
620 	}
621 
622 	*properties = props;
623 
624 	return props ? kIOReturnSuccess : kIOReturnNoMemory;
625 }
626 
627 kern_return_t
628 IOService::CopyProperties_Impl(
629 	OSDictionary ** properties)
630 {
631 	return CopyProperties_Local(properties);
632 }
633 
634 kern_return_t
635 IOService::RequireMaxBusStall_Impl(
636 	uint64_t u64ns)
637 {
638 	IOReturn ret;
639 	UInt32   ns;
640 
641 	if (os_convert_overflow(u64ns, &ns)) {
642 		return kIOReturnBadArgument;
643 	}
644 	ret = requireMaxBusStall(ns);
645 
646 	return ret;
647 }
648 
649 #if PRIVATE_WIFI_ONLY
650 kern_return_t
651 IOService::UserSetProperties_Impl(
652 	OSContainer * properties)
653 {
654 	return kIOReturnUnsupported;
655 }
656 
657 kern_return_t
658 IOService::SendIOMessageServicePropertyChange_Impl(void)
659 {
660 	return messageClients(kIOMessageServicePropertyChange);
661 }
662 #endif /* PRIVATE_WIFI_ONLY */
663 
664 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
665 
666 kern_return_t
667 IOMemoryDescriptor::_CopyState_Impl(
668 	_IOMDPrivateState * state)
669 {
670 	IOReturn ret;
671 
672 	state->length = _length;
673 	state->options = _flags;
674 
675 	ret = kIOReturnSuccess;
676 
677 	return ret;
678 }
679 
680 kern_return_t
681 IOMemoryDescriptor::GetLength(uint64_t * returnLength)
682 {
683 	*returnLength = getLength();
684 
685 	return kIOReturnSuccess;
686 }
687 
688 kern_return_t
689 IOMemoryDescriptor::CreateMapping_Impl(
690 	uint64_t options,
691 	uint64_t address,
692 	uint64_t offset,
693 	uint64_t length,
694 	uint64_t alignment,
695 	IOMemoryMap ** map)
696 {
697 	IOReturn          ret;
698 	IOMemoryMap     * resultMap;
699 	IOOptionBits      koptions;
700 	mach_vm_address_t atAddress;
701 
702 	ret       = kIOReturnSuccess;
703 	koptions  = 0;
704 	resultMap = NULL;
705 
706 	if (kIOMemoryMapFixedAddress & options) {
707 		atAddress   = address;
708 		koptions    = 0;
709 	} else {
710 		switch (kIOMemoryMapGuardedMask & options) {
711 		default:
712 		case kIOMemoryMapGuardedDefault:
713 			koptions |= kIOMapGuardedSmall;
714 			break;
715 		case kIOMemoryMapGuardedNone:
716 			break;
717 		case kIOMemoryMapGuardedSmall:
718 			koptions |= kIOMapGuardedSmall;
719 			break;
720 		case kIOMemoryMapGuardedLarge:
721 			koptions |= kIOMapGuardedLarge;
722 			break;
723 		}
724 		atAddress   = 0;
725 		koptions   |= kIOMapAnywhere;
726 	}
727 
728 	if ((kIOMemoryMapReadOnly & options) || (kIODirectionOut == getDirection())) {
729 		if (!reserved || (current_task() != reserved->creator)) {
730 			koptions   |= kIOMapReadOnly;
731 		}
732 	}
733 
734 	switch (0xFF00 & options) {
735 	case kIOMemoryMapCacheModeDefault:
736 		koptions |= kIOMapDefaultCache;
737 		break;
738 	case kIOMemoryMapCacheModeInhibit:
739 		koptions |= kIOMapInhibitCache;
740 		break;
741 	case kIOMemoryMapCacheModeCopyback:
742 		koptions |= kIOMapCopybackCache;
743 		break;
744 	case kIOMemoryMapCacheModeWriteThrough:
745 		koptions |= kIOMapWriteThruCache;
746 		break;
747 	case kIOMemoryMapCacheModeRealTime:
748 		koptions |= kIOMapRealTimeCache;
749 		break;
750 	default:
751 		ret = kIOReturnBadArgument;
752 	}
753 
754 	if (kIOReturnSuccess == ret) {
755 		resultMap = createMappingInTask(current_task(), atAddress, koptions, offset, length);
756 		if (!resultMap) {
757 			ret = kIOReturnError;
758 		}
759 	}
760 
761 	*map = resultMap;
762 
763 	return ret;
764 }
765 
766 kern_return_t
767 IOMemoryDescriptor::CreateSubMemoryDescriptor_Impl(
768 	uint64_t memoryDescriptorCreateOptions,
769 	uint64_t offset,
770 	uint64_t length,
771 	IOMemoryDescriptor * ofDescriptor,
772 	IOMemoryDescriptor ** memory)
773 {
774 	IOReturn             ret;
775 	IOMemoryDescriptor * iomd;
776 	IOByteCount          mdOffset;
777 	IOByteCount          mdLength;
778 	IOByteCount          mdEnd;
779 
780 	if (!ofDescriptor) {
781 		return kIOReturnBadArgument;
782 	}
783 	if (memoryDescriptorCreateOptions & ~kIOMemoryDirectionOutIn) {
784 		return kIOReturnBadArgument;
785 	}
786 	if (os_convert_overflow(offset, &mdOffset)) {
787 		return kIOReturnBadArgument;
788 	}
789 	if (os_convert_overflow(length, &mdLength)) {
790 		return kIOReturnBadArgument;
791 	}
792 	if (os_add_overflow(mdOffset, mdLength, &mdEnd)) {
793 		return kIOReturnBadArgument;
794 	}
795 	if (mdEnd > ofDescriptor->getLength()) {
796 		return kIOReturnBadArgument;
797 	}
798 
799 	iomd = IOSubMemoryDescriptor::withSubRange(
800 		ofDescriptor, mdOffset, mdLength, (IOOptionBits) memoryDescriptorCreateOptions);
801 
802 	if (iomd) {
803 		ret = kIOReturnSuccess;
804 		*memory = iomd;
805 	} else {
806 		ret = kIOReturnNoMemory;
807 		*memory = NULL;
808 	}
809 
810 	return ret;
811 }
812 
813 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
814 
815 kern_return_t
816 IOMemoryDescriptor::CreateWithMemoryDescriptors_Impl(
817 	uint64_t memoryDescriptorCreateOptions,
818 	uint32_t withDescriptorsCount,
819 	IOMemoryDescriptor ** const withDescriptors,
820 	IOMemoryDescriptor ** memory)
821 {
822 	IOReturn             ret;
823 	IOMemoryDescriptor * iomd;
824 
825 	if (!withDescriptors) {
826 		return kIOReturnBadArgument;
827 	}
828 	if (!withDescriptorsCount) {
829 		return kIOReturnBadArgument;
830 	}
831 	if (memoryDescriptorCreateOptions & ~kIOMemoryDirectionOutIn) {
832 		return kIOReturnBadArgument;
833 	}
834 
835 	for (unsigned int idx = 0; idx < withDescriptorsCount; idx++) {
836 		if (NULL == withDescriptors[idx]) {
837 			return kIOReturnBadArgument;
838 		}
839 	}
840 
841 	iomd = IOMultiMemoryDescriptor::withDescriptors(withDescriptors, withDescriptorsCount,
842 	    (IODirection) memoryDescriptorCreateOptions, false);
843 
844 	if (iomd) {
845 		ret = kIOReturnSuccess;
846 		*memory = iomd;
847 	} else {
848 		ret = kIOReturnNoMemory;
849 		*memory = NULL;
850 	}
851 
852 	return ret;
853 }
854 
855 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  * * * * * * * * * * * * * * * * * * * */
856 
857 kern_return_t
858 IOUserClient::CreateMemoryDescriptorFromClient_Impl(
859 	uint64_t memoryDescriptorCreateOptions,
860 	uint32_t segmentsCount,
861 	const IOAddressSegment segments[32],
862 	IOMemoryDescriptor ** memory)
863 {
864 	IOReturn             ret;
865 	IOMemoryDescriptor * iomd;
866 	IOOptionBits         mdOptions;
867 	IOUserUserClient   * me;
868 	IOAddressRange     * ranges;
869 
870 	me = OSDynamicCast(IOUserUserClient, this);
871 	if (!me) {
872 		return kIOReturnBadArgument;
873 	}
874 	if (!me->fTask) {
875 		return kIOReturnNotReady;
876 	}
877 
878 	mdOptions = kIOMemoryThreadSafe;
879 	if (kIOMemoryDirectionOut & memoryDescriptorCreateOptions) {
880 		mdOptions |= kIODirectionOut;
881 	}
882 	if (kIOMemoryDirectionIn & memoryDescriptorCreateOptions) {
883 		mdOptions |= kIODirectionIn;
884 	}
885 	if (!(kIOMemoryDisableCopyOnWrite & memoryDescriptorCreateOptions)) {
886 		mdOptions |= kIOMemoryMapCopyOnWrite;
887 	}
888 
889 	static_assert(sizeof(IOAddressRange) == sizeof(IOAddressSegment));
890 	ranges = __DECONST(IOAddressRange *, &segments[0]);
891 
892 	iomd = IOMemoryDescriptor::withAddressRanges(
893 		ranges, segmentsCount,
894 		mdOptions, me->fTask);
895 
896 	if (iomd) {
897 		ret = kIOReturnSuccess;
898 		*memory = iomd;
899 	} else {
900 		ret = kIOReturnNoMemory;
901 		*memory = NULL;
902 	}
903 
904 	return ret;
905 }
906 
907 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
908 
909 kern_return_t
910 IOMemoryMap::_CopyState_Impl(
911 	_IOMemoryMapPrivateState * state)
912 {
913 	IOReturn ret;
914 
915 	state->offset  = fOffset;
916 	state->length  = getLength();
917 	state->address = getAddress();
918 	state->options = getMapOptions();
919 
920 	ret = kIOReturnSuccess;
921 
922 	return ret;
923 }
924 
925 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
926 
927 kern_return_t
928 IOBufferMemoryDescriptor::Create_Impl(
929 	uint64_t options,
930 	uint64_t capacity,
931 	uint64_t alignment,
932 	IOBufferMemoryDescriptor ** memory)
933 {
934 	IOReturn ret;
935 	IOOptionBits                 bmdOptions;
936 	IOBufferMemoryDescriptor   * bmd;
937 	IOMemoryDescriptorReserved * reserved;
938 
939 	if (options & ~((uint64_t) kIOMemoryDirectionOutIn)) {
940 		// no other options currently defined
941 		return kIOReturnBadArgument;
942 	}
943 	bmdOptions = (options & kIOMemoryDirectionOutIn) | kIOMemoryKernelUserShared | kIOMemoryThreadSafe;
944 	bmd = IOBufferMemoryDescriptor::inTaskWithOptions(
945 		kernel_task, bmdOptions, capacity, alignment);
946 
947 	*memory = bmd;
948 
949 	if (!bmd) {
950 		return kIOReturnNoMemory;
951 	}
952 
953 	reserved = bmd->getKernelReserved();
954 	reserved->creator = current_task();
955 	task_reference(reserved->creator);
956 
957 	ret = kIOReturnSuccess;
958 
959 	return ret;
960 }
961 
962 kern_return_t
963 IOBufferMemoryDescriptor::SetLength_Impl(
964 	uint64_t length)
965 {
966 	setLength(length);
967 	return kIOReturnSuccess;
968 }
969 
970 
971 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
972 
973 kern_return_t
974 IODMACommand::Create_Impl(
975 	IOService * device,
976 	uint64_t options,
977 	const IODMACommandSpecification * specification,
978 	IODMACommand ** command)
979 {
980 	IOReturn ret;
981 	IODMACommand   * dma;
982 	IODMACommand::SegmentOptions segmentOptions;
983 	IOMapper             * mapper;
984 
985 	if (options & ~((uint64_t) kIODMACommandCreateNoOptions)) {
986 		// no other options currently defined
987 		return kIOReturnBadArgument;
988 	}
989 
990 	if (os_convert_overflow(specification->maxAddressBits, &segmentOptions.fNumAddressBits)) {
991 		return kIOReturnBadArgument;
992 	}
993 	segmentOptions.fMaxSegmentSize            = 0;
994 	segmentOptions.fMaxTransferSize           = 0;
995 	segmentOptions.fAlignment                 = 1;
996 	segmentOptions.fAlignmentLength           = 1;
997 	segmentOptions.fAlignmentInternalSegments = 1;
998 	segmentOptions.fStructSize                = sizeof(segmentOptions);
999 
1000 	mapper = IOMapper::copyMapperForDevice(device);
1001 
1002 	dma = IODMACommand::withSpecification(
1003 		kIODMACommandOutputHost64,
1004 		&segmentOptions,
1005 		kIODMAMapOptionDextOwner |
1006 		kIODMAMapOptionMapped,
1007 		mapper,
1008 		NULL);
1009 
1010 	OSSafeReleaseNULL(mapper);
1011 	*command = dma;
1012 
1013 	if (!dma) {
1014 		return kIOReturnNoMemory;
1015 	}
1016 	ret = kIOReturnSuccess;
1017 
1018 	return ret;
1019 }
1020 
1021 #define fInternalState reserved
1022 
1023 kern_return_t
1024 IODMACommand::PrepareForDMA_Impl(
1025 	uint64_t options,
1026 	IOMemoryDescriptor * memory,
1027 	uint64_t offset,
1028 	uint64_t length,
1029 	uint64_t * flags,
1030 	uint32_t * segmentsCount,
1031 	IOAddressSegment * segments)
1032 {
1033 	IOReturn ret;
1034 	uint64_t lflags, mdFlags;
1035 	UInt32   numSegments;
1036 	UInt64   genOffset;
1037 
1038 	if (options & ~((uint64_t) kIODMACommandPrepareForDMANoOptions)) {
1039 		// no other options currently defined
1040 		return kIOReturnBadArgument;
1041 	}
1042 
1043 	if (memory == NULL) {
1044 		return kIOReturnBadArgument;
1045 	}
1046 
1047 	assert(fInternalState->fDextLock);
1048 	IOLockLock(fInternalState->fDextLock);
1049 
1050 	// uses IOMD direction
1051 	ret = memory->prepare();
1052 	if (kIOReturnSuccess != ret) {
1053 		goto exit;
1054 	}
1055 
1056 	ret = setMemoryDescriptor(memory, false);
1057 	if (kIOReturnSuccess != ret) {
1058 		memory->complete();
1059 		goto exit;
1060 	}
1061 
1062 	ret = prepare(offset, length);
1063 	if (kIOReturnSuccess != ret) {
1064 		clearMemoryDescriptor(false);
1065 		memory->complete();
1066 		goto exit;
1067 	}
1068 
1069 	static_assert(sizeof(IODMACommand::Segment64) == sizeof(IOAddressSegment));
1070 
1071 	numSegments = *segmentsCount;
1072 	genOffset   = 0;
1073 	ret = genIOVMSegments(&genOffset, segments, &numSegments);
1074 
1075 	if (kIOReturnSuccess != ret) {
1076 		clearMemoryDescriptor(true);
1077 		memory->complete();
1078 		goto exit;
1079 	}
1080 
1081 	mdFlags = fMemory->getFlags();
1082 	lflags  = 0;
1083 	if (kIODirectionOut & mdFlags) {
1084 		lflags |= kIOMemoryDirectionOut;
1085 	}
1086 	if (kIODirectionIn & mdFlags) {
1087 		lflags |= kIOMemoryDirectionIn;
1088 	}
1089 	*flags = lflags;
1090 	*segmentsCount = numSegments;
1091 
1092 exit:
1093 	IOLockUnlock(fInternalState->fDextLock);
1094 
1095 	return ret;
1096 }
1097 
1098 kern_return_t
1099 IODMACommand::CompleteDMA_Impl(
1100 	uint64_t options)
1101 {
1102 	IOReturn ret, completeRet;
1103 	IOMemoryDescriptor * md;
1104 
1105 	if (options & ~((uint64_t) kIODMACommandCompleteDMANoOptions)) {
1106 		// no other options currently defined
1107 		return kIOReturnBadArgument;
1108 	}
1109 
1110 	assert(fInternalState->fDextLock);
1111 	IOLockLock(fInternalState->fDextLock);
1112 
1113 	if (!fInternalState->fPrepared) {
1114 		ret = kIOReturnNotReady;
1115 		goto exit;
1116 	}
1117 
1118 	md = __DECONST(IOMemoryDescriptor *, fMemory);
1119 	if (md) {
1120 		md->retain();
1121 	}
1122 
1123 	ret = clearMemoryDescriptor(true);
1124 
1125 	if (md) {
1126 		completeRet = md->complete();
1127 		OSSafeReleaseNULL(md);
1128 		if (kIOReturnSuccess == ret) {
1129 			ret = completeRet;
1130 		}
1131 	}
1132 exit:
1133 	IOLockUnlock(fInternalState->fDextLock);
1134 
1135 	return ret;
1136 }
1137 
1138 kern_return_t
1139 IODMACommand::GetPreparation_Impl(
1140 	uint64_t * offset,
1141 	uint64_t * length,
1142 	IOMemoryDescriptor ** memory)
1143 {
1144 	IOReturn ret;
1145 	IOMemoryDescriptor * md;
1146 
1147 	if (!fActive) {
1148 		return kIOReturnNotReady;
1149 	}
1150 
1151 	ret = getPreparedOffsetAndLength(offset, length);
1152 	if (kIOReturnSuccess != ret) {
1153 		return ret;
1154 	}
1155 
1156 	if (memory) {
1157 		md = __DECONST(IOMemoryDescriptor *, fMemory);
1158 		*memory = md;
1159 		if (!md) {
1160 			ret = kIOReturnNotReady;
1161 		} else {
1162 			md->retain();
1163 		}
1164 	}
1165 	return ret;
1166 }
1167 
1168 kern_return_t
1169 IODMACommand::PerformOperation_Impl(
1170 	uint64_t options,
1171 	uint64_t dmaOffset,
1172 	uint64_t length,
1173 	uint64_t dataOffset,
1174 	IOMemoryDescriptor * data)
1175 {
1176 	IOReturn ret;
1177 	OSDataAllocation<uint8_t> buffer;
1178 	UInt64 copiedDMA;
1179 	IOByteCount mdOffset, mdLength, copied;
1180 
1181 	if (options & ~((uint64_t)
1182 	    (kIODMACommandPerformOperationOptionRead
1183 	    | kIODMACommandPerformOperationOptionWrite
1184 	    | kIODMACommandPerformOperationOptionZero))) {
1185 		// no other options currently defined
1186 		return kIOReturnBadArgument;
1187 	}
1188 
1189 	if (!fActive) {
1190 		return kIOReturnNotReady;
1191 	}
1192 	if (os_convert_overflow(dataOffset, &mdOffset)) {
1193 		return kIOReturnBadArgument;
1194 	}
1195 	if (os_convert_overflow(length, &mdLength)) {
1196 		return kIOReturnBadArgument;
1197 	}
1198 	if (length > fMemory->getLength()) {
1199 		return kIOReturnBadArgument;
1200 	}
1201 	buffer = OSDataAllocation<uint8_t>(length, OSAllocateMemory);
1202 	if (!buffer) {
1203 		return kIOReturnNoMemory;
1204 	}
1205 
1206 	switch (options) {
1207 	case kIODMACommandPerformOperationOptionZero:
1208 		bzero(buffer.data(), length);
1209 		copiedDMA = writeBytes(dmaOffset, buffer.data(), length);
1210 		if (copiedDMA != length) {
1211 			ret = kIOReturnUnderrun;
1212 			break;
1213 		}
1214 		ret = kIOReturnSuccess;
1215 		break;
1216 
1217 	case kIODMACommandPerformOperationOptionRead:
1218 	case kIODMACommandPerformOperationOptionWrite:
1219 
1220 		if (!data) {
1221 			ret = kIOReturnBadArgument;
1222 			break;
1223 		}
1224 		if (length > data->getLength()) {
1225 			ret = kIOReturnBadArgument;
1226 			break;
1227 		}
1228 		if (kIODMACommandPerformOperationOptionWrite == options) {
1229 			copied = data->readBytes(mdOffset, buffer.data(), mdLength);
1230 			if (copied != mdLength) {
1231 				ret = kIOReturnUnderrun;
1232 				break;
1233 			}
1234 			copiedDMA = writeBytes(dmaOffset, buffer.data(), length);
1235 			if (copiedDMA != length) {
1236 				ret = kIOReturnUnderrun;
1237 				break;
1238 			}
1239 		} else {       /* kIODMACommandPerformOperationOptionRead */
1240 			copiedDMA = readBytes(dmaOffset, buffer.data(), length);
1241 			if (copiedDMA != length) {
1242 				ret = kIOReturnUnderrun;
1243 				break;
1244 			}
1245 			copied = data->writeBytes(mdOffset, buffer.data(), mdLength);
1246 			if (copied != mdLength) {
1247 				ret = kIOReturnUnderrun;
1248 				break;
1249 			}
1250 		}
1251 		ret = kIOReturnSuccess;
1252 		break;
1253 	default:
1254 		ret = kIOReturnBadArgument;
1255 		break;
1256 	}
1257 
1258 	return ret;
1259 }
1260 
1261 
1262 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1263 
1264 static kern_return_t
1265 OSActionCreateWithTypeNameInternal(OSObject * target, uint64_t targetmsgid, uint64_t msgid, size_t referenceSize, OSString * typeName, bool fromKernel, OSAction ** action)
1266 {
1267 	OSAction * inst = NULL;
1268 	void * reference = NULL; // must release
1269 	const OSSymbol *sym = NULL; // must release
1270 	OSObject *obj = NULL; // must release
1271 	const OSMetaClass *actionMetaClass = NULL; // do not release
1272 	kern_return_t ret;
1273 
1274 	if (fromKernel && typeName) {
1275 		/* The action is being constructed in the kernel with a type name */
1276 		sym = OSSymbol::withString(typeName);
1277 		actionMetaClass = OSMetaClass::getMetaClassWithName(sym);
1278 		if (actionMetaClass && actionMetaClass->getSuperClass() == OSTypeID(OSAction)) {
1279 			obj = actionMetaClass->alloc();
1280 			if (!obj) {
1281 				ret = kIOReturnNoMemory;
1282 				goto finish;
1283 			}
1284 			inst = OSDynamicCast(OSAction, obj);
1285 			obj = NULL; // prevent release
1286 			assert(inst); // obj is a subclass of OSAction so the dynamic cast should always work
1287 		} else {
1288 			DKLOG("Attempted to create action object with type \"%s\" which does not inherit from OSAction\n", typeName->getCStringNoCopy());
1289 			ret = kIOReturnBadArgument;
1290 			goto finish;
1291 		}
1292 	} else {
1293 		inst = OSTypeAlloc(OSAction);
1294 		if (!inst) {
1295 			ret = kIOReturnNoMemory;
1296 			goto finish;
1297 		}
1298 	}
1299 
1300 	if (referenceSize != 0) {
1301 		reference = IONewZeroData(uint8_t, referenceSize);
1302 		if (reference == NULL) {
1303 			ret = kIOReturnNoMemory;
1304 			goto finish;
1305 		}
1306 	}
1307 
1308 	inst->ivars = IONewZero(OSAction_IVars, 1);
1309 	if (!inst->ivars) {
1310 		ret = kIOReturnNoMemory;
1311 		goto finish;
1312 	}
1313 	if (target) {
1314 		target->retain();
1315 		if (!fromKernel && !OSDynamicCast(IOService, target)) {
1316 			IOUserServer * us;
1317 			us = (typeof(us))thread_iokit_tls_get(0);
1318 			inst->ivars->userServer = OSDynamicCast(IOUserServer, us);
1319 			assert(inst->ivars->userServer);
1320 			inst->ivars->userServer->retain();
1321 		}
1322 	}
1323 	inst->ivars->target        = target;
1324 	inst->ivars->targetmsgid   = targetmsgid;
1325 	inst->ivars->msgid         = msgid;
1326 
1327 	inst->ivars->reference     = reference;
1328 	inst->ivars->referenceSize = referenceSize;
1329 	reference = NULL; // prevent release
1330 
1331 	if (typeName) {
1332 		typeName->retain();
1333 	}
1334 	inst->ivars->typeName      = typeName;
1335 
1336 	*action = inst;
1337 	inst = NULL; // prevent release
1338 	ret = kIOReturnSuccess;
1339 
1340 finish:
1341 	OSSafeReleaseNULL(obj);
1342 	OSSafeReleaseNULL(sym);
1343 	OSSafeReleaseNULL(inst);
1344 	if (reference) {
1345 		IODeleteData(reference, uint8_t, referenceSize);
1346 	}
1347 
1348 	return ret;
1349 }
1350 
1351 kern_return_t
1352 OSAction::Create(OSAction_Create_Args)
1353 {
1354 	return OSAction::CreateWithTypeName(target, targetmsgid, msgid, referenceSize, NULL, action);
1355 }
1356 
1357 kern_return_t
1358 OSAction::CreateWithTypeName(OSAction_CreateWithTypeName_Args)
1359 {
1360 	return OSActionCreateWithTypeNameInternal(target, targetmsgid, msgid, referenceSize, typeName, true, action);
1361 }
1362 
1363 kern_return_t
1364 OSAction::Create_Impl(
1365 	OSObject * target,
1366 	uint64_t targetmsgid,
1367 	uint64_t msgid,
1368 	size_t referenceSize,
1369 	OSAction ** action)
1370 {
1371 	return OSAction::CreateWithTypeName_Impl(target, targetmsgid, msgid, referenceSize, NULL, action);
1372 }
1373 
1374 kern_return_t
1375 OSAction::CreateWithTypeName_Impl(
1376 	OSObject * target,
1377 	uint64_t targetmsgid,
1378 	uint64_t msgid,
1379 	size_t referenceSize,
1380 	OSString * typeName,
1381 	OSAction ** action)
1382 {
1383 	return OSActionCreateWithTypeNameInternal(target, targetmsgid, msgid, referenceSize, typeName, false, action);
1384 }
1385 
1386 void
1387 OSAction::free()
1388 {
1389 	if (ivars) {
1390 		if (ivars->abortedHandler) {
1391 			Block_release(ivars->abortedHandler);
1392 			ivars->abortedHandler = NULL;
1393 		}
1394 		OSSafeReleaseNULL(ivars->target);
1395 		OSSafeReleaseNULL(ivars->typeName);
1396 		OSSafeReleaseNULL(ivars->userServer);
1397 		if (ivars->reference) {
1398 			assert(ivars->referenceSize > 0);
1399 			IODeleteData(ivars->reference, uint8_t, ivars->referenceSize);
1400 		}
1401 		IOSafeDeleteNULL(ivars, OSAction_IVars, 1);
1402 	}
1403 	return super::free();
1404 }
1405 
1406 void *
1407 OSAction::GetReference()
1408 {
1409 	assert(ivars && ivars->referenceSize && ivars->reference);
1410 	return ivars->reference;
1411 }
1412 
1413 kern_return_t
1414 OSAction::SetAbortedHandler(OSActionAbortedHandler handler)
1415 {
1416 	ivars->abortedHandler = Block_copy(handler);
1417 	return kIOReturnSuccess;
1418 }
1419 
1420 void
1421 OSAction::Aborted_Impl(void)
1422 {
1423 	if (!os_atomic_cmpxchg(&ivars->aborted, false, true, relaxed)) {
1424 		// already aborted
1425 		return;
1426 	}
1427 	if (ivars->abortedHandler) {
1428 		ivars->abortedHandler();
1429 	}
1430 }
1431 
1432 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1433 
1434 struct IODispatchSource_IVars {
1435 	queue_chain_t           link;
1436 	IODispatchSource      * source;
1437 	IOUserServer          * server;
1438 	IODispatchQueue_IVars * queue;
1439 	bool                    enabled;
1440 };
1441 
1442 bool
1443 IODispatchSource::init()
1444 {
1445 	if (!super::init()) {
1446 		return false;
1447 	}
1448 
1449 	ivars = IOMallocType(IODispatchSource_IVars);
1450 
1451 	ivars->source = this;
1452 
1453 	return true;
1454 }
1455 
1456 void
1457 IODispatchSource::free()
1458 {
1459 	IOFreeType(ivars, IODispatchSource_IVars);
1460 	super::free();
1461 }
1462 
1463 kern_return_t
1464 IODispatchSource::SetEnable_Impl(
1465 	bool enable)
1466 {
1467 	return SetEnableWithCompletion(enable, NULL);
1468 }
1469 
1470 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1471 
1472 struct IOInterruptDispatchSource_IVars {
1473 	IOService    * provider;
1474 	uint32_t       intIndex;
1475 	uint32_t       flags;
1476 	int            interruptType;
1477 	IOSimpleLock * lock;
1478 	thread_t       waiter;
1479 	uint64_t       count;
1480 	uint64_t       time;
1481 	OSAction     * action;
1482 	bool           enable;
1483 	bool           canceled;
1484 };
1485 
1486 static void
1487 IOInterruptDispatchSourceInterrupt(OSObject * target, void * refCon,
1488     IOService * nub, int source )
1489 {
1490 	IOInterruptDispatchSource_IVars * ivars = (typeof(ivars))refCon;
1491 	IOInterruptState is;
1492 
1493 	is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1494 	ivars->count++;
1495 	ivars->time = (kIOInterruptSourceContinuousTime & ivars->flags)
1496 	    ? mach_continuous_time() : mach_absolute_time();
1497 	if (ivars->waiter) {
1498 		thread_wakeup_thread((event_t) ivars, ivars->waiter);
1499 		ivars->waiter = NULL;
1500 	}
1501 	if (kIOInterruptTypeLevel & ivars->interruptType) {
1502 		ivars->provider->disableInterrupt(ivars->intIndex);
1503 	}
1504 	IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1505 }
1506 
1507 kern_return_t
1508 IOInterruptDispatchSource::Create_Impl(
1509 	IOService * provider,
1510 	uint32_t indexAndFlags,
1511 	IODispatchQueue * queue,
1512 	IOInterruptDispatchSource ** source)
1513 {
1514 	IOReturn ret;
1515 	IOInterruptDispatchSource * inst;
1516 	uint32_t index;
1517 	uint32_t flags;
1518 
1519 	index = indexAndFlags & kIOInterruptSourceIndexMask;
1520 	flags = indexAndFlags & ~kIOInterruptSourceIndexMask;
1521 
1522 	inst = OSTypeAlloc(IOInterruptDispatchSource);
1523 	if (!inst->init()) {
1524 		inst->free();
1525 		return kIOReturnNoMemory;
1526 	}
1527 
1528 	inst->ivars->lock = IOSimpleLockAlloc();
1529 
1530 	ret = provider->getInterruptType(index, &inst->ivars->interruptType);
1531 	if (kIOReturnSuccess != ret) {
1532 		OSSafeReleaseNULL(inst);
1533 		return ret;
1534 	}
1535 	ret = provider->registerInterrupt(index, inst, IOInterruptDispatchSourceInterrupt, inst->ivars);
1536 	if (kIOReturnSuccess == ret) {
1537 		inst->ivars->intIndex = index;
1538 		inst->ivars->flags    = flags;
1539 		inst->ivars->provider = provider;
1540 		inst->ivars->provider->retain();
1541 		*source = inst;
1542 	}
1543 	return ret;
1544 }
1545 
1546 kern_return_t
1547 IOInterruptDispatchSource::GetInterruptType_Impl(
1548 	IOService * provider,
1549 	uint32_t index,
1550 	uint64_t * interruptType)
1551 {
1552 	IOReturn ret;
1553 	int      type;
1554 
1555 	*interruptType = 0;
1556 	ret = provider->getInterruptType(index, &type);
1557 	if (kIOReturnSuccess == ret) {
1558 		*interruptType = type;
1559 	}
1560 
1561 	return ret;
1562 }
1563 
1564 bool
1565 IOInterruptDispatchSource::init()
1566 {
1567 	if (!super::init()) {
1568 		return false;
1569 	}
1570 	ivars = IOMallocType(IOInterruptDispatchSource_IVars);
1571 
1572 	return true;
1573 }
1574 
1575 void
1576 IOInterruptDispatchSource::free()
1577 {
1578 	if (ivars && ivars->provider) {
1579 		(void) ivars->provider->unregisterInterrupt(ivars->intIndex);
1580 		ivars->provider->release();
1581 	}
1582 
1583 	if (ivars && ivars->lock) {
1584 		IOSimpleLockFree(ivars->lock);
1585 	}
1586 
1587 	IOFreeType(ivars, IOInterruptDispatchSource_IVars);
1588 
1589 	super::free();
1590 }
1591 
1592 kern_return_t
1593 IOInterruptDispatchSource::SetHandler_Impl(
1594 	OSAction * action)
1595 {
1596 	IOReturn ret;
1597 	OSAction * oldAction;
1598 
1599 	oldAction = (typeof(oldAction))ivars->action;
1600 	if (oldAction && OSCompareAndSwapPtr(oldAction, NULL, &ivars->action)) {
1601 		oldAction->release();
1602 	}
1603 	action->retain();
1604 	ivars->action = action;
1605 
1606 	ret = kIOReturnSuccess;
1607 
1608 	return ret;
1609 }
1610 
1611 kern_return_t
1612 IOInterruptDispatchSource::SetEnableWithCompletion_Impl(
1613 	bool enable,
1614 	IODispatchSourceCancelHandler handler)
1615 {
1616 	IOReturn ret;
1617 	IOInterruptState is;
1618 
1619 	if (enable == ivars->enable) {
1620 		return kIOReturnSuccess;
1621 	}
1622 
1623 	if (enable) {
1624 		is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1625 		ivars->enable = enable;
1626 		IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1627 		ret = ivars->provider->enableInterrupt(ivars->intIndex);
1628 	} else {
1629 		ret = ivars->provider->disableInterrupt(ivars->intIndex);
1630 		is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1631 		ivars->enable = enable;
1632 		IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1633 	}
1634 
1635 	return ret;
1636 }
1637 
1638 kern_return_t
1639 IOInterruptDispatchSource::Cancel_Impl(
1640 	IODispatchSourceCancelHandler handler)
1641 {
1642 	IOInterruptState is;
1643 	IOService * provider;
1644 
1645 	is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1646 	ivars->canceled = true;
1647 	if (ivars->waiter) {
1648 		thread_wakeup_thread((event_t) ivars, ivars->waiter);
1649 		ivars->waiter = NULL;
1650 	}
1651 	provider = ivars->provider;
1652 	if (provider) {
1653 		ivars->provider = NULL;
1654 	}
1655 	IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1656 
1657 	if (provider) {
1658 		(void) provider->unregisterInterrupt(ivars->intIndex);
1659 		provider->release();
1660 	}
1661 
1662 	return kIOReturnSuccess;
1663 }
1664 
1665 kern_return_t
1666 IOInterruptDispatchSource::CheckForWork_Impl(
1667 	const IORPC rpc,
1668 	bool synchronous)
1669 {
1670 	IOReturn         ret = kIOReturnNotReady;
1671 	IOInterruptState is;
1672 	bool             willWait;
1673 	bool             canceled;
1674 	wait_result_t    waitResult;
1675 	uint64_t         icount;
1676 	uint64_t         itime;
1677 	thread_t         self;
1678 
1679 	self = current_thread();
1680 	icount = 0;
1681 	do {
1682 		willWait = false;
1683 		is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1684 		canceled = ivars->canceled;
1685 		if (!canceled) {
1686 			if ((icount = ivars->count)) {
1687 				itime = ivars->time;
1688 				ivars->count = 0;
1689 				waitResult = THREAD_AWAKENED;
1690 			} else if (synchronous) {
1691 				assert(NULL == ivars->waiter);
1692 				ivars->waiter = self;
1693 				waitResult = assert_wait((event_t) ivars, THREAD_INTERRUPTIBLE);
1694 			}
1695 			willWait = (synchronous && (waitResult == THREAD_WAITING));
1696 			if (willWait && (kIOInterruptTypeLevel & ivars->interruptType) && ivars->enable) {
1697 				IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1698 				ivars->provider->enableInterrupt(ivars->intIndex);
1699 			} else {
1700 				IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1701 			}
1702 		} else {
1703 			IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1704 		}
1705 		if (willWait) {
1706 			waitResult = thread_block(THREAD_CONTINUE_NULL);
1707 			if (THREAD_INTERRUPTED == waitResult) {
1708 				is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1709 				ivars->waiter = NULL;
1710 				IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1711 				canceled = true;
1712 				break;
1713 			}
1714 		}
1715 	} while (synchronous && !icount && !canceled);
1716 
1717 	if (icount && ivars->action) {
1718 		ret = InterruptOccurred(rpc, ivars->action, icount, itime);
1719 	}
1720 
1721 	return ret;
1722 }
1723 
1724 void
1725 IOInterruptDispatchSource::InterruptOccurred_Impl(
1726 	OSAction * action,
1727 	uint64_t count,
1728 	uint64_t time)
1729 {
1730 }
1731 
1732 kern_return_t
1733 IOInterruptDispatchSource::GetLastInterrupt_Impl(
1734 	uint64_t  * pCount,
1735 	uint64_t  * pTime)
1736 {
1737 	IOInterruptState is;
1738 	uint64_t count, time;
1739 
1740 	is = IOSimpleLockLockDisableInterrupt(ivars->lock);
1741 	count = ivars->count;
1742 	time  = ivars->time;
1743 	IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
1744 
1745 	if (pCount) {
1746 		*pCount = count;
1747 	}
1748 	if (pTime) {
1749 		*pTime = time;
1750 	}
1751 	return kIOReturnSuccess;
1752 }
1753 
1754 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1755 
1756 enum {
1757 	kIOServiceNotificationTypeCount = kIOServiceNotificationTypeLast + 1,
1758 };
1759 
1760 struct IOServiceNotificationDispatchSource_IVars {
1761 	OSObject     * serverName;
1762 	OSAction     * action;
1763 	IOLock       * lock;
1764 	IONotifier   * notifier;
1765 	OSDictionary * interestNotifiers;
1766 	OSBoundedArray<OSArray *, kIOServiceNotificationTypeCount> pending;
1767 	bool           enable;
1768 };
1769 
1770 kern_return_t
1771 IOServiceNotificationDispatchSource::Create_Impl(
1772 	OSDictionary * matching,
1773 	uint64_t options,
1774 	IODispatchQueue * queue,
1775 	IOServiceNotificationDispatchSource ** notification)
1776 {
1777 	IOUserServer * us;
1778 	IOReturn       ret;
1779 	IOServiceNotificationDispatchSource * inst;
1780 
1781 	inst = OSTypeAlloc(IOServiceNotificationDispatchSource);
1782 	if (!inst->init()) {
1783 		OSSafeReleaseNULL(inst);
1784 		return kIOReturnNoMemory;
1785 	}
1786 
1787 	us = (typeof(us))thread_iokit_tls_get(0);
1788 	assert(OSDynamicCast(IOUserServer, us));
1789 	if (!us) {
1790 		OSSafeReleaseNULL(inst);
1791 		return kIOReturnError;
1792 	}
1793 	inst->ivars->serverName = us->copyProperty(gIOUserServerNameKey);
1794 	if (!inst->ivars->serverName) {
1795 		OSSafeReleaseNULL(inst);
1796 		return kIOReturnNoMemory;
1797 	}
1798 
1799 	inst->ivars->lock    = IOLockAlloc();
1800 	if (!inst->ivars->lock) {
1801 		OSSafeReleaseNULL(inst);
1802 		return kIOReturnNoMemory;
1803 	}
1804 	for (uint32_t idx = 0; idx < kIOServiceNotificationTypeCount; idx++) {
1805 		inst->ivars->pending[idx] = OSArray::withCapacity(4);
1806 		if (!inst->ivars->pending[idx]) {
1807 			OSSafeReleaseNULL(inst);
1808 			return kIOReturnNoMemory;
1809 		}
1810 	}
1811 	inst->ivars->interestNotifiers = OSDictionary::withCapacity(4);
1812 	if (!inst->ivars->interestNotifiers) {
1813 		OSSafeReleaseNULL(inst);
1814 		return kIOReturnNoMemory;
1815 	}
1816 
1817 	inst->ivars->notifier = IOService::addMatchingNotification(gIOMatchedNotification, matching, 0 /*priority*/,
1818 	    ^bool (IOService * newService, IONotifier * notifier) {
1819 		bool         notifyReady = false;
1820 		IONotifier * interest;
1821 		OSObject   * serverName;
1822 		bool         okToUse;
1823 
1824 		serverName = newService->copyProperty(gIOUserServerNameKey);
1825 		okToUse = (serverName && inst->ivars->serverName->isEqualTo(serverName));
1826 		OSSafeReleaseNULL(serverName);
1827 		if (!okToUse) {
1828 		        OSObject * prop;
1829 		        OSObject * str;
1830 
1831 		        if (!newService->reserved->uvars || !newService->reserved->uvars->userServer) {
1832 		                return false;
1833 			}
1834 		        str = OSString::withCStringNoCopy(kIODriverKitAllowsPublishEntitlementsKey);
1835 		        if (!str) {
1836 		                return false;
1837 			}
1838 		        okToUse = newService->reserved->uvars->userServer->checkEntitlements(str, NULL, NULL);
1839 		        if (!okToUse) {
1840 		                if (kIODKLogSetup & gIODKDebug) {
1841 		                        DKLOG(DKS ": publisher entitlements check failed\n", DKN(newService));
1842 				}
1843 		                return false;
1844 			}
1845 		        prop = newService->copyProperty(kIODriverKitPublishEntitlementsKey);
1846 		        if (!prop) {
1847 		                return false;
1848 			}
1849 		        okToUse = us->checkEntitlements(prop, NULL, NULL);
1850 		        if (!okToUse) {
1851 		                if (kIODKLogSetup & gIODKDebug) {
1852 		                        DKLOG(DKS ": subscriber entitlements check failed\n", DKN(newService));
1853 				}
1854 		                return false;
1855 			}
1856 		}
1857 
1858 		IOLockLock(inst->ivars->lock);
1859 		notifyReady = (0 == inst->ivars->pending[kIOServiceNotificationTypeMatched]->getCount());
1860 		inst->ivars->pending[kIOServiceNotificationTypeMatched]->setObject(newService);
1861 		IOLockUnlock(inst->ivars->lock);
1862 
1863 		interest = newService->registerInterest(gIOGeneralInterest,
1864 		^IOReturn (uint32_t messageType, IOService * provider,
1865 		void * messageArgument, size_t argSize) {
1866 			IONotifier * interest;
1867 			bool         notifyReady = false;
1868 
1869 			switch (messageType) {
1870 			case kIOMessageServiceIsTerminated:
1871 				IOLockLock(inst->ivars->lock);
1872 				notifyReady = (0 == inst->ivars->pending[kIOServiceNotificationTypeTerminated]->getCount());
1873 				inst->ivars->pending[kIOServiceNotificationTypeTerminated]->setObject(provider);
1874 				if (inst->ivars->interestNotifiers != NULL) {
1875 				        interest = (typeof(interest))inst->ivars->interestNotifiers->getObject((const OSSymbol *) newService);
1876 				        assert(interest);
1877 				        interest->remove();
1878 				        inst->ivars->interestNotifiers->removeObject((const OSSymbol *) newService);
1879 				}
1880 				IOLockUnlock(inst->ivars->lock);
1881 				break;
1882 			default:
1883 				break;
1884 			}
1885 			if (notifyReady && inst->ivars->action) {
1886 			        inst->ServiceNotificationReady(inst->ivars->action);
1887 			}
1888 			return kIOReturnSuccess;
1889 		});
1890 		if (interest) {
1891 		        IOLockLock(inst->ivars->lock);
1892 		        inst->ivars->interestNotifiers->setObject((const OSSymbol *) newService, interest);
1893 		        IOLockUnlock(inst->ivars->lock);
1894 		}
1895 		if (notifyReady) {
1896 		        if (inst->ivars->action) {
1897 		                inst->ServiceNotificationReady(inst->ivars->action);
1898 			}
1899 		}
1900 		return false;
1901 	});
1902 
1903 	if (!inst->ivars->notifier) {
1904 		OSSafeReleaseNULL(inst);
1905 		ret = kIOReturnError;
1906 	}
1907 
1908 	*notification = inst;
1909 	ret = kIOReturnSuccess;
1910 
1911 	return ret;
1912 }
1913 
1914 kern_return_t
1915 IOServiceNotificationDispatchSource::CopyNextNotification_Impl(
1916 	uint64_t * type,
1917 	IOService ** service,
1918 	uint64_t * options)
1919 {
1920 	IOService * next;
1921 	uint32_t    idx;
1922 
1923 	IOLockLock(ivars->lock);
1924 	for (idx = 0; idx < kIOServiceNotificationTypeCount; idx++) {
1925 		next = (IOService *) ivars->pending[idx]->getObject(0);
1926 		if (next) {
1927 			next->retain();
1928 			ivars->pending[idx]->removeObject(0);
1929 			break;
1930 		}
1931 	}
1932 	IOLockUnlock(ivars->lock);
1933 
1934 	if (idx == kIOServiceNotificationTypeCount) {
1935 		idx = kIOServiceNotificationTypeNone;
1936 	}
1937 	*type    = idx;
1938 	*service = next;
1939 	*options = 0;
1940 
1941 	return kIOReturnSuccess;
1942 }
1943 
1944 bool
1945 IOServiceNotificationDispatchSource::init()
1946 {
1947 	if (!super::init()) {
1948 		return false;
1949 	}
1950 	ivars = IOMallocType(IOServiceNotificationDispatchSource_IVars);
1951 
1952 	return true;
1953 }
1954 
1955 void
1956 IOServiceNotificationDispatchSource::free()
1957 {
1958 	if (ivars) {
1959 		if (ivars->notifier) {
1960 			ivars->notifier->remove();
1961 			ivars->notifier = NULL;
1962 		}
1963 		if (ivars->interestNotifiers) {
1964 			OSDictionary * savedInterestNotifiers = NULL;
1965 
1966 			// the lock is always initialized first, so it should exist
1967 			assert(ivars->lock);
1968 
1969 			// Prevent additional changes to interestNotifiers
1970 			IOLockLock(ivars->lock);
1971 			savedInterestNotifiers = ivars->interestNotifiers;
1972 			ivars->interestNotifiers = NULL;
1973 			IOLockUnlock(ivars->lock);
1974 
1975 			// Remove all interest notifiers
1976 			savedInterestNotifiers->iterateObjects(^bool (const OSSymbol * key, OSObject * object) {
1977 				IONotifier * interest = (typeof(interest))object;
1978 				interest->remove();
1979 				return false;
1980 			});
1981 			OSSafeReleaseNULL(savedInterestNotifiers);
1982 		}
1983 		for (uint32_t idx = 0; idx < kIOServiceNotificationTypeCount; idx++) {
1984 			OSSafeReleaseNULL(ivars->pending[idx]);
1985 		}
1986 		if (ivars->lock) {
1987 			IOLockFree(ivars->lock);
1988 			ivars->lock = NULL;
1989 		}
1990 		OSSafeReleaseNULL(ivars->serverName);
1991 		IOFreeType(ivars, IOServiceNotificationDispatchSource_IVars);
1992 	}
1993 
1994 	super::free();
1995 }
1996 
1997 kern_return_t
1998 IOServiceNotificationDispatchSource::SetHandler_Impl(
1999 	OSAction * action)
2000 {
2001 	IOReturn ret;
2002 	bool     notifyReady;
2003 
2004 	notifyReady = false;
2005 
2006 	IOLockLock(ivars->lock);
2007 	OSSafeReleaseNULL(ivars->action);
2008 	action->retain();
2009 	ivars->action = action;
2010 	if (action) {
2011 		for (uint32_t idx = 0; idx < kIOServiceNotificationTypeCount; idx++) {
2012 			notifyReady = (ivars->pending[idx]->getCount());
2013 			if (notifyReady) {
2014 				break;
2015 			}
2016 		}
2017 	}
2018 	IOLockUnlock(ivars->lock);
2019 
2020 	if (notifyReady) {
2021 		ServiceNotificationReady(action);
2022 	}
2023 	ret = kIOReturnSuccess;
2024 
2025 	return ret;
2026 }
2027 
2028 kern_return_t
2029 IOServiceNotificationDispatchSource::SetEnableWithCompletion_Impl(
2030 	bool enable,
2031 	IODispatchSourceCancelHandler handler)
2032 {
2033 	if (enable == ivars->enable) {
2034 		return kIOReturnSuccess;
2035 	}
2036 
2037 	IOLockLock(ivars->lock);
2038 	ivars->enable = enable;
2039 	IOLockUnlock(ivars->lock);
2040 
2041 	return kIOReturnSuccess;
2042 }
2043 
2044 kern_return_t
2045 IOServiceNotificationDispatchSource::Cancel_Impl(
2046 	IODispatchSourceCancelHandler handler)
2047 {
2048 	return kIOReturnUnsupported;
2049 }
2050 
2051 kern_return_t
2052 IOServiceNotificationDispatchSource::CheckForWork_Impl(
2053 	const IORPC rpc,
2054 	bool synchronous)
2055 {
2056 	return kIOReturnNotReady;
2057 }
2058 
2059 kern_return_t
2060 IOServiceNotificationDispatchSource::DeliverNotifications(IOServiceNotificationBlock block)
2061 {
2062 	return kIOReturnUnsupported;
2063 }
2064 
2065 
2066 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2067 
2068 OSDictionary *
2069 IOService::CreatePropertyMatchingDictionary(const char * key, OSObjectPtr value, OSDictionary * matching)
2070 {
2071 	OSDictionary   * result;
2072 	const OSSymbol * keySym;
2073 
2074 	keySym = OSSymbol::withCString(key);
2075 	result = propertyMatching(keySym, (const OSObject *) value, matching);
2076 	OSSafeReleaseNULL(keySym);
2077 
2078 	return result;
2079 }
2080 
2081 OSDictionary *
2082 IOService::CreatePropertyMatchingDictionary(const char * key, const char * stringValue, OSDictionary * matching)
2083 {
2084 	OSDictionary * result;
2085 	OSString     * value;
2086 
2087 	value = OSString::withCString(stringValue);
2088 	result = CreatePropertyMatchingDictionary(key, value, matching);
2089 	OSSafeReleaseNULL(value);
2090 
2091 	return result;
2092 }
2093 
2094 OSDictionary *
2095 IOService::CreateKernelClassMatchingDictionary(OSString * className, OSDictionary * matching)
2096 {
2097 	if (!className) {
2098 		return NULL;
2099 	}
2100 	if (!matching) {
2101 		matching = OSDictionary::withCapacity(2);
2102 		if (!matching) {
2103 			return NULL;
2104 		}
2105 	}
2106 	matching->setObject(kIOProviderClassKey, className);
2107 
2108 	return matching;
2109 }
2110 
2111 OSDictionary *
2112 IOService::CreateKernelClassMatchingDictionary(const char * className, OSDictionary * matching)
2113 {
2114 	OSDictionary * result;
2115 	OSString     * string;
2116 
2117 	string = OSString::withCString(className);
2118 	result = CreateKernelClassMatchingDictionary(string, matching);
2119 	OSSafeReleaseNULL(string);
2120 
2121 	return result;
2122 }
2123 
2124 OSDictionary *
2125 IOService::CreateUserClassMatchingDictionary(OSString * className, OSDictionary * matching)
2126 {
2127 	return CreatePropertyMatchingDictionary(kIOUserClassKey, className, matching);
2128 }
2129 
2130 OSDictionary *
2131 IOService::CreateUserClassMatchingDictionary(const char * className, OSDictionary * matching)
2132 {
2133 	return CreatePropertyMatchingDictionary(kIOUserClassKey, className, matching);
2134 }
2135 
2136 OSDictionary *
2137 IOService::CreateNameMatchingDictionary(OSString * serviceName, OSDictionary * matching)
2138 {
2139 	if (!serviceName) {
2140 		return NULL;
2141 	}
2142 	if (!matching) {
2143 		matching = OSDictionary::withCapacity(2);
2144 		if (!matching) {
2145 			return NULL;
2146 		}
2147 	}
2148 	matching->setObject(kIONameMatchKey, serviceName);
2149 
2150 	return matching;
2151 }
2152 
2153 OSDictionary *
2154 IOService::CreateNameMatchingDictionary(const char * serviceName, OSDictionary * matching)
2155 {
2156 	OSDictionary * result;
2157 	OSString     * string;
2158 
2159 	string = OSString::withCString(serviceName);
2160 	result = CreateNameMatchingDictionary(string, matching);
2161 	OSSafeReleaseNULL(string);
2162 
2163 	return result;
2164 }
2165 
2166 
2167 
2168 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2169 
2170 kern_return_t
2171 IOUserServer::waitInterruptTrap(void * p1, void * p2, void * p3, void * p4, void * p5, void * p6)
2172 {
2173 	IOReturn         ret = kIOReturnBadArgument;
2174 	IOInterruptState is;
2175 	IOInterruptDispatchSource * interrupt;
2176 	IOInterruptDispatchSource_IVars * ivars;
2177 	IOInterruptDispatchSourcePayload payload;
2178 
2179 	bool             willWait;
2180 	bool             canceled;
2181 	wait_result_t    waitResult;
2182 	thread_t         self;
2183 
2184 	OSObject * object;
2185 
2186 	object = iokit_lookup_object_with_port_name((mach_port_name_t)(uintptr_t)p1, IKOT_UEXT_OBJECT, current_task());
2187 
2188 	if (!object) {
2189 		return kIOReturnBadArgument;
2190 	}
2191 	if (!(interrupt = OSDynamicCast(IOInterruptDispatchSource, object))) {
2192 		ret = kIOReturnBadArgument;
2193 	} else {
2194 		self = current_thread();
2195 		ivars = interrupt->ivars;
2196 		payload.count = 0;
2197 		do {
2198 			willWait = false;
2199 			is = IOSimpleLockLockDisableInterrupt(ivars->lock);
2200 			canceled = ivars->canceled;
2201 			if (!canceled) {
2202 				if ((payload.count = ivars->count)) {
2203 					payload.time = ivars->time;
2204 					ivars->count = 0;
2205 					waitResult = THREAD_AWAKENED;
2206 				} else {
2207 					assert(NULL == ivars->waiter);
2208 					ivars->waiter = self;
2209 					waitResult = assert_wait((event_t) ivars, THREAD_INTERRUPTIBLE);
2210 				}
2211 				willWait = (waitResult == THREAD_WAITING);
2212 				if (willWait && (kIOInterruptTypeLevel & ivars->interruptType) && ivars->enable) {
2213 					IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
2214 					ivars->provider->enableInterrupt(ivars->intIndex);
2215 				} else {
2216 					IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
2217 				}
2218 			} else {
2219 				IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
2220 			}
2221 			if (willWait) {
2222 				waitResult = thread_block(THREAD_CONTINUE_NULL);
2223 				if (THREAD_INTERRUPTED == waitResult) {
2224 					is = IOSimpleLockLockDisableInterrupt(ivars->lock);
2225 					ivars->waiter = NULL;
2226 					IOSimpleLockUnlockEnableInterrupt(ivars->lock, is);
2227 					canceled = true;
2228 					break;
2229 				}
2230 			}
2231 		} while (!payload.count && !canceled);
2232 		ret = (payload.count ? kIOReturnSuccess : kIOReturnAborted);
2233 	}
2234 
2235 	if (kIOReturnSuccess == ret) {
2236 		int copyerr = copyout(&payload, (user_addr_t) p2, sizeof(payload));
2237 		if (copyerr) {
2238 			ret = kIOReturnVMError;
2239 		}
2240 	}
2241 
2242 	object->release();
2243 
2244 	return ret;
2245 }
2246 
2247 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2248 
2249 kern_return_t
2250 IOUserServer::Create_Impl(
2251 	const char * name,
2252 	uint64_t tag,
2253 	uint64_t options,
2254 	OSString * bundleID,
2255 	IOUserServer ** server)
2256 {
2257 	IOReturn          ret;
2258 	IOUserServer    * us;
2259 	const OSSymbol  * sym;
2260 	OSNumber        * serverTag;
2261 	io_name_t         rname;
2262 	OSKext          * kext;
2263 
2264 	us = (typeof(us))thread_iokit_tls_get(0);
2265 	assert(OSDynamicCast(IOUserServer, us));
2266 	if (kIODKLogSetup & gIODKDebug) {
2267 		DKLOG(DKS "::Create(" DKS ") %p\n", DKN(us), name, tag, us);
2268 	}
2269 	if (!us) {
2270 		return kIOReturnError;
2271 	}
2272 
2273 	if (bundleID) {
2274 		kext = OSKext::lookupKextWithIdentifier(bundleID->getCStringNoCopy());
2275 		if (kext) {
2276 			us->setTaskLoadTag(kext);
2277 			us->setDriverKitUUID(kext);
2278 			us->setDriverKitStatistics(kext);
2279 			OSKext::OSKextLogDriverKitInfoLoad(kext);
2280 			OSSafeReleaseNULL(kext);
2281 		} else {
2282 			DKLOG(DKS "::Create(" DKS "): could not find OSKext for %s\n", DKN(us), name, tag, bundleID->getCStringNoCopy());
2283 		}
2284 
2285 		us->fAllocationName = kern_allocation_name_allocate(bundleID->getCStringNoCopy(), 0);
2286 		assert(us->fAllocationName);
2287 	}
2288 
2289 	sym       = OSSymbol::withCString(name);
2290 	serverTag = OSNumber::withNumber(tag, 64);
2291 
2292 	us->setProperty(gIOUserServerNameKey, (OSObject *) sym);
2293 	us->setProperty(gIOUserServerTagKey, serverTag);
2294 
2295 	serverTag->release();
2296 	OSSafeReleaseNULL(sym);
2297 
2298 	snprintf(rname, sizeof(rname), "IOUserServer(%s-0x%qx)", name, tag);
2299 	us->setName(rname);
2300 
2301 	us->retain();
2302 	*server = us;
2303 	ret = kIOReturnSuccess;
2304 
2305 	return ret;
2306 }
2307 
2308 kern_return_t
2309 IOUserServer::RegisterService_Impl()
2310 {
2311 	kern_return_t ret = IOService::RegisterService_Impl();
2312 
2313 	return ret;
2314 }
2315 
2316 kern_return_t
2317 IOUserServer::Exit_Impl(
2318 	const char * reason)
2319 {
2320 	return kIOReturnUnsupported;
2321 }
2322 
2323 kern_return_t
2324 IOUserServer::LoadModule_Impl(
2325 	const char * path)
2326 {
2327 	return kIOReturnUnsupported;
2328 }
2329 
2330 
2331 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2332 
2333 kern_return_t
2334 IODispatchQueue::Create_Impl(
2335 	const char * name,
2336 	uint64_t options,
2337 	uint64_t priority,
2338 	IODispatchQueue ** queue)
2339 {
2340 	IODispatchQueue * result;
2341 	IOUserServer    * us;
2342 
2343 	result = OSTypeAlloc(IODispatchQueue);
2344 	if (!result) {
2345 		return kIOReturnNoMemory;
2346 	}
2347 	if (!result->init()) {
2348 		OSSafeReleaseNULL(result);
2349 		return kIOReturnNoMemory;
2350 	}
2351 
2352 	*queue = result;
2353 
2354 	if (!strcmp("Root", name)) {
2355 		us = (typeof(us))thread_iokit_tls_get(0);
2356 		assert(OSDynamicCast(IOUserServer, us));
2357 		us->setRootQueue(result);
2358 	}
2359 
2360 	if (kIODKLogSetup & gIODKDebug) {
2361 		DKLOG("IODispatchQueue::Create %s %p\n", name, result);
2362 	}
2363 
2364 	return kIOReturnSuccess;
2365 }
2366 
2367 kern_return_t
2368 IODispatchQueue::SetPort_Impl(
2369 	mach_port_t port)
2370 {
2371 	if (MACH_PORT_NULL != ivars->serverPort) {
2372 		return kIOReturnNotReady;
2373 	}
2374 	ivars->serverPort = ipc_port_copy_send_mqueue(port);
2375 	if (ivars->serverPort == MACH_PORT_NULL) {
2376 		return kIOReturnBadArgument;
2377 	}
2378 	return kIOReturnSuccess;
2379 }
2380 
2381 bool
2382 IODispatchQueue::init()
2383 {
2384 	ivars = IOMallocType(IODispatchQueue_IVars);
2385 	ivars->queue = this;
2386 
2387 	return true;
2388 }
2389 
2390 void
2391 IODispatchQueue::free()
2392 {
2393 	if (ivars && ivars->serverPort) {
2394 		ipc_port_release_send(ivars->serverPort);
2395 		ivars->serverPort = MACH_PORT_NULL;
2396 	}
2397 	IOFreeType(ivars, IODispatchQueue_IVars);
2398 	super::free();
2399 }
2400 
2401 bool
2402 IODispatchQueue::OnQueue()
2403 {
2404 	return false;
2405 }
2406 
2407 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2408 
2409 
2410 kern_return_t
2411 OSMetaClassBase::Dispatch(IORPC rpc)
2412 {
2413 	return kIOReturnUnsupported;
2414 }
2415 
2416 kern_return_t
2417 OSMetaClassBase::Invoke(IORPC rpc)
2418 {
2419 	IOReturn          ret = kIOReturnUnsupported;
2420 	OSMetaClassBase * object;
2421 	OSAction        * action;
2422 	IOService       * service;
2423 	IOUserServer    * us;
2424 	IORPCMessage    * message;
2425 
2426 	assert(rpc.sendSize >= (sizeof(IORPCMessageMach) + sizeof(IORPCMessage)));
2427 	message = rpc.kernelContent;
2428 	if (!message) {
2429 		return kIOReturnIPCError;
2430 	}
2431 	message->flags |= kIORPCMessageKernel;
2432 
2433 	us = NULL;
2434 	if (!(kIORPCMessageLocalHost & message->flags)) {
2435 		us = OSDynamicCast(IOUserServer, this);
2436 		if (!us) {
2437 			IOEventLink * eventLink = NULL;
2438 			IOWorkGroup * workgroup = NULL;
2439 
2440 			if ((action = OSDynamicCast(OSAction, this))) {
2441 				object = IOUserServer::target(action, message);
2442 			} else {
2443 				object = this;
2444 			}
2445 			if ((service = OSDynamicCast(IOService, object))
2446 			    && service->reserved->uvars) {
2447 				// xxx other classes
2448 				us = service->reserved->uvars->userServer;
2449 			} else if (action) {
2450 				us = action->ivars->userServer;
2451 			} else if ((eventLink = OSDynamicCast(IOEventLink, object))) {
2452 				us = eventLink->ivars->userServer;
2453 			} else if ((workgroup = OSDynamicCast(IOWorkGroup, object))) {
2454 				us = workgroup->ivars->userServer;
2455 			}
2456 		}
2457 	}
2458 	if (us) {
2459 		message->flags |= kIORPCMessageRemote;
2460 		ret = us->rpc(rpc);
2461 		if (kIOReturnSuccess != ret) {
2462 			if (kIODKLogIPC & gIODKDebug) {
2463 				DKLOG("OSMetaClassBase::Invoke user 0x%x\n", ret);
2464 			}
2465 		}
2466 	} else {
2467 		if (kIODKLogIPC & gIODKDebug) {
2468 			DKLOG("OSMetaClassBase::Invoke kernel %s 0x%qx\n", getMetaClass()->getClassName(), message->msgid);
2469 		}
2470 		void * prior = thread_iokit_tls_get(0);
2471 		thread_iokit_tls_set(0, NULL);
2472 		ret = Dispatch(rpc);
2473 		thread_iokit_tls_set(0, prior);
2474 	}
2475 
2476 	return ret;
2477 }
2478 
2479 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2480 
2481 struct IOPStrings {
2482 	uint32_t     dataSize;
2483 	uint32_t     count;
2484 	const char   strings[0];
2485 };
2486 
2487 kern_return_t
2488 OSUserMetaClass::Dispatch(IORPC rpc)
2489 {
2490 	if (meta) {
2491 		return const_cast<OSMetaClass *>(meta)->Dispatch(rpc);
2492 	} else {
2493 		return kIOReturnUnsupported;
2494 	}
2495 }
2496 
2497 void
2498 OSUserMetaClass::free()
2499 {
2500 	if (queueNames) {
2501 		IOFreeData(queueNames, sizeof(IOPStrings) + queueNames->dataSize * sizeof(char));
2502 		queueNames = NULL;
2503 	}
2504 	if (description) {
2505 		IOFreeData(description, description->descriptionSize);
2506 		description = NULL;
2507 	}
2508 	IODeleteData(methods, uint64_t, 2 * methodCount);
2509 	if (meta) {
2510 		meta->releaseMetaClass();
2511 	}
2512 	if (name) {
2513 		name->release();
2514 	}
2515 	OSObject::free();
2516 }
2517 
2518 /*
2519  * Sets the loadTag of the associated OSKext
2520  * in the dext task.
2521  * NOTE: different instances of the same OSKext
2522  * (so same BounleID but different tasks)
2523  * will have the same loadTag.
2524  */
2525 void
2526 IOUserServer::setTaskLoadTag(OSKext *kext)
2527 {
2528 	task_t owningTask;
2529 	uint32_t loadTag, prev_taskloadTag;
2530 
2531 	owningTask = this->fOwningTask;
2532 	if (!owningTask) {
2533 		printf("%s: fOwningTask not found\n", __FUNCTION__);
2534 		return;
2535 	}
2536 
2537 	loadTag = kext->getLoadTag();
2538 	prev_taskloadTag = set_task_loadTag(owningTask, loadTag);
2539 	if (prev_taskloadTag) {
2540 		printf("%s: found the task loadTag already set to %u (set to %u)\n",
2541 		    __FUNCTION__, prev_taskloadTag, loadTag);
2542 	}
2543 }
2544 
2545 /*
2546  * Sets the OSKext uuid as the uuid of the userspace
2547  * dext executable.
2548  */
2549 void
2550 IOUserServer::setDriverKitUUID(OSKext *kext)
2551 {
2552 	task_t task;
2553 	proc_t p;
2554 	uuid_t p_uuid, k_uuid;
2555 	OSData *k_data_uuid;
2556 	OSData *new_uuid;
2557 	uuid_string_t       uuid_string = "";
2558 
2559 	task = this->fOwningTask;
2560 	if (!task) {
2561 		printf("%s: fOwningTask not found\n", __FUNCTION__);
2562 		return;
2563 	}
2564 
2565 	p = (proc_t)(get_bsdtask_info(task));
2566 	if (!p) {
2567 		printf("%s: proc not found\n", __FUNCTION__);
2568 		return;
2569 	}
2570 	proc_getexecutableuuid(p, p_uuid, sizeof(p_uuid));
2571 
2572 	k_data_uuid = kext->copyUUID();
2573 	if (k_data_uuid) {
2574 		memcpy(&k_uuid, k_data_uuid->getBytesNoCopy(), sizeof(k_uuid));
2575 		OSSafeReleaseNULL(k_data_uuid);
2576 		if (uuid_compare(k_uuid, p_uuid) != 0) {
2577 			printf("%s: uuid not matching\n", __FUNCTION__);
2578 		}
2579 		return;
2580 	}
2581 
2582 	uuid_unparse(p_uuid, uuid_string);
2583 	new_uuid = OSData::withValue(p_uuid);
2584 	kext->setDriverKitUUID(new_uuid);
2585 }
2586 
2587 void
2588 IOUserServer::setDriverKitStatistics(OSKext *kext)
2589 {
2590 	OSDextStatistics * statistics = kext->copyDextStatistics();
2591 	if (statistics == NULL) {
2592 		panic("Kext %s was not a DriverKit OSKext", kext->getIdentifierCString());
2593 	}
2594 	fStatistics = statistics;
2595 }
2596 
2597 IOReturn
2598 IOUserServer::setCheckInToken(IOUserServerCheckInToken *token)
2599 {
2600 	IOReturn ret = kIOReturnError;
2601 	if (token != NULL && fCheckInToken == NULL) {
2602 		token->retain();
2603 		fCheckInToken = token;
2604 		ret = fCheckInToken->complete();
2605 		iokit_clear_registered_ports(fOwningTask);
2606 	} else {
2607 		printf("%s: failed to set check in token. token=%p, fCheckInToken=%p\n", __FUNCTION__, token, fCheckInToken);
2608 	}
2609 	return ret;
2610 }
2611 
2612 bool
2613 IOUserServer::serviceMatchesCheckInToken(IOUserServerCheckInToken *token)
2614 {
2615 	if (token != NULL) {
2616 		bool result = token == fCheckInToken;
2617 		return result;
2618 	} else {
2619 		printf("%s: null check in token\n", __FUNCTION__);
2620 		return false;
2621 	}
2622 }
2623 
2624 // entitlements - dict of entitlements to check
2625 // prop - string - if present return true
2626 //      - array of strings - if any present return true
2627 //      - array of arrays of strings - in each leaf array all must be present
2628 //                                   - if any top level array succeeds return true
2629 // consumes one reference of prop
2630 bool
2631 IOUserServer::checkEntitlements(
2632 	OSDictionary * entitlements, OSObject * prop,
2633 	IOService * provider, IOService * dext)
2634 {
2635 	OSDictionary * matching;
2636 
2637 	if (!prop) {
2638 		return true;
2639 	}
2640 	if (!entitlements) {
2641 		OSSafeReleaseNULL(prop);
2642 		return false;
2643 	}
2644 
2645 	matching = NULL;
2646 	if (dext) {
2647 		matching = dext->dictionaryWithProperties();
2648 		if (!matching) {
2649 			OSSafeReleaseNULL(prop);
2650 			return false;
2651 		}
2652 	}
2653 
2654 	bool allPresent __block = false;
2655 	prop->iterateObjects(^bool (OSObject * object) {
2656 		allPresent = false;
2657 		object->iterateObjects(^bool (OSObject * object) {
2658 			OSString * string;
2659 			OSObject * value;
2660 			string = OSDynamicCast(OSString, object);
2661 			value = entitlements->getObject(string);
2662 			if (matching && value) {
2663 			        matching->setObject(string, value);
2664 			}
2665 			allPresent = (NULL != value);
2666 			// early terminate if not found
2667 			return !allPresent;
2668 		});
2669 		// early terminate if found
2670 		return allPresent;
2671 	});
2672 
2673 	if (allPresent && matching && provider) {
2674 		allPresent = provider->matchPropertyTable(matching);
2675 	}
2676 
2677 	OSSafeReleaseNULL(matching);
2678 	OSSafeReleaseNULL(prop);
2679 
2680 	return allPresent;
2681 }
2682 
2683 bool
2684 IOUserServer::checkEntitlements(OSObject * prop, IOService * provider, IOService * dext)
2685 {
2686 	return checkEntitlements(fEntitlements, prop, provider, dext);
2687 }
2688 
2689 bool
2690 IOUserServer::checkEntitlements(IOService * provider, IOService * dext)
2691 {
2692 	OSObject     * prop;
2693 	bool           ok;
2694 
2695 	if (!fOwningTask) {
2696 		return false;
2697 	}
2698 
2699 	prop = provider->copyProperty(gIOServiceDEXTEntitlementsKey);
2700 	ok = checkEntitlements(fEntitlements, prop, provider, dext);
2701 	if (!ok) {
2702 		DKLOG(DKS ": provider entitlements check failed\n", DKN(dext));
2703 	}
2704 	if (ok) {
2705 		prop = dext->copyProperty(gIOServiceDEXTEntitlementsKey);
2706 		ok = checkEntitlements(fEntitlements, prop, NULL, NULL);
2707 		if (!ok) {
2708 			DKLOG(DKS ": family entitlements check failed\n", DKN(dext));
2709 		}
2710 	}
2711 
2712 	return ok;
2713 }
2714 
2715 IOReturn
2716 IOUserServer::exit(const char * reason)
2717 {
2718 	DKLOG("%s::exit(%s)\n", getName(), reason);
2719 	Exit(reason);
2720 	return kIOReturnSuccess;
2721 }
2722 
2723 IOReturn
2724 IOUserServer::kill(const char * reason)
2725 {
2726 	IOReturn ret = kIOReturnError;
2727 	if (fOwningTask != NULL) {
2728 		DKLOG("%s::kill(%s)\n", getName(), reason);
2729 		task_bsdtask_kill(fOwningTask);
2730 		ret = kIOReturnSuccess;
2731 	}
2732 	return ret;
2733 }
2734 
2735 OSObjectUserVars *
2736 IOUserServer::varsForObject(OSObject * obj)
2737 {
2738 	IOService * service;
2739 
2740 	if ((service = OSDynamicCast(IOService, obj))) {
2741 		return service->reserved->uvars;
2742 	}
2743 
2744 	return NULL;
2745 }
2746 
2747 IOPStrings *
2748 IOUserServer::copyInStringArray(const char * string, uint32_t userSize)
2749 {
2750 	IOPStrings * array;
2751 	vm_size_t    alloc;
2752 	size_t       len;
2753 	const char * end;
2754 	OSBoundedPtr<const char> cstr;
2755 
2756 	if (userSize <= 1) {
2757 		return NULL;
2758 	}
2759 
2760 	if (os_add_overflow(sizeof(IOPStrings), userSize, &alloc)) {
2761 		assert(false);
2762 		return NULL;
2763 	}
2764 	if (alloc > 16384) {
2765 		assert(false);
2766 		return NULL;
2767 	}
2768 	array = (typeof(array))IOMallocData(alloc);
2769 	if (!array) {
2770 		return NULL;
2771 	}
2772 	array->dataSize = userSize;
2773 	bcopy(string, (void *) &array->strings[0], userSize);
2774 
2775 	array->count = 0;
2776 	end =  &array->strings[array->dataSize];
2777 	cstr = OSBoundedPtr<const char>(&array->strings[0], &array->strings[0], end);
2778 	while ((len = (unsigned char)cstr[0])) {
2779 		cstr++;
2780 		if ((cstr + len) >= end) {
2781 			break;
2782 		}
2783 		cstr += len;
2784 		array->count++;
2785 	}
2786 	if (len) {
2787 		IOFreeData(array, alloc);
2788 		array = NULL;
2789 	}
2790 
2791 	return array;
2792 }
2793 
2794 uint32_t
2795 IOUserServer::stringArrayIndex(IOPStrings * array, const char * look)
2796 {
2797 	uint32_t     idx;
2798 	size_t       len, llen;
2799 	OSBoundedPtr<const char> cstr;
2800 	const char * end;
2801 
2802 	idx  = 0;
2803 	end  =  &array->strings[array->dataSize];
2804 	cstr = OSBoundedPtr<const char>(&array->strings[0], &array->strings[0], end);
2805 
2806 	llen = strlen(look);
2807 	while ((len = (unsigned char)cstr[0])) {
2808 		cstr++;
2809 		if ((cstr + len) >= end) {
2810 			break;
2811 		}
2812 		if ((len == llen) && !strncmp(cstr.discard_bounds(), look, len)) {
2813 			return idx;
2814 		}
2815 		cstr += len;
2816 		idx++;
2817 	}
2818 
2819 	return -1U;
2820 }
2821 #define kIODispatchQueueStopped ((IODispatchQueue *) -1L)
2822 
2823 IODispatchQueue *
2824 IOUserServer::queueForObject(OSObject * obj, uint64_t msgid)
2825 {
2826 	IODispatchQueue  * queue;
2827 	OSObjectUserVars * uvars;
2828 	uint64_t           option;
2829 
2830 	uvars = varsForObject(obj);
2831 	if (!uvars) {
2832 		return NULL;
2833 	}
2834 	if (!uvars->queueArray) {
2835 		if (uvars->stopped) {
2836 			return kIODispatchQueueStopped;
2837 		}
2838 		return NULL;
2839 	}
2840 	queue = uvars->queueArray[0];
2841 
2842 	if (uvars->userMeta
2843 	    && uvars->userMeta->methods) {
2844 		uint32_t idx, baseIdx;
2845 		uint32_t lim;
2846 		// bsearch
2847 		for (baseIdx = 0, lim = uvars->userMeta->methodCount; lim; lim >>= 1) {
2848 			idx = baseIdx + (lim >> 1);
2849 			if (msgid == uvars->userMeta->methods[idx]) {
2850 				option = uvars->userMeta->methods[uvars->userMeta->methodCount + idx];
2851 				option &= 0xFF;
2852 				if (option < uvars->userMeta->queueNames->count) {
2853 					queue = uvars->queueArray[option + 1];
2854 				}
2855 				break;
2856 			} else if (msgid > uvars->userMeta->methods[idx]) {
2857 				// move right
2858 				baseIdx += (lim >> 1) + 1;
2859 				lim--;
2860 			}
2861 			// else move left
2862 		}
2863 	}
2864 	return queue;
2865 }
2866 
2867 IOReturn
2868 IOUserServer::objectInstantiate(OSObject * obj, IORPC rpc, IORPCMessage * message)
2869 {
2870 	IOReturn         ret;
2871 	OSString       * str;
2872 	OSObject       * prop;
2873 	IOService      * service;
2874 
2875 	OSAction       * action;
2876 	OSObject       * target;
2877 	uint32_t         queueCount, queueAlloc;
2878 	const char     * resultClassName;
2879 	uint64_t         resultFlags;
2880 
2881 	mach_msg_size_t    replySize;
2882 	uint32_t           methodCount;
2883 	const uint64_t   * methods;
2884 	IODispatchQueue  * queue;
2885 	OSUserMetaClass  * userMeta;
2886 	OSObjectUserVars * uvars;
2887 	uint32_t           idx;
2888 	ipc_port_t         sendPort;
2889 	bool               serviceInactive;
2890 
2891 	OSObject_Instantiate_Rpl_Content * reply;
2892 	IODispatchQueue ** unboundedQueueArray = NULL;
2893 	queueCount      = 0;
2894 	methodCount     = 0;
2895 	methods         = NULL;
2896 	str             = NULL;
2897 	prop            = NULL;
2898 	userMeta        = NULL;
2899 	resultClassName = NULL;
2900 	resultFlags     = 0;
2901 	ret = kIOReturnUnsupportedMode;
2902 
2903 	service = OSDynamicCast(IOService, obj);
2904 	action = OSDynamicCast(OSAction, obj);
2905 	if (!service) {
2906 		// xxx other classes hosted
2907 		resultFlags |= kOSObjectRPCKernel;
2908 		resultFlags |= kOSObjectRPCRemote;
2909 	} else {
2910 		serviceInactive = false;
2911 		if (service->lockForArbitration()) {
2912 			if (service->isInactive() && (service->__state[1] & kIOServiceStartState) == 0) {
2913 				serviceInactive = true;
2914 			}
2915 			service->unlockForArbitration();
2916 		}
2917 		if (serviceInactive) {
2918 			DKLOG(DKS "::instantiate inactive\n", DKN(service));
2919 			return kIOReturnOffline;
2920 		}
2921 		prop = service->copyProperty(gIOUserClassKey);
2922 		str = OSDynamicCast(OSString, prop);
2923 		if (!service->reserved->uvars) {
2924 			resultFlags |= kOSObjectRPCRemote;
2925 			resultFlags |= kOSObjectRPCKernel;
2926 		} else if (this != service->reserved->uvars->userServer) {
2927 			// remote, use base class
2928 			resultFlags |= kOSObjectRPCRemote;
2929 		}
2930 		if (service->reserved->uvars && service->reserved->uvars->userServer) {
2931 			if (!str) {
2932 				DKLOG("no IOUserClass defined for " DKS "\n", DKN(service));
2933 				OSSafeReleaseNULL(prop);
2934 				return kIOReturnError;
2935 			}
2936 			IOLockLock(service->reserved->uvars->userServer->fLock);
2937 			userMeta = (typeof(userMeta))service->reserved->uvars->userServer->fClasses->getObject(str);
2938 			IOLockUnlock(service->reserved->uvars->userServer->fLock);
2939 		}
2940 	}
2941 	if (!str && !userMeta) {
2942 		const OSMetaClass * meta;
2943 		meta = obj->getMetaClass();
2944 		IOLockLock(fLock);
2945 		if (action) {
2946 			str = action->ivars->typeName;
2947 			if (str) {
2948 				userMeta = (typeof(userMeta))fClasses->getObject(str);
2949 			}
2950 		}
2951 		while (meta && !userMeta) {
2952 			str = (OSString *) meta->getClassNameSymbol();
2953 			userMeta = (typeof(userMeta))fClasses->getObject(str);
2954 			if (!userMeta) {
2955 				meta = meta->getSuperClass();
2956 			}
2957 		}
2958 		IOLockUnlock(fLock);
2959 	}
2960 	if (str) {
2961 		if (!userMeta) {
2962 			IOLockLock(fLock);
2963 			userMeta = (typeof(userMeta))fClasses->getObject(str);
2964 			IOLockUnlock(fLock);
2965 		}
2966 		if (kIODKLogSetup & gIODKDebug) {
2967 			DKLOG("userMeta %s %p\n", str->getCStringNoCopy(), userMeta);
2968 		}
2969 		if (userMeta) {
2970 			if (kOSObjectRPCRemote & resultFlags) {
2971 				if (!action) {
2972 					/* Special case: For OSAction subclasses, do not use the superclass */
2973 					while (userMeta && !(kOSClassCanRemote & userMeta->description->flags)) {
2974 						userMeta = userMeta->superMeta;
2975 					}
2976 				}
2977 				if (userMeta) {
2978 					resultClassName = userMeta->description->name;
2979 					ret = kIOReturnSuccess;
2980 				}
2981 			} else {
2982 				service->reserved->uvars->userMeta = userMeta;
2983 				queueAlloc = 1;
2984 				if (userMeta->queueNames) {
2985 					queueAlloc += userMeta->queueNames->count;
2986 				}
2987 				unboundedQueueArray = IONewZero(IODispatchQueue *, queueAlloc);
2988 				service->reserved->uvars->queueArray =
2989 				    OSBoundedArrayRef<IODispatchQueue *>(unboundedQueueArray, queueAlloc);
2990 				resultClassName = str->getCStringNoCopy();
2991 				ret = kIOReturnSuccess;
2992 			}
2993 		} else if (kIODKLogSetup & gIODKDebug) {
2994 			DKLOG("userMeta %s was not found in fClasses\n", str->getCStringNoCopy());
2995 			IOLockLock(fLock);
2996 			fClasses->iterateObjects(^bool (const OSSymbol * key, OSObject * val) {
2997 				DKLOG(" fClasses[\"%s\"] => %p\n", key->getCStringNoCopy(), val);
2998 				return false;
2999 			});
3000 			IOLockUnlock(fLock);
3001 		}
3002 	}
3003 	OSSafeReleaseNULL(prop);
3004 
3005 	IORPCMessageMach * machReply = rpc.reply;
3006 	replySize = sizeof(OSObject_Instantiate_Rpl);
3007 
3008 	if ((kIOReturnSuccess == ret) && (kOSObjectRPCRemote & resultFlags)) {
3009 		target = obj;
3010 		if (action) {
3011 			if (action->ivars->referenceSize) {
3012 				resultFlags |= kOSObjectRPCKernel;
3013 			} else {
3014 				resultFlags &= ~kOSObjectRPCKernel;
3015 				if (action->ivars->target) {
3016 					target = action->ivars->target;
3017 					queueCount = 1;
3018 					queue = queueForObject(target, action->ivars->targetmsgid);
3019 					if (!queue && action->ivars->userServer) {
3020 						queue = action->ivars->userServer->fRootQueue;
3021 					}
3022 					idx = 0;
3023 					sendPort = NULL;
3024 					if (queue && (kIODispatchQueueStopped != queue)) {
3025 						sendPort = ipc_port_copy_send_mqueue(queue->ivars->serverPort);
3026 					}
3027 					replySize = sizeof(OSObject_Instantiate_Rpl)
3028 					    + queueCount * sizeof(machReply->objects[0])
3029 					    + 2 * methodCount * sizeof(reply->methods[0]);
3030 					if (replySize > rpc.replySize) {
3031 						assert(false);
3032 						return kIOReturnIPCError;
3033 					}
3034 					machReply->objects[idx].type        = MACH_MSG_PORT_DESCRIPTOR;
3035 					machReply->objects[idx].disposition = MACH_MSG_TYPE_MOVE_SEND;
3036 					machReply->objects[idx].name        = sendPort;
3037 					machReply->objects[idx].pad2        = 0;
3038 					machReply->objects[idx].pad_end     = 0;
3039 				}
3040 			}
3041 		} else {
3042 			uvars = varsForObject(target);
3043 			if (uvars && uvars->userMeta) {
3044 				queueCount = 1;
3045 				if (uvars->userMeta->queueNames) {
3046 					queueCount += uvars->userMeta->queueNames->count;
3047 				}
3048 				methods = &uvars->userMeta->methods[0];
3049 				methodCount = uvars->userMeta->methodCount;
3050 				replySize = sizeof(OSObject_Instantiate_Rpl)
3051 				    + queueCount * sizeof(machReply->objects[0])
3052 				    + 2 * methodCount * sizeof(reply->methods[0]);
3053 				if (replySize > rpc.replySize) {
3054 					assert(false);
3055 					return kIOReturnIPCError;
3056 				}
3057 				for (idx = 0; idx < queueCount; idx++) {
3058 					queue = uvars->queueArray[idx];
3059 					sendPort = NULL;
3060 					if (queue) {
3061 						sendPort = ipc_port_copy_send_mqueue(queue->ivars->serverPort);
3062 					}
3063 					machReply->objects[idx].type        = MACH_MSG_PORT_DESCRIPTOR;
3064 					machReply->objects[idx].disposition = MACH_MSG_TYPE_MOVE_SEND;
3065 					machReply->objects[idx].name        = sendPort;
3066 					machReply->objects[idx].pad2        = 0;
3067 					machReply->objects[idx].pad_end     = 0;
3068 				}
3069 			}
3070 		}
3071 	}
3072 
3073 	if (kIODKLogIPC & gIODKDebug) {
3074 		DKLOG("instantiate object %s with user class %s\n", obj->getMetaClass()->getClassName(), str ? str->getCStringNoCopy() : "(null)");
3075 	}
3076 
3077 	if (kIOReturnSuccess != ret) {
3078 		DKLOG("%s: no user class found\n", str ? str->getCStringNoCopy() : obj->getMetaClass()->getClassName());
3079 		resultClassName = "unknown";
3080 	}
3081 
3082 	machReply->msgh.msgh_id                    = kIORPCVersionCurrentReply;
3083 	machReply->msgh.msgh_size                  = replySize;
3084 	machReply->msgh_body.msgh_descriptor_count = queueCount;
3085 
3086 	reply = (typeof(reply))IORPCMessageFromMachReply(machReply);
3087 	if (!reply) {
3088 		return kIOReturnIPCError;
3089 	}
3090 	if (methodCount) {
3091 		bcopy(methods, &reply->methods[0], methodCount * 2 * sizeof(reply->methods[0]));
3092 	}
3093 	reply->__hdr.msgid       = OSObject_Instantiate_ID;
3094 	reply->__hdr.flags       = kIORPCMessageOneway;
3095 	reply->__hdr.objectRefs  = 0;
3096 	reply->__pad             = 0;
3097 	reply->flags             = resultFlags;
3098 	strlcpy(reply->classname, resultClassName, sizeof(reply->classname));
3099 	reply->__result          = ret;
3100 
3101 	ret = kIOReturnSuccess;
3102 
3103 	return ret;
3104 }
3105 
3106 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3107 
3108 IOReturn
3109 IOUserServer::kernelDispatch(OSObject * obj, IORPC rpc)
3110 {
3111 	IOReturn       ret;
3112 	IORPCMessage * message;
3113 
3114 	message = rpc.kernelContent;
3115 	if (!message) {
3116 		return kIOReturnIPCError;
3117 	}
3118 
3119 	if (OSObject_Instantiate_ID == message->msgid) {
3120 		ret = objectInstantiate(obj, rpc, message);
3121 		if (kIOReturnSuccess != ret) {
3122 			DKLOG("%s: instantiate failed 0x%x\n", obj->getMetaClass()->getClassName(), ret);
3123 		}
3124 	} else {
3125 		if (kIODKLogIPC & gIODKDebug) {
3126 			DKLOG("%s::Dispatch kernel 0x%qx\n", obj->getMetaClass()->getClassName(), message->msgid);
3127 		}
3128 		ret = obj->Dispatch(rpc);
3129 		if (kIODKLogIPC & gIODKDebug) {
3130 			DKLOG("%s::Dispatch kernel 0x%qx result 0x%x\n", obj->getMetaClass()->getClassName(), message->msgid, ret);
3131 		}
3132 	}
3133 
3134 	return ret;
3135 }
3136 
3137 
3138 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3139 
3140 OSObject *
3141 IOUserServer::target(OSAction * action, IORPCMessage * message)
3142 {
3143 	OSObject * object;
3144 
3145 	if (message->msgid != action->ivars->msgid) {
3146 		return action;
3147 	}
3148 	object = action->ivars->target;
3149 	if (!object) {
3150 		return action;
3151 	}
3152 	message->msgid      = action->ivars->targetmsgid;
3153 	message->objects[0] = (OSObjectRef) object;
3154 	if (kIORPCMessageRemote & message->flags) {
3155 		object->retain();
3156 #ifndef __clang_analyzer__
3157 		// Hide the release of 'action' from the clang static analyzer to suppress
3158 		// an overrelease diagnostic. The analyzer doesn't have a way to express the
3159 		// non-standard contract of this method, which is that it releases 'action' when
3160 		// the message flags have kIORPCMessageRemote set.
3161 		action->release();
3162 #endif
3163 	}
3164 	if (kIODKLogIPC & gIODKDebug) {
3165 		DKLOG("TARGET %s msg 0x%qx from 0x%qx\n", object->getMetaClass()->getClassName(), message->msgid, action->ivars->msgid);
3166 	}
3167 
3168 	return object;
3169 }
3170 
3171 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3172 
3173 kern_return_t
3174 uext_server(ipc_port_t receiver, ipc_kmsg_t requestkmsg, ipc_kmsg_t * pReply)
3175 {
3176 	kern_return_t      ret;
3177 	OSObject         * object;
3178 	IOUserServer     * server;
3179 
3180 	object = IOUserServer::copyObjectForSendRight(receiver, IKOT_UEXT_OBJECT);
3181 	server = OSDynamicCast(IOUserServer, object);
3182 	if (!server) {
3183 		OSSafeReleaseNULL(object);
3184 		return KERN_INVALID_NAME;
3185 	}
3186 
3187 	IORPCMessage * message = (typeof(message))ikm_udata_from_header(requestkmsg);
3188 
3189 	ret = server->server(requestkmsg, message, pReply);
3190 	object->release();
3191 
3192 	return ret;
3193 }
3194 
3195 /*
3196  * Chosen to hit kalloc zones (as opposed to the VM).
3197  * doesn't include the trailer size which ipc_kmsg_alloc() will add
3198  */
3199 #define MAX_UEXT_REPLY_SIZE     0x17c0
3200 static_assert(MAX_UEXT_REPLY_SIZE + MAX_TRAILER_SIZE <= KALLOC_SAFE_ALLOC_SIZE);
3201 
3202 kern_return_t
3203 IOUserServer::server(ipc_kmsg_t requestkmsg, IORPCMessage * message, ipc_kmsg_t * pReply)
3204 {
3205 	kern_return_t      ret;
3206 	mach_msg_size_t    replyAlloc;
3207 	ipc_kmsg_t         replykmsg;
3208 	IORPCMessageMach * msgin;
3209 	IORPCMessageMach * msgout;
3210 	IORPCMessage     * reply;
3211 	uint32_t           replySize;
3212 	OSObject         * object;
3213 	OSAction         * action;
3214 	bool               oneway;
3215 	uint64_t           msgid;
3216 
3217 	msgin   = (typeof(msgin))ikm_header(requestkmsg);
3218 	replyAlloc = 0;
3219 	msgout = NULL;
3220 	replykmsg = NULL;
3221 
3222 	if (msgin->msgh.msgh_size < (sizeof(IORPCMessageMach) + sizeof(IORPCMessage))) {
3223 		if (kIODKLogIPC & gIODKDebug) {
3224 			DKLOG("UEXT notify %o\n", msgin->msgh.msgh_id);
3225 		}
3226 		return KERN_NOT_SUPPORTED;
3227 	}
3228 
3229 	if (!(MACH_MSGH_BITS_COMPLEX & msgin->msgh.msgh_bits)) {
3230 		msgin->msgh_body.msgh_descriptor_count = 0;
3231 	}
3232 	if (!message) {
3233 		return kIOReturnIPCError;
3234 	}
3235 	if (message->objectRefs == 0) {
3236 		return kIOReturnIPCError;
3237 	}
3238 	ret = copyInObjects(msgin, message, msgin->msgh.msgh_size, true, false);
3239 	if (kIOReturnSuccess != ret) {
3240 		if (kIODKLogIPC & gIODKDebug) {
3241 			DKLOG("UEXT copyin(0x%x) %x\n", ret, msgin->msgh.msgh_id);
3242 		}
3243 		// release objects and ports
3244 		consumeObjects(msgin, message, msgin->msgh.msgh_size);
3245 		copyInObjects(msgin, message, msgin->msgh.msgh_size, false, true);
3246 		return KERN_NOT_SUPPORTED;
3247 	}
3248 
3249 	if (msgin->msgh_body.msgh_descriptor_count < 1) {
3250 		return KERN_NOT_SUPPORTED;
3251 	}
3252 	object = (OSObject *) message->objects[0];
3253 	msgid = message->msgid;
3254 	message->flags &= ~kIORPCMessageKernel;
3255 	message->flags |= kIORPCMessageRemote;
3256 
3257 	if ((action = OSDynamicCast(OSAction, object))) {
3258 		object = target(action, message);
3259 		msgid  = message->msgid;
3260 	}
3261 
3262 	oneway = (0 != (kIORPCMessageOneway & message->flags));
3263 	assert(oneway || (MACH_PORT_NULL != msgin->msgh.msgh_local_port));
3264 
3265 	replyAlloc = oneway ? 0 : MAX_UEXT_REPLY_SIZE;
3266 
3267 
3268 
3269 
3270 	if (replyAlloc) {
3271 		/*
3272 		 * Same as:
3273 		 *    ipc_kmsg_alloc(MAX_UEXT_REPLY_SIZE_MACH, MAX_UEXT_REPLY_SIZE_MESSAGE,
3274 		 *        IPC_KMSG_ALLOC_KERNEL | IPC_KMSG_ALLOC_ZERO | IPC_KMSG_ALLOC_LINEAR |
3275 		 *        IPC_KMSG_ALLOC_NOFAIL);
3276 		 */
3277 		replykmsg = ipc_kmsg_alloc_uext_reply(MAX_UEXT_REPLY_SIZE);
3278 		msgout = (typeof(msgout))ikm_header(replykmsg);
3279 	}
3280 
3281 	IORPC rpc = { .message = msgin, .reply = msgout, .sendSize = msgin->msgh.msgh_size, .replySize = replyAlloc, .kernelContent = message };
3282 
3283 	if (object) {
3284 		kern_allocation_name_t prior;
3285 		bool                   setAllocationName;
3286 
3287 		setAllocationName = (NULL != fAllocationName);
3288 		if (setAllocationName) {
3289 			prior = thread_set_allocation_name(fAllocationName);
3290 		}
3291 		thread_iokit_tls_set(0, this);
3292 		ret = kernelDispatch(object, rpc);
3293 		thread_iokit_tls_set(0, NULL);
3294 		if (setAllocationName) {
3295 			thread_set_allocation_name(prior);
3296 		}
3297 	} else {
3298 		ret = kIOReturnBadArgument;
3299 	}
3300 
3301 	// release objects
3302 	consumeObjects(msgin, message, msgin->msgh.msgh_size);
3303 
3304 	// release ports
3305 	copyInObjects(msgin, message, msgin->msgh.msgh_size, false, true);
3306 
3307 	if (!oneway) {
3308 		if (kIOReturnSuccess == ret) {
3309 			replySize = msgout->msgh.msgh_size;
3310 			reply = IORPCMessageFromMachReply(msgout);
3311 			if (!reply) {
3312 				ret = kIOReturnIPCError;
3313 			} else {
3314 				ret = copyOutObjects(msgout, reply, replySize, (kIORPCVersionCurrentReply == msgout->msgh.msgh_id) /* =>!InvokeReply */);
3315 			}
3316 		}
3317 		if (kIOReturnSuccess != ret) {
3318 			IORPCMessageErrorReturnContent * errorMsg;
3319 
3320 			msgout->msgh_body.msgh_descriptor_count = 0;
3321 			msgout->msgh.msgh_id                    = kIORPCVersionCurrentReply;
3322 			errorMsg = (typeof(errorMsg))IORPCMessageFromMachReply(msgout);
3323 			errorMsg->hdr.msgid      = message->msgid;
3324 			errorMsg->hdr.flags      = kIORPCMessageOneway | kIORPCMessageError;
3325 			errorMsg->hdr.objectRefs = 0;
3326 			errorMsg->result         = ret;
3327 			errorMsg->pad            = 0;
3328 			replySize                = sizeof(IORPCMessageErrorReturn);
3329 		}
3330 
3331 		msgout->msgh.msgh_bits = MACH_MSGH_BITS_COMPLEX |
3332 		    MACH_MSGH_BITS_SET(MACH_MSGH_BITS_LOCAL(msgin->msgh.msgh_bits) /*remote*/, 0 /*local*/, 0, 0);
3333 
3334 		msgout->msgh.msgh_remote_port  = msgin->msgh.msgh_local_port;
3335 		msgout->msgh.msgh_local_port   = MACH_PORT_NULL;
3336 		msgout->msgh.msgh_voucher_port = (mach_port_name_t) 0;
3337 		msgout->msgh.msgh_reserved     = 0;
3338 		msgout->msgh.msgh_size         = replySize;
3339 	}
3340 
3341 	*pReply = replykmsg;
3342 	return KERN_SUCCESS;
3343 }
3344 
3345 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3346 
3347 static inline uint32_t
3348 MAX_OBJECT_COUNT(IORPCMessageMach *mach, size_t size, IORPCMessage *message __unused)
3349 {
3350 	assert(mach->msgh.msgh_size == size);
3351 	size_t used_size;
3352 	size_t remaining_size;
3353 	if (os_mul_and_add_overflow(
3354 		    mach->msgh_body.msgh_descriptor_count,
3355 		    sizeof(mach_msg_port_descriptor_t),
3356 		    sizeof(mach->msgh) + sizeof(mach->msgh_body) + offsetof(IORPCMessage, objects[0]),
3357 		    &used_size)) {
3358 		return 0;
3359 	}
3360 	if (os_sub_overflow(size, used_size, &remaining_size)) {
3361 		return 0;
3362 	}
3363 	return (uint32_t)(remaining_size / sizeof(OSObjectRef));
3364 }
3365 
3366 #pragma pack(push, 4)
3367 struct UEXTTrapReply {
3368 	uint64_t replySize;
3369 	IORPCMessage replyMessage;
3370 };
3371 #pragma pack(pop)
3372 
3373 kern_return_t
3374 IOUserServerUEXTTrap(OSObject * object, void * p1, void * p2, void * p3, void * p4, void * p5, void * p6)
3375 {
3376 	const user_addr_t msg              = (uintptr_t) p1;
3377 	size_t            inSize           = (uintptr_t) p2;
3378 	user_addr_t       out              = (uintptr_t) p3;
3379 	size_t            outSize          = (uintptr_t) p4;
3380 	mach_port_name_t  objectName1      = (mach_port_name_t)(uintptr_t) p5;
3381 	size_t            totalSize;
3382 	OSObject        * objectArg1;
3383 
3384 	IORPCMessageMach *  mach;
3385 	mach_msg_port_descriptor_t * descs;
3386 
3387 #pragma pack(4)
3388 	struct {
3389 		uint32_t                   pad;
3390 		IORPCMessageMach           mach;
3391 		mach_msg_port_descriptor_t objects[2];
3392 		IOTrapMessageBuffer        buffer;
3393 	} buffer;
3394 #pragma pack()
3395 
3396 	IOReturn           ret;
3397 	OSAction         * action;
3398 	int                copyerr;
3399 	IORPCMessage     * message;
3400 	IORPCMessage     * reply;
3401 	IORPC              rpc;
3402 	uint64_t           refs;
3403 	uint32_t           maxObjectCount;
3404 	size_t             copySize;
3405 	UEXTTrapReply    * replyHdr;
3406 	uintptr_t          p;
3407 
3408 	bzero(&buffer, sizeof(buffer));
3409 
3410 	p = (typeof(p)) & buffer.buffer[0];
3411 	if (os_add_overflow(inSize, outSize, &totalSize)) {
3412 		return kIOReturnMessageTooLarge;
3413 	}
3414 	if (totalSize > sizeof(buffer.buffer)) {
3415 		return kIOReturnMessageTooLarge;
3416 	}
3417 	if (inSize < sizeof(IORPCMessage)) {
3418 		return kIOReturnIPCError;
3419 	}
3420 	copyerr = copyin(msg, &buffer.buffer[0], inSize);
3421 	if (copyerr) {
3422 		return kIOReturnVMError;
3423 	}
3424 
3425 	message = (typeof(message))p;
3426 	refs    = message->objectRefs;
3427 	if ((refs > 2) || !refs) {
3428 		return kIOReturnUnsupported;
3429 	}
3430 	if (!(kIORPCMessageSimpleReply & message->flags)) {
3431 		return kIOReturnUnsupported;
3432 	}
3433 	message->flags &= ~(kIORPCMessageKernel | kIORPCMessageRemote);
3434 
3435 	descs = (typeof(descs))(p - refs * sizeof(*descs));
3436 	mach  = (typeof(mach))(p - refs * sizeof(*descs) - sizeof(*mach));
3437 
3438 	mach->msgh.msgh_id   = kIORPCVersionCurrent;
3439 	mach->msgh.msgh_size = (mach_msg_size_t) (sizeof(IORPCMessageMach) + refs * sizeof(*descs) + inSize); // totalSize was checked
3440 	mach->msgh_body.msgh_descriptor_count = ((mach_msg_size_t) refs);
3441 
3442 	rpc.message   = mach;
3443 	rpc.sendSize  = mach->msgh.msgh_size;
3444 	rpc.reply     = (IORPCMessageMach *) (p + inSize);
3445 	rpc.replySize = ((uint32_t) (sizeof(buffer.buffer) - inSize));    // inSize was checked
3446 	rpc.kernelContent = message;
3447 
3448 	message->objects[0] = 0;
3449 	if ((action = OSDynamicCast(OSAction, object))) {
3450 		maxObjectCount = MAX_OBJECT_COUNT(rpc.message, rpc.sendSize, message);
3451 		if (refs > maxObjectCount) {
3452 			return kIOReturnBadArgument;
3453 		}
3454 		if (refs < 2) {
3455 			DKLOG("invalid refs count %qd in message id 0x%qx\n", refs, message->msgid);
3456 			return kIOReturnBadArgument;
3457 		}
3458 		object = IOUserServer::target(action, message);
3459 		message->objects[1] = (OSObjectRef) action;
3460 		if (kIODKLogIPC & gIODKDebug) {
3461 			DKLOG("%s::Dispatch(trap) kernel 0x%qx\n", object->getMetaClass()->getClassName(), message->msgid);
3462 		}
3463 		ret = object->Dispatch(rpc);
3464 	} else {
3465 		objectArg1 = NULL;
3466 		if (refs > 1) {
3467 			if (objectName1) {
3468 				objectArg1 = iokit_lookup_uext_ref_current_task(objectName1);
3469 				if (!objectArg1) {
3470 					return kIOReturnIPCError;
3471 				}
3472 			}
3473 			message->objects[1] = (OSObjectRef) objectArg1;
3474 		}
3475 		if (kIODKLogIPC & gIODKDebug) {
3476 			DKLOG("%s::Dispatch(trap) kernel 0x%qx\n", object->getMetaClass()->getClassName(), message->msgid);
3477 		}
3478 		ret = object->Dispatch(rpc);
3479 		if (kIODKLogIPC & gIODKDebug) {
3480 			DKLOG("%s::Dispatch(trap) kernel 0x%qx 0x%x\n", object->getMetaClass()->getClassName(), message->msgid, ret);
3481 		}
3482 		OSSafeReleaseNULL(objectArg1);
3483 
3484 		if (kIOReturnSuccess == ret) {
3485 			if (rpc.reply->msgh_body.msgh_descriptor_count) {
3486 				return kIOReturnIPCError;
3487 			}
3488 			reply = IORPCMessageFromMachReply(rpc.reply);
3489 			if (!reply) {
3490 				return kIOReturnIPCError;
3491 			}
3492 			copySize = rpc.reply->msgh.msgh_size - (((uintptr_t) reply) - ((uintptr_t) rpc.reply)) + sizeof(uint64_t);
3493 			if (copySize > outSize) {
3494 				return kIOReturnIPCError;
3495 			}
3496 			replyHdr = (UEXTTrapReply *) ((uintptr_t)reply - sizeof(uint64_t));
3497 			replyHdr->replySize = copySize;
3498 			copyerr = copyout(replyHdr, out, copySize);
3499 			if (copyerr) {
3500 				return kIOReturnVMError;
3501 			}
3502 		}
3503 	}
3504 
3505 	return ret;
3506 }
3507 
3508 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3509 
3510 IOReturn
3511 IOUserServer::rpc(IORPC rpc)
3512 {
3513 	if (isInactive() && !fRootQueue) {
3514 		return kIOReturnOffline;
3515 	}
3516 
3517 	IOReturn           ret;
3518 	IORPCMessage     * message;
3519 	IORPCMessageMach * mach;
3520 	mach_msg_id_t      machid;
3521 	uint32_t           sendSize, replySize;
3522 	bool               oneway;
3523 	uint64_t           msgid;
3524 	IODispatchQueue  * queue;
3525 	IOService        * service;
3526 	ipc_port_t         port;
3527 	ipc_port_t         sendPort;
3528 
3529 	queue    = NULL;
3530 	port     = NULL;
3531 	sendPort = NULL;
3532 
3533 	mach      = rpc.message;
3534 	sendSize  = rpc.sendSize;
3535 	replySize = rpc.replySize;
3536 
3537 	assert(sendSize >= (sizeof(IORPCMessageMach) + sizeof(IORPCMessage)));
3538 
3539 	message = rpc.kernelContent;
3540 	if (!message) {
3541 		return kIOReturnIPCError;
3542 	}
3543 	msgid   = message->msgid;
3544 	machid  = (msgid >> 32);
3545 
3546 	if (mach->msgh_body.msgh_descriptor_count < 1) {
3547 		return kIOReturnNoMedia;
3548 	}
3549 
3550 	IOLockLock(gIOUserServerLock);
3551 	if ((service = OSDynamicCast(IOService, (OSObject *) message->objects[0]))) {
3552 		queue = queueForObject(service, msgid);
3553 	}
3554 	if (!queue) {
3555 		queue = fRootQueue;
3556 	}
3557 	if (queue && (kIODispatchQueueStopped != queue)) {
3558 		port = queue->ivars->serverPort;
3559 	}
3560 	if (port) {
3561 		sendPort = ipc_port_copy_send_mqueue(port);
3562 	}
3563 	IOLockUnlock(gIOUserServerLock);
3564 	if (!sendPort) {
3565 		return kIOReturnNotReady;
3566 	}
3567 
3568 	oneway = (0 != (kIORPCMessageOneway & message->flags));
3569 
3570 	ret = copyOutObjects(mach, message, sendSize, false);
3571 
3572 	mach->msgh.msgh_bits = MACH_MSGH_BITS_COMPLEX |
3573 	    MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, (oneway ? 0 : MACH_MSG_TYPE_MAKE_SEND_ONCE));
3574 	mach->msgh.msgh_remote_port  = sendPort;
3575 	mach->msgh.msgh_local_port   = (oneway ? MACH_PORT_NULL : mig_get_reply_port());
3576 	mach->msgh.msgh_id           = kIORPCVersionCurrent;
3577 	mach->msgh.msgh_reserved     = 0;
3578 
3579 	boolean_t message_moved;
3580 
3581 	if (oneway) {
3582 		ret = kernel_mach_msg_send(&mach->msgh, sendSize,
3583 		    MACH_SEND_KERNEL_DEFAULT, 0, &message_moved);
3584 	} else {
3585 		assert(replySize >= (sizeof(IORPCMessageMach) + sizeof(IORPCMessage)));
3586 		ret = kernel_mach_msg_rpc(&mach->msgh, sendSize, replySize, FALSE, &message_moved);
3587 	}
3588 
3589 	ipc_port_release_send(sendPort);
3590 
3591 	if (MACH_MSG_SUCCESS != ret) {
3592 		if (kIODKLogIPC & gIODKDebug) {
3593 			DKLOG("mach_msg() failed 0x%x\n", ret);
3594 		}
3595 		if (!message_moved) {
3596 			// release ports
3597 			copyInObjects(mach, message, sendSize, false, true);
3598 		}
3599 	}
3600 
3601 	if ((KERN_SUCCESS == ret) && !oneway) {
3602 		if (kIORPCVersionCurrentReply != mach->msgh.msgh_id) {
3603 			ret = (MACH_NOTIFY_SEND_ONCE == mach->msgh.msgh_id) ? MIG_SERVER_DIED : MIG_REPLY_MISMATCH;
3604 		} else if ((replySize = mach->msgh.msgh_size) < (sizeof(IORPCMessageMach) + sizeof(IORPCMessage))) {
3605 //				printf("BAD REPLY SIZE\n");
3606 			ret = MIG_BAD_ARGUMENTS;
3607 		} else {
3608 			if (!(MACH_MSGH_BITS_COMPLEX & mach->msgh.msgh_bits)) {
3609 				mach->msgh_body.msgh_descriptor_count = 0;
3610 			}
3611 			message = IORPCMessageFromMachReply(mach);
3612 			if (!message) {
3613 				ret = kIOReturnIPCError;
3614 			} else if (message->msgid != msgid) {
3615 //					printf("BAD REPLY ID\n");
3616 				ret = MIG_BAD_ARGUMENTS;
3617 			} else {
3618 				bool isError = (0 != (kIORPCMessageError & message->flags));
3619 				ret = copyInObjects(mach, message, replySize, !isError, true);
3620 				if (kIOReturnSuccess != ret) {
3621 					if (kIODKLogIPC & gIODKDebug) {
3622 						DKLOG("rpc copyin(0x%x) %x\n", ret, mach->msgh.msgh_id);
3623 					}
3624 					if (!isError) {
3625 						consumeObjects(mach, message, replySize);
3626 						copyInObjects(mach, message, replySize, false, true);
3627 					}
3628 					return KERN_NOT_SUPPORTED;
3629 				}
3630 				if (isError) {
3631 					IORPCMessageErrorReturnContent * errorMsg = (typeof(errorMsg))message;
3632 					ret = errorMsg->result;
3633 				}
3634 			}
3635 		}
3636 	}
3637 
3638 	return ret;
3639 }
3640 
3641 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3642 
3643 static IORPCMessage *
3644 IORPCMessageFromMachReply(IORPCMessageMach * msg)
3645 {
3646 	mach_msg_size_t              idx, count;
3647 	mach_msg_port_descriptor_t * desc;
3648 	mach_msg_port_descriptor_t * maxDesc;
3649 	size_t                       size, msgsize;
3650 	bool                         upgrade;
3651 	bool                         reply = true;
3652 
3653 	msgsize = msg->msgh.msgh_size;
3654 	count   = msg->msgh_body.msgh_descriptor_count;
3655 	desc    = &msg->objects[0];
3656 	maxDesc = (typeof(maxDesc))(((uintptr_t) msg) + msgsize);
3657 	upgrade = (msg->msgh.msgh_id != (reply ? kIORPCVersionCurrentReply : kIORPCVersionCurrent));
3658 
3659 	if (upgrade) {
3660 		OSReportWithBacktrace("obsolete message");
3661 		return NULL;
3662 	}
3663 
3664 	for (idx = 0; idx < count; idx++) {
3665 		if (desc >= maxDesc) {
3666 			return NULL;
3667 		}
3668 		switch (desc->type) {
3669 		case MACH_MSG_PORT_DESCRIPTOR:
3670 			size = sizeof(mach_msg_port_descriptor_t);
3671 			break;
3672 		case MACH_MSG_OOL_DESCRIPTOR:
3673 			size = sizeof(mach_msg_ool_descriptor_t);
3674 			break;
3675 		default:
3676 			return NULL;
3677 		}
3678 		desc = (typeof(desc))(((uintptr_t) desc) + size);
3679 	}
3680 	return (IORPCMessage *)(uintptr_t) desc;
3681 }
3682 
3683 ipc_port_t
3684 IOUserServer::copySendRightForObject(OSObject * object, ipc_kobject_type_t type)
3685 {
3686 	ipc_port_t port;
3687 	ipc_port_t sendPort = NULL;
3688 	ipc_kobject_t kobj;
3689 
3690 	port = iokit_port_for_object(object, type, &kobj);
3691 	if (port) {
3692 		sendPort = ipc_kobject_make_send(port, kobj, type);
3693 		iokit_release_port(port);
3694 	}
3695 
3696 	return sendPort;
3697 }
3698 
3699 OSObject *
3700 IOUserServer::copyObjectForSendRight(ipc_port_t port, ipc_kobject_type_t type)
3701 {
3702 	OSObject * object;
3703 	object = iokit_lookup_io_object(port, type);
3704 	return object;
3705 }
3706 
3707 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3708 
3709 // Create a vm_map_copy_t or kalloc'ed data for memory
3710 // to be copied out. ipc will free after the copyout.
3711 
3712 static kern_return_t
3713 copyoutkdata(const void * data, vm_size_t len, void ** buf)
3714 {
3715 	kern_return_t       err;
3716 	vm_map_copy_t       copy;
3717 
3718 	err = vm_map_copyin( kernel_map, CAST_USER_ADDR_T(data), len,
3719 	    false /* src_destroy */, &copy);
3720 
3721 	assert( err == KERN_SUCCESS );
3722 	if (err == KERN_SUCCESS) {
3723 		*buf = (char *) copy;
3724 	}
3725 
3726 	return err;
3727 }
3728 
3729 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3730 
3731 IOReturn
3732 IOUserServer::copyOutObjects(IORPCMessageMach * mach, IORPCMessage * message,
3733     size_t size, bool consume)
3734 {
3735 	uint64_t           refs;
3736 	uint32_t           idx, maxObjectCount;
3737 	ipc_port_t         port;
3738 	OSObject         * object;
3739 	size_t             descsize;
3740 	mach_msg_port_descriptor_t * desc;
3741 	mach_msg_ool_descriptor_t  * ool;
3742 	vm_map_copy_t                copy;
3743 	void                       * address;
3744 	mach_msg_size_t              length;
3745 	kern_return_t                kr;
3746 	OSSerialize                * s;
3747 
3748 	refs           = message->objectRefs;
3749 	maxObjectCount = MAX_OBJECT_COUNT(mach, size, message);
3750 //	assert(refs <= mach->msgh_body.msgh_descriptor_count);
3751 //	assert(refs <= maxObjectCount);
3752 	if (refs > mach->msgh_body.msgh_descriptor_count) {
3753 		return kIOReturnBadArgument;
3754 	}
3755 	if (refs > maxObjectCount) {
3756 		return kIOReturnBadArgument;
3757 	}
3758 
3759 	desc = &mach->objects[0];
3760 	for (idx = 0; idx < refs; idx++) {
3761 		object = (OSObject *) message->objects[idx];
3762 
3763 		switch (desc->type) {
3764 		case MACH_MSG_PORT_DESCRIPTOR:
3765 			descsize = sizeof(mach_msg_port_descriptor_t);
3766 			port = NULL;
3767 			if (object) {
3768 #if DEVELOPMENT || DEBUG
3769 				if (kIODKLogIPC & gIODKDebug) {
3770 					IOMemoryDescriptor * iomd = OSDynamicCast(IOMemoryDescriptor, object);
3771 					if (iomd != NULL && (iomd->getFlags() & kIOMemoryThreadSafe) == 0) {
3772 						OSReportWithBacktrace("IOMemoryDescriptor %p was created without kIOMemoryThreadSafe flag", iomd);
3773 					}
3774 				}
3775 #endif /* DEVELOPMENT || DEBUG */
3776 
3777 				port = copySendRightForObject(object, IKOT_UEXT_OBJECT);
3778 				if (!port) {
3779 					break;
3780 				}
3781 				if (consume) {
3782 					object->release();
3783 				}
3784 				message->objects[idx] = 0;
3785 			}
3786 //		    desc->type        = MACH_MSG_PORT_DESCRIPTOR;
3787 			desc->disposition = MACH_MSG_TYPE_MOVE_SEND;
3788 			desc->name        = port;
3789 			desc->pad2        = 0;
3790 			desc->pad_end     = 0;
3791 			break;
3792 
3793 		case MACH_MSG_OOL_DESCRIPTOR:
3794 			descsize = sizeof(mach_msg_ool_descriptor_t);
3795 
3796 			length = 0;
3797 			address = NULL;
3798 			if (object) {
3799 				s = OSSerialize::binaryWithCapacity(4096);
3800 				assert(s);
3801 				if (!s) {
3802 					break;
3803 				}
3804 				s->setIndexed(true);
3805 				if (!object->serialize(s)) {
3806 					assert(false);
3807 					descsize = -1UL;
3808 					s->release();
3809 					break;
3810 				}
3811 				length = s->getLength();
3812 				kr = copyoutkdata(s->text(), length, &address);
3813 				s->release();
3814 				if (KERN_SUCCESS != kr) {
3815 					descsize = -1UL;
3816 					address = NULL;
3817 					length = 0;
3818 				}
3819 				if (consume) {
3820 					object->release();
3821 				}
3822 				message->objects[idx] = 0;
3823 			}
3824 			ool = (typeof(ool))desc;
3825 //		    ool->type        = MACH_MSG_OOL_DESCRIPTOR;
3826 			ool->deallocate  = false;
3827 			ool->copy        = MACH_MSG_PHYSICAL_COPY;
3828 			ool->size        = length;
3829 			ool->address     = address;
3830 			break;
3831 
3832 		default:
3833 			descsize = -1UL;
3834 			break;
3835 		}
3836 		if (-1UL == descsize) {
3837 			break;
3838 		}
3839 		desc = (typeof(desc))(((uintptr_t) desc) + descsize);
3840 	}
3841 
3842 	if (idx >= refs) {
3843 		return kIOReturnSuccess;
3844 	}
3845 
3846 	desc = &mach->objects[0];
3847 	while (idx--) {
3848 		switch (desc->type) {
3849 		case MACH_MSG_PORT_DESCRIPTOR:
3850 			descsize = sizeof(mach_msg_port_descriptor_t);
3851 			port = desc->name;
3852 			if (port) {
3853 				ipc_port_release_send(port);
3854 			}
3855 			break;
3856 
3857 		case MACH_MSG_OOL_DESCRIPTOR:
3858 			descsize = sizeof(mach_msg_ool_descriptor_t);
3859 			ool = (typeof(ool))desc;
3860 			copy = (vm_map_copy_t) ool->address;
3861 			if (copy) {
3862 				vm_map_copy_discard(copy);
3863 			}
3864 			break;
3865 
3866 		default:
3867 			descsize = -1UL;
3868 			break;
3869 		}
3870 		if (-1UL == descsize) {
3871 			break;
3872 		}
3873 		desc = (typeof(desc))(((uintptr_t) desc) + descsize);
3874 	}
3875 
3876 	return kIOReturnBadArgument;
3877 }
3878 
3879 IOReturn
3880 IOUserServer::copyInObjects(IORPCMessageMach * mach, IORPCMessage * message,
3881     size_t size, bool copyObjects, bool consumePorts)
3882 {
3883 	uint64_t           refs;
3884 	uint32_t           idx, maxObjectCount;
3885 	ipc_port_t         port;
3886 	OSObject         * object;
3887 	size_t                       descsize;
3888 	mach_msg_port_descriptor_t * desc;
3889 	mach_msg_ool_descriptor_t  * ool;
3890 	vm_map_address_t             copyoutdata;
3891 	kern_return_t                kr;
3892 
3893 	refs           = message->objectRefs;
3894 	maxObjectCount = MAX_OBJECT_COUNT(mach, size, message);
3895 //	assert(refs <= mach->msgh_body.msgh_descriptor_count);
3896 //	assert(refs <= maxObjectCount);
3897 	if (refs > mach->msgh_body.msgh_descriptor_count) {
3898 		return kIOReturnBadArgument;
3899 	}
3900 	if (refs > maxObjectCount) {
3901 		return kIOReturnBadArgument;
3902 	}
3903 
3904 	for (idx = 0; idx < refs; idx++) {
3905 		message->objects[idx] = (OSObjectRef) NULL;
3906 	}
3907 
3908 	desc = &mach->objects[0];
3909 	for (idx = 0; idx < mach->msgh_body.msgh_descriptor_count; idx++) {
3910 		bool isObjectPort = idx < refs;
3911 
3912 		switch (desc->type) {
3913 		case MACH_MSG_PORT_DESCRIPTOR:
3914 			descsize = sizeof(mach_msg_port_descriptor_t);
3915 
3916 			object = NULL;
3917 			port = desc->name;
3918 			if (port) {
3919 				if (isObjectPort && copyObjects) {
3920 					object = copyObjectForSendRight(port, IKOT_UEXT_OBJECT);
3921 					if (!object) {
3922 						descsize = -1UL;
3923 						break;
3924 					}
3925 				}
3926 				if (consumePorts) {
3927 					ipc_port_release_send(port);
3928 					desc->name = MACH_PORT_NULL;
3929 				}
3930 			}
3931 			break;
3932 
3933 		case MACH_MSG_OOL_DESCRIPTOR:
3934 			descsize = sizeof(mach_msg_ool_descriptor_t);
3935 			ool = (typeof(ool))desc;
3936 
3937 			object = NULL;
3938 			if (isObjectPort && copyObjects && ool->size && ool->address) {
3939 				kr = vm_map_copyout(kernel_map, &copyoutdata, (vm_map_copy_t) ool->address);
3940 				if (KERN_SUCCESS == kr) {
3941 					object = OSUnserializeXML((const char *) copyoutdata, ool->size);
3942 					kr = vm_deallocate(kernel_map, copyoutdata, ool->size);
3943 					assert(KERN_SUCCESS == kr);
3944 					// vm_map_copyout() has consumed the vm_map_copy_t in the message
3945 					ool->size = 0;
3946 					ool->address = NULL;
3947 				}
3948 				if (!object) {
3949 					descsize = -1UL;
3950 					break;
3951 				}
3952 			}
3953 			break;
3954 
3955 		default:
3956 			descsize = -1UL;
3957 			break;
3958 		}
3959 		if (-1UL == descsize) {
3960 			break;
3961 		}
3962 		if (isObjectPort && copyObjects) {
3963 			message->objects[idx] = (OSObjectRef) object;
3964 		}
3965 		desc = (typeof(desc))(((uintptr_t) desc) + descsize);
3966 	}
3967 
3968 	if (idx >= refs) {
3969 		return kIOReturnSuccess;
3970 	}
3971 
3972 	while (idx--) {
3973 		object = (OSObject *) message->objects[idx];
3974 		OSSafeReleaseNULL(object);
3975 		message->objects[idx] = 0;
3976 	}
3977 
3978 	return kIOReturnBadArgument;
3979 }
3980 
3981 IOReturn
3982 IOUserServer::consumeObjects(IORPCMessageMach *mach, IORPCMessage * message, size_t messageSize)
3983 {
3984 	uint64_t    refs, idx;
3985 	OSObject  * object;
3986 
3987 	refs   = message->objectRefs;
3988 	uint32_t maxObjectCount = MAX_OBJECT_COUNT(mach, messageSize, message);
3989 	if (refs > mach->msgh_body.msgh_descriptor_count) {
3990 		return kIOReturnBadArgument;
3991 	}
3992 	if (refs > maxObjectCount) {
3993 		return kIOReturnBadArgument;
3994 	}
3995 
3996 	for (idx = 0; idx < refs; idx++) {
3997 		object = (OSObject *) message->objects[idx];
3998 		if (object) {
3999 			object->release();
4000 			message->objects[idx] = 0;
4001 		}
4002 	}
4003 
4004 	return kIOReturnSuccess;
4005 }
4006 
4007 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4008 
4009 bool
4010 IOUserServer::finalize(IOOptionBits options)
4011 {
4012 	OSArray   * services;
4013 
4014 	if (kIODKLogSetup & gIODKDebug) {
4015 		DKLOG("%s::finalize(%p)\n", getName(), this);
4016 	}
4017 
4018 	IOLockLock(gIOUserServerLock);
4019 	OSSafeReleaseNULL(fRootQueue);
4020 	IOLockUnlock(gIOUserServerLock);
4021 
4022 	services = NULL;
4023 	IOLockLock(fLock);
4024 	if (fServices) {
4025 		services = OSArray::withArray(fServices);
4026 	}
4027 	IOLockUnlock(fLock);
4028 
4029 	IOOptionBits terminateFlags = kIOServiceTerminateNeedWillTerminate | kIOServiceTerminateWithRematch;
4030 	if (fCheckInToken) {
4031 		bool can_rematch = fCheckInToken->dextTerminate();
4032 		if (can_rematch) {
4033 			terminateFlags |= kIOServiceTerminateWithRematchCurrentDext;
4034 		} else {
4035 			DKLOG("%s::finalize(%p) dext was replaced, do not rematch current dext\n", getName(), this);
4036 		}
4037 	} else {
4038 		terminateFlags |= kIOServiceTerminateWithRematchCurrentDext;
4039 		DKLOG("%s::finalize(%p) could not find fCheckInToken\n", getName(), this);
4040 	}
4041 
4042 	if (services) {
4043 		services->iterateObjects(^bool (OSObject * obj) {
4044 			int         service __unused;       // hide outer defn
4045 			IOService * nextService;
4046 			IOService * provider;
4047 			bool        started = false;
4048 
4049 			nextService = (IOService *) obj;
4050 			if (kIODKLogSetup & gIODKDebug) {
4051 			        DKLOG("%s::terminate(" DKS ")\n", getName(), DKN(nextService));
4052 			}
4053 			if (nextService->reserved->uvars) {
4054 			        IOUserClient * nextUserClient = OSDynamicCast(IOUserClient, nextService);
4055 			        provider = nextService->getProvider();
4056 			        if (nextUserClient) {
4057 			                nextUserClient->setTerminateDefer(provider, false);
4058 				}
4059 			        started = nextService->reserved->uvars->started;
4060 			        nextService->reserved->uvars->serverDied = true;
4061 
4062 			        serviceDidStop(nextService, provider);
4063 			        if (provider != NULL && (terminateFlags & kIOServiceTerminateWithRematchCurrentDext) == 0) {
4064 			                provider->resetRematchProperties();
4065 				}
4066 			        if (started) {
4067 			                nextService->terminate(terminateFlags);
4068 				}
4069 			}
4070 			if (!started) {
4071 			        DKLOG("%s::terminate(" DKS ") server exit before start()\n", getName(), DKN(nextService));
4072 			        serviceStop(nextService, NULL);
4073 			}
4074 			return false;
4075 		});
4076 		services->release();
4077 	}
4078 
4079 	return IOUserClient::finalize(options);
4080 }
4081 
4082 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4083 
4084 #undef super
4085 #define super IOUserClient2022
4086 
4087 OSDefineMetaClassAndStructors(IOUserServer, IOUserClient2022)
4088 
4089 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4090 
4091 IOUserClient * IOUserServer::withTask(task_t owningTask)
4092 {
4093 	IOUserServer * inst;
4094 
4095 	assert(owningTask == current_task());
4096 	if (!task_is_driver(owningTask)) {
4097 		DKLOG("IOUserServer may only be created with driver tasks\n");
4098 		return NULL;
4099 	}
4100 
4101 	inst = new IOUserServer;
4102 	if (inst && !inst->init()) {
4103 		inst->release();
4104 		inst = NULL;
4105 		return inst;
4106 	}
4107 	OS_ANALYZER_SUPPRESS("82033761") inst->PMinit();
4108 
4109 	inst->fOwningTask = current_task();
4110 	task_reference(inst->fOwningTask);
4111 
4112 	inst->fEntitlements = IOUserClient::copyClientEntitlements(inst->fOwningTask);
4113 
4114 	if (!(kIODKDisableEntitlementChecking & gIODKDebug)) {
4115 		proc_t p;
4116 		pid_t  pid;
4117 		const char * name;
4118 		p = (proc_t)get_bsdtask_info(inst->fOwningTask);
4119 		if (p) {
4120 			name = proc_best_name(p);
4121 			pid = proc_pid(p);
4122 		} else {
4123 			name = "unknown";
4124 			pid = 0;
4125 		}
4126 
4127 		if (inst->fEntitlements == NULL) {
4128 #if DEVELOPMENT || DEBUG
4129 			panic("entitlements are missing for %s[%d]\n", name, pid);
4130 #else
4131 			DKLOG("entitlements are missing for %s[%d]\n", name, pid);
4132 #endif /* DEVELOPMENT || DEBUG */
4133 		}
4134 
4135 
4136 		const char * dextTeamID = csproc_get_teamid(p);
4137 		if (dextTeamID != NULL) {
4138 			inst->fTeamIdentifier = OSString::withCString(dextTeamID);
4139 			DKLOG("%s[%d] has team identifier %s\n", name, pid, dextTeamID);
4140 		}
4141 
4142 		if (!IOCurrentTaskHasEntitlement(gIODriverKitEntitlementKey->getCStringNoCopy())) {
4143 			IOLog(kIODriverKitEntitlementKey " entitlement check failed for %s[%d]\n", name, pid);
4144 			inst->release();
4145 			inst = NULL;
4146 			return inst;
4147 		}
4148 	}
4149 
4150 	/* Mark the current task's space as eligible for uext object ports */
4151 	iokit_label_dext_task(inst->fOwningTask);
4152 
4153 	inst->fLock     = IOLockAlloc();
4154 	inst->fServices = OSArray::withCapacity(4);
4155 	inst->fClasses  = OSDictionary::withCapacity(16);
4156 	inst->fClasses->setOptions(OSCollection::kSort, OSCollection::kSort);
4157 	inst->fPlatformDriver = task_get_platform_binary(inst->fOwningTask);
4158 	if (csproc_get_validation_category(current_proc(), &inst->fCSValidationCategory) != KERN_SUCCESS) {
4159 		inst->fCSValidationCategory = CS_VALIDATION_CATEGORY_INVALID;
4160 	}
4161 
4162 	inst->setProperty(kIOUserClientDefaultLockingKey, kOSBooleanTrue);
4163 	inst->setProperty(kIOUserClientDefaultLockingSetPropertiesKey, kOSBooleanTrue);
4164 	inst->setProperty(kIOUserClientDefaultLockingSingleThreadExternalMethodKey, kOSBooleanTrue);
4165 	//requirement for gIODriverKitEntitlementKey is enforced elsewhere conditionally
4166 	inst->setProperty(kIOUserClientEntitlementsKey, kOSBooleanFalse);
4167 
4168 	return inst;
4169 }
4170 
4171 static bool gIOUserServerLeakObjects = false;
4172 
4173 bool
4174 IOUserServer::shouldLeakObjects()
4175 {
4176 	return gIOUserServerLeakObjects;
4177 }
4178 
4179 void
4180 IOUserServer::beginLeakingObjects()
4181 {
4182 	gIOUserServerLeakObjects = true;
4183 }
4184 
4185 bool
4186 IOUserServer::isPlatformDriver()
4187 {
4188 	return fPlatformDriver;
4189 }
4190 
4191 int
4192 IOUserServer::getCSValidationCategory()
4193 {
4194 	return fCSValidationCategory;
4195 }
4196 
4197 
4198 struct IOUserServerRecordExitReasonContext {
4199 	task_t task;
4200 	os_reason_t reason;
4201 };
4202 
4203 static bool
4204 IOUserServerRecordExitReasonMatch(const OSObject *obj, void * context)
4205 {
4206 	IOUserServerRecordExitReasonContext * ctx = (IOUserServerRecordExitReasonContext *)context;
4207 	IOUserServer * us = OSDynamicCast(IOUserServer, obj);
4208 	if (us == NULL) {
4209 		return false;
4210 	}
4211 
4212 	if (us->fOwningTask == ctx->task) {
4213 		assert(us->fTaskCrashReason == OS_REASON_NULL);
4214 		assert(ctx->reason != OS_REASON_NULL);
4215 		os_reason_ref(ctx->reason);
4216 		us->fTaskCrashReason = ctx->reason;
4217 		return true;
4218 	}
4219 
4220 	return false;
4221 }
4222 
4223 extern "C" void
4224 IOUserServerRecordExitReason(task_t task, os_reason_t reason)
4225 {
4226 	IOUserServerRecordExitReasonContext ctx { task, reason };
4227 	IOUserServer::gMetaClass.applyToInstances(IOUserServerRecordExitReasonMatch, &ctx);
4228 }
4229 
4230 IOReturn
4231 IOUserServer::clientClose(void)
4232 {
4233 	OSArray   * services;
4234 	bool __block unexpectedExit = false;
4235 
4236 	if (kIODKLogSetup & gIODKDebug) {
4237 		DKLOG("%s::clientClose(%p)\n", getName(), this);
4238 	}
4239 	services = NULL;
4240 	IOLockLock(fLock);
4241 	if (fServices) {
4242 		services = OSArray::withArray(fServices);
4243 	}
4244 	IOLockUnlock(fLock);
4245 
4246 	// if this was a an expected exit, termination and stop should have detached at this
4247 	// point, so send any provider still attached and not owned by this user server
4248 	// the ClientCrashed() notification
4249 	if (services) {
4250 		services->iterateObjects(^bool (OSObject * obj) {
4251 			int         service __unused;       // hide outer defn
4252 			IOService * nextService;
4253 			IOService * provider;
4254 
4255 			nextService = (IOService *) obj;
4256 			if (nextService->isInactive()) {
4257 			        return false;
4258 			}
4259 			if (nextService->reserved && nextService->reserved->uvars && nextService->reserved->uvars->started) {
4260 			        unexpectedExit = true;
4261 			}
4262 			provider = nextService->getProvider();
4263 			if (provider
4264 			&& (!provider->reserved->uvars || (provider->reserved->uvars->userServer != this))) {
4265 			        if (kIODKLogSetup & gIODKDebug) {
4266 			                DKLOG(DKS "::ClientCrashed(" DKS ")\n", DKN(provider), DKN(nextService));
4267 				}
4268 			        if (unexpectedExit) {
4269 			                provider->unregisterAllInterrupts();
4270 				}
4271 			        provider->ClientCrashed(nextService, 0);
4272 			}
4273 			return false;
4274 		});
4275 		services->release();
4276 	}
4277 
4278 	if (unexpectedExit &&
4279 	    !gInUserspaceReboot &&
4280 	    (fTaskCrashReason != OS_REASON_NULL && fTaskCrashReason->osr_namespace != OS_REASON_JETSAM && fTaskCrashReason->osr_namespace != OS_REASON_RUNNINGBOARD) &&
4281 	    fStatistics != NULL) {
4282 		OSDextCrashPolicy policy = fStatistics->recordCrash();
4283 		bool allowPanic;
4284 #if DEVELOPMENT || DEBUG
4285 		allowPanic = !restore_boot && fPlatformDriver && fEntitlements->getObject(gIODriverKitTestDriverEntitlementKey) != kOSBooleanTrue && !disable_dext_crash_reboot;
4286 #else
4287 		allowPanic = !restore_boot && fPlatformDriver;
4288 #endif /* DEVELOPMENT || DEBUG */
4289 
4290 		if (policy == kOSDextCrashPolicyReboot && allowPanic) {
4291 			panic("Driver %s has crashed too many times\n", getName());
4292 		}
4293 	}
4294 
4295 	terminate();
4296 	return kIOReturnSuccess;
4297 }
4298 
4299 IOReturn
4300 IOUserServer::setProperties(OSObject * properties)
4301 {
4302 	IOReturn kr = kIOReturnUnsupported;
4303 	return kr;
4304 }
4305 
4306 void
4307 IOUserServer::stop(IOService * provider)
4308 {
4309 	if (fOwningTask) {
4310 		task_deallocate(fOwningTask);
4311 		fOwningTask = TASK_NULL;
4312 	}
4313 
4314 	PMstop();
4315 
4316 	IOServicePH::serverRemove(this);
4317 
4318 	OSSafeReleaseNULL(fRootQueue);
4319 
4320 	if (fInterruptLock) {
4321 		IOSimpleLockFree(fInterruptLock);
4322 	}
4323 }
4324 
4325 void
4326 IOUserServer::free()
4327 {
4328 	OSSafeReleaseNULL(fEntitlements);
4329 	OSSafeReleaseNULL(fClasses);
4330 	if (fOwningTask) {
4331 		task_deallocate(fOwningTask);
4332 		fOwningTask = TASK_NULL;
4333 	}
4334 	if (fLock) {
4335 		IOLockFree(fLock);
4336 	}
4337 	OSSafeReleaseNULL(fServices);
4338 	OSSafeReleaseNULL(fCheckInToken);
4339 	OSSafeReleaseNULL(fStatistics);
4340 	OSSafeReleaseNULL(fTeamIdentifier);
4341 	if (fAllocationName) {
4342 		kern_allocation_name_release(fAllocationName);
4343 		fAllocationName = NULL;
4344 	}
4345 	if (fTaskCrashReason != OS_REASON_NULL) {
4346 		os_reason_free(fTaskCrashReason);
4347 	}
4348 	IOUserClient::free();
4349 }
4350 
4351 IOReturn
4352 IOUserServer::registerClass(OSClassDescription * desc, uint32_t size, OSUserMetaClass ** pCls)
4353 {
4354 	OSUserMetaClass * cls;
4355 	const OSSymbol  * sym;
4356 	uint64_t        * methodOptions;
4357 	const char      * queueNames;
4358 	uint32_t          methodOptionsEnd, queueNamesEnd;
4359 	IOReturn          ret = kIOReturnSuccess;
4360 
4361 	if (size < sizeof(OSClassDescription)) {
4362 		assert(false);
4363 		return kIOReturnBadArgument;
4364 	}
4365 
4366 	if (kIODKLogSetup & gIODKDebug) {
4367 		DKLOG("%s::registerClass %s, %d, %d\n", getName(), desc->name, desc->queueNamesSize, desc->methodNamesSize);
4368 	}
4369 
4370 	if (desc->descriptionSize != size) {
4371 		assert(false);
4372 		return kIOReturnBadArgument;
4373 	}
4374 	if (os_add_overflow(desc->queueNamesOffset, desc->queueNamesSize, &queueNamesEnd)) {
4375 		assert(false);
4376 		return kIOReturnBadArgument;
4377 	}
4378 	if (queueNamesEnd > size) {
4379 		assert(false);
4380 		return kIOReturnBadArgument;
4381 	}
4382 	if (os_add_overflow(desc->methodOptionsOffset, desc->methodOptionsSize, &methodOptionsEnd)) {
4383 		assert(false);
4384 		return kIOReturnBadArgument;
4385 	}
4386 	if (methodOptionsEnd > size) {
4387 		assert(false);
4388 		return kIOReturnBadArgument;
4389 	}
4390 	// overlaps?
4391 	if ((desc->queueNamesOffset >= desc->methodOptionsOffset) && (desc->queueNamesOffset < methodOptionsEnd)) {
4392 		assert(false);
4393 		return kIOReturnBadArgument;
4394 	}
4395 	if ((queueNamesEnd >= desc->methodOptionsOffset) && (queueNamesEnd < methodOptionsEnd)) {
4396 		assert(false);
4397 		return kIOReturnBadArgument;
4398 	}
4399 
4400 	if (desc->methodOptionsSize & ((2 * sizeof(uint64_t)) - 1)) {
4401 		assert(false);
4402 		return kIOReturnBadArgument;
4403 	}
4404 	if (sizeof(desc->name) == strnlen(desc->name, sizeof(desc->name))) {
4405 		assert(false);
4406 		return kIOReturnBadArgument;
4407 	}
4408 	if (sizeof(desc->superName) == strnlen(desc->superName, sizeof(desc->superName))) {
4409 		assert(false);
4410 		return kIOReturnBadArgument;
4411 	}
4412 
4413 	cls = OSTypeAlloc(OSUserMetaClass);
4414 	assert(cls);
4415 	if (!cls) {
4416 		return kIOReturnNoMemory;
4417 	}
4418 
4419 	cls->description = (typeof(cls->description))IOMallocData(size);
4420 	assert(cls->description);
4421 	if (!cls->description) {
4422 		assert(false);
4423 		cls->release();
4424 		return kIOReturnNoMemory;
4425 	}
4426 	bcopy(desc, cls->description, size);
4427 
4428 	cls->methodCount = desc->methodOptionsSize / (2 * sizeof(uint64_t));
4429 	cls->methods = IONewData(uint64_t, 2 * cls->methodCount);
4430 	if (!cls->methods) {
4431 		assert(false);
4432 		cls->release();
4433 		return kIOReturnNoMemory;
4434 	}
4435 
4436 	methodOptions = (typeof(methodOptions))(((uintptr_t) desc) + desc->methodOptionsOffset);
4437 	bcopy(methodOptions, cls->methods, 2 * cls->methodCount * sizeof(uint64_t));
4438 
4439 	queueNames = (typeof(queueNames))(((uintptr_t) desc) + desc->queueNamesOffset);
4440 	cls->queueNames = copyInStringArray(queueNames, desc->queueNamesSize);
4441 
4442 	sym = OSSymbol::withCString(desc->name);
4443 	assert(sym);
4444 	if (!sym) {
4445 		assert(false);
4446 		cls->release();
4447 		return kIOReturnNoMemory;
4448 	}
4449 
4450 	cls->name = sym;
4451 	cls->meta = OSMetaClass::copyMetaClassWithName(sym);
4452 	IOLockLock(fLock);
4453 	cls->superMeta = OSDynamicCast(OSUserMetaClass, fClasses->getObject(desc->superName));
4454 	if (fClasses->getObject(sym) != NULL) {
4455 		/* class with this name exists */
4456 		ret = kIOReturnBadArgument;
4457 	} else {
4458 		if (fClasses->setObject(sym, cls)) {
4459 			*pCls = cls;
4460 		} else {
4461 			/* could not add class to fClasses */
4462 			ret = kIOReturnNoMemory;
4463 		}
4464 	}
4465 	IOLockUnlock(fLock);
4466 	cls->release();
4467 	return ret;
4468 }
4469 
4470 IOReturn
4471 IOUserServer::registerClass(OSClassDescription * desc, uint32_t size, OSSharedPtr<OSUserMetaClass>& pCls)
4472 {
4473 	OSUserMetaClass* pClsRaw = NULL;
4474 	IOReturn result = registerClass(desc, size, &pClsRaw);
4475 	if (result == kIOReturnSuccess) {
4476 		pCls.reset(pClsRaw, OSRetain);
4477 	}
4478 	return result;
4479 }
4480 
4481 IOReturn
4482 IOUserServer::setRootQueue(IODispatchQueue * queue)
4483 {
4484 	assert(!fRootQueue);
4485 	if (fRootQueue) {
4486 		return kIOReturnStillOpen;
4487 	}
4488 	queue->retain();
4489 	fRootQueue = queue;
4490 
4491 	return kIOReturnSuccess;
4492 }
4493 
4494 
4495 IOReturn
4496 IOUserServer::externalMethod(uint32_t selector, IOExternalMethodArgumentsOpaque * args)
4497 {
4498 	static const IOExternalMethodDispatch2022 dispatchArray[] = {
4499 		[kIOUserServerMethodRegisterClass] = {
4500 			.function                 = &IOUserServer::externalMethodRegisterClass,
4501 			.checkScalarInputCount    = 0,
4502 			.checkStructureInputSize  = kIOUCVariableStructureSize,
4503 			.checkScalarOutputCount   = 2,
4504 			.checkStructureOutputSize = 0,
4505 			.allowAsync               = false,
4506 			.checkEntitlement         = NULL,
4507 		},
4508 		[kIOUserServerMethodStart] = {
4509 			.function                 = &IOUserServer::externalMethodStart,
4510 			.checkScalarInputCount    = 1,
4511 			.checkStructureInputSize  = 0,
4512 			.checkScalarOutputCount   = 1,
4513 			.checkStructureOutputSize = 0,
4514 			.allowAsync               = false,
4515 			.checkEntitlement         = NULL,
4516 		},
4517 	};
4518 
4519 	return dispatchExternalMethod(selector, args, dispatchArray, sizeof(dispatchArray) / sizeof(dispatchArray[0]), this, NULL);
4520 }
4521 
4522 IOReturn
4523 IOUserServer::externalMethodRegisterClass(OSObject * target, void * reference, IOExternalMethodArguments * args)
4524 {
4525 	IOReturn ret = kIOReturnBadArgument;
4526 	mach_port_name_t portname;
4527 
4528 	IOUserServer * me = (typeof(me))target;
4529 
4530 	OSUserMetaClass * cls;
4531 	if (!args->structureInputSize) {
4532 		return kIOReturnBadArgument;
4533 	}
4534 
4535 	ret = me->registerClass((OSClassDescription *) args->structureInput, args->structureInputSize, &cls);
4536 	if (kIOReturnSuccess == ret) {
4537 		portname = iokit_make_send_right(me->fOwningTask, cls, IKOT_UEXT_OBJECT);
4538 		assert(portname);
4539 		args->scalarOutput[0] = portname;
4540 		args->scalarOutput[1] = kOSObjectRPCRemote;
4541 	}
4542 
4543 	return ret;
4544 }
4545 
4546 IOReturn
4547 IOUserServer::externalMethodStart(OSObject * target, void * reference, IOExternalMethodArguments * args)
4548 {
4549 	mach_port_name_t portname = 0;
4550 	IOReturn ret = kIOReturnSuccess;
4551 
4552 	IOUserServer * me = (typeof(me))target;
4553 
4554 	if (!(kIODKDisableCheckInTokenVerification & gIODKDebug)) {
4555 		mach_port_name_t checkInPortName = ((typeof(checkInPortName))args->scalarInput[0]);
4556 		OSObject * obj = iokit_lookup_object_with_port_name(checkInPortName, IKOT_IOKIT_IDENT, me->fOwningTask);
4557 		IOUserServerCheckInToken * retrievedToken = OSDynamicCast(IOUserServerCheckInToken, obj);
4558 		if (retrievedToken != NULL) {
4559 			ret = me->setCheckInToken(retrievedToken);
4560 		} else {
4561 			ret = kIOReturnBadArgument;
4562 		}
4563 		OSSafeReleaseNULL(obj);
4564 	}
4565 	if (ret == kIOReturnSuccess) {
4566 		portname = iokit_make_send_right(me->fOwningTask, me, IKOT_UEXT_OBJECT);
4567 		assert(portname);
4568 	}
4569 	args->scalarOutput[0] = portname;
4570 	return ret;
4571 }
4572 IOExternalTrap *
4573 IOUserServer::getTargetAndTrapForIndex( IOService **targetP, UInt32 index )
4574 {
4575 	static const OSBoundedArray<IOExternalTrap, 1> trapTemplate = {{
4576 									       { NULL, (IOTrap) & IOUserServer::waitInterruptTrap},
4577 								       }};
4578 	if (index >= trapTemplate.size()) {
4579 		return NULL;
4580 	}
4581 	*targetP = this;
4582 	return (IOExternalTrap *)&trapTemplate[index];
4583 }
4584 
4585 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4586 
4587 IOReturn
4588 IOUserServer::serviceAttach(IOService * service, IOService * provider)
4589 {
4590 	IOReturn           ret;
4591 	OSObjectUserVars * vars;
4592 	OSObject         * prop;
4593 	OSString         * str;
4594 	OSSymbol const*   bundleID;
4595 	char               execPath[1024];
4596 
4597 	vars = IOMallocType(OSObjectUserVars);
4598 	service->reserved->uvars = vars;
4599 
4600 	vars->userServer = this;
4601 	vars->userServer->retain();
4602 	vars->uvarsLock = IOLockAlloc();
4603 	IOLockLock(fLock);
4604 	if (-1U == fServices->getNextIndexOfObject(service, 0)) {
4605 		fServices->setObject(service);
4606 
4607 		// Add to IOAssociatedServices
4608 		OSObject * serviceArrayObj = copyProperty(gIOAssociatedServicesKey);
4609 		OSArray * serviceArray = OSDynamicCast(OSArray, serviceArrayObj);
4610 		if (!serviceArray) {
4611 			serviceArray = OSArray::withCapacity(0);
4612 		} else {
4613 			serviceArray = OSDynamicCast(OSArray, serviceArray->copyCollection());
4614 			assert(serviceArray != NULL);
4615 		}
4616 
4617 		OSNumber * registryEntryNumber = OSNumber::withNumber(service->getRegistryEntryID(), 64);
4618 		serviceArray->setObject(registryEntryNumber);
4619 		setProperty(gIOAssociatedServicesKey, serviceArray);
4620 		OSSafeReleaseNULL(registryEntryNumber);
4621 		OSSafeReleaseNULL(serviceArray);
4622 		OSSafeReleaseNULL(serviceArrayObj);
4623 
4624 		// populate kIOUserClassesKey
4625 
4626 		OSUserMetaClass * userMeta;
4627 		OSArray         * classesArray;
4628 		const OSString  * str2;
4629 
4630 		classesArray = OSArray::withCapacity(4);
4631 		prop = service->copyProperty(gIOUserClassKey);
4632 		str2 = OSDynamicCast(OSString, prop);
4633 		userMeta = (typeof(userMeta))service->reserved->uvars->userServer->fClasses->getObject(str2);
4634 		while (str2 && userMeta) {
4635 			classesArray->setObject(str2);
4636 			userMeta = userMeta->superMeta;
4637 			if (userMeta) {
4638 				str2 = userMeta->name;
4639 			}
4640 		}
4641 		service->setProperty(gIOUserClassesKey, classesArray);
4642 		OSSafeReleaseNULL(classesArray);
4643 		OSSafeReleaseNULL(prop);
4644 	}
4645 	IOLockUnlock(fLock);
4646 
4647 	prop = service->copyProperty(gIOUserClassKey);
4648 	str = OSDynamicCast(OSString, prop);
4649 	if (str) {
4650 		service->setName(str);
4651 	}
4652 	OSSafeReleaseNULL(prop);
4653 
4654 	prop = service->copyProperty(gIOModuleIdentifierKey);
4655 	bundleID = OSDynamicCast(OSSymbol, prop);
4656 	if (bundleID) {
4657 		execPath[0] = 0;
4658 		bool ok = OSKext::copyUserExecutablePath(bundleID, execPath, sizeof(execPath));
4659 		if (ok) {
4660 			ret = LoadModule(execPath);
4661 			if (kIODKLogSetup & gIODKDebug) {
4662 				DKLOG("%s::LoadModule 0x%x %s\n", getName(), ret, execPath);
4663 			}
4664 		}
4665 	}
4666 	OSSafeReleaseNULL(prop);
4667 
4668 	ret = kIOReturnSuccess;
4669 
4670 	return ret;
4671 }
4672 
4673 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4674 
4675 IOReturn
4676 IOUserServer::serviceNewUserClient(IOService * service, task_t owningTask, void * securityID,
4677     uint32_t type, OSDictionary * properties, IOUserClient ** handler)
4678 {
4679 	IOReturn           ret;
4680 	IOUserClient     * uc;
4681 	IOUserUserClient * userUC;
4682 	OSDictionary     * entitlements;
4683 	OSObject         * prop;
4684 	OSObject         * bundleID;
4685 	bool               ok = false;
4686 
4687 	entitlements = IOUserClient::copyClientEntitlements(owningTask);
4688 	if (!entitlements) {
4689 		entitlements = OSDictionary::withCapacity(8);
4690 	}
4691 	if (entitlements) {
4692 		if (kIOReturnSuccess == clientHasPrivilege((void *) owningTask, kIOClientPrivilegeAdministrator)) {
4693 			entitlements->setObject(kIODriverKitUserClientEntitlementAdministratorKey, kOSBooleanTrue);
4694 		}
4695 		OSString * creatorName = IOCopyLogNameForPID(proc_selfpid());
4696 		if (creatorName) {
4697 			entitlements->setObject(kIOUserClientCreatorKey, creatorName);
4698 			OSSafeReleaseNULL(creatorName);
4699 		}
4700 	}
4701 
4702 	*handler = NULL;
4703 	ret = service->_NewUserClient(type, entitlements, &uc);
4704 	if (kIOReturnSuccess != ret) {
4705 		OSSafeReleaseNULL(entitlements);
4706 		return ret;
4707 	}
4708 	userUC = OSDynamicCast(IOUserUserClient, uc);
4709 	if (!userUC) {
4710 		uc->terminate(kIOServiceTerminateNeedWillTerminate);
4711 		uc->setTerminateDefer(service, false);
4712 		OSSafeReleaseNULL(uc);
4713 		OSSafeReleaseNULL(entitlements);
4714 		return kIOReturnUnsupported;
4715 	}
4716 	userUC->setTask(owningTask);
4717 
4718 	if (!(kIODKDisableEntitlementChecking & gIODKDebug)) {
4719 		do {
4720 			bool checkiOS3pEntitlements;
4721 
4722 			// check if client has com.apple.private.driverkit.driver-access and the required entitlements match the driver's entitlements
4723 			if (entitlements && (prop = entitlements->getObject(gIODriverKitRequiredEntitlementsKey))) {
4724 				prop->retain();
4725 				ok = checkEntitlements(fEntitlements, prop, NULL, NULL);
4726 				if (ok) {
4727 					break;
4728 				} else {
4729 					DKLOG(DKS ":UC failed required entitlement check\n", DKN(userUC));
4730 				}
4731 			}
4732 
4733 #if XNU_TARGET_OS_IOS
4734 			checkiOS3pEntitlements = !fPlatformDriver;
4735 			if (checkiOS3pEntitlements && fTeamIdentifier == NULL) {
4736 				DKLOG("warning: " DKS " does not have a team identifier\n", DKN(this));
4737 			}
4738 #else
4739 			checkiOS3pEntitlements = false;
4740 #endif
4741 			if (checkiOS3pEntitlements) {
4742 				// App must have com.apple.developer.driverkit.communicates-with-drivers
4743 				ok = entitlements && entitlements->getObject(gIODriverKitUserClientEntitlementCommunicatesWithDriversKey) == kOSBooleanTrue;
4744 				if (ok) {
4745 					// check team ID
4746 					const char * clientTeamID = csproc_get_teamid(current_proc());
4747 					bool sameTeam = fTeamIdentifier != NULL && clientTeamID != NULL && strncmp(fTeamIdentifier->getCStringNoCopy(), clientTeamID, CS_MAX_TEAMID_LEN) == 0;
4748 
4749 					if (sameTeam) {
4750 						ok = true;
4751 					} else {
4752 						// different team IDs, dext must have com.apple.developer.driverkit.allow-third-party-userclients
4753 						ok = fEntitlements && fEntitlements->getObject(gIODriverKitUserClientEntitlementAllowThirdPartyUserClientsKey) == kOSBooleanTrue;
4754 					}
4755 					if (!ok) {
4756 						DKLOG(DKS ":UC failed team ID check. client team=%s, driver team=%s\n", DKN(userUC), clientTeamID ? clientTeamID : "(null)", fTeamIdentifier ? fTeamIdentifier->getCStringNoCopy() : "(null)");
4757 					}
4758 				} else {
4759 					DKLOG(DKS ":UC entitlement check failed, app does not have %s entitlement\n", DKN(userUC), gIODriverKitUserClientEntitlementCommunicatesWithDriversKey->getCStringNoCopy());
4760 				}
4761 
4762 				// When checking iOS 3rd party entitlements, do not fall through to other entitlement checks
4763 				break;
4764 			}
4765 
4766 			// first party dexts and third party macOS dexts
4767 
4768 			// check if driver has com.apple.developer.driverkit.allow-any-userclient-access
4769 			if (fEntitlements && fEntitlements->getObject(gIODriverKitUserClientEntitlementAllowAnyKey)) {
4770 				ok = true;
4771 				break;
4772 			}
4773 
4774 			// check if client has com.apple.developer.driverkit.userclient-access and its value matches the bundle ID of the service
4775 			bundleID = service->copyProperty(gIOModuleIdentifierKey);
4776 			ok = (entitlements
4777 			    && bundleID
4778 			    && (prop = entitlements->getObject(gIODriverKitUserClientEntitlementsKey)));
4779 			if (ok) {
4780 				bool found __block = false;
4781 				ok = prop->iterateObjects(^bool (OSObject * object) {
4782 					found = object->isEqualTo(bundleID);
4783 					return found;
4784 				});
4785 				ok = found;
4786 			} else {
4787 				OSString * bundleIDStr = OSDynamicCast(OSString, bundleID);
4788 				DKLOG(DKS ":UC failed userclient-access check, needed bundle ID %s\n", DKN(userUC), bundleIDStr ? bundleIDStr->getCStringNoCopy() : "(null)");
4789 			}
4790 			OSSafeReleaseNULL(bundleID);
4791 		} while (false);
4792 
4793 		if (ok) {
4794 			prop = userUC->copyProperty(gIOServiceDEXTEntitlementsKey);
4795 			ok = checkEntitlements(entitlements, prop, NULL, NULL);
4796 		}
4797 
4798 		if (!ok) {
4799 			DKLOG(DKS ":UC entitlements check failed\n", DKN(userUC));
4800 			uc->terminate(kIOServiceTerminateNeedWillTerminate);
4801 			uc->setTerminateDefer(service, false);
4802 			OSSafeReleaseNULL(uc);
4803 			OSSafeReleaseNULL(entitlements);
4804 			return kIOReturnNotPermitted;
4805 		}
4806 	}
4807 
4808 	OSSafeReleaseNULL(entitlements);
4809 	*handler = userUC;
4810 
4811 	return ret;
4812 }
4813 
4814 IOReturn
4815 IOUserServer::serviceNewUserClient(IOService * service, task_t owningTask, void * securityID,
4816     uint32_t type, OSDictionary * properties, OSSharedPtr<IOUserClient>& handler)
4817 {
4818 	IOUserClient* handlerRaw = NULL;
4819 	IOReturn result = serviceNewUserClient(service, owningTask, securityID, type, properties, &handlerRaw);
4820 	handler.reset(handlerRaw, OSNoRetain);
4821 	return result;
4822 }
4823 
4824 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4825 
4826 static IOPMPowerState
4827     sPowerStates[] = {
4828 	{   .version                = kIOPMPowerStateVersion1,
4829 	    .capabilityFlags        = 0,
4830 	    .outputPowerCharacter   = 0,
4831 	    .inputPowerRequirement  = 0},
4832 	{   .version                = kIOPMPowerStateVersion1,
4833 	    .capabilityFlags        = kIOPMLowPower,
4834 	    .outputPowerCharacter   = kIOPMLowPower,
4835 	    .inputPowerRequirement  = kIOPMLowPower},
4836 	{   .version                = kIOPMPowerStateVersion1,
4837 	    .capabilityFlags        = kIOPMPowerOn,
4838 	    .outputPowerCharacter   = kIOPMPowerOn,
4839 	    .inputPowerRequirement  = kIOPMPowerOn},
4840 };
4841 
4842 enum {
4843 	kUserServerMaxPowerState    = 2
4844 };
4845 
4846 IOReturn
4847 IOUserServer::serviceJoinPMTree(IOService * service)
4848 {
4849 	IOReturn    ret;
4850 	IOService * pmProvider;
4851 	bool        joinTree;
4852 
4853 	if (service->reserved->uvars->userServerPM) {
4854 		return kIOReturnSuccess;
4855 	}
4856 
4857 	if (!fRootNotifier) {
4858 		ret = registerPowerDriver(this, sPowerStates, sizeof(sPowerStates) / sizeof(sPowerStates[0]));
4859 		assert(kIOReturnSuccess == ret);
4860 		IOServicePH::serverAdd(this);
4861 		fRootNotifier = true;
4862 	}
4863 
4864 	joinTree = false;
4865 	if (!(kIODKDisablePM & gIODKDebug) && !service->pm_vars) {
4866 		kern_return_t  kr;
4867 		OSDictionary * props;
4868 		kr = service->CopyProperties_Local(&props);
4869 		if (kIOReturnSuccess == kr) {
4870 			if (props->getObject(kIOPMResetPowerStateOnWakeKey) == kOSBooleanTrue) {
4871 				service->setProperty(kIOPMResetPowerStateOnWakeKey, kOSBooleanTrue);
4872 			}
4873 			OSSafeReleaseNULL(props);
4874 		}
4875 		service->PMinit();
4876 		ret = service->registerPowerDriver(this, sPowerStates, sizeof(sPowerStates) / sizeof(sPowerStates[0]));
4877 		assert(kIOReturnSuccess == ret);
4878 		joinTree = true;
4879 	}
4880 
4881 	pmProvider = service;
4882 	while (pmProvider && !pmProvider->inPlane(gIOPowerPlane)) {
4883 		pmProvider = pmProvider->getProvider();
4884 	}
4885 	if (!pmProvider) {
4886 		pmProvider = getPMRootDomain();
4887 	}
4888 	if (pmProvider) {
4889 		IOService * entry;
4890 		OSObject  * prop;
4891 		OSObject  * nextProp;
4892 		OSString  * str;
4893 
4894 		entry = pmProvider;
4895 		prop  = NULL;
4896 		do {
4897 			nextProp = entry->copyProperty("non-removable");
4898 			if (nextProp) {
4899 				OSSafeReleaseNULL(prop);
4900 				prop = nextProp;
4901 			}
4902 			entry = entry->getProvider();
4903 		} while (entry);
4904 		if (prop) {
4905 			str = OSDynamicCast(OSString, prop);
4906 			if (str && str->isEqualTo("yes")) {
4907 				pmProvider = NULL;
4908 			}
4909 			prop->release();
4910 		}
4911 	}
4912 
4913 	if (!(kIODKDisablePM & gIODKDebug) && pmProvider) {
4914 		IOLockLock(fLock);
4915 		service->reserved->uvars->powerState = true;
4916 		IOLockUnlock(fLock);
4917 
4918 		if (joinTree) {
4919 			pmProvider->joinPMtree(service);
4920 			service->reserved->uvars->userServerPM = true;
4921 			service->reserved->uvars->resetPowerOnWake = service->propertyExists(kIOPMResetPowerStateOnWakeKey);
4922 		}
4923 	}
4924 
4925 	service->registerInterestedDriver(this);
4926 	return kIOReturnSuccess;
4927 }
4928 
4929 IOReturn
4930 IOUserServer::setPowerState(unsigned long state, IOService * service)
4931 {
4932 	if (kIODKLogPM & gIODKDebug) {
4933 		DKLOG(DKS "::setPowerState(%ld) %d\n", DKN(service), state, fSystemPowerAck);
4934 	}
4935 	return kIOPMAckImplied;
4936 }
4937 
4938 
4939 IOReturn
4940 IOUserServer::serviceSetPowerState(IOService * controllingDriver, IOService * service, IOPMPowerFlags flags, unsigned long state)
4941 {
4942 	IOReturn ret;
4943 	bool sendIt = false;
4944 
4945 	IOLockLock(fLock);
4946 	if (service->reserved->uvars) {
4947 		if (!fSystemOff && !(kIODKDisablePM & gIODKDebug)) {
4948 			OSDictionary * wakeDescription;
4949 			OSObject     * prop;
4950 			char           wakeReasonString[128];
4951 
4952 			wakeDescription = OSDictionary::withCapacity(4);
4953 			if (wakeDescription) {
4954 				wakeReasonString[0] = 0;
4955 				getPMRootDomain()->copyWakeReasonString(wakeReasonString, sizeof(wakeReasonString));
4956 
4957 				if (wakeReasonString[0]) {
4958 					prop = OSString::withCString(&wakeReasonString[0]);
4959 					wakeDescription->setObject(gIOSystemStateWakeDescriptionWakeReasonKey, prop);
4960 					OSSafeReleaseNULL(prop);
4961 				}
4962 #if defined(__arm__) || defined(__arm64__)
4963 				prop = OSNumber::withNumber(ml_get_conttime_offset(), sizeof(uint64_t) * CHAR_BIT);
4964 				wakeDescription->setObject(gIOSystemStateWakeDescriptionContinuousTimeOffsetKey, prop);
4965 				OSSafeReleaseNULL(prop);
4966 #endif /* defined(__arm__) || defined(__arm64__) */
4967 				getSystemStateNotificationService()->StateNotificationItemSet(gIOSystemStateWakeDescriptionKey, wakeDescription);
4968 				OSSafeReleaseNULL(wakeDescription);
4969 			}
4970 
4971 			service->reserved->uvars->willPower = true;
4972 			service->reserved->uvars->willPowerState = state;
4973 			service->reserved->uvars->controllingDriver = controllingDriver;
4974 			sendIt = true;
4975 		} else {
4976 			service->reserved->uvars->willPower = false;
4977 		}
4978 	}
4979 	IOLockUnlock(fLock);
4980 
4981 	if (sendIt) {
4982 		if (kIODKLogPM & gIODKDebug) {
4983 			DKLOG(DKS "::serviceSetPowerState(%ld) %d\n", DKN(service), state, fSystemPowerAck);
4984 		}
4985 		ret = service->SetPowerState((uint32_t) flags);
4986 		if (kIOReturnSuccess == ret) {
4987 			return 20 * 1000 * 1000;
4988 		} else {
4989 			IOLockLock(fLock);
4990 			service->reserved->uvars->willPower = false;
4991 			IOLockUnlock(fLock);
4992 		}
4993 	}
4994 
4995 	return kIOPMAckImplied;
4996 }
4997 
4998 IOReturn
4999 IOUserServer::powerStateWillChangeTo(IOPMPowerFlags flags, unsigned long state, IOService * service)
5000 {
5001 	return kIOPMAckImplied;
5002 }
5003 
5004 IOReturn
5005 IOUserServer::powerStateDidChangeTo(IOPMPowerFlags flags, unsigned long state, IOService * service)
5006 {
5007 	unsigned int idx;
5008 	bool         pmAck;
5009 
5010 	pmAck = false;
5011 	IOLockLock(fLock);
5012 	idx = fServices->getNextIndexOfObject(service, 0);
5013 	if (-1U == idx) {
5014 		IOLockUnlock(fLock);
5015 		return kIOPMAckImplied;
5016 	}
5017 
5018 	service->reserved->uvars->powerState = (0 != state);
5019 	bool allPowerStates __block = service->reserved->uvars->powerState;
5020 	if (!allPowerStates) {
5021 		// any service on?
5022 		fServices->iterateObjects(^bool (OSObject * obj) {
5023 			int         service __unused;       // hide outer defn
5024 			IOService * nextService;
5025 			nextService = (IOService *) obj;
5026 			allPowerStates = nextService->reserved->uvars->powerState;
5027 			// early terminate if true
5028 			return allPowerStates;
5029 		});
5030 	}
5031 	if (kIODKLogPM & gIODKDebug) {
5032 		DKLOG(DKS "::powerStateDidChangeTo(%ld) %d, %d\n", DKN(service), state, allPowerStates, fSystemPowerAck);
5033 	}
5034 	if (!allPowerStates && (pmAck = fSystemPowerAck)) {
5035 		fSystemPowerAck = false;
5036 		fSystemOff      = true;
5037 	}
5038 	IOLockUnlock(fLock);
5039 
5040 	if (pmAck) {
5041 		IOServicePH::serverAck(this);
5042 	}
5043 
5044 	return kIOPMAckImplied;
5045 }
5046 
5047 bool
5048 IOUserServer::checkPMReady()
5049 {
5050 	bool __block ready = true;
5051 
5052 	IOLockLock(fLock);
5053 	// Check if any services have not completely joined the PM tree (i.e.
5054 	// addPowerChild has not compeleted).
5055 	fServices->iterateObjects(^bool (OSObject * obj) {
5056 		IOPowerConnection *conn;
5057 		IOService *service = (IOService *) obj;
5058 		IORegistryEntry *parent = service->getParentEntry(gIOPowerPlane);
5059 		if ((conn = OSDynamicCast(IOPowerConnection, parent))) {
5060 		        if (!conn->getReadyFlag()) {
5061 		                ready = false;
5062 		                return true;
5063 			}
5064 		}
5065 		return false;
5066 	});
5067 	IOLockUnlock(fLock);
5068 
5069 	return ready;
5070 }
5071 
5072 kern_return_t
5073 IOService::JoinPMTree_Impl(void)
5074 {
5075 	if (!reserved->uvars || !reserved->uvars->userServer) {
5076 		return kIOReturnNotReady;
5077 	}
5078 	return reserved->uvars->userServer->serviceJoinPMTree(this);
5079 }
5080 
5081 kern_return_t
5082 IOService::SetPowerState_Impl(
5083 	uint32_t powerFlags)
5084 {
5085 	if (kIODKLogPM & gIODKDebug) {
5086 		DKLOG(DKS "::SetPowerState(%d), %d\n", DKN(this), powerFlags, reserved->uvars->willPower);
5087 	}
5088 	if (reserved->uvars
5089 	    && reserved->uvars->userServer
5090 	    && reserved->uvars->willPower) {
5091 		IOReturn ret;
5092 		reserved->uvars->willPower = false;
5093 		ret = reserved->uvars->controllingDriver->setPowerState(reserved->uvars->willPowerState, this);
5094 		if (kIOPMAckImplied == ret) {
5095 			acknowledgeSetPowerState();
5096 		}
5097 		return kIOReturnSuccess;
5098 	}
5099 	return kIOReturnNotReady;
5100 }
5101 
5102 kern_return_t
5103 IOService::ChangePowerState_Impl(
5104 	uint32_t powerFlags)
5105 {
5106 	switch (powerFlags) {
5107 	case kIOServicePowerCapabilityOff:
5108 		changePowerStateToPriv(0);
5109 		break;
5110 	case kIOServicePowerCapabilityLow:
5111 		changePowerStateToPriv(1);
5112 		break;
5113 	case kIOServicePowerCapabilityOn:
5114 		changePowerStateToPriv(2);
5115 		break;
5116 	default:
5117 		return kIOReturnBadArgument;
5118 	}
5119 
5120 	return kIOReturnSuccess;
5121 }
5122 
5123 kern_return_t
5124 IOService::_ClaimSystemWakeEvent_Impl(
5125 	IOService          * device,
5126 	uint64_t             flags,
5127 	const char         * reason,
5128 	OSContainer        * details)
5129 {
5130 	IOPMrootDomain * rootDomain;
5131 	IOOptionBits     pmFlags;
5132 
5133 	rootDomain = getPMRootDomain();
5134 	if (!rootDomain) {
5135 		return kIOReturnNotReady;
5136 	}
5137 	if (os_convert_overflow(flags, &pmFlags)) {
5138 		return kIOReturnBadArgument;
5139 	}
5140 	rootDomain->claimSystemWakeEvent(device, pmFlags, reason, details);
5141 
5142 	return kIOReturnSuccess;
5143 }
5144 
5145 kern_return_t
5146 IOService::Create_Impl(
5147 	IOService * provider,
5148 	const char * propertiesKey,
5149 	IOService ** result)
5150 {
5151 	OSObject       * inst;
5152 	IOService      * service;
5153 	OSString       * str;
5154 	const OSSymbol * sym;
5155 	OSObject       * prop = NULL;
5156 	OSObject       * moduleIdentifier = NULL;
5157 	OSObject       * userServerName = NULL;
5158 	OSDictionary   * properties = NULL;
5159 	OSDictionary   * copyProperties = NULL;
5160 	kern_return_t    ret;
5161 
5162 	if (provider != this) {
5163 		return kIOReturnUnsupported;
5164 	}
5165 
5166 	ret = kIOReturnUnsupported;
5167 	inst = NULL;
5168 	service = NULL;
5169 
5170 	prop = copyProperty(propertiesKey);
5171 	properties = OSDynamicCast(OSDictionary, prop);
5172 	if (!properties) {
5173 		ret = kIOReturnBadArgument;
5174 		goto finish;
5175 	}
5176 	copyProperties = OSDynamicCast(OSDictionary, properties->copyCollection());
5177 	if (!copyProperties) {
5178 		ret = kIOReturnNoMemory;
5179 		goto finish;
5180 	}
5181 	moduleIdentifier = copyProperty(gIOModuleIdentifierKey);
5182 	if (moduleIdentifier) {
5183 		copyProperties->setObject(gIOModuleIdentifierKey, moduleIdentifier);
5184 	}
5185 	userServerName = reserved->uvars->userServer->copyProperty(gIOUserServerNameKey);
5186 	if (userServerName) {
5187 		copyProperties->setObject(gIOUserServerNameKey, userServerName);
5188 	}
5189 
5190 	str = OSDynamicCast(OSString, copyProperties->getObject(gIOClassKey));
5191 	if (!str) {
5192 		ret = kIOReturnBadArgument;
5193 		goto finish;
5194 	}
5195 	sym = OSSymbol::withString(str);
5196 	if (sym) {
5197 		inst = OSMetaClass::allocClassWithName(sym);
5198 		service = OSDynamicCast(IOService, inst);
5199 		if (service && service->init(copyProperties) && service->attach(this)) {
5200 			reserved->uvars->userServer->serviceAttach(service, this);
5201 			service->reserved->uvars->started = true;
5202 			ret = kIOReturnSuccess;
5203 			*result = service;
5204 		}
5205 		OSSafeReleaseNULL(sym);
5206 	}
5207 
5208 finish:
5209 	OSSafeReleaseNULL(prop);
5210 	OSSafeReleaseNULL(copyProperties);
5211 	OSSafeReleaseNULL(moduleIdentifier);
5212 	OSSafeReleaseNULL(userServerName);
5213 	if (kIOReturnSuccess != ret) {
5214 		OSSafeReleaseNULL(inst);
5215 	}
5216 
5217 	return ret;
5218 }
5219 
5220 kern_return_t
5221 IOService::Terminate_Impl(
5222 	uint64_t options)
5223 {
5224 	IOUserServer * us;
5225 
5226 	if (options) {
5227 		return kIOReturnUnsupported;
5228 	}
5229 
5230 	us = (typeof(us))thread_iokit_tls_get(0);
5231 	if (us && (!reserved->uvars
5232 	    || (reserved->uvars->userServer != us))) {
5233 		return kIOReturnNotPermitted;
5234 	}
5235 	terminate(kIOServiceTerminateNeedWillTerminate);
5236 
5237 	return kIOReturnSuccess;
5238 }
5239 
5240 kern_return_t
5241 IOService::NewUserClient_Impl(
5242 	uint32_t type,
5243 	IOUserClient ** userClient)
5244 {
5245 	return kIOReturnError;
5246 }
5247 
5248 kern_return_t
5249 IOService::_NewUserClient_Impl(
5250 	uint32_t type,
5251 	OSDictionary * entitlements,
5252 	IOUserClient ** userClient)
5253 {
5254 	return kIOReturnError;
5255 }
5256 
5257 kern_return_t
5258 IOService::SearchProperty_Impl(
5259 	const char * name,
5260 	const char * plane,
5261 	uint64_t options,
5262 	OSContainer ** property)
5263 {
5264 	OSObject   * object __block;
5265 	IOService  * provider;
5266 	IOOptionBits regOptions;
5267 
5268 	if (kIOServiceSearchPropertyParents & options) {
5269 		regOptions = kIORegistryIterateParents | kIORegistryIterateRecursively;
5270 	} else {
5271 		regOptions = 0;
5272 	}
5273 
5274 	object = copyProperty(name, IORegistryEntry::getPlane(plane), regOptions);
5275 
5276 	if (NULL == object) {
5277 		for (provider = this; provider; provider = provider->getProvider()) {
5278 			provider->runPropertyActionBlock(^IOReturn (void) {
5279 				OSDictionary * userProps;
5280 				object = provider->getProperty(name);
5281 				if (!object
5282 				&& (userProps = OSDynamicCast(OSDictionary, provider->getProperty(gIOUserServicePropertiesKey)))) {
5283 				        object = userProps->getObject(name);
5284 				}
5285 				if (object) {
5286 				        object->retain();
5287 				}
5288 				return kIOReturnSuccess;
5289 			});
5290 			if (object || !(kIORegistryIterateParents & options)) {
5291 				break;
5292 			}
5293 		}
5294 	}
5295 
5296 	*property = object;
5297 
5298 	return object ? kIOReturnSuccess : kIOReturnNotFound;
5299 }
5300 
5301 kern_return_t
5302 IOService::StringFromReturn_Impl(
5303 	IOReturn retval,
5304 	OSString ** str)
5305 {
5306 	OSString *obj = OSString::withCString(stringFromReturn(retval));
5307 	*str = obj;
5308 	return obj ? kIOReturnSuccess : kIOReturnError;
5309 }
5310 
5311 #if PRIVATE_WIFI_ONLY
5312 const char *
5313 IOService::StringFromReturn(
5314 	IOReturn retval)
5315 {
5316 	return stringFromReturn(retval);
5317 }
5318 #endif /* PRIVATE_WIFI_ONLY */
5319 
5320 kern_return_t
5321 IOService::CopyProviderProperties_Impl(
5322 	OSArray * propertyKeys,
5323 	OSArray ** properties)
5324 {
5325 	IOReturn    ret;
5326 	OSArray   * result;
5327 	IOService * provider;
5328 
5329 	result = OSArray::withCapacity(8);
5330 	if (!result) {
5331 		return kIOReturnNoMemory;
5332 	}
5333 
5334 	ret = kIOReturnSuccess;
5335 	for (provider = this; provider; provider = provider->getProvider()) {
5336 		OSObject     * obj;
5337 		OSDictionary * props;
5338 
5339 		obj = provider->copyProperty(gIOSupportedPropertiesKey);
5340 		props = OSDynamicCast(OSDictionary, obj);
5341 		if (!props) {
5342 			OSSafeReleaseNULL(obj);
5343 			props = provider->dictionaryWithProperties();
5344 		}
5345 		if (!props) {
5346 			ret = kIOReturnNoMemory;
5347 			break;
5348 		}
5349 
5350 		bool __block addClass = true;
5351 		if (propertyKeys) {
5352 			OSDictionary * retProps;
5353 			retProps = OSDictionary::withCapacity(4);
5354 			addClass = false;
5355 			if (!retProps) {
5356 				ret = kIOReturnNoMemory;
5357 				OSSafeReleaseNULL(props);
5358 				break;
5359 			}
5360 			propertyKeys->iterateObjects(^bool (OSObject * _key) {
5361 				OSString * key = OSDynamicCast(OSString, _key);
5362 				if (gIOClassKey->isEqualTo(key)) {
5363 				        addClass = true;
5364 				        return false;
5365 				}
5366 				retProps->setObject(key, props->getObject(key));
5367 				return false;
5368 			});
5369 			OSSafeReleaseNULL(props);
5370 			props = retProps;
5371 		}
5372 		if (addClass) {
5373 			OSArray * classes = OSArray::withCapacity(8);
5374 			if (!classes) {
5375 				OSSafeReleaseNULL(props);
5376 				ret = kIOReturnNoMemory;
5377 				break;
5378 			}
5379 			for (const OSMetaClass * meta = provider->getMetaClass(); meta; meta = meta->getSuperClass()) {
5380 				classes->setObject(meta->getClassNameSymbol());
5381 			}
5382 			props->setObject(gIOClassKey, classes);
5383 			OSSafeReleaseNULL(classes);
5384 		}
5385 		bool ok = result->setObject(props);
5386 		props->release();
5387 		if (!ok) {
5388 			ret = kIOReturnNoMemory;
5389 			break;
5390 		}
5391 	}
5392 	if (kIOReturnSuccess != ret) {
5393 		OSSafeReleaseNULL(result);
5394 	}
5395 	*properties = result;
5396 	return ret;
5397 }
5398 
5399 IOReturn
5400 IOService::AdjustBusy_Impl(int32_t delta)
5401 {
5402 	adjustBusy(delta);
5403 	return kIOReturnSuccess;
5404 }
5405 
5406 IOReturn
5407 IOService::GetBusyState_Impl(uint32_t *busyState)
5408 {
5409 	*busyState = getBusyState();
5410 	return kIOReturnSuccess;
5411 }
5412 
5413 void
5414 IOUserServer::systemPower(bool powerOff, bool hibernate)
5415 {
5416 	OSArray * services;
5417 	{
5418 		OSDictionary * sleepDescription;
5419 		OSObject     * prop;
5420 
5421 		sleepDescription = OSDictionary::withCapacity(4);
5422 		if (sleepDescription) {
5423 			prop = getPMRootDomain()->copyProperty(kRootDomainSleepReasonKey);
5424 			if (prop) {
5425 				sleepDescription->setObject(gIOSystemStateSleepDescriptionReasonKey, prop);
5426 				OSSafeReleaseNULL(prop);
5427 			}
5428 			prop = getPMRootDomain()->copyProperty(kIOHibernateStateKey);
5429 			if (prop) {
5430 				sleepDescription->setObject(gIOSystemStateSleepDescriptionHibernateStateKey, prop);
5431 				OSSafeReleaseNULL(prop);
5432 			}
5433 			if (hibernate) {
5434 				uint32_t correctHibernateState = kIOSystemStateSleepDescriptionHibernateStateHibernating;
5435 				OSData *correctHibernateStateData = OSData::withValue(correctHibernateState);
5436 				assert(correctHibernateStateData != NULL);
5437 				sleepDescription->setObject(gIOSystemStateSleepDescriptionHibernateStateKey, correctHibernateStateData);
5438 				OSSafeReleaseNULL(correctHibernateStateData);
5439 			}
5440 			getSystemStateNotificationService()->StateNotificationItemSet(gIOSystemStateSleepDescriptionKey, sleepDescription);
5441 			OSSafeReleaseNULL(sleepDescription);
5442 		}
5443 	}
5444 
5445 	IOLockLock(fLock);
5446 
5447 	services = OSArray::withArray(fServices);
5448 
5449 	bool allPowerStates __block = 0;
5450 	// any service on?
5451 	fServices->iterateObjects(^bool (OSObject * obj) {
5452 		int         service __unused;       // hide outer defn
5453 		IOService * nextService;
5454 		nextService = (IOService *) obj;
5455 		allPowerStates = nextService->reserved->uvars->powerState;
5456 		// early terminate if true
5457 		return allPowerStates;
5458 	});
5459 
5460 	if (kIODKLogPM & gIODKDebug) {
5461 		DKLOG("%s::powerOff(%d) %d\n", getName(), powerOff, allPowerStates);
5462 	}
5463 
5464 	if (powerOff) {
5465 		fSystemPowerAck = allPowerStates;
5466 		if (!fSystemPowerAck) {
5467 			fSystemOff = true;
5468 		}
5469 		IOLockUnlock(fLock);
5470 
5471 		if (!fSystemPowerAck) {
5472 			IOServicePH::serverAck(this);
5473 		} else {
5474 			if (services) {
5475 				services->iterateObjects(^bool (OSObject * obj) {
5476 					int         service __unused;       // hide outer defn
5477 					IOService * nextService;
5478 					nextService = (IOService *) obj;
5479 					if (kIODKLogPM & gIODKDebug) {
5480 					        DKLOG("changePowerStateWithOverrideTo(" DKS ", %d)\n", DKN(nextService), 0);
5481 					}
5482 					nextService->reserved->uvars->powerOverride = nextService->reserved->uvars->userServerPM ? kUserServerMaxPowerState : nextService->getPowerState();
5483 					nextService->changePowerStateWithOverrideTo(0, 0);
5484 					return false;
5485 				});
5486 			}
5487 		}
5488 	} else {
5489 		fSystemOff = false;
5490 		IOLockUnlock(fLock);
5491 		if (services) {
5492 			services->iterateObjects(^bool (OSObject * obj) {
5493 				int         service __unused;       // hide outer defn
5494 				IOService * nextService;
5495 				nextService = (IOService *) obj;
5496 				if (-1U != nextService->reserved->uvars->powerOverride) {
5497 				        if (kIODKLogPM & gIODKDebug) {
5498 				                DKLOG("%schangePowerStateWithOverrideTo(" DKS ", %d)\n", nextService->reserved->uvars->resetPowerOnWake ? "!" : "", DKN(nextService), nextService->reserved->uvars->powerOverride);
5499 					}
5500 				        if (!nextService->reserved->uvars->resetPowerOnWake) {
5501 				                nextService->changePowerStateWithOverrideTo(nextService->reserved->uvars->powerOverride, 0);
5502 					}
5503 				        nextService->reserved->uvars->powerOverride = -1U;
5504 				}
5505 				return false;
5506 			});
5507 		}
5508 	}
5509 	OSSafeReleaseNULL(services);
5510 }
5511 
5512 
5513 void
5514 IOUserServer::systemHalt(int howto)
5515 {
5516 	OSArray * services;
5517 
5518 	if (true || (kIODKLogPM & gIODKDebug)) {
5519 		DKLOG("%s::systemHalt()\n", getName());
5520 	}
5521 
5522 	{
5523 		OSDictionary * haltDescription;
5524 		OSNumber     * state;
5525 		uint64_t       haltStateFlags;
5526 
5527 		haltDescription = OSDictionary::withCapacity(4);
5528 		if (haltDescription) {
5529 			haltStateFlags = 0;
5530 			if (RB_HALT & howto) {
5531 				haltStateFlags |= kIOServiceHaltStatePowerOff;
5532 			} else {
5533 				haltStateFlags |= kIOServiceHaltStateRestart;
5534 			}
5535 			state = OSNumber::withNumber(haltStateFlags, 64);
5536 			haltDescription->setObject(gIOSystemStateHaltDescriptionHaltStateKey, state);
5537 			getSystemStateNotificationService()->StateNotificationItemSet(gIOSystemStateHaltDescriptionKey, haltDescription);
5538 
5539 			OSSafeReleaseNULL(state);
5540 			OSSafeReleaseNULL(haltDescription);
5541 		}
5542 	}
5543 
5544 	IOLockLock(fLock);
5545 	services = OSArray::withArray(fServices);
5546 	IOLockUnlock(fLock);
5547 
5548 	if (services) {
5549 		services->iterateObjects(^bool (OSObject * obj) {
5550 			int         service __unused;       // hide outer defn
5551 			IOService  * nextService;
5552 			IOService  * provider;
5553 			IOOptionBits terminateOptions;
5554 			bool         root;
5555 
5556 			nextService = (IOService *) obj;
5557 			provider = nextService->getProvider();
5558 			if (!provider) {
5559 			        DKLOG("stale service " DKS " found, skipping termination\n", DKN(nextService));
5560 			        return false;
5561 			}
5562 			root = (NULL == provider->getProperty(gIOUserServerNameKey, gIOServicePlane));
5563 			if (true || (kIODKLogPM & gIODKDebug)) {
5564 			        DKLOG("%d: terminate(" DKS ")\n", root, DKN(nextService));
5565 			}
5566 			if (!root) {
5567 			        return false;
5568 			}
5569 			terminateOptions = kIOServiceRequired | kIOServiceTerminateNeedWillTerminate;
5570 			if (!nextService->terminate(terminateOptions)) {
5571 			        IOLog("failed to terminate service %s-0x%llx\n", nextService->getName(), nextService->getRegistryEntryID());
5572 			}
5573 			return false;
5574 		});
5575 	}
5576 	OSSafeReleaseNULL(services);
5577 }
5578 
5579 void
5580 IOUserServer::powerSourceChanged(bool acAttached)
5581 {
5582 	OSDictionary * powerSourceDescription;
5583 
5584 	powerSourceDescription = OSDictionary::withCapacity(4);
5585 	if (!powerSourceDescription) {
5586 		return;
5587 	}
5588 	powerSourceDescription->setObject(gIOSystemStatePowerSourceDescriptionACAttachedKey, acAttached ? kOSBooleanTrue : kOSBooleanFalse);
5589 	getSystemStateNotificationService()->StateNotificationItemSet(gIOSystemStatePowerSourceDescriptionKey, powerSourceDescription);
5590 
5591 	OSSafeReleaseNULL(powerSourceDescription);
5592 }
5593 
5594 IOReturn
5595 IOUserServer::serviceStarted(IOService * service, IOService * provider, bool result)
5596 {
5597 	IOReturn    ret;
5598 
5599 	DKLOG(DKS "::start(" DKS ") %s\n", DKN(service), DKN(provider), result ? "ok" : "fail");
5600 
5601 	if (!result) {
5602 		ret = kIOReturnSuccess;
5603 		return ret;
5604 	}
5605 
5606 	ret = serviceJoinPMTree(service);
5607 
5608 	service->reserved->uvars->started = true;
5609 
5610 	if (service->reserved->uvars->deferredRegisterService) {
5611 		service->registerService(kIOServiceAsynchronous | kIOServiceDextRequirePowerForMatching);
5612 		service->reserved->uvars->deferredRegisterService = false;
5613 	}
5614 
5615 	return kIOReturnSuccess;
5616 }
5617 
5618 
5619 IOReturn
5620 IOUserServer::serviceOpen(IOService * provider, IOService * client)
5621 {
5622 	OSObjectUserVars * uvars;
5623 	IOReturn ret;
5624 
5625 	IOLockLock(client->reserved->uvars->uvarsLock);
5626 	uvars = client->reserved->uvars;
5627 	if (uvars->willTerminate || uvars->stopped) {
5628 		DKLOG(DKS "- " DKS " blocked attempt to open " DKS "\n", DKN(this), DKN(client), DKN(provider));
5629 		ret = kIOReturnBadArgument;
5630 	} else {
5631 		if (!uvars->openProviders) {
5632 			uvars->openProviders = OSArray::withObjects((const OSObject **) &provider, 1);
5633 		} else if (-1U == uvars->openProviders->getNextIndexOfObject(provider, 0)) {
5634 			uvars->openProviders->setObject(provider);
5635 		}
5636 		ret = kIOReturnSuccess;
5637 	}
5638 
5639 	IOLockUnlock(client->reserved->uvars->uvarsLock);
5640 
5641 	return ret;
5642 }
5643 
5644 IOReturn
5645 IOUserServer::serviceClose(IOService * provider, IOService * client)
5646 {
5647 	OSObjectUserVars * uvars;
5648 	unsigned int       idx;
5649 	IOReturn           ret;
5650 
5651 	IOLockLock(client->reserved->uvars->uvarsLock);
5652 	uvars = client->reserved->uvars;
5653 	if (!uvars->openProviders) {
5654 		ret = kIOReturnNotOpen;
5655 		goto finish;
5656 	}
5657 	idx = uvars->openProviders->getNextIndexOfObject(provider, 0);
5658 	if (-1U == idx) {
5659 		ret = kIOReturnNotOpen;
5660 		goto finish;
5661 	}
5662 	uvars->openProviders->removeObject(idx);
5663 	if (!uvars->openProviders->getCount()) {
5664 		OSSafeReleaseNULL(uvars->openProviders);
5665 	}
5666 
5667 	ret = kIOReturnSuccess;
5668 
5669 finish:
5670 	IOLockUnlock(client->reserved->uvars->uvarsLock);
5671 
5672 	return ret;
5673 }
5674 
5675 
5676 IOReturn
5677 IOUserServer::serviceStop(IOService * service, IOService *)
5678 {
5679 	IOReturn           ret;
5680 	uint32_t           idx;
5681 	bool               pmAck;
5682 	OSObjectUserVars * uvars;
5683 	pmAck = false;
5684 	IOLockLock(fLock);
5685 	idx = fServices->getNextIndexOfObject(service, 0);
5686 	if (-1U != idx) {
5687 		fServices->removeObject(idx);
5688 
5689 		// Remove the service from IOAssociatedServices
5690 		OSObject * serviceArrayObj = copyProperty(gIOAssociatedServicesKey);
5691 		OSArray * serviceArray = OSDynamicCast(OSArray, serviceArrayObj);
5692 		assert(serviceArray != NULL);
5693 
5694 		serviceArray = OSDynamicCast(OSArray, serviceArray->copyCollection());
5695 		assert(serviceArray != NULL);
5696 
5697 		// Index should be the same as it was in fServices
5698 		OSNumber * __assert_only registryEntryID = OSDynamicCast(OSNumber, serviceArray->getObject(idx));
5699 		assert(registryEntryID);
5700 
5701 		// ensure it is the right service
5702 		assert(registryEntryID->unsigned64BitValue() == service->getRegistryEntryID());
5703 		serviceArray->removeObject(idx);
5704 
5705 		setProperty(gIOAssociatedServicesKey, serviceArray);
5706 		OSSafeReleaseNULL(serviceArray);
5707 		OSSafeReleaseNULL(serviceArrayObj);
5708 
5709 		uvars = service->reserved->uvars;
5710 		uvars->stopped = true;
5711 		uvars->powerState = 0;
5712 
5713 		bool allPowerStates __block = 0;
5714 		// any service on?
5715 		fServices->iterateObjects(^bool (OSObject * obj) {
5716 			int         service __unused;       // hide outer defn
5717 			IOService * nextService;
5718 			nextService = (IOService *) obj;
5719 			allPowerStates = nextService->reserved->uvars->powerState;
5720 			// early terminate if true
5721 			return allPowerStates;
5722 		});
5723 
5724 		if (!allPowerStates && (pmAck = fSystemPowerAck)) {
5725 			fSystemPowerAck = false;
5726 			fSystemOff      = true;
5727 		}
5728 	}
5729 	IOLockUnlock(fLock);
5730 	if (pmAck) {
5731 		IOServicePH::serverAck(this);
5732 	}
5733 
5734 	if (-1U == idx) {
5735 		return kIOReturnSuccess;
5736 	}
5737 
5738 	(void) service->deRegisterInterestedDriver(this);
5739 	if (uvars->userServerPM) {
5740 		service->PMstop();
5741 	}
5742 
5743 	ret = kIOReturnSuccess;
5744 	return ret;
5745 }
5746 
5747 void
5748 IOUserServer::serviceFree(IOService * service)
5749 {
5750 	OSObjectUserVars * uvars;
5751 	uint32_t idx, queueAlloc;
5752 	IODispatchQueue ** unboundedQueueArray = NULL;
5753 
5754 	uvars = service->reserved->uvars;
5755 	if (!uvars) {
5756 		return;
5757 	}
5758 	if (uvars->queueArray && uvars->userMeta) {
5759 		queueAlloc = 1;
5760 		if (uvars->userMeta->queueNames) {
5761 			queueAlloc += uvars->userMeta->queueNames->count;
5762 		}
5763 		for (idx = 0; idx < queueAlloc; idx++) {
5764 			OSSafeReleaseNULL(uvars->queueArray[idx]);
5765 		}
5766 		unboundedQueueArray = uvars->queueArray.data();
5767 		IOSafeDeleteNULL(unboundedQueueArray, IODispatchQueue *, queueAlloc);
5768 		uvars->queueArray = OSBoundedArrayRef<IODispatchQueue *>();
5769 	}
5770 	OSSafeReleaseNULL(uvars->userServer);
5771 	IOLockFree(uvars->uvarsLock);
5772 	IOFreeType(service->reserved->uvars, OSObjectUserVars);
5773 }
5774 
5775 void
5776 IOUserServer::serviceWillTerminate(IOService * client, IOService * provider, IOOptionBits options)
5777 {
5778 	IOReturn ret;
5779 	bool     willTerminate;
5780 
5781 	willTerminate = false;
5782 	IOLockLock(client->reserved->uvars->uvarsLock);
5783 	if (!client->reserved->uvars->serverDied
5784 	    && !client->reserved->uvars->willTerminate) {
5785 		client->reserved->uvars->willTerminate = true;
5786 		willTerminate = true;
5787 	}
5788 	IOLockUnlock(client->reserved->uvars->uvarsLock);
5789 
5790 	if (willTerminate) {
5791 		if (provider->isInactive() || IOServicePH::serverSlept()) {
5792 			client->Stop_async(provider);
5793 			ret = kIOReturnOffline;
5794 		} else {
5795 			ret = client->Stop(provider);
5796 		}
5797 		if (kIOReturnSuccess != ret) {
5798 			IOUserServer::serviceDidStop(client, provider);
5799 			ret = kIOReturnSuccess;
5800 		}
5801 	}
5802 }
5803 
5804 void
5805 IOUserServer::serviceDidTerminate(IOService * client, IOService * provider, IOOptionBits options, bool * defer)
5806 {
5807 	IOLockLock(client->reserved->uvars->uvarsLock);
5808 	client->reserved->uvars->didTerminate = true;
5809 	if (!client->reserved->uvars->serverDied
5810 	    && !client->reserved->uvars->stopped) {
5811 		*defer = true;
5812 	}
5813 	IOLockUnlock(client->reserved->uvars->uvarsLock);
5814 }
5815 
5816 void
5817 IOUserServer::serviceDidStop(IOService * client, IOService * provider)
5818 {
5819 	bool complete;
5820 	OSArray * closeArray;
5821 
5822 	complete = false;
5823 	closeArray = NULL;
5824 
5825 	IOLockLock(client->reserved->uvars->uvarsLock);
5826 	if (client->reserved->uvars
5827 	    && client->reserved->uvars->willTerminate
5828 	    && !client->reserved->uvars->stopped) {
5829 		client->reserved->uvars->stopped = true;
5830 		complete = client->reserved->uvars->didTerminate;
5831 	}
5832 
5833 	if (client->reserved->uvars) {
5834 		closeArray = client->reserved->uvars->openProviders;
5835 		client->reserved->uvars->openProviders = NULL;
5836 	}
5837 	IOLockUnlock(client->reserved->uvars->uvarsLock);
5838 
5839 	if (closeArray) {
5840 		closeArray->iterateObjects(^bool (OSObject * obj) {
5841 			IOService * toClose;
5842 			toClose = OSDynamicCast(IOService, obj);
5843 			if (toClose) {
5844 			        DKLOG(DKS ":force close (" DKS ")\n", DKN(client), DKN(toClose));
5845 			        toClose->close(client);
5846 			}
5847 			return false;
5848 		});
5849 		closeArray->release();
5850 	}
5851 
5852 	if (complete) {
5853 		bool defer = false;
5854 		client->didTerminate(provider, 0, &defer);
5855 	}
5856 }
5857 
5858 kern_return_t
5859 IOService::ClientCrashed_Impl(
5860 	IOService * client,
5861 	uint64_t    options)
5862 {
5863 	return kIOReturnUnsupported;
5864 }
5865 
5866 kern_return_t
5867 IOService::Stop_Impl(
5868 	IOService * provider)
5869 {
5870 	IOUserServer::serviceDidStop(this, provider);
5871 
5872 	return kIOReturnSuccess;
5873 }
5874 
5875 void
5876 IOService::Stop_async_Impl(
5877 	IOService * provider)
5878 {
5879 }
5880 
5881 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5882 
5883 #undef super
5884 #define super IOUserClient
5885 
5886 OSDefineMetaClassAndStructors(IOUserUserClient, IOUserClient)
5887 
5888 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5889 
5890 bool
5891 IOUserUserClient::init(OSDictionary * properties)
5892 {
5893 	if (!super::init(properties)) {
5894 		return false;
5895 	}
5896 
5897 	fWorkGroups = OSDictionary::withCapacity(0);
5898 	if (fWorkGroups == NULL) {
5899 		return false;
5900 	}
5901 
5902 	fEventLinks = OSDictionary::withCapacity(0);
5903 	if (fEventLinks == NULL) {
5904 		return false;
5905 	}
5906 
5907 	fLock = IOLockAlloc();
5908 
5909 	return true;
5910 }
5911 
5912 void
5913 IOUserUserClient::free()
5914 {
5915 	OSSafeReleaseNULL(fWorkGroups);
5916 	OSSafeReleaseNULL(fEventLinks);
5917 	if (fLock) {
5918 		IOLockFree(fLock);
5919 	}
5920 
5921 	super::free();
5922 }
5923 
5924 IOReturn
5925 IOUserUserClient::setTask(task_t task)
5926 {
5927 	task_reference(task);
5928 	fTask = task;
5929 
5930 	return kIOReturnSuccess;
5931 }
5932 
5933 void
5934 IOUserUserClient::stop(IOService * provider)
5935 {
5936 	if (fTask) {
5937 		task_deallocate(fTask);
5938 		fTask = NULL;
5939 	}
5940 	super::stop(provider);
5941 }
5942 
5943 IOReturn
5944 IOUserUserClient::clientClose(void)
5945 {
5946 	terminate(kIOServiceTerminateNeedWillTerminate);
5947 	return kIOReturnSuccess;
5948 }
5949 
5950 IOReturn
5951 IOUserUserClient::setProperties(OSObject * properties)
5952 {
5953 	IOReturn ret = kIOReturnUnsupported;
5954 	return ret;
5955 }
5956 
5957 // p1 - name of object
5958 // p2 - length of object name
5959 // p3 - mach port name
5960 
5961 kern_return_t
5962 IOUserUserClient::eventlinkConfigurationTrap(void * p1, void * p2, void * p3, void * p4, void * p5, void * p6)
5963 {
5964 	user_addr_t userObjectName = (user_addr_t)p1;
5965 	mach_port_name_t portName = (mach_port_name_t)(uintptr_t)p3;
5966 	mach_port_t port = MACH_PORT_NULL;
5967 	ipc_kobject_type_t portType;
5968 	char eventlinkName[kIOEventLinkMaxNameLength + 1] = {0};
5969 	size_t eventLinkNameLen;
5970 	OSString * eventlinkNameStr = NULL; // must release
5971 	IOEventLink * eventLink = NULL; // do not release
5972 	kern_return_t ret;
5973 
5974 	ret = copyinstr(userObjectName, &eventlinkName[0], sizeof(eventlinkName), &eventLinkNameLen);
5975 	if (ret != kIOReturnSuccess) {
5976 		goto finish;
5977 	}
5978 
5979 	// ensure string length matches trap argument
5980 	if (eventLinkNameLen != (size_t)p2 + 1) {
5981 		ret = kIOReturnBadArgument;
5982 		goto finish;
5983 	}
5984 
5985 	eventlinkNameStr = OSString::withCStringNoCopy(eventlinkName);
5986 	if (eventlinkNameStr == NULL) {
5987 		ret = kIOReturnNoMemory;
5988 		goto finish;
5989 	}
5990 
5991 	IOLockLock(fLock);
5992 	eventLink = OSDynamicCast(IOEventLink, fEventLinks->getObject(eventlinkNameStr));
5993 	if (eventLink) {
5994 		eventLink->retain();
5995 	}
5996 	IOLockUnlock(fLock);
5997 
5998 	if (eventLink == NULL) {
5999 		ret = kIOReturnNotFound;
6000 		goto finish;
6001 	}
6002 
6003 	port = iokit_lookup_raw_current_task(portName, &portType);
6004 
6005 	if (port == NULL) {
6006 		ret = kIOReturnNotFound;
6007 		goto finish;
6008 	}
6009 
6010 	if (portType != IKOT_EVENTLINK) {
6011 		ret = kIOReturnBadArgument;
6012 		goto finish;
6013 	}
6014 
6015 	ret = eventLink->SetEventlinkPort(port);
6016 	if (ret != kIOReturnSuccess) {
6017 		if (kIODKLogSetup & gIODKDebug) {
6018 			DKLOG(DKS " %s SetEventlinkPort() returned %x\n", DKN(this), eventlinkNameStr->getCStringNoCopy(), ret);
6019 		}
6020 		goto finish;
6021 	}
6022 
6023 finish:
6024 	if (port != NULL) {
6025 		iokit_release_port_send(port);
6026 	}
6027 
6028 	OSSafeReleaseNULL(eventlinkNameStr);
6029 	OSSafeReleaseNULL(eventLink);
6030 
6031 	return ret;
6032 }
6033 
6034 kern_return_t
6035 IOUserUserClient::workgroupConfigurationTrap(void * p1, void * p2, void * p3, void * p4, void * p5, void * p6)
6036 {
6037 	user_addr_t userObjectName = (user_addr_t)p1;
6038 	mach_port_name_t portName = (mach_port_name_t)(uintptr_t)p3;
6039 	mach_port_t port = MACH_PORT_NULL;
6040 	ipc_kobject_type_t portType;
6041 	char workgroupName[kIOWorkGroupMaxNameLength + 1] = {0};
6042 	size_t workgroupNameLen;
6043 	OSString * workgroupNameStr = NULL; // must release
6044 	IOWorkGroup * workgroup = NULL; // do not release
6045 	kern_return_t ret;
6046 
6047 	ret = copyinstr(userObjectName, &workgroupName[0], sizeof(workgroupName), &workgroupNameLen);
6048 	if (ret != kIOReturnSuccess) {
6049 		goto finish;
6050 	}
6051 
6052 	// ensure string length matches trap argument
6053 	if (workgroupNameLen != (size_t)p2 + 1) {
6054 		ret = kIOReturnBadArgument;
6055 		goto finish;
6056 	}
6057 
6058 	workgroupNameStr = OSString::withCStringNoCopy(workgroupName);
6059 	if (workgroupNameStr == NULL) {
6060 		ret = kIOReturnNoMemory;
6061 		goto finish;
6062 	}
6063 
6064 	IOLockLock(fLock);
6065 	workgroup = OSDynamicCast(IOWorkGroup, fWorkGroups->getObject(workgroupNameStr));
6066 	if (workgroup) {
6067 		workgroup->retain();
6068 	}
6069 	IOLockUnlock(fLock);
6070 
6071 	if (workgroup == NULL) {
6072 		ret = kIOReturnNotFound;
6073 		goto finish;
6074 	}
6075 
6076 	port = iokit_lookup_raw_current_task(portName, &portType);
6077 
6078 	if (port == NULL) {
6079 		ret = kIOReturnNotFound;
6080 		goto finish;
6081 	}
6082 
6083 	if (portType != IKOT_WORK_INTERVAL) {
6084 		ret = kIOReturnBadArgument;
6085 		goto finish;
6086 	}
6087 
6088 	ret = workgroup->SetWorkGroupPort(port);
6089 	if (ret != kIOReturnSuccess) {
6090 		if (kIODKLogSetup & gIODKDebug) {
6091 			DKLOG(DKS " %s SetWorkGroupPort() returned %x\n", DKN(this), workgroupNameStr->getCStringNoCopy(), ret);
6092 		}
6093 		goto finish;
6094 	}
6095 
6096 finish:
6097 
6098 	if (port != NULL) {
6099 		iokit_release_port_send(port);
6100 	}
6101 
6102 	OSSafeReleaseNULL(workgroupNameStr);
6103 	OSSafeReleaseNULL(workgroup);
6104 
6105 	return ret;
6106 }
6107 
6108 IOExternalTrap *
6109 IOUserUserClient::getTargetAndTrapForIndex( IOService **targetP, UInt32 index )
6110 {
6111 	static const OSBoundedArray<IOExternalTrap, 2> trapTemplate = {{
6112 									       { NULL, (IOTrap) & IOUserUserClient::eventlinkConfigurationTrap},
6113 									       { NULL, (IOTrap) & IOUserUserClient::workgroupConfigurationTrap},
6114 								       }};
6115 	if (index >= trapTemplate.size()) {
6116 		return NULL;
6117 	}
6118 	*targetP = this;
6119 	return (IOExternalTrap *)&trapTemplate[index];
6120 }
6121 
6122 kern_return_t
6123 IOUserClient::CopyClientEntitlements_Impl(OSDictionary ** entitlements)
6124 {
6125 	return kIOReturnUnsupported;
6126 };
6127 
6128 struct IOUserUserClientActionRef {
6129 	OSAsyncReference64 asyncRef;
6130 };
6131 
6132 void
6133 IOUserClient::KernelCompletion_Impl(
6134 	OSAction * action,
6135 	IOReturn status,
6136 	const unsigned long long * asyncData,
6137 	uint32_t asyncDataCount)
6138 {
6139 	IOUserUserClientActionRef * ref;
6140 
6141 	ref = (typeof(ref))action->GetReference();
6142 
6143 	IOUserClient::sendAsyncResult64(ref->asyncRef, status, (io_user_reference_t *) asyncData, asyncDataCount);
6144 }
6145 
6146 kern_return_t
6147 IOUserClient::_ExternalMethod_Impl(
6148 	uint64_t selector,
6149 	const unsigned long long * scalarInput,
6150 	uint32_t scalarInputCount,
6151 	OSData * structureInput,
6152 	IOMemoryDescriptor * structureInputDescriptor,
6153 	unsigned long long * scalarOutput,
6154 	uint32_t * scalarOutputCount,
6155 	uint64_t structureOutputMaximumSize,
6156 	OSData ** structureOutput,
6157 	IOMemoryDescriptor * structureOutputDescriptor,
6158 	OSAction * completion)
6159 {
6160 	return kIOReturnUnsupported;
6161 }
6162 
6163 IOReturn
6164 IOUserUserClient::clientMemoryForType(UInt32 type,
6165     IOOptionBits * koptions,
6166     IOMemoryDescriptor ** kmemory)
6167 {
6168 	IOReturn             kr;
6169 	uint64_t             options;
6170 	IOMemoryDescriptor * memory;
6171 
6172 	kr = CopyClientMemoryForType(type, &options, &memory);
6173 
6174 	*koptions = 0;
6175 	*kmemory  = NULL;
6176 	if (kIOReturnSuccess != kr) {
6177 		return kr;
6178 	}
6179 
6180 	if (kIOUserClientMemoryReadOnly & options) {
6181 		*koptions |= kIOMapReadOnly;
6182 	}
6183 	*kmemory = memory;
6184 
6185 	return kr;
6186 }
6187 
6188 IOReturn
6189 IOUserUserClient::externalMethod(uint32_t selector, IOExternalMethodArguments * args,
6190     IOExternalMethodDispatch * dispatch, OSObject * target, void * reference)
6191 {
6192 	IOReturn   kr;
6193 	OSData   * structureInput;
6194 	OSData   * structureOutput;
6195 	size_t     copylen;
6196 	uint64_t   structureOutputSize;
6197 	OSAction                  * action;
6198 	IOUserUserClientActionRef * ref;
6199 	mach_port_t wake_port = MACH_PORT_NULL;
6200 
6201 	kr             = kIOReturnUnsupported;
6202 	structureInput = NULL;
6203 	action         = NULL;
6204 	ref            = NULL;
6205 
6206 	if (args->structureInputSize) {
6207 		structureInput = OSData::withBytesNoCopy((void *) args->structureInput, args->structureInputSize);
6208 	}
6209 
6210 	if (MACH_PORT_NULL != args->asyncWakePort) {
6211 		// this retain is for the OSAction to release
6212 		wake_port = ipc_port_make_send_mqueue(args->asyncWakePort);
6213 		kr = CreateActionKernelCompletion(sizeof(IOUserUserClientActionRef), &action);
6214 		assert(KERN_SUCCESS == kr);
6215 		ref = (typeof(ref))action->GetReference();
6216 		bcopy(args->asyncReference, &ref->asyncRef[0], args->asyncReferenceCount * sizeof(ref->asyncRef[0]));
6217 		kr = action->SetAbortedHandler(^(void) {
6218 			IOUserUserClientActionRef * ref;
6219 			IOReturn ret;
6220 
6221 			ref = (typeof(ref))action->GetReference();
6222 			ret = releaseAsyncReference64(ref->asyncRef);
6223 			assert(kIOReturnSuccess == ret);
6224 			bzero(&ref->asyncRef[0], sizeof(ref->asyncRef));
6225 		});
6226 		assert(KERN_SUCCESS == kr);
6227 	}
6228 
6229 	if (args->structureVariableOutputData) {
6230 		structureOutputSize = kIOUserClientVariableStructureSize;
6231 	} else if (args->structureOutputDescriptor) {
6232 		structureOutputSize = args->structureOutputDescriptor->getLength();
6233 	} else {
6234 		structureOutputSize = args->structureOutputSize;
6235 	}
6236 
6237 	kr = _ExternalMethod(selector, &args->scalarInput[0], args->scalarInputCount,
6238 	    structureInput, args->structureInputDescriptor,
6239 	    args->scalarOutput, &args->scalarOutputCount,
6240 	    structureOutputSize, &structureOutput, args->structureOutputDescriptor,
6241 	    action);
6242 
6243 	OSSafeReleaseNULL(structureInput);
6244 	OSSafeReleaseNULL(action);
6245 
6246 	if (kr == kIOReturnSuccess && structureOutput) {
6247 		if (args->structureVariableOutputData) {
6248 			*args->structureVariableOutputData = structureOutput;
6249 		} else {
6250 			copylen = structureOutput->getLength();
6251 			if (copylen > args->structureOutputSize) {
6252 				kr = kIOReturnBadArgument;
6253 			} else {
6254 				bcopy((const void *) structureOutput->getBytesNoCopy(), args->structureOutput, copylen);
6255 				args->structureOutputSize = (uint32_t) copylen;
6256 			}
6257 			OSSafeReleaseNULL(structureOutput);
6258 		}
6259 	}
6260 
6261 	if (kIOReturnSuccess != kr) {
6262 		// mig will destroy any async port
6263 		return kr;
6264 	}
6265 
6266 	// We must never return error after this point in order to preserve MIG ownership semantics
6267 	assert(kr == kIOReturnSuccess);
6268 	if (MACH_PORT_NULL != wake_port) {
6269 		// this release is for the mig created send right
6270 		iokit_release_port_send(wake_port);
6271 	}
6272 
6273 	return kr;
6274 }
6275 
6276 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6277 
6278 extern IORecursiveLock               * gDriverKitLaunchLock;
6279 extern OSSet                         * gDriverKitLaunches;
6280 
6281 _IOUserServerCheckInCancellationHandler *
6282 IOUserServerCheckInToken::setCancellationHandler(IOUserServerCheckInCancellationHandler handler,
6283     void* handlerArgs)
6284 {
6285 	_IOUserServerCheckInCancellationHandler * handlerObj = _IOUserServerCheckInCancellationHandler::withHandler(handler, handlerArgs);
6286 	if (!handlerObj) {
6287 		goto finish;
6288 	}
6289 
6290 	IORecursiveLockLock(gDriverKitLaunchLock);
6291 
6292 	if (fState == kIOUserServerCheckInCanceled) {
6293 		// Send cancel notification if we set the handler after this was canceled
6294 		handlerObj->call(this);
6295 	} else if (fState == kIOUserServerCheckInPending) {
6296 		fHandlers->setObject(handlerObj);
6297 	}
6298 
6299 	IORecursiveLockUnlock(gDriverKitLaunchLock);
6300 
6301 finish:
6302 	return handlerObj;
6303 }
6304 
6305 void
6306 IOUserServerCheckInToken::removeCancellationHandler(_IOUserServerCheckInCancellationHandler * handler)
6307 {
6308 	IORecursiveLockLock(gDriverKitLaunchLock);
6309 
6310 	fHandlers->removeObject(handler);
6311 
6312 	IORecursiveLockUnlock(gDriverKitLaunchLock);
6313 }
6314 
6315 void
6316 IOUserServerCheckInToken::cancel()
6317 {
6318 	IORecursiveLockLock(gDriverKitLaunchLock);
6319 
6320 	if (fState == kIOUserServerCheckInPending) {
6321 		fState = kIOUserServerCheckInCanceled;
6322 		if (gDriverKitLaunches != NULL) {
6323 			// Remove pending launch from list, if we have not shut down yet.
6324 			gDriverKitLaunches->removeObject(this);
6325 		}
6326 
6327 		fHandlers->iterateObjects(^bool (OSObject * obj){
6328 			_IOUserServerCheckInCancellationHandler * handlerObj = OSDynamicCast(_IOUserServerCheckInCancellationHandler, obj);
6329 			if (handlerObj) {
6330 			        handlerObj->call(this);
6331 			}
6332 			return false;
6333 		});
6334 		fHandlers->flushCollection();
6335 	}
6336 
6337 	IORecursiveLockUnlock(gDriverKitLaunchLock);
6338 }
6339 
6340 IOReturn
6341 IOUserServerCheckInToken::complete()
6342 {
6343 	IOReturn ret;
6344 	IORecursiveLockLock(gDriverKitLaunchLock);
6345 
6346 	if (fState == kIOUserServerCheckInCanceled) {
6347 		ret = kIOReturnError;
6348 	} else {
6349 		ret = kIOReturnSuccess;
6350 	}
6351 
6352 	if (fState == kIOUserServerCheckInPending && --fPendingCount == 0) {
6353 		fState = kIOUserServerCheckInComplete;
6354 		if (gDriverKitLaunches != NULL) {
6355 			// Remove pending launch from list, if we have not shut down yet.
6356 			gDriverKitLaunches->removeObject(this);
6357 		}
6358 
6359 		// No need to hold on to the cancellation handlers
6360 		fHandlers->flushCollection();
6361 	}
6362 
6363 	IORecursiveLockUnlock(gDriverKitLaunchLock);
6364 	return ret;
6365 }
6366 
6367 bool
6368 IOUserServerCheckInToken::init(const OSSymbol * serverName, OSNumber * serverTag, OSKext *driverKext, OSData *serverDUI)
6369 {
6370 	if (!OSObject::init()) {
6371 		return false;
6372 	}
6373 
6374 	if (!serverName) {
6375 		return false;
6376 	}
6377 	fServerName = serverName;
6378 	fServerName->retain();
6379 
6380 	if (!serverTag) {
6381 		return false;
6382 	}
6383 	fServerTag = serverTag;
6384 	fServerTag->retain();
6385 
6386 	fHandlers = OSSet::withCapacity(0);
6387 	if (!fHandlers) {
6388 		return false;
6389 	}
6390 
6391 	fState = kIOUserServerCheckInPending;
6392 	fPendingCount = 1;
6393 
6394 	fKextBundleID = NULL;
6395 	fNeedDextDec = false;
6396 
6397 	fExecutableName = NULL;
6398 
6399 	if (driverKext) {
6400 		fExecutableName = OSDynamicCast(OSSymbol, driverKext->getBundleExecutable());
6401 
6402 		if (fExecutableName) {
6403 			fExecutableName->retain();
6404 		}
6405 
6406 		/*
6407 		 * We need to keep track of how many dexts we have started.
6408 		 * For every new dext we are going to create a new token, and
6409 		 * we consider the token creation as the initial step to
6410 		 * create a dext as it is the data structure that will back up
6411 		 * the userspace dance to start a dext.
6412 		 * We later have to decrement only once per token.
6413 		 * If no error occurs we consider the finalize() call on IOUserServer
6414 		 * as the moment in which we do not consider the dext "alive" anymore;
6415 		 * however in case of errors we will still need to decrement the count
6416 		 * otherwise upgrades of the dext will never make progress.
6417 		 */
6418 		if (OSKext::incrementDextLaunchCount(driverKext, serverDUI)) {
6419 			/*
6420 			 * If fKext holds a pointer,
6421 			 * it is the indication that a decrements needs
6422 			 * to be called.
6423 			 */
6424 			fNeedDextDec = true;
6425 			fKextBundleID = OSDynamicCast(OSString, driverKext->getIdentifier());
6426 			fKextBundleID->retain();
6427 		} else {
6428 			return false;
6429 		}
6430 	}
6431 
6432 	return true;
6433 }
6434 
6435 /*
6436  * Returns if the dext can be re-used
6437  * for matching.
6438  */
6439 bool
6440 IOUserServerCheckInToken::dextTerminate(void)
6441 {
6442 	bool ret = true;
6443 
6444 	if (fNeedDextDec == true) {
6445 		/*
6446 		 * We can decrement DextLaunchCount only
6447 		 * once per token.
6448 		 */
6449 		ret = !(OSKext::decrementDextLaunchCount(fKextBundleID));
6450 		fNeedDextDec = false;
6451 	}
6452 
6453 	return ret;
6454 }
6455 
6456 void
6457 IOUserServerCheckInToken::free()
6458 {
6459 	OSSafeReleaseNULL(fServerName);
6460 	OSSafeReleaseNULL(fServerTag);
6461 	OSSafeReleaseNULL(fExecutableName);
6462 	OSSafeReleaseNULL(fHandlers);
6463 	if (fKextBundleID != NULL) {
6464 		dextTerminate();
6465 		OSSafeReleaseNULL(fKextBundleID);
6466 	}
6467 
6468 	OSObject::free();
6469 }
6470 
6471 const OSSymbol *
6472 IOUserServerCheckInToken::copyServerName() const
6473 {
6474 	fServerName->retain();
6475 	return fServerName;
6476 }
6477 
6478 OSNumber *
6479 IOUserServerCheckInToken::copyServerTag() const
6480 {
6481 	fServerTag->retain();
6482 	return fServerTag;
6483 }
6484 
6485 IOUserServer *
6486 IOUserServer::launchUserServer(OSString * bundleID, const OSSymbol * serverName, OSNumber * serverTag, bool reuseIfExists, IOUserServerCheckInToken ** resultToken, OSData *serverDUI)
6487 {
6488 	IOUserServer *me = NULL;
6489 	IOUserServerCheckInToken * token = NULL;
6490 	OSDictionary * matching = NULL;  // must release
6491 	OSKext * driverKext = NULL; // must release
6492 	OSDextStatistics * driverStatistics = NULL; // must release
6493 	bool reslide = false;
6494 
6495 	/* TODO: Check we are looking for same dextID
6496 	 * and if it is not the same
6497 	 * restart the matching process.
6498 	 */
6499 	driverKext = OSKext::lookupDextWithIdentifier(bundleID, serverDUI);
6500 	if (driverKext != NULL) {
6501 		driverStatistics = driverKext->copyDextStatistics();
6502 		if (driverStatistics == NULL) {
6503 			panic("Kext %s was not a DriverKit OSKext", bundleID->getCStringNoCopy());
6504 		}
6505 		IOLog("Driver %s has crashed %zu time(s)\n", bundleID->getCStringNoCopy(), driverStatistics->getCrashCount());
6506 		reslide = driverStatistics->getCrashCount() > 0;
6507 	} else {
6508 		DKLOG("Could not find OSKext for %s\n", bundleID->getCStringNoCopy());
6509 		*resultToken = NULL;
6510 		return NULL;
6511 	}
6512 
6513 	IORecursiveLockLock(gDriverKitLaunchLock);
6514 
6515 	if (gDriverKitLaunches == NULL) {
6516 		// About to shut down, don't launch anything
6517 		goto finish;
6518 	}
6519 
6520 	if (reuseIfExists) {
6521 		const char * serverNameCStr;
6522 		const char * bundleIDCStr;
6523 		const char * endOrgCStr;
6524 
6525 		serverNameCStr = serverName->getCStringNoCopy();
6526 		bundleIDCStr = bundleID->getCStringNoCopy();
6527 		(endOrgCStr = strchr(bundleIDCStr, '.')) && (endOrgCStr = strchr(endOrgCStr + 1, '.'));
6528 		reuseIfExists = endOrgCStr && (0 == strncmp(bundleIDCStr, serverNameCStr, endOrgCStr + 1 - bundleIDCStr));
6529 		if (!reuseIfExists) {
6530 			IOLog(kIOUserServerNameKey " \"%s\" not correct organization for bundleID \"%s\"\n", serverNameCStr, bundleIDCStr);
6531 		}
6532 	}
6533 
6534 	// Find existing server
6535 	if (reuseIfExists) {
6536 		token = IOUserServerCheckInToken::findExistingToken(serverName);
6537 		if (token) {
6538 			// Launch in progress, return token
6539 			goto finish;
6540 		} else {
6541 			// Check if launch completed
6542 			matching = IOService::serviceMatching(gIOUserServerClassKey);
6543 			if (!matching) {
6544 				goto finish;
6545 			}
6546 			IOService::propertyMatching(gIOUserServerNameKey, serverName, matching);
6547 			IOService * service = IOService::copyMatchingService(matching);
6548 			IOUserServer * userServer = OSDynamicCast(IOUserServer, service);
6549 			if (userServer) {
6550 				// found existing user server
6551 				me = userServer;
6552 				goto finish;
6553 			} else {
6554 				OSSafeReleaseNULL(service);
6555 			}
6556 		}
6557 	}
6558 
6559 	// No existing server, request launch
6560 	token = new IOUserServerCheckInToken;
6561 	if (!token) {
6562 		goto finish;
6563 	}
6564 
6565 	/*
6566 	 * TODO: If the init fails because the personalities are not up to date
6567 	 * restart the whole matching process.
6568 	 */
6569 	if (token && !token->init(serverName, serverTag, driverKext, serverDUI)) {
6570 		IOLog("Could not initialize token\n");
6571 		OSSafeReleaseNULL(token);
6572 		goto finish;
6573 	}
6574 
6575 	/*
6576 	 * If the launch fails at any point terminate() will
6577 	 * be called on this IOUserServer.
6578 	 */
6579 	gDriverKitLaunches->setObject(token);
6580 	OSKext::requestDaemonLaunch(bundleID, (OSString *)serverName, serverTag, reslide ? kOSBooleanTrue : kOSBooleanFalse, token, serverDUI);
6581 
6582 finish:
6583 	IORecursiveLockUnlock(gDriverKitLaunchLock);
6584 	OSSafeReleaseNULL(matching);
6585 	OSSafeReleaseNULL(driverStatistics);
6586 	OSSafeReleaseNULL(driverKext);
6587 
6588 	if (resultToken) {
6589 		*resultToken = token;
6590 	} else {
6591 		OSSafeReleaseNULL(token);
6592 	}
6593 
6594 	return me;
6595 }
6596 
6597 /*
6598  * IOUserServerCheckInTokens are used to track dext launches. They have three possible states:
6599  *
6600  * - Pending: A dext launch is pending
6601  * - Canceled: Dext launch failed
6602  * - Complete: Dext launch is complete
6603  *
6604  * A token can be shared among multiple IOServices that are waiting for dexts if the IOUserServerName
6605  * is the same. This allows dexts to be reused and host multiple services. All pending tokens are stored
6606  * in gDriverKitLaunches and we check here before creating a new token when launching a dext.
6607  *
6608  * A token starts in the pending state with a pending count of 1. When we reuse a token, we increase the
6609  * pending count of the token.
6610  *
6611  * The token is sent to userspace as a mach port through kernelmanagerd/driverkitd to the dext. The dext then
6612  * uses that token to check in to the kernel. If any part of the dext launch failed (dext crashed, kmd crashed, etc.)
6613  * we get a no-senders notification for the token in the kernel and the token goes into the Canceled state.
6614  *
6615  * Once the dext checks in to the kernel, we decrement the pending count for the token. When the pending count reaches
6616  * 0, the token goes into the Complete state. So if the token is in the Complete state, there are no kernel matching threads
6617  * waiting on the dext to check in.
6618  */
6619 
6620 IOUserServerCheckInToken *
6621 IOUserServerCheckInToken::findExistingToken(const OSSymbol * serverName)
6622 {
6623 	IOUserServerCheckInToken * __block result = NULL;
6624 
6625 	IORecursiveLockLock(gDriverKitLaunchLock);
6626 	if (gDriverKitLaunches == NULL) {
6627 		goto finish;
6628 	}
6629 
6630 	gDriverKitLaunches->iterateObjects(^(OSObject * obj) {
6631 		IOUserServerCheckInToken * token = OSDynamicCast(IOUserServerCheckInToken, obj);
6632 		if (token) {
6633 		        // Check if server name matches
6634 		        const OSSymbol * tokenServerName = token->fServerName;
6635 		        if (tokenServerName->isEqualTo(serverName)) {
6636 		                assert(token->fState == kIOUserServerCheckInPending);
6637 		                token->fPendingCount++;
6638 		                result = token;
6639 		                result->retain();
6640 			}
6641 		}
6642 		return result != NULL;
6643 	});
6644 
6645 finish:
6646 	IORecursiveLockUnlock(gDriverKitLaunchLock);
6647 	return result;
6648 }
6649 
6650 void
6651 IOUserServerCheckInToken::cancelAll()
6652 {
6653 	OSSet * tokensToCancel;
6654 
6655 	IORecursiveLockLock(gDriverKitLaunchLock);
6656 	tokensToCancel = gDriverKitLaunches;
6657 	gDriverKitLaunches = NULL;
6658 
6659 
6660 	tokensToCancel->iterateObjects(^(OSObject *obj) {
6661 		IOUserServerCheckInToken * token = OSDynamicCast(IOUserServerCheckInToken, obj);
6662 		if (token) {
6663 		        token->cancel();
6664 		}
6665 		return false;
6666 	});
6667 
6668 	IORecursiveLockUnlock(gDriverKitLaunchLock);
6669 
6670 	OSSafeReleaseNULL(tokensToCancel);
6671 }
6672 
6673 void
6674 _IOUserServerCheckInCancellationHandler::call(IOUserServerCheckInToken * token)
6675 {
6676 	fHandler(token, fHandlerArgs);
6677 }
6678 
6679 _IOUserServerCheckInCancellationHandler *
6680 _IOUserServerCheckInCancellationHandler::withHandler(IOUserServerCheckInCancellationHandler handler, void * args)
6681 {
6682 	_IOUserServerCheckInCancellationHandler * handlerObj = NULL;
6683 	if (!handler) {
6684 		goto finish;
6685 	}
6686 
6687 	handlerObj = new _IOUserServerCheckInCancellationHandler;
6688 	if (!handlerObj) {
6689 		goto finish;
6690 	}
6691 
6692 	handlerObj->fHandler = handler;
6693 	handlerObj->fHandlerArgs = args;
6694 
6695 finish:
6696 	return handlerObj;
6697 }
6698 
6699 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6700 
6701 struct IOServiceStateNotificationDispatchSource_IVars {
6702 	IOLock                       * fLock;
6703 	IOService                    * fStateNotification;
6704 	IOStateNotificationListenerRef fListener;
6705 	OSAction                     * fAction;
6706 	bool                           fEnable;
6707 	bool                           fArmed;
6708 };
6709 
6710 kern_return_t
6711 IOServiceStateNotificationDispatchSource::Create_Impl(IOService * service, OSArray * items,
6712     IODispatchQueue * queue, IOServiceStateNotificationDispatchSource ** outSource)
6713 {
6714 	kern_return_t kr;
6715 	IOServiceStateNotificationDispatchSource * source;
6716 
6717 	source = OSTypeAlloc(IOServiceStateNotificationDispatchSource);
6718 	source->init();
6719 
6720 	source->ivars->fStateNotification = service;
6721 	kr = service->stateNotificationListenerAdd(items, &source->ivars->fListener, ^kern_return_t () {
6722 		OSAction * action;
6723 
6724 		action = NULL;
6725 		IOLockLock(source->ivars->fLock);
6726 		if (source->ivars->fArmed && source->ivars->fAction) {
6727 		        source->ivars->fArmed = false;
6728 		        action = source->ivars->fAction;
6729 		        action->retain();
6730 		}
6731 		IOLockUnlock(source->ivars->fLock);
6732 		if (action) {
6733 		        source->StateNotificationReady(action);
6734 		        OSSafeReleaseNULL(action);
6735 		}
6736 		return kIOReturnSuccess;
6737 	});
6738 
6739 	if (kIOReturnSuccess != kr) {
6740 		OSSafeReleaseNULL(source);
6741 	}
6742 	*outSource = source;
6743 
6744 	return kr;
6745 }
6746 
6747 
6748 bool
6749 IOServiceStateNotificationDispatchSource::init()
6750 {
6751 	if (!IODispatchSource::init()) {
6752 		return false;
6753 	}
6754 	ivars = IOMallocType(IOServiceStateNotificationDispatchSource_IVars);
6755 	if (!ivars) {
6756 		return false;
6757 	}
6758 	ivars->fLock = IOLockAlloc();
6759 	if (!ivars->fLock) {
6760 		return false;
6761 	}
6762 	ivars->fArmed = true;
6763 
6764 	return true;
6765 }
6766 
6767 void
6768 IOServiceStateNotificationDispatchSource::free()
6769 {
6770 	if (ivars) {
6771 		if (ivars->fListener) {
6772 			ivars->fStateNotification->stateNotificationListenerRemove(ivars->fListener);
6773 		}
6774 		if (ivars->fLock) {
6775 			IOLockFree(ivars->fLock);
6776 		}
6777 		IOFreeType(ivars, IOServiceStateNotificationDispatchSource_IVars);
6778 	}
6779 	IODispatchSource::free();
6780 }
6781 
6782 kern_return_t
6783 IOServiceStateNotificationDispatchSource::SetHandler_Impl(OSAction * action)
6784 {
6785 	IOReturn ret;
6786 	bool     notifyReady;
6787 
6788 	notifyReady = false;
6789 
6790 	IOLockLock(ivars->fLock);
6791 	action->retain();
6792 	OSSafeReleaseNULL(ivars->fAction);
6793 	ivars->fAction = action;
6794 	if (action) {
6795 		notifyReady = true;
6796 	}
6797 	IOLockUnlock(ivars->fLock);
6798 
6799 	if (notifyReady) {
6800 		StateNotificationReady(action);
6801 	}
6802 	ret = kIOReturnSuccess;
6803 
6804 	return ret;
6805 }
6806 
6807 kern_return_t
6808 IOServiceStateNotificationDispatchSource::SetEnableWithCompletion_Impl(
6809 	bool enable,
6810 	IODispatchSourceCancelHandler handler)
6811 {
6812 	if (enable == ivars->fEnable) {
6813 		return kIOReturnSuccess;
6814 	}
6815 
6816 	IOLockLock(ivars->fLock);
6817 	ivars->fEnable = enable;
6818 	IOLockUnlock(ivars->fLock);
6819 
6820 	return kIOReturnSuccess;
6821 }
6822 
6823 kern_return_t
6824 IOServiceStateNotificationDispatchSource::Cancel_Impl(
6825 	IODispatchSourceCancelHandler handler)
6826 {
6827 	return kIOReturnUnsupported;
6828 }
6829 
6830 kern_return_t
6831 IOServiceStateNotificationDispatchSource::StateNotificationBegin_Impl(void)
6832 {
6833 	IOLockLock(ivars->fLock);
6834 	ivars->fArmed = true;
6835 	IOLockUnlock(ivars->fLock);
6836 
6837 	return kIOReturnSuccess;
6838 }
6839 
6840 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6841 
6842 #include <IOKit/IOServiceStateNotificationEventSource.h>
6843 
6844 OSDefineMetaClassAndStructors(IOServiceStateNotificationEventSource, IOEventSource)
6845 OSMetaClassDefineReservedUnused(IOServiceStateNotificationEventSource, 0);
6846 OSMetaClassDefineReservedUnused(IOServiceStateNotificationEventSource, 1);
6847 OSMetaClassDefineReservedUnused(IOServiceStateNotificationEventSource, 2);
6848 OSMetaClassDefineReservedUnused(IOServiceStateNotificationEventSource, 3);
6849 OSMetaClassDefineReservedUnused(IOServiceStateNotificationEventSource, 4);
6850 OSMetaClassDefineReservedUnused(IOServiceStateNotificationEventSource, 5);
6851 OSMetaClassDefineReservedUnused(IOServiceStateNotificationEventSource, 6);
6852 OSMetaClassDefineReservedUnused(IOServiceStateNotificationEventSource, 7);
6853 
6854 OSPtr<IOServiceStateNotificationEventSource>
6855 IOServiceStateNotificationEventSource::serviceStateNotificationEventSource(IOService *service,
6856     OSArray * items,
6857     ActionBlock inAction)
6858 {
6859 	kern_return_t kr;
6860 	IOServiceStateNotificationEventSource * source;
6861 
6862 	source = OSTypeAlloc(IOServiceStateNotificationEventSource);
6863 	if (source && !source->init(service, NULL)) {
6864 		OSSafeReleaseNULL(source);
6865 	}
6866 
6867 	if (!source) {
6868 		return nullptr;
6869 	}
6870 
6871 	source->fStateNotification = service;
6872 	kr = service->stateNotificationListenerAdd(items, &source->fListener, ^kern_return_t () {
6873 		if (!source->workLoop) {
6874 		        return kIOReturnSuccess;
6875 		}
6876 		source->workLoop->runActionBlock(^IOReturn (void) {
6877 			source->fArmed = true;
6878 			return kIOReturnSuccess;
6879 		});
6880 		source->signalWorkAvailable();
6881 		return kIOReturnSuccess;
6882 	});
6883 
6884 	if (kIOReturnSuccess != kr) {
6885 		OSSafeReleaseNULL(source);
6886 	}
6887 
6888 	if (source) {
6889 		source->setActionBlock((IOEventSource::ActionBlock) inAction);
6890 	}
6891 
6892 	return source;
6893 }
6894 
6895 void
6896 IOServiceStateNotificationEventSource::free()
6897 {
6898 	if (fListener) {
6899 		fStateNotification->stateNotificationListenerRemove(fListener);
6900 	}
6901 	IOEventSource::free();
6902 }
6903 
6904 void
6905 IOServiceStateNotificationEventSource::enable()
6906 {
6907 	fEnable = true;
6908 }
6909 
6910 void
6911 IOServiceStateNotificationEventSource::disable()
6912 {
6913 	fEnable = false;
6914 }
6915 
6916 void
6917 IOServiceStateNotificationEventSource::setWorkLoop(IOWorkLoop *inWorkLoop)
6918 {
6919 	IOEventSource::setWorkLoop(inWorkLoop);
6920 }
6921 
6922 bool
6923 IOServiceStateNotificationEventSource::checkForWork()
6924 {
6925 	ActionBlock intActionBlock = (ActionBlock) actionBlock;
6926 
6927 	if (fArmed) {
6928 		fArmed = false;
6929 		(intActionBlock)();
6930 	}
6931 
6932 	return false;
6933 }
6934 
6935 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6936 
6937 OSDefineMetaClassAndStructors(IOSystemStateNotification, IOService);
6938 
6939 class IOStateNotificationItem : public OSObject
6940 {
6941 	OSDeclareDefaultStructors(IOStateNotificationItem);
6942 
6943 public:
6944 	virtual bool init() override;
6945 
6946 	OSDictionary * fSchema;
6947 	OSDictionary * fValue;
6948 	OSSet        * fListeners;
6949 };
6950 OSDefineMetaClassAndStructors(IOStateNotificationItem, OSObject);
6951 
6952 
6953 class IOStateNotificationListener : public OSObject
6954 {
6955 	OSDeclareDefaultStructors(IOStateNotificationListener);
6956 
6957 public:
6958 	virtual bool init() override;
6959 	virtual void free() override;
6960 
6961 	IOStateNotificationHandler fHandler;
6962 };
6963 OSDefineMetaClassAndStructors(IOStateNotificationListener, OSObject);
6964 
6965 
6966 bool
6967 IOStateNotificationItem::init()
6968 {
6969 	return OSObject::init();
6970 }
6971 
6972 bool
6973 IOStateNotificationListener::init()
6974 {
6975 	return OSObject::init();
6976 }
6977 
6978 void
6979 IOStateNotificationListener::free()
6980 {
6981 	if (fHandler) {
6982 		Block_release(fHandler);
6983 	}
6984 	OSObject::free();
6985 }
6986 
6987 
6988 struct IOServiceStateChangeVars {
6989 	IOLock       * fLock;
6990 	OSDictionary * fItems;
6991 };
6992 
6993 IOService *
6994 IOSystemStateNotification::initialize(void)
6995 {
6996 	IOSystemStateNotification * me;
6997 	IOServiceStateChangeVars  * vars;
6998 
6999 	me = OSTypeAlloc(IOSystemStateNotification);
7000 	me->init();
7001 	vars = IOMallocType(IOServiceStateChangeVars);
7002 	me->reserved->svars = vars;
7003 	vars->fLock  = IOLockAlloc();
7004 	vars->fItems = OSDictionary::withCapacity(16);
7005 	{
7006 		kern_return_t ret;
7007 
7008 		gIOSystemStateSleepDescriptionKey = (OSString *)OSSymbol::withCStringNoCopy(kIOSystemStateSleepDescriptionKey);
7009 		gIOSystemStateSleepDescriptionHibernateStateKey = OSSymbol::withCStringNoCopy(kIOSystemStateSleepDescriptionHibernateStateKey);
7010 		gIOSystemStateSleepDescriptionReasonKey = OSSymbol::withCStringNoCopy(kIOSystemStateSleepDescriptionReasonKey);
7011 
7012 		ret = me->StateNotificationItemCreate(gIOSystemStateSleepDescriptionKey, NULL);
7013 		assert(kIOReturnSuccess == ret);
7014 
7015 		gIOSystemStateWakeDescriptionKey = (OSString *)OSSymbol::withCStringNoCopy(kIOSystemStateWakeDescriptionKey);
7016 		gIOSystemStateWakeDescriptionWakeReasonKey = OSSymbol::withCStringNoCopy(kIOSystemStateWakeDescriptionWakeReasonKey);
7017 		gIOSystemStateWakeDescriptionContinuousTimeOffsetKey = OSSymbol::withCStringNoCopy(kIOSystemStateWakeDescriptionContinuousTimeOffsetKey);
7018 
7019 		ret = me->StateNotificationItemCreate(gIOSystemStateWakeDescriptionKey, NULL);
7020 		assert(kIOReturnSuccess == ret);
7021 
7022 		gIOSystemStateHaltDescriptionKey = (OSString *)OSSymbol::withCStringNoCopy(kIOSystemStateHaltDescriptionKey);
7023 		gIOSystemStateHaltDescriptionHaltStateKey = OSSymbol::withCStringNoCopy(kIOSystemStateHaltDescriptionHaltStateKey);
7024 
7025 		ret = me->StateNotificationItemCreate(gIOSystemStateHaltDescriptionKey, NULL);
7026 		assert(kIOReturnSuccess == ret);
7027 
7028 		gIOSystemStatePowerSourceDescriptionKey = (OSString *)OSSymbol::withCStringNoCopy(kIOSystemStatePowerSourceDescriptionKey);
7029 		gIOSystemStatePowerSourceDescriptionACAttachedKey = OSSymbol::withCStringNoCopy(kIOSystemStatePowerSourceDescriptionACAttachedKey);
7030 
7031 		ret = me->StateNotificationItemCreate(gIOSystemStatePowerSourceDescriptionKey, NULL);
7032 		assert(kIOReturnSuccess == ret);
7033 	}
7034 
7035 	return me;
7036 }
7037 
7038 bool
7039 IOSystemStateNotification::serializeProperties(OSSerialize * s) const
7040 {
7041 	IOServiceStateChangeVars * ivars = reserved->svars;
7042 
7043 	bool ok;
7044 	OSDictionary * result;
7045 
7046 	result = OSDictionary::withCapacity(16);
7047 
7048 	IOLockLock(ivars->fLock);
7049 	ivars->fItems->iterateObjects(^bool (const OSSymbol * key, OSObject * object) {
7050 		IOStateNotificationItem * item;
7051 
7052 		item = (typeof(item))object;
7053 		if (!item->fValue) {
7054 		        return false;
7055 		}
7056 		result->setObject(key, item->fValue);
7057 		return false;
7058 	});
7059 	IOLockUnlock(ivars->fLock);
7060 
7061 	ok = result->serialize(s);
7062 	OSSafeReleaseNULL(result);
7063 
7064 	return ok;
7065 }
7066 
7067 kern_return_t
7068 IOSystemStateNotification::setProperties(OSObject * properties)
7069 {
7070 	kern_return_t  kr;
7071 	OSDictionary * dict;
7072 	OSDictionary * schema;
7073 	OSDictionary * value;
7074 	OSString     * itemName;
7075 
7076 	dict = OSDynamicCast(OSDictionary, properties);
7077 	if (!dict) {
7078 		return kIOReturnBadArgument;
7079 	}
7080 
7081 	if (!IOCurrentTaskHasEntitlement(kIOSystemStateEntitlement)) {
7082 		return kIOReturnNotPermitted;
7083 	}
7084 
7085 	if ((schema = OSDynamicCast(OSDictionary, dict->getObject(kIOStateNotificationItemCreateKey)))) {
7086 		itemName = OSDynamicCast(OSString, schema->getObject(kIOStateNotificationNameKey));
7087 		kr = StateNotificationItemCreate(itemName, schema);
7088 	} else if ((value = OSDynamicCast(OSDictionary, dict->getObject(kIOStateNotificationItemSetKey)))) {
7089 		itemName = OSDynamicCast(OSString, value->getObject(kIOStateNotificationNameKey));
7090 		itemName->retain();
7091 		value->removeObject(kIOStateNotificationNameKey);
7092 		kr = StateNotificationItemSet(itemName, value);
7093 		itemName->release();
7094 	} else {
7095 		kr = kIOReturnError;
7096 	}
7097 
7098 	return kr;
7099 }
7100 
7101 kern_return_t
7102 IOService::CopySystemStateNotificationService_Impl(IOService ** outService)
7103 {
7104 	IOService * service;
7105 
7106 	service = getSystemStateNotificationService();
7107 	service->retain();
7108 	*outService = service;
7109 
7110 	return kIOReturnSuccess;
7111 }
7112 
7113 IOStateNotificationItem *
7114 IOService::stateNotificationItemCopy(OSString * itemName, OSDictionary * schema)
7115 {
7116 	IOServiceStateChangeVars * ivars = reserved->svars;
7117 
7118 	const OSSymbol          * name;
7119 	IOStateNotificationItem * item;
7120 
7121 	name = OSSymbol::withString(itemName);
7122 
7123 	IOLockLock(ivars->fLock);
7124 	if ((item = (typeof(item))ivars->fItems->getObject(name))) {
7125 		item->retain();
7126 	} else {
7127 		item = OSTypeAlloc(IOStateNotificationItem);
7128 		item->init();
7129 		item->fListeners = OSSet::withCapacity(16);
7130 
7131 		if (schema) {
7132 			schema->retain();
7133 		} else {
7134 			schema = OSDictionary::withCapacity(8);
7135 		}
7136 		schema->setObject(kIOStateNotificationNameKey, name);
7137 		item->fSchema = schema;
7138 		ivars->fItems->setObject(name, item);
7139 	}
7140 	IOLockUnlock(ivars->fLock);
7141 
7142 	OSSafeReleaseNULL(name);
7143 
7144 	return item;
7145 }
7146 
7147 kern_return_t
7148 IOService::StateNotificationItemCreate_Impl(OSString * itemName, OSDictionary * schema)
7149 {
7150 	IOStateNotificationItem * item;
7151 
7152 	item = stateNotificationItemCopy(itemName, schema);
7153 	if (!item) {
7154 		return kIOReturnNoMemory;
7155 	}
7156 	item->release();
7157 
7158 	return kIOReturnSuccess;
7159 }
7160 
7161 kern_return_t
7162 IOService::StateNotificationItemSet_Impl(OSString * itemName, OSDictionary * value)
7163 {
7164 	IOServiceStateChangeVars * ivars = reserved->svars;
7165 
7166 	OSSet                   * listeners;
7167 	IOStateNotificationItem * item;
7168 
7169 	value->retain();
7170 	IOLockLock(ivars->fLock);
7171 	item = (typeof(item))ivars->fItems->getObject(itemName);
7172 	OSSafeReleaseNULL(item->fValue);
7173 	item->fValue = value;
7174 	listeners = NULL;
7175 	if (item->fListeners->getCount()) {
7176 		listeners = OSSet::withSet(item->fListeners);
7177 	}
7178 	IOLockUnlock(ivars->fLock);
7179 
7180 	if (listeners) {
7181 		listeners->iterateObjects(^bool (OSObject * object) {
7182 			IOStateNotificationListener * listener;
7183 
7184 			listener = (typeof(listener))object;
7185 			listener->fHandler();
7186 			return false;
7187 		});
7188 		OSSafeReleaseNULL(listeners);
7189 	}
7190 
7191 	return kIOReturnSuccess;
7192 }
7193 
7194 kern_return_t
7195 IOService::StateNotificationItemCopy_Impl(OSString * itemName, OSDictionary ** outValue)
7196 {
7197 	IOServiceStateChangeVars * ivars = reserved->svars;
7198 
7199 	kern_return_t              ret;
7200 	IOStateNotificationItem  * item;
7201 	OSDictionary             * value;
7202 
7203 	IOLockLock(ivars->fLock);
7204 	item = (typeof(item))ivars->fItems->getObject(itemName);
7205 	if (item) {
7206 		value = item->fValue;
7207 	} else {
7208 		value = NULL;
7209 	}
7210 	if (!value) {
7211 		ret = kIOReturnNotFound;
7212 	} else {
7213 		value->retain();
7214 		ret = kIOReturnSuccess;
7215 	}
7216 	IOLockUnlock(ivars->fLock);
7217 
7218 	*outValue = value;
7219 
7220 	return ret;
7221 }
7222 
7223 kern_return_t
7224 IOService::stateNotificationListenerAdd(OSArray * items,
7225     IOStateNotificationListenerRef * outRef,
7226     IOStateNotificationHandler handler)
7227 {
7228 	IOServiceStateChangeVars * ivars = reserved->svars;
7229 
7230 	kern_return_t                 kr __block;
7231 	IOStateNotificationListener * listener;
7232 
7233 	listener = OSTypeAlloc(IOStateNotificationListener);
7234 	listener->init();
7235 	listener->fHandler = Block_copy(handler);
7236 
7237 	kr = kIOReturnSuccess;
7238 	items->iterateObjects(^bool (OSObject * object) {
7239 		OSString                * itemName;
7240 		IOStateNotificationItem * item;
7241 
7242 		itemName = OSDynamicCast(OSString, object);
7243 		if (!itemName) {
7244 		        kr = kIOReturnBadArgument;
7245 		        return true;
7246 		}
7247 		item = stateNotificationItemCopy(itemName, NULL);
7248 		if (!item) {
7249 		        kr = kIOReturnNoMemory;
7250 		        return true;
7251 		}
7252 		IOLockLock(ivars->fLock);
7253 		item->fListeners->setObject(listener);
7254 		IOLockUnlock(ivars->fLock);
7255 		item->release();
7256 		return false;
7257 	});
7258 
7259 	if (kIOReturnSuccess != kr) {
7260 		stateNotificationListenerRemove(listener);
7261 		OSSafeReleaseNULL(listener);
7262 	}
7263 	*outRef = listener;
7264 
7265 	return kr;
7266 }
7267 
7268 
7269 kern_return_t
7270 IOService::stateNotificationListenerRemove(IOStateNotificationListenerRef ref)
7271 {
7272 	IOServiceStateChangeVars * ivars = reserved->svars;
7273 
7274 	IOStateNotificationListener * listener;
7275 	kern_return_t                 kr;
7276 
7277 	kr = kIOReturnSuccess;
7278 	listener = (typeof(listener))ref;
7279 
7280 	IOLockLock(ivars->fLock);
7281 	ivars->fItems->iterateObjects(^bool (const OSSymbol * key, OSObject * object) {
7282 		IOStateNotificationItem * item;
7283 
7284 		item = (typeof(item))object;
7285 		item->fListeners->removeObject(listener);
7286 		return false;
7287 	});
7288 	IOLockUnlock(ivars->fLock);
7289 
7290 	return kr;
7291 }
7292 
7293 
7294 
7295 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7296 
7297 kern_return_t
7298 IOWorkGroup::Create_Impl(OSString * name, IOUserClient * userClient, IOWorkGroup ** workgroup)
7299 {
7300 	IOWorkGroup * inst = NULL;
7301 	IOUserUserClient * uc = NULL;
7302 	kern_return_t ret = kIOReturnError;
7303 	IOUserServer * us;
7304 
7305 	if (name == NULL) {
7306 		ret = kIOReturnBadArgument;
7307 		goto finish;
7308 	}
7309 
7310 	if (name->getLength() > kIOWorkGroupMaxNameLength) {
7311 		ret = kIOReturnBadArgument;
7312 		goto finish;
7313 	}
7314 
7315 	uc = OSDynamicCast(IOUserUserClient, userClient);
7316 	if (uc == NULL) {
7317 		ret = kIOReturnBadArgument;
7318 		goto finish;
7319 	}
7320 
7321 	inst = OSTypeAlloc(IOWorkGroup);
7322 	if (!inst->init()) {
7323 		inst->free();
7324 		inst = NULL;
7325 		ret = kIOReturnNoMemory;
7326 		goto finish;
7327 	}
7328 
7329 	us = (typeof(us))thread_iokit_tls_get(0);
7330 	inst->ivars->userServer = OSDynamicCast(IOUserServer, us);
7331 
7332 	if (inst->ivars->userServer == NULL) {
7333 		ret = kIOReturnBadArgument;
7334 		goto finish;
7335 	}
7336 	inst->ivars->userServer->retain();
7337 
7338 	inst->ivars->name = name;
7339 	inst->ivars->name->retain();
7340 
7341 	inst->ivars->userClient = uc; // no retain
7342 
7343 	IOLockLock(uc->fLock);
7344 	uc->fWorkGroups->setObject(name, inst);
7345 	IOLockUnlock(uc->fLock);
7346 	ret = kIOReturnSuccess;
7347 
7348 finish:
7349 	if (ret != kIOReturnSuccess) {
7350 		OSSafeReleaseNULL(inst);
7351 	} else {
7352 		*workgroup = inst;
7353 	}
7354 
7355 	return ret;
7356 }
7357 
7358 kern_return_t
7359 IOWorkGroup::InvalidateKernel_Impl(IOUserClient * client)
7360 {
7361 	IOUserUserClient * uc = OSDynamicCast(IOUserUserClient, client);
7362 
7363 	if (uc == NULL) {
7364 		return kIOReturnBadArgument;
7365 	}
7366 
7367 	if (uc != ivars->userClient) {
7368 		return kIOReturnBadArgument;
7369 	}
7370 
7371 	IOLockLock(uc->fLock);
7372 	uc->fWorkGroups->removeObject(ivars->name);
7373 	IOLockUnlock(uc->fLock);
7374 
7375 	return kIOReturnSuccess;
7376 }
7377 
7378 kern_return_t
7379 IOWorkGroup::SetWorkGroupPort_Impl(mach_port_t port)
7380 {
7381 	return kIOReturnUnsupported;
7382 }
7383 
7384 bool
7385 IOWorkGroup::init()
7386 {
7387 	if (!OSObject::init()) {
7388 		return false;
7389 	}
7390 	ivars = IOMallocType(IOWorkGroup_IVars);
7391 
7392 	return true;
7393 }
7394 
7395 void
7396 IOWorkGroup::free()
7397 {
7398 	if (ivars) {
7399 		OSSafeReleaseNULL(ivars->userServer);
7400 		OSSafeReleaseNULL(ivars->name);
7401 		IOFreeType(ivars, IOWorkGroup_IVars);
7402 	}
7403 
7404 	OSObject::free();
7405 }
7406 
7407 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7408 
7409 kern_return_t
7410 IOEventLink::Create_Impl(OSString * name, IOUserClient * userClient, IOEventLink ** eventlink)
7411 {
7412 	IOEventLink * inst = NULL;
7413 	IOUserUserClient * uc = NULL;
7414 	IOUserServer * us;
7415 	kern_return_t ret = kIOReturnError;
7416 
7417 	if (name == NULL) {
7418 		ret = kIOReturnBadArgument;
7419 		goto finish;
7420 	}
7421 
7422 	if (name->getLength() > kIOEventLinkMaxNameLength) {
7423 		ret = kIOReturnBadArgument;
7424 		goto finish;
7425 	}
7426 
7427 	uc = OSDynamicCast(IOUserUserClient, userClient);
7428 	if (uc == NULL) {
7429 		ret = kIOReturnBadArgument;
7430 		goto finish;
7431 	}
7432 
7433 	inst = OSTypeAlloc(IOEventLink);
7434 	if (!inst->init()) {
7435 		inst->free();
7436 		inst = NULL;
7437 		ret = kIOReturnNoMemory;
7438 		goto finish;
7439 	}
7440 
7441 	us = (typeof(us))thread_iokit_tls_get(0);
7442 	inst->ivars->userServer = OSDynamicCast(IOUserServer, us);
7443 
7444 	if (inst->ivars->userServer == NULL) {
7445 		ret = kIOReturnBadArgument;
7446 		goto finish;
7447 	}
7448 	inst->ivars->userServer->retain();
7449 
7450 	inst->ivars->name = name;
7451 	inst->ivars->name->retain();
7452 
7453 	inst->ivars->userClient = uc; // no retain
7454 
7455 	IOLockLock(uc->fLock);
7456 	uc->fEventLinks->setObject(name, inst);
7457 	IOLockUnlock(uc->fLock);
7458 
7459 	ret = kIOReturnSuccess;
7460 
7461 finish:
7462 	if (ret != kIOReturnSuccess) {
7463 		OSSafeReleaseNULL(inst);
7464 	} else {
7465 		*eventlink = inst;
7466 	}
7467 
7468 	return ret;
7469 }
7470 
7471 kern_return_t
7472 IOEventLink::InvalidateKernel_Impl(IOUserClient * client)
7473 {
7474 	IOUserUserClient * uc = OSDynamicCast(IOUserUserClient, client);
7475 
7476 	if (uc == NULL) {
7477 		return kIOReturnBadArgument;
7478 	}
7479 
7480 	if (uc != ivars->userClient) {
7481 		return kIOReturnBadArgument;
7482 	}
7483 
7484 	IOLockLock(uc->fLock);
7485 	uc->fEventLinks->removeObject(ivars->name);
7486 	IOLockUnlock(uc->fLock);
7487 
7488 	return kIOReturnSuccess;
7489 }
7490 
7491 bool
7492 IOEventLink::init()
7493 {
7494 	if (!OSObject::init()) {
7495 		return false;
7496 	}
7497 	ivars = IOMallocType(IOEventLink_IVars);
7498 
7499 	return true;
7500 }
7501 
7502 void
7503 IOEventLink::free()
7504 {
7505 	if (ivars) {
7506 		OSSafeReleaseNULL(ivars->userServer);
7507 		OSSafeReleaseNULL(ivars->name);
7508 		IOFreeType(ivars, IOEventLink_IVars);
7509 	}
7510 
7511 	OSObject::free();
7512 }
7513 
7514 kern_return_t
7515 IOEventLink::SetEventlinkPort_Impl(mach_port_t port __unused)
7516 {
7517 	return kIOReturnUnsupported;
7518 }
7519