]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOUserClient.cpp
xnu-7195.101.1.tar.gz
[apple/xnu.git] / iokit / Kernel / IOUserClient.cpp
CommitLineData
1c79356b 1/*
cb323159 2 * Copyright (c) 1998-2019 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
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.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b 27 */
55e303ae 28
1c79356b 29
b0d623f7 30#include <libkern/c++/OSKext.h>
f427ee49 31#include <libkern/c++/OSSharedPtr.h>
1c79356b 32#include <IOKit/IOKitServer.h>
8f6c56a5 33#include <IOKit/IOKitKeysPrivate.h>
1c79356b
A
34#include <IOKit/IOUserClient.h>
35#include <IOKit/IOService.h>
36#include <IOKit/IORegistryEntry.h>
37#include <IOKit/IOCatalogue.h>
38#include <IOKit/IOMemoryDescriptor.h>
b0d623f7 39#include <IOKit/IOBufferMemoryDescriptor.h>
1c79356b 40#include <IOKit/IOLib.h>
4d15aeb1 41#include <IOKit/IOBSD.h>
6d2010ae
A
42#include <IOKit/IOStatisticsPrivate.h>
43#include <IOKit/IOTimeStamp.h>
a39ff7e2 44#include <IOKit/IODeviceTreeSupport.h>
cb323159 45#include <IOKit/IOUserServer.h>
39236c6e 46#include <IOKit/system.h>
b0d623f7 47#include <libkern/OSDebug.h>
cb323159 48#include <DriverKit/OSAction.h>
2d21ac55 49#include <sys/proc.h>
6d2010ae 50#include <sys/kauth.h>
fe8ab488 51#include <sys/codesign.h>
6d2010ae 52
39037602 53#include <mach/sdt.h>
cb323159 54#include <os/hash.h>
39037602 55
6d2010ae
A
56#if CONFIG_MACF
57
58extern "C" {
59#include <security/mac_framework.h>
60};
61#include <sys/kauth.h>
62
63#define IOMACF_LOG 0
64
65#endif /* CONFIG_MACF */
1c79356b
A
66
67#include <IOKit/assert.h>
68
55e303ae 69#include "IOServicePrivate.h"
2d21ac55
A
70#include "IOKitKernelInternal.h"
71
72#define SCALAR64(x) ((io_user_scalar_t)((unsigned int)x))
73#define SCALAR32(x) ((uint32_t )x)
39236c6e 74#define ARG32(x) ((void *)(uintptr_t)SCALAR32(x))
b0d623f7 75#define REF64(x) ((io_user_reference_t)((UInt64)(x)))
2d21ac55
A
76#define REF32(x) ((int)(x))
77
0a7de745
A
78enum{
79 kIOUCAsync0Flags = 3ULL,
80 kIOUCAsync64Flag = 1ULL,
81 kIOUCAsyncErrorLoggedFlag = 2ULL
2d21ac55 82};
55e303ae 83
6d2010ae
A
84#if IOKITSTATS
85
86#define IOStatisticsRegisterCounter() \
87do { \
88 reserved->counter = IOStatistics::registerUserClient(this); \
89} while (0)
90
91#define IOStatisticsUnregisterCounter() \
92do { \
93 if (reserved) \
0a7de745 94 IOStatistics::unregisterUserClient(reserved->counter); \
6d2010ae
A
95} while (0)
96
97#define IOStatisticsClientCall() \
98do { \
99 IOStatistics::countUserClientCall(client); \
100} while (0)
101
102#else
103
104#define IOStatisticsRegisterCounter()
105#define IOStatisticsUnregisterCounter()
106#define IOStatisticsClientCall()
107
108#endif /* IOKITSTATS */
109
39037602
A
110#if DEVELOPMENT || DEBUG
111
112#define FAKE_STACK_FRAME(a) \
0a7de745
A
113 const void ** __frameptr; \
114 const void * __retaddr; \
115 __frameptr = (typeof(__frameptr)) __builtin_frame_address(0); \
116 __retaddr = __frameptr[1]; \
117 __frameptr[1] = (a);
39037602
A
118
119#define FAKE_STACK_FRAME_END() \
0a7de745 120 __frameptr[1] = __retaddr;
39037602
A
121
122#else /* DEVELOPMENT || DEBUG */
123
124#define FAKE_STACK_FRAME(a)
125#define FAKE_STACK_FRAME_END()
126
127#endif /* DEVELOPMENT || DEBUG */
128
0a7de745
A
129#define ASYNC_REF_COUNT (sizeof(io_async_ref_t) / sizeof(natural_t))
130#define ASYNC_REF64_COUNT (sizeof(io_async_ref64_t) / sizeof(io_user_reference_t))
131
1c79356b
A
132/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
133
1c79356b 134extern "C" {
91447636 135#include <mach/mach_traps.h>
1c79356b 136#include <vm/vm_map.h>
1c79356b
A
137} /* extern "C" */
138
cb323159
A
139struct IOMachPortHashList;
140
141static_assert(IKOT_MAX_TYPE <= 255);
142
1c79356b
A
143/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
144
145// IOMachPort maps OSObjects to ports, avoiding adding an ivar to OSObject.
1c79356b
A
146class IOMachPort : public OSObject
147{
cb323159 148 OSDeclareDefaultStructors(IOMachPort);
1c79356b 149public:
cb323159 150 SLIST_ENTRY(IOMachPort) link;
0a7de745 151 ipc_port_t port;
cb323159 152 OSObject* object;
0a7de745
A
153 UInt32 mscount;
154 UInt8 holdDestroy;
cb323159
A
155 UInt8 type;
156
157 static IOMachPort* withObjectAndType(OSObject *obj, ipc_kobject_type_t type);
158
159 static IOMachPortHashList* bucketForObject(OSObject *obj,
160 ipc_kobject_type_t type);
161
162 static IOMachPort* portForObjectInBucket(IOMachPortHashList *bucket, OSObject *obj, ipc_kobject_type_t type);
1c79356b 163
0a7de745
A
164 static bool noMoreSendersForObject( OSObject * obj,
165 ipc_kobject_type_t type, mach_port_mscount_t * mscount );
166 static void releasePortForObject( OSObject * obj,
167 ipc_kobject_type_t type );
168 static void setHoldDestroy( OSObject * obj, ipc_kobject_type_t type );
55e303ae 169
0a7de745
A
170 static mach_port_name_t makeSendRightForTask( task_t task,
171 io_object_t obj, ipc_kobject_type_t type );
1c79356b 172
0a7de745 173 virtual void free() APPLE_KEXT_OVERRIDE;
1c79356b
A
174};
175
176#define super OSObject
f427ee49 177OSDefineMetaClassAndStructorsWithZone(IOMachPort, OSObject, ZC_ZFREE_CLEARMEM)
1c79356b 178
0a7de745 179static IOLock * gIOObjectPortLock;
cb323159 180IOLock * gIOUserServerLock;
1c79356b 181
f427ee49
A
182SECURITY_READ_ONLY_LATE(const struct io_filter_callbacks *) gIOUCFilterCallbacks;
183
1c79356b
A
184/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
185
cb323159 186SLIST_HEAD(IOMachPortHashList, IOMachPort);
1c79356b 187
f427ee49 188#if defined(XNU_TARGET_OS_OSX)
cb323159 189#define PORT_HASH_SIZE 4096
f427ee49
A
190#else /* defined(!XNU_TARGET_OS_OSX) */
191#define PORT_HASH_SIZE 256
192#endif /* !defined(!XNU_TARGET_OS_OSX) */
1c79356b 193
f427ee49 194IOMachPortHashList gIOMachPortHash[PORT_HASH_SIZE];
1c79356b 195
cb323159
A
196void
197IOMachPortInitialize(void)
198{
199 for (size_t i = 0; i < PORT_HASH_SIZE; i++) {
f427ee49 200 SLIST_INIT(&gIOMachPortHash[i]);
0a7de745 201 }
1c79356b
A
202}
203
cb323159
A
204IOMachPortHashList*
205IOMachPort::bucketForObject(OSObject *obj, ipc_kobject_type_t type )
1c79356b 206{
f427ee49 207 return &gIOMachPortHash[os_hash_kernel_pointer(obj) % PORT_HASH_SIZE];
cb323159 208}
1c79356b 209
cb323159
A
210IOMachPort*
211IOMachPort::portForObjectInBucket(IOMachPortHashList *bucket, OSObject *obj, ipc_kobject_type_t type)
212{
213 IOMachPort *machPort;
1c79356b 214
cb323159
A
215 SLIST_FOREACH(machPort, bucket, link) {
216 if (machPort->object == obj && machPort->type == type) {
217 return machPort;
0a7de745 218 }
cb323159
A
219 }
220 return NULL;
221}
1c79356b 222
cb323159
A
223IOMachPort*
224IOMachPort::withObjectAndType(OSObject *obj, ipc_kobject_type_t type)
225{
226 IOMachPort *machPort = NULL;
1c79356b 227
cb323159
A
228 machPort = new IOMachPort;
229 if (__improbable(machPort && !machPort->init())) {
230 return NULL;
231 }
1c79356b 232
cb323159
A
233 machPort->object = obj;
234 machPort->type = (typeof(machPort->type))type;
235 machPort->port = iokit_alloc_object_port(obj, type);
1c79356b 236
cb323159
A
237 obj->taggedRetain(OSTypeID(OSCollection));
238 machPort->mscount++;
1c79356b 239
cb323159 240 return machPort;
1c79356b
A
241}
242
0a7de745
A
243bool
244IOMachPort::noMoreSendersForObject( OSObject * obj,
245 ipc_kobject_type_t type, mach_port_mscount_t * mscount )
246{
cb323159
A
247 IOMachPort *machPort = NULL;
248 IOUserClient *uc;
249 OSAction *action;
250 bool destroyed = true;
0a7de745 251
cb323159 252 IOMachPortHashList *bucket = IOMachPort::bucketForObject(obj, type);
0a7de745 253
cb323159 254 obj->retain();
0a7de745 255
cb323159
A
256 lck_mtx_lock(gIOObjectPortLock);
257
258 machPort = IOMachPort::portForObjectInBucket(bucket, obj, type);
259
260 if (machPort) {
261 destroyed = (machPort->mscount <= *mscount);
262 if (!destroyed) {
263 *mscount = machPort->mscount;
264 lck_mtx_unlock(gIOObjectPortLock);
265 } else {
266 if ((IKOT_IOKIT_CONNECT == type) && (uc = OSDynamicCast(IOUserClient, obj))) {
267 uc->noMoreSenders();
0a7de745 268 }
cb323159
A
269 SLIST_REMOVE(bucket, machPort, IOMachPort, link);
270
271 lck_mtx_unlock(gIOObjectPortLock);
272
273 machPort->release();
274 obj->taggedRelease(OSTypeID(OSCollection));
7e41aa88 275 }
cb323159
A
276 } else {
277 lck_mtx_unlock(gIOObjectPortLock);
278 }
279
280 if ((IKOT_UEXT_OBJECT == type) && (action = OSDynamicCast(OSAction, obj))) {
281 action->Aborted();
0a7de745 282 }
9bccf70c 283
cb323159 284 obj->release();
9bccf70c 285
0a7de745 286 return destroyed;
9bccf70c
A
287}
288
0a7de745
A
289void
290IOMachPort::releasePortForObject( OSObject * obj,
291 ipc_kobject_type_t type )
1c79356b 292{
cb323159
A
293 IOMachPort *machPort;
294 IOMachPortHashList *bucket = IOMachPort::bucketForObject(obj, type);
1c79356b 295
0a7de745 296 assert(IKOT_IOKIT_CONNECT != type);
7e41aa88 297
cb323159
A
298 lck_mtx_lock(gIOObjectPortLock);
299
300 machPort = IOMachPort::portForObjectInBucket(bucket, obj, type);
1c79356b 301
cb323159 302 if (machPort && !machPort->holdDestroy) {
0a7de745 303 obj->retain();
cb323159
A
304 SLIST_REMOVE(bucket, machPort, IOMachPort, link);
305
306 lck_mtx_unlock(gIOObjectPortLock);
307
308 machPort->release();
309 obj->taggedRelease(OSTypeID(OSCollection));
0a7de745 310 obj->release();
cb323159
A
311 } else {
312 lck_mtx_unlock(gIOObjectPortLock);
0a7de745 313 }
1c79356b
A
314}
315
0a7de745
A
316void
317IOMachPort::setHoldDestroy( OSObject * obj, ipc_kobject_type_t type )
55e303ae 318{
0a7de745 319 IOMachPort * machPort;
55e303ae 320
cb323159
A
321 IOMachPortHashList *bucket = IOMachPort::bucketForObject(obj, type);
322 lck_mtx_lock(gIOObjectPortLock);
55e303ae 323
cb323159
A
324 machPort = IOMachPort::portForObjectInBucket(bucket, obj, type);
325
326 if (machPort) {
327 machPort->holdDestroy = true;
0a7de745 328 }
55e303ae 329
cb323159
A
330 lck_mtx_unlock(gIOObjectPortLock);
331}
332
333void
334IOMachPortDestroyUserReferences(OSObject * obj, natural_t type)
335{
336 IOMachPort::releasePortForObject(obj, type);
55e303ae
A
337}
338
0a7de745
A
339void
340IOUserClient::destroyUserReferences( OSObject * obj )
341{
cb323159
A
342 IOMachPort *machPort;
343
0a7de745
A
344 IOMachPort::releasePortForObject( obj, IKOT_IOKIT_OBJECT );
345
346 // panther, 3160200
347 // IOMachPort::releasePortForObject( obj, IKOT_IOKIT_CONNECT );
348
0a7de745 349 obj->retain();
cb323159
A
350 IOMachPortHashList *bucket = IOMachPort::bucketForObject(obj, IKOT_IOKIT_CONNECT);
351 IOMachPortHashList *mappingBucket = NULL;
0a7de745 352
cb323159 353 lck_mtx_lock(gIOObjectPortLock);
0a7de745 354
cb323159
A
355 IOUserClient * uc = OSDynamicCast(IOUserClient, obj);
356 if (uc && uc->mappings) {
357 mappingBucket = IOMachPort::bucketForObject(uc->mappings, IKOT_IOKIT_CONNECT);
358 }
359
360 machPort = IOMachPort::portForObjectInBucket(bucket, obj, IKOT_IOKIT_CONNECT);
361
362 if (machPort == NULL) {
363 lck_mtx_unlock(gIOObjectPortLock);
364 goto end;
365 }
366
367 SLIST_REMOVE(bucket, machPort, IOMachPort, link);
368 obj->taggedRelease(OSTypeID(OSCollection));
369
370 if (uc) {
371 uc->noMoreSenders();
372 if (uc->mappings) {
373 uc->mappings->taggedRetain(OSTypeID(OSCollection));
374 machPort->object = uc->mappings;
375 SLIST_INSERT_HEAD(mappingBucket, machPort, link);
376 iokit_switch_object_port(machPort->port, uc->mappings, IKOT_IOKIT_CONNECT);
377
378 lck_mtx_unlock(gIOObjectPortLock);
379
380 uc->mappings->release();
381 uc->mappings = NULL;
382 } else {
383 lck_mtx_unlock(gIOObjectPortLock);
384 machPort->release();
0a7de745 385 }
cb323159
A
386 } else {
387 lck_mtx_unlock(gIOObjectPortLock);
388 machPort->release();
43866e37 389 }
cb323159
A
390
391
392end:
393
0a7de745 394 obj->release();
1c79356b
A
395}
396
0a7de745
A
397mach_port_name_t
398IOMachPort::makeSendRightForTask( task_t task,
399 io_object_t obj, ipc_kobject_type_t type )
1c79356b 400{
0a7de745 401 return iokit_make_send_right( task, obj, type );
1c79356b
A
402}
403
0a7de745
A
404void
405IOMachPort::free( void )
1c79356b 406{
0a7de745
A
407 if (port) {
408 iokit_destroy_object_port( port );
409 }
410 super::free();
1c79356b
A
411}
412
413/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
414
f427ee49
A
415static bool
416IOTaskRegistryCompatibility(task_t task)
417{
418 return false;
419}
420
421static void
422IOTaskRegistryCompatibilityMatching(task_t task, OSDictionary * matching)
423{
424 if (!IOTaskRegistryCompatibility(task)) {
425 return;
426 }
427 matching->setObject(gIOCompatibilityMatchKey, kOSBooleanTrue);
428}
429
430/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
431
4bd07ac2
A
432class IOUserIterator : public OSIterator
433{
cb323159 434 OSDeclareDefaultStructors(IOUserIterator);
4bd07ac2 435public:
0a7de745
A
436 OSObject * userIteratorObject;
437 IOLock * lock;
4bd07ac2 438
0a7de745
A
439 static IOUserIterator * withIterator(LIBKERN_CONSUMED OSIterator * iter);
440 virtual bool init( void ) APPLE_KEXT_OVERRIDE;
441 virtual void free() APPLE_KEXT_OVERRIDE;
4bd07ac2 442
0a7de745
A
443 virtual void reset() APPLE_KEXT_OVERRIDE;
444 virtual bool isValid() APPLE_KEXT_OVERRIDE;
445 virtual OSObject * getNextObject() APPLE_KEXT_OVERRIDE;
446 virtual OSObject * copyNextObject();
4bd07ac2
A
447};
448
449/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
450
451class IOUserNotification : public IOUserIterator
55e303ae 452{
cb323159 453 OSDeclareDefaultStructors(IOUserNotification);
55e303ae 454
0a7de745 455#define holdNotify userIteratorObject
55e303ae
A
456
457public:
458
0a7de745 459 virtual void free() APPLE_KEXT_OVERRIDE;
55e303ae 460
0a7de745 461 virtual void setNotification( IONotifier * obj );
55e303ae 462
0a7de745
A
463 virtual void reset() APPLE_KEXT_OVERRIDE;
464 virtual bool isValid() APPLE_KEXT_OVERRIDE;
55e303ae
A
465};
466
4bd07ac2
A
467/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
468
469OSDefineMetaClassAndStructors( IOUserIterator, OSIterator )
470
471IOUserIterator *
472IOUserIterator::withIterator(OSIterator * iter)
473{
0a7de745 474 IOUserIterator * me;
4bd07ac2 475
0a7de745 476 if (!iter) {
cb323159 477 return NULL;
0a7de745 478 }
4bd07ac2 479
0a7de745
A
480 me = new IOUserIterator;
481 if (me && !me->init()) {
482 me->release();
cb323159 483 me = NULL;
0a7de745
A
484 }
485 if (!me) {
486 return me;
487 }
488 me->userIteratorObject = iter;
4bd07ac2 489
0a7de745 490 return me;
4bd07ac2
A
491}
492
493bool
494IOUserIterator::init( void )
495{
0a7de745
A
496 if (!OSObject::init()) {
497 return false;
498 }
4bd07ac2 499
0a7de745
A
500 lock = IOLockAlloc();
501 if (!lock) {
502 return false;
503 }
4bd07ac2 504
0a7de745 505 return true;
4bd07ac2
A
506}
507
508void
509IOUserIterator::free()
510{
0a7de745
A
511 if (userIteratorObject) {
512 userIteratorObject->release();
513 }
514 if (lock) {
515 IOLockFree(lock);
516 }
517 OSObject::free();
4bd07ac2
A
518}
519
520void
521IOUserIterator::reset()
522{
0a7de745
A
523 IOLockLock(lock);
524 assert(OSDynamicCast(OSIterator, userIteratorObject));
525 ((OSIterator *)userIteratorObject)->reset();
526 IOLockUnlock(lock);
4bd07ac2
A
527}
528
529bool
530IOUserIterator::isValid()
531{
0a7de745 532 bool ret;
4bd07ac2 533
0a7de745
A
534 IOLockLock(lock);
535 assert(OSDynamicCast(OSIterator, userIteratorObject));
536 ret = ((OSIterator *)userIteratorObject)->isValid();
537 IOLockUnlock(lock);
4bd07ac2 538
0a7de745 539 return ret;
4bd07ac2
A
540}
541
542OSObject *
543IOUserIterator::getNextObject()
544{
0a7de745
A
545 assert(false);
546 return NULL;
d9a64523
A
547}
548
549OSObject *
550IOUserIterator::copyNextObject()
551{
0a7de745 552 OSObject * ret = NULL;
4bd07ac2 553
0a7de745
A
554 IOLockLock(lock);
555 if (userIteratorObject) {
556 ret = ((OSIterator *)userIteratorObject)->getNextObject();
557 if (ret) {
558 ret->retain();
559 }
560 }
561 IOLockUnlock(lock);
4bd07ac2 562
0a7de745 563 return ret;
4bd07ac2
A
564}
565
55e303ae 566/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1c79356b 567extern "C" {
1c79356b
A
568// functions called from osfmk/device/iokit_rpc.c
569
570void
ea3f0419
A
571iokit_port_object_description(io_object_t obj, kobject_description_t desc)
572{
573 IORegistryEntry * regEntry;
574 IOUserNotification * __unused noti;
575 _IOServiceNotifier * __unused serviceNoti;
576 OSSerialize * __unused s;
577
578 if ((regEntry = OSDynamicCast(IORegistryEntry, obj))) {
579 snprintf(desc, KOBJECT_DESCRIPTION_LENGTH, "%s(0x%qx)", obj->getMetaClass()->getClassName(), regEntry->getRegistryEntryID());
580#if DEVELOPMENT || DEBUG
581 } else if ((noti = OSDynamicCast(IOUserNotification, obj))
582 && ((serviceNoti = OSDynamicCast(_IOServiceNotifier, noti->holdNotify)))) {
f427ee49 583 s = OSSerialize::withCapacity((unsigned int) page_size);
ea3f0419
A
584 if (s && serviceNoti->matching->serialize(s)) {
585 snprintf(desc, KOBJECT_DESCRIPTION_LENGTH, "%s(%s)", obj->getMetaClass()->getClassName(), s->text());
586 }
587 OSSafeReleaseNULL(s);
588#endif /* DEVELOPMENT || DEBUG */
589 } else {
590 snprintf(desc, KOBJECT_DESCRIPTION_LENGTH, "%s", obj->getMetaClass()->getClassName());
591 }
592}
593
f427ee49
A
594// FIXME: Implementation of these functions are hidden from the static analyzer.
595// As for now, the analyzer doesn't consistently support wrapper functions
596// for retain and release.
597#ifndef __clang_analyzer__
ea3f0419
A
598void
599iokit_add_reference( io_object_t obj, natural_t type )
1c79356b 600{
0a7de745 601 IOUserClient * uc;
a39ff7e2 602
0a7de745
A
603 if (!obj) {
604 return;
605 }
a39ff7e2 606
0a7de745
A
607 if ((IKOT_IOKIT_CONNECT == type)
608 && (uc = OSDynamicCast(IOUserClient, obj))) {
609 OSIncrementAtomic(&uc->__ipc);
610 }
a39ff7e2 611
0a7de745 612 obj->retain();
1c79356b
A
613}
614
615void
616iokit_remove_reference( io_object_t obj )
617{
0a7de745
A
618 if (obj) {
619 obj->release();
620 }
1c79356b 621}
f427ee49 622#endif // __clang_analyzer__
1c79356b 623
490019cf
A
624void
625iokit_remove_connect_reference( io_object_t obj )
626{
0a7de745
A
627 IOUserClient * uc;
628 bool finalize = false;
490019cf 629
0a7de745
A
630 if (!obj) {
631 return;
632 }
490019cf 633
0a7de745
A
634 if ((uc = OSDynamicCast(IOUserClient, obj))) {
635 if (1 == OSDecrementAtomic(&uc->__ipc) && uc->isInactive()) {
636 IOLockLock(gIOObjectPortLock);
637 if ((finalize = uc->__ipcFinal)) {
638 uc->__ipcFinal = false;
639 }
640 IOLockUnlock(gIOObjectPortLock);
641 }
642 if (finalize) {
643 uc->scheduleFinalize(true);
644 }
490019cf 645 }
490019cf 646
0a7de745 647 obj->release();
490019cf
A
648}
649
650bool
651IOUserClient::finalizeUserReferences(OSObject * obj)
652{
0a7de745
A
653 IOUserClient * uc;
654 bool ok = true;
490019cf 655
0a7de745
A
656 if ((uc = OSDynamicCast(IOUserClient, obj))) {
657 IOLockLock(gIOObjectPortLock);
658 if ((uc->__ipcFinal = (0 != uc->__ipc))) {
659 ok = false;
660 }
661 IOLockUnlock(gIOObjectPortLock);
662 }
663 return ok;
490019cf
A
664}
665
1c79356b
A
666ipc_port_t
667iokit_port_for_object( io_object_t obj, ipc_kobject_type_t type )
668{
cb323159
A
669 IOMachPort *machPort = NULL;
670 ipc_port_t port = NULL;
9bccf70c 671
cb323159 672 IOMachPortHashList *bucket = IOMachPort::bucketForObject(obj, type);
9bccf70c 673
cb323159
A
674 lck_mtx_lock(gIOObjectPortLock);
675
676 machPort = IOMachPort::portForObjectInBucket(bucket, obj, type);
677
678 if (__improbable(machPort == NULL)) {
679 machPort = IOMachPort::withObjectAndType(obj, type);
680 if (__improbable(machPort == NULL)) {
681 goto end;
682 }
683 SLIST_INSERT_HEAD(bucket, machPort, link);
0a7de745 684 } else {
cb323159 685 machPort->mscount++;
0a7de745 686 }
9bccf70c 687
cb323159
A
688 iokit_retain_port(machPort->port);
689 port = machPort->port;
690
691end:
692 lck_mtx_unlock(gIOObjectPortLock);
693
0a7de745 694 return port;
1c79356b
A
695}
696
697kern_return_t
698iokit_client_died( io_object_t obj, ipc_port_t /* port */,
0a7de745
A
699 ipc_kobject_type_t type, mach_port_mscount_t * mscount )
700{
701 IOUserClient * client;
702 IOMemoryMap * map;
703 IOUserNotification * notify;
f427ee49 704 IOUserServerCheckInToken * token;
0a7de745
A
705
706 if (!IOMachPort::noMoreSendersForObject( obj, type, mscount )) {
707 return kIOReturnNotReady;
708 }
709
f427ee49
A
710 switch (type) {
711 case IKOT_IOKIT_CONNECT:
0a7de745
A
712 if ((client = OSDynamicCast( IOUserClient, obj ))) {
713 IOStatisticsClientCall();
f427ee49 714 IORWLockWrite(client->lock);
0a7de745 715 client->clientDied();
f427ee49 716 IORWLockUnlock(client->lock);
0a7de745 717 }
f427ee49
A
718 break;
719 case IKOT_IOKIT_OBJECT:
0a7de745
A
720 if ((map = OSDynamicCast( IOMemoryMap, obj ))) {
721 map->taskDied();
722 } else if ((notify = OSDynamicCast( IOUserNotification, obj ))) {
cb323159 723 notify->setNotification( NULL );
0a7de745 724 }
f427ee49
A
725 break;
726 case IKOT_IOKIT_IDENT:
727 if ((token = OSDynamicCast( IOUserServerCheckInToken, obj ))) {
728 IOUserServerCheckInToken::notifyNoSenders( token );
729 }
730 break;
0a7de745
A
731 }
732
733 return kIOReturnSuccess;
734}
735}; /* extern "C" */
1c79356b
A
736
737/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
738
55e303ae 739class IOServiceUserNotification : public IOUserNotification
1c79356b 740{
cb323159 741 OSDeclareDefaultStructors(IOServiceUserNotification);
1c79356b 742
0a7de745
A
743 struct PingMsg {
744 mach_msg_header_t msgHdr;
745 OSNotificationHeader64 notifyHeader;
746 };
1c79356b 747
0a7de745 748 enum { kMaxOutstanding = 1024 };
1c79356b 749
0a7de745 750 PingMsg * pingMsg;
f427ee49 751 mach_msg_size_t msgSize;
0a7de745
A
752 OSArray * newSet;
753 bool armed;
754 bool ipcLogged;
1c79356b
A
755
756public:
757
0a7de745
A
758 virtual bool init( mach_port_t port, natural_t type,
759 void * reference, vm_size_t referenceSize,
760 bool clientIs64 );
761 virtual void free() APPLE_KEXT_OVERRIDE;
762 void invalidatePort(void);
1c79356b 763
0a7de745
A
764 static bool _handler( void * target,
765 void * ref, IOService * newService, IONotifier * notifier );
766 virtual bool handler( void * ref, IOService * newService );
1c79356b 767
0a7de745
A
768 virtual OSObject * getNextObject() APPLE_KEXT_OVERRIDE;
769 virtual OSObject * copyNextObject() APPLE_KEXT_OVERRIDE;
1c79356b
A
770};
771
772class IOServiceMessageUserNotification : public IOUserNotification
773{
cb323159 774 OSDeclareDefaultStructors(IOServiceMessageUserNotification);
1c79356b 775
0a7de745
A
776 struct PingMsg {
777 mach_msg_header_t msgHdr;
778 mach_msg_body_t msgBody;
779 mach_msg_port_descriptor_t ports[1];
780 OSNotificationHeader64 notifyHeader __attribute__ ((packed));
781 };
55e303ae 782
0a7de745 783 PingMsg * pingMsg;
f427ee49 784 mach_msg_size_t msgSize;
0a7de745
A
785 uint8_t clientIs64;
786 int owningPID;
787 bool ipcLogged;
55e303ae 788
1c79356b
A
789public:
790
0a7de745
A
791 virtual bool init( mach_port_t port, natural_t type,
792 void * reference, vm_size_t referenceSize,
f427ee49 793 mach_msg_size_t extraSize,
0a7de745
A
794 bool clientIs64 );
795
796 virtual void free() APPLE_KEXT_OVERRIDE;
797 void invalidatePort(void);
798
799 static IOReturn _handler( void * target, void * ref,
800 UInt32 messageType, IOService * provider,
801 void * messageArgument, vm_size_t argSize );
802 virtual IOReturn handler( void * ref,
803 UInt32 messageType, IOService * provider,
804 void * messageArgument, vm_size_t argSize );
805
806 virtual OSObject * getNextObject() APPLE_KEXT_OVERRIDE;
807 virtual OSObject * copyNextObject() APPLE_KEXT_OVERRIDE;
1c79356b
A
808};
809
810/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
811
812#undef super
4bd07ac2 813#define super IOUserIterator
cb323159
A
814OSDefineMetaClass( IOUserNotification, IOUserIterator );
815OSDefineAbstractStructors( IOUserNotification, IOUserIterator );
1c79356b
A
816
817/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
818
0a7de745
A
819void
820IOUserNotification::free( void )
1c79356b 821{
0a7de745
A
822 if (holdNotify) {
823 assert(OSDynamicCast(IONotifier, holdNotify));
824 ((IONotifier *)holdNotify)->remove();
cb323159 825 holdNotify = NULL;
0a7de745
A
826 }
827 // can't be in handler now
1c79356b 828
0a7de745 829 super::free();
1c79356b
A
830}
831
832
0a7de745
A
833void
834IOUserNotification::setNotification( IONotifier * notify )
1c79356b 835{
0a7de745 836 OSObject * previousNotify;
1c79356b 837
0a7de745 838 IOLockLock( gIOObjectPortLock);
55e303ae 839
0a7de745
A
840 previousNotify = holdNotify;
841 holdNotify = notify;
55e303ae 842
0a7de745 843 IOLockUnlock( gIOObjectPortLock);
55e303ae 844
0a7de745
A
845 if (previousNotify) {
846 assert(OSDynamicCast(IONotifier, previousNotify));
847 ((IONotifier *)previousNotify)->remove();
848 }
1c79356b
A
849}
850
0a7de745
A
851void
852IOUserNotification::reset()
1c79356b 853{
0a7de745 854 // ?
1c79356b
A
855}
856
0a7de745
A
857bool
858IOUserNotification::isValid()
1c79356b 859{
0a7de745 860 return true;
1c79356b
A
861}
862
863/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
864
865#undef super
866#define super IOUserNotification
867OSDefineMetaClassAndStructors(IOServiceUserNotification, IOUserNotification)
868
869/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
870
0a7de745
A
871bool
872IOServiceUserNotification::init( mach_port_t port, natural_t type,
873 void * reference, vm_size_t referenceSize,
874 bool clientIs64 )
1c79356b 875{
0a7de745
A
876 if (!super::init()) {
877 return false;
878 }
316670eb 879
0a7de745
A
880 newSet = OSArray::withCapacity( 1 );
881 if (!newSet) {
882 return false;
883 }
1c79356b 884
0a7de745
A
885 if (referenceSize > sizeof(OSAsyncReference64)) {
886 return false;
887 }
2d21ac55 888
f427ee49
A
889 msgSize = (mach_msg_size_t) (sizeof(PingMsg) - sizeof(OSAsyncReference64) + referenceSize);
890
0a7de745
A
891 pingMsg = (PingMsg *) IOMalloc( msgSize);
892 if (!pingMsg) {
893 return false;
894 }
55e303ae 895
0a7de745 896 bzero( pingMsg, msgSize);
55e303ae 897
0a7de745
A
898 pingMsg->msgHdr.msgh_remote_port = port;
899 pingMsg->msgHdr.msgh_bits = MACH_MSGH_BITS(
900 MACH_MSG_TYPE_COPY_SEND /*remote*/,
901 MACH_MSG_TYPE_MAKE_SEND /*local*/);
902 pingMsg->msgHdr.msgh_size = msgSize;
903 pingMsg->msgHdr.msgh_id = kOSNotificationMessageID;
55e303ae 904
0a7de745
A
905 pingMsg->notifyHeader.size = 0;
906 pingMsg->notifyHeader.type = type;
907 bcopy( reference, pingMsg->notifyHeader.reference, referenceSize );
55e303ae 908
0a7de745 909 return true;
1c79356b
A
910}
911
0a7de745
A
912void
913IOServiceUserNotification::invalidatePort(void)
5ba3f43e 914{
0a7de745
A
915 if (pingMsg) {
916 pingMsg->msgHdr.msgh_remote_port = MACH_PORT_NULL;
917 }
5ba3f43e
A
918}
919
0a7de745
A
920void
921IOServiceUserNotification::free( void )
1c79356b 922{
0a7de745
A
923 PingMsg * _pingMsg;
924 vm_size_t _msgSize;
925 OSArray * _newSet;
1c79356b 926
0a7de745
A
927 _pingMsg = pingMsg;
928 _msgSize = msgSize;
929 _newSet = newSet;
1c79356b 930
0a7de745 931 super::free();
55e303ae 932
0a7de745 933 if (_pingMsg && _msgSize) {
316670eb
A
934 if (_pingMsg->msgHdr.msgh_remote_port) {
935 iokit_release_port_send(_pingMsg->msgHdr.msgh_remote_port);
936 }
0a7de745 937 IOFree(_pingMsg, _msgSize);
316670eb 938 }
55e303ae 939
0a7de745
A
940 if (_newSet) {
941 _newSet->release();
942 }
1c79356b
A
943}
944
0a7de745
A
945bool
946IOServiceUserNotification::_handler( void * target,
947 void * ref, IOService * newService, IONotifier * notifier )
1c79356b 948{
0a7de745 949 return ((IOServiceUserNotification *) target)->handler( ref, newService );
1c79356b
A
950}
951
0a7de745
A
952bool
953IOServiceUserNotification::handler( void * ref,
954 IOService * newService )
1c79356b 955{
0a7de745
A
956 unsigned int count;
957 kern_return_t kr;
958 ipc_port_t port = NULL;
959 bool sendPing = false;
1c79356b 960
0a7de745 961 IOTakeLock( lock );
1c79356b 962
0a7de745
A
963 count = newSet->getCount();
964 if (count < kMaxOutstanding) {
965 newSet->setObject( newService );
966 if ((sendPing = (armed && (0 == count)))) {
967 armed = false;
968 }
969 }
1c79356b 970
0a7de745 971 IOUnlock( lock );
1c79356b 972
0a7de745
A
973 if (kIOServiceTerminatedNotificationType == pingMsg->notifyHeader.type) {
974 IOMachPort::setHoldDestroy( newService, IKOT_IOKIT_OBJECT );
975 }
55e303ae 976
0a7de745
A
977 if (sendPing) {
978 if ((port = iokit_port_for_object( this, IKOT_IOKIT_OBJECT ))) {
979 pingMsg->msgHdr.msgh_local_port = port;
980 } else {
981 pingMsg->msgHdr.msgh_local_port = NULL;
982 }
1c79356b 983
0a7de745
A
984 kr = mach_msg_send_from_kernel_with_options( &pingMsg->msgHdr,
985 pingMsg->msgHdr.msgh_size,
986 (MACH_SEND_MSG | MACH_SEND_ALWAYS | MACH_SEND_IMPORTANCE),
987 0);
988 if (port) {
989 iokit_release_port( port );
990 }
9bccf70c 991
0a7de745
A
992 if ((KERN_SUCCESS != kr) && !ipcLogged) {
993 ipcLogged = true;
994 IOLog("%s: mach_msg_send_from_kernel_proper(0x%x)\n", __PRETTY_FUNCTION__, kr );
995 }
996 }
1c79356b 997
0a7de745 998 return true;
1c79356b 999}
0a7de745
A
1000OSObject *
1001IOServiceUserNotification::getNextObject()
d9a64523 1002{
0a7de745
A
1003 assert(false);
1004 return NULL;
d9a64523
A
1005}
1006
0a7de745
A
1007OSObject *
1008IOServiceUserNotification::copyNextObject()
1c79356b 1009{
0a7de745
A
1010 unsigned int count;
1011 OSObject * result;
1c79356b 1012
0a7de745 1013 IOLockLock(lock);
1c79356b 1014
0a7de745
A
1015 count = newSet->getCount();
1016 if (count) {
1017 result = newSet->getObject( count - 1 );
1018 result->retain();
1019 newSet->removeObject( count - 1);
1020 } else {
cb323159 1021 result = NULL;
0a7de745
A
1022 armed = true;
1023 }
1c79356b 1024
0a7de745 1025 IOLockUnlock(lock);
39037602 1026
0a7de745 1027 return result;
1c79356b
A
1028}
1029
1030/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1031
1032OSDefineMetaClassAndStructors(IOServiceMessageUserNotification, IOUserNotification)
1033
1034/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1035
0a7de745
A
1036bool
1037IOServiceMessageUserNotification::init( mach_port_t port, natural_t type,
f427ee49 1038 void * reference, vm_size_t referenceSize, mach_msg_size_t extraSize,
0a7de745 1039 bool client64 )
1c79356b 1040{
0a7de745
A
1041 if (!super::init()) {
1042 return false;
1043 }
55e303ae 1044
0a7de745
A
1045 if (referenceSize > sizeof(OSAsyncReference64)) {
1046 return false;
1047 }
2d21ac55 1048
0a7de745 1049 clientIs64 = client64;
2d21ac55 1050
0a7de745 1051 owningPID = proc_selfpid();
2d21ac55 1052
0a7de745 1053 extraSize += sizeof(IOServiceInterestContent64);
f427ee49 1054 msgSize = (mach_msg_size_t) (sizeof(PingMsg) - sizeof(OSAsyncReference64) + referenceSize);
0a7de745
A
1055 pingMsg = (PingMsg *) IOMalloc( msgSize);
1056 if (!pingMsg) {
1057 return false;
1058 }
55e303ae 1059
0a7de745 1060 bzero( pingMsg, msgSize);
55e303ae 1061
0a7de745
A
1062 pingMsg->msgHdr.msgh_remote_port = port;
1063 pingMsg->msgHdr.msgh_bits = MACH_MSGH_BITS_COMPLEX
1064 | MACH_MSGH_BITS(
1065 MACH_MSG_TYPE_COPY_SEND /*remote*/,
1066 MACH_MSG_TYPE_MAKE_SEND /*local*/);
1067 pingMsg->msgHdr.msgh_size = msgSize;
1068 pingMsg->msgHdr.msgh_id = kOSNotificationMessageID;
55e303ae 1069
0a7de745 1070 pingMsg->msgBody.msgh_descriptor_count = 1;
55e303ae 1071
cb323159 1072 pingMsg->ports[0].name = NULL;
0a7de745
A
1073 pingMsg->ports[0].disposition = MACH_MSG_TYPE_MAKE_SEND;
1074 pingMsg->ports[0].type = MACH_MSG_PORT_DESCRIPTOR;
55e303ae 1075
0a7de745
A
1076 pingMsg->notifyHeader.size = extraSize;
1077 pingMsg->notifyHeader.type = type;
1078 bcopy( reference, pingMsg->notifyHeader.reference, referenceSize );
55e303ae 1079
0a7de745 1080 return true;
1c79356b
A
1081}
1082
0a7de745
A
1083void
1084IOServiceMessageUserNotification::invalidatePort(void)
5ba3f43e 1085{
0a7de745
A
1086 if (pingMsg) {
1087 pingMsg->msgHdr.msgh_remote_port = MACH_PORT_NULL;
1088 }
5ba3f43e
A
1089}
1090
0a7de745
A
1091void
1092IOServiceMessageUserNotification::free( void )
1c79356b 1093{
0a7de745
A
1094 PingMsg * _pingMsg;
1095 vm_size_t _msgSize;
55e303ae 1096
0a7de745
A
1097 _pingMsg = pingMsg;
1098 _msgSize = msgSize;
55e303ae 1099
0a7de745 1100 super::free();
55e303ae 1101
0a7de745 1102 if (_pingMsg && _msgSize) {
316670eb
A
1103 if (_pingMsg->msgHdr.msgh_remote_port) {
1104 iokit_release_port_send(_pingMsg->msgHdr.msgh_remote_port);
1105 }
0a7de745
A
1106 IOFree( _pingMsg, _msgSize);
1107 }
1108}
1109
1110IOReturn
1111IOServiceMessageUserNotification::_handler( void * target, void * ref,
1112 UInt32 messageType, IOService * provider,
1113 void * argument, vm_size_t argSize )
1114{
1115 return ((IOServiceMessageUserNotification *) target)->handler(
1116 ref, messageType, provider, argument, argSize);
1117}
1118
1119IOReturn
1120IOServiceMessageUserNotification::handler( void * ref,
1121 UInt32 messageType, IOService * provider,
1122 void * messageArgument, vm_size_t callerArgSize )
1123{
1124 enum { kLocalMsgSize = 0x100 };
1125 uint64_t stackMsg[kLocalMsgSize / sizeof(uint64_t)];
1126 void * allocMsg;
1127 kern_return_t kr;
1128 vm_size_t argSize;
f427ee49 1129 mach_msg_size_t thisMsgSize;
0a7de745
A
1130 ipc_port_t thisPort, providerPort;
1131 struct PingMsg * thisMsg;
1132 IOServiceInterestContent64 * data;
1133
1134 if (kIOMessageCopyClientID == messageType) {
1135 *((void **) messageArgument) = OSNumber::withNumber(owningPID, 32);
1136 return kIOReturnSuccess;
1137 }
1138
1139 if (callerArgSize == 0) {
1140 if (clientIs64) {
1141 argSize = sizeof(data->messageArgument[0]);
1142 } else {
1143 argSize = sizeof(uint32_t);
1144 }
1145 } else {
1146 if (callerArgSize > kIOUserNotifyMaxMessageSize) {
1147 callerArgSize = kIOUserNotifyMaxMessageSize;
1148 }
1149 argSize = callerArgSize;
1150 }
1151
1152 // adjust message size for ipc restrictions
1153 natural_t type;
1154 type = pingMsg->notifyHeader.type;
1155 type &= ~(kIOKitNoticationMsgSizeMask << kIOKitNoticationTypeSizeAdjShift);
1156 type |= ((argSize & kIOKitNoticationMsgSizeMask) << kIOKitNoticationTypeSizeAdjShift);
1157 argSize = (argSize + kIOKitNoticationMsgSizeMask) & ~kIOKitNoticationMsgSizeMask;
1158
f427ee49
A
1159 if (os_add3_overflow(msgSize, sizeof(IOServiceInterestContent64) - sizeof(data->messageArgument), argSize, &thisMsgSize)) {
1160 return kIOReturnBadArgument;
1161 }
0a7de745
A
1162
1163 if (thisMsgSize > sizeof(stackMsg)) {
1164 allocMsg = IOMalloc(thisMsgSize);
1165 if (!allocMsg) {
1166 return kIOReturnNoMemory;
1167 }
1168 thisMsg = (typeof(thisMsg))allocMsg;
1169 } else {
cb323159 1170 allocMsg = NULL;
0a7de745
A
1171 thisMsg = (typeof(thisMsg))stackMsg;
1172 }
1173
1174 bcopy(pingMsg, thisMsg, msgSize);
1175 thisMsg->notifyHeader.type = type;
1176 data = (IOServiceInterestContent64 *) (((uint8_t *) thisMsg) + msgSize);
39037602 1177 // == pingMsg->notifyHeader.content;
0a7de745 1178 data->messageType = messageType;
39037602 1179
0a7de745
A
1180 if (callerArgSize == 0) {
1181 data->messageArgument[0] = (io_user_reference_t) messageArgument;
1182 if (!clientIs64) {
1183 data->messageArgument[0] |= (data->messageArgument[0] << 32);
1184 }
1185 } else {
1186 bcopy( messageArgument, data->messageArgument, callerArgSize );
1187 bzero((void *)(((uintptr_t) &data->messageArgument[0]) + callerArgSize), argSize - callerArgSize);
39037602 1188 }
39037602 1189
0a7de745
A
1190 thisMsg->notifyHeader.type = type;
1191 thisMsg->msgHdr.msgh_size = thisMsgSize;
1c79356b 1192
0a7de745
A
1193 providerPort = iokit_port_for_object( provider, IKOT_IOKIT_OBJECT );
1194 thisMsg->ports[0].name = providerPort;
1195 thisPort = iokit_port_for_object( this, IKOT_IOKIT_OBJECT );
1196 thisMsg->msgHdr.msgh_local_port = thisPort;
39037602 1197
0a7de745
A
1198 kr = mach_msg_send_from_kernel_with_options( &thisMsg->msgHdr,
1199 thisMsg->msgHdr.msgh_size,
1200 (MACH_SEND_MSG | MACH_SEND_ALWAYS | MACH_SEND_IMPORTANCE),
1201 0);
1202 if (thisPort) {
1203 iokit_release_port( thisPort );
1204 }
1205 if (providerPort) {
1206 iokit_release_port( providerPort );
1207 }
9bccf70c 1208
0a7de745
A
1209 if (allocMsg) {
1210 IOFree(allocMsg, thisMsgSize);
1211 }
39037602 1212
0a7de745
A
1213 if ((KERN_SUCCESS != kr) && !ipcLogged) {
1214 ipcLogged = true;
1215 IOLog("%s: mach_msg_send_from_kernel_proper (0x%x)\n", __PRETTY_FUNCTION__, kr );
1216 }
1c79356b 1217
0a7de745 1218 return kIOReturnSuccess;
1c79356b
A
1219}
1220
0a7de745
A
1221OSObject *
1222IOServiceMessageUserNotification::getNextObject()
1c79356b 1223{
cb323159 1224 return NULL;
1c79356b
A
1225}
1226
0a7de745
A
1227OSObject *
1228IOServiceMessageUserNotification::copyNextObject()
d9a64523 1229{
0a7de745 1230 return NULL;
d9a64523
A
1231}
1232
1c79356b
A
1233/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1234
1235#undef super
1236#define super IOService
1237OSDefineMetaClassAndAbstractStructors( IOUserClient, IOService )
1238
7e41aa88
A
1239IOLock * gIOUserClientOwnersLock;
1240
0a7de745
A
1241void
1242IOUserClient::initialize( void )
1243{
1244 gIOObjectPortLock = IOLockAlloc();
1245 gIOUserClientOwnersLock = IOLockAlloc();
cb323159 1246 gIOUserServerLock = IOLockAlloc();
0a7de745 1247 assert(gIOObjectPortLock && gIOUserClientOwnersLock);
f427ee49
A
1248
1249#if IOTRACKING
1250 IOTrackingQueueCollectUser(IOUserIterator::gMetaClass.getTracking());
1251 IOTrackingQueueCollectUser(IOServiceMessageUserNotification::gMetaClass.getTracking());
1252 IOTrackingQueueCollectUser(IOServiceUserNotification::gMetaClass.getTracking());
1253 IOTrackingQueueCollectUser(IOUserClient::gMetaClass.getTracking());
1254 IOTrackingQueueCollectUser(IOMachPort::gMetaClass.getTracking());
1255#endif /* IOTRACKING */
0a7de745
A
1256}
1257
1258void
f427ee49
A
1259#if __LP64__
1260__attribute__((__noreturn__))
1261#endif
0a7de745
A
1262IOUserClient::setAsyncReference(OSAsyncReference asyncRef,
1263 mach_port_t wakePort,
1264 void *callback, void *refcon)
1c79356b 1265{
f427ee49
A
1266#if __LP64__
1267 panic("setAsyncReference not valid for 64b");
1268#else
0a7de745
A
1269 asyncRef[kIOAsyncReservedIndex] = ((uintptr_t) wakePort)
1270 | (kIOUCAsync0Flags & asyncRef[kIOAsyncReservedIndex]);
1271 asyncRef[kIOAsyncCalloutFuncIndex] = (uintptr_t) callback;
1272 asyncRef[kIOAsyncCalloutRefconIndex] = (uintptr_t) refcon;
f427ee49 1273#endif
1c79356b
A
1274}
1275
0a7de745
A
1276void
1277IOUserClient::setAsyncReference64(OSAsyncReference64 asyncRef,
1278 mach_port_t wakePort,
1279 mach_vm_address_t callback, io_user_reference_t refcon)
1c79356b 1280{
0a7de745
A
1281 asyncRef[kIOAsyncReservedIndex] = ((io_user_reference_t) wakePort)
1282 | (kIOUCAsync0Flags & asyncRef[kIOAsyncReservedIndex]);
1283 asyncRef[kIOAsyncCalloutFuncIndex] = (io_user_reference_t) callback;
1284 asyncRef[kIOAsyncCalloutRefconIndex] = refcon;
1c79356b
A
1285}
1286
0a7de745
A
1287void
1288IOUserClient::setAsyncReference64(OSAsyncReference64 asyncRef,
1289 mach_port_t wakePort,
1290 mach_vm_address_t callback, io_user_reference_t refcon, task_t task)
2d21ac55 1291{
0a7de745
A
1292 setAsyncReference64(asyncRef, wakePort, callback, refcon);
1293 if (vm_map_is_64bit(get_task_map(task))) {
1294 asyncRef[kIOAsyncReservedIndex] |= kIOUCAsync64Flag;
1295 }
2d21ac55
A
1296}
1297
0a7de745
A
1298static OSDictionary *
1299CopyConsoleUser(UInt32 uid)
39236c6e 1300{
0a7de745 1301 OSArray * array;
cb323159 1302 OSDictionary * user = NULL;
0a7de745
A
1303
1304 if ((array = OSDynamicCast(OSArray,
1305 IORegistryEntry::getRegistryRoot()->copyProperty(gIOConsoleUsersKey)))) {
1306 for (unsigned int idx = 0;
1307 (user = OSDynamicCast(OSDictionary, array->getObject(idx)));
1308 idx++) {
1309 OSNumber * num;
1310
1311 if ((num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionUIDKey)))
1312 && (uid == num->unsigned32BitValue())) {
1313 user->retain();
1314 break;
1315 }
1316 }
1317 array->release();
1318 }
1319 return user;
39236c6e
A
1320}
1321
0a7de745
A
1322static OSDictionary *
1323CopyUserOnConsole(void)
1c79356b 1324{
8f6c56a5 1325 OSArray * array;
cb323159 1326 OSDictionary * user = NULL;
55e303ae
A
1327
1328 if ((array = OSDynamicCast(OSArray,
0a7de745
A
1329 IORegistryEntry::getRegistryRoot()->copyProperty(gIOConsoleUsersKey)))) {
1330 for (unsigned int idx = 0;
55e303ae 1331 (user = OSDynamicCast(OSDictionary, array->getObject(idx)));
8f6c56a5 1332 idx++) {
0a7de745
A
1333 if (kOSBooleanTrue == user->getObject(gIOConsoleSessionOnConsoleKey)) {
1334 user->retain();
1335 break;
1336 }
1337 }
1338 array->release();
1339 }
1340 return user;
1341}
1342
1343IOReturn
1344IOUserClient::clientHasAuthorization( task_t task,
1345 IOService * service )
1346{
1347 proc_t p;
1348
6d2010ae 1349 p = (proc_t) get_bsdtask_info(task);
0a7de745
A
1350 if (p) {
1351 uint64_t authorizationID;
1352
1353 authorizationID = proc_uniqueid(p);
1354 if (authorizationID) {
1355 if (service->getAuthorizationID() == authorizationID) {
1356 return kIOReturnSuccess;
1357 }
1358 }
1359 }
1360
1361 return kIOReturnNotPermitted;
1362}
1363
1364IOReturn
1365IOUserClient::clientHasPrivilege( void * securityToken,
1366 const char * privilegeName )
1367{
1368 kern_return_t kr;
1369 security_token_t token;
1370 mach_msg_type_number_t count;
1371 task_t task;
1372 OSDictionary * user;
1373 bool secureConsole;
1374
1375
1376 if (!strncmp(privilegeName, kIOClientPrivilegeForeground,
1377 sizeof(kIOClientPrivilegeForeground))) {
1378 if (task_is_gpu_denied(current_task())) {
1379 return kIOReturnNotPrivileged;
1380 } else {
1381 return kIOReturnSuccess;
1382 }
1383 }
1384
1385 if (!strncmp(privilegeName, kIOClientPrivilegeConsoleSession,
1386 sizeof(kIOClientPrivilegeConsoleSession))) {
1387 kauth_cred_t cred;
1388 proc_t p;
1389
1390 task = (task_t) securityToken;
1391 if (!task) {
1392 task = current_task();
1393 }
1394 p = (proc_t) get_bsdtask_info(task);
1395 kr = kIOReturnNotPrivileged;
1396
1397 if (p && (cred = kauth_cred_proc_ref(p))) {
1398 user = CopyUserOnConsole();
1399 if (user) {
1400 OSNumber * num;
1401 if ((num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionAuditIDKey)))
1402 && (cred->cr_audit.as_aia_p->ai_asid == (au_asid_t) num->unsigned32BitValue())) {
1403 kr = kIOReturnSuccess;
1404 }
1405 user->release();
1406 }
1407 kauth_cred_unref(&cred);
1408 }
1409 return kr;
1410 }
1411
1412 if ((secureConsole = !strncmp(privilegeName, kIOClientPrivilegeSecureConsoleProcess,
1413 sizeof(kIOClientPrivilegeSecureConsoleProcess)))) {
1414 task = (task_t)((IOUCProcessToken *)securityToken)->token;
1415 } else {
1416 task = (task_t)securityToken;
1417 }
1418
1419 count = TASK_SECURITY_TOKEN_COUNT;
1420 kr = task_info( task, TASK_SECURITY_TOKEN, (task_info_t) &token, &count );
1421
1422 if (KERN_SUCCESS != kr) {
1423 } else if (!strncmp(privilegeName, kIOClientPrivilegeAdministrator,
1424 sizeof(kIOClientPrivilegeAdministrator))) {
1425 if (0 != token.val[0]) {
1426 kr = kIOReturnNotPrivileged;
1427 }
1428 } else if (!strncmp(privilegeName, kIOClientPrivilegeLocalUser,
1429 sizeof(kIOClientPrivilegeLocalUser))) {
1430 user = CopyConsoleUser(token.val[0]);
1431 if (user) {
1432 user->release();
1433 } else {
1434 kr = kIOReturnNotPrivileged;
1435 }
1436 } else if (secureConsole || !strncmp(privilegeName, kIOClientPrivilegeConsoleUser,
1437 sizeof(kIOClientPrivilegeConsoleUser))) {
1438 user = CopyConsoleUser(token.val[0]);
1439 if (user) {
1440 if (user->getObject(gIOConsoleSessionOnConsoleKey) != kOSBooleanTrue) {
1441 kr = kIOReturnNotPrivileged;
1442 } else if (secureConsole) {
1443 OSNumber * pid = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionSecureInputPIDKey));
1444 if (pid && pid->unsigned32BitValue() != ((IOUCProcessToken *)securityToken)->pid) {
1445 kr = kIOReturnNotPrivileged;
1446 }
1447 }
1448 user->release();
1449 } else {
1450 kr = kIOReturnNotPrivileged;
1451 }
1452 } else {
1453 kr = kIOReturnUnsupported;
1454 }
1455
1456 return kr;
1457}
f427ee49 1458#define MAX_ENTITLEMENTS_LEN (128 * 1024)
0a7de745 1459
cb323159
A
1460OSDictionary *
1461IOUserClient::copyClientEntitlements(task_t task)
0a7de745 1462{
fe8ab488
A
1463 proc_t p = NULL;
1464 pid_t pid = 0;
fe8ab488
A
1465 size_t len = 0;
1466 void *entitlements_blob = NULL;
fe8ab488 1467 OSDictionary *entitlements = NULL;
fe8ab488
A
1468
1469 p = (proc_t)get_bsdtask_info(task);
0a7de745 1470 if (p == NULL) {
f427ee49 1471 return NULL;
0a7de745 1472 }
fe8ab488 1473 pid = proc_pid(p);
cb323159
A
1474
1475 if (cs_entitlements_dictionary_copy(p, (void **)&entitlements) == 0) {
1476 if (entitlements) {
1477 return entitlements;
1478 }
1479 }
fe8ab488 1480
0a7de745 1481 if (cs_entitlements_blob_get(p, &entitlements_blob, &len) != 0) {
f427ee49 1482 return NULL;
0a7de745 1483 }
f427ee49
A
1484 return IOUserClient::copyEntitlementsFromBlob(entitlements_blob, len);
1485}
1486
1487OSDictionary *
1488IOUserClient::copyEntitlementsFromBlob(void *entitlements_blob, size_t len)
1489{
1490 char *entitlements_data = NULL;
1491 OSObject *entitlements_obj = NULL;
1492 OSString *errorString = NULL;
1493 OSDictionary *entitlements = NULL;
fe8ab488 1494
0a7de745 1495 if (len <= offsetof(CS_GenericBlob, data)) {
fe8ab488 1496 goto fail;
0a7de745 1497 }
fe8ab488
A
1498
1499 /*
1500 * Per <rdar://problem/11593877>, enforce a limit on the amount of XML
1501 * we'll try to parse in the kernel.
1502 */
1503 len -= offsetof(CS_GenericBlob, data);
1504 if (len > MAX_ENTITLEMENTS_LEN) {
f427ee49
A
1505 IOLog("failed to parse entitlements: %lu bytes of entitlements exceeds maximum of %u\n",
1506 len, MAX_ENTITLEMENTS_LEN);
fe8ab488
A
1507 goto fail;
1508 }
1509
1510 /*
1511 * OSUnserializeXML() expects a nul-terminated string, but that isn't
1512 * what is stored in the entitlements blob. Copy the string and
1513 * terminate it.
1514 */
1515 entitlements_data = (char *)IOMalloc(len + 1);
0a7de745 1516 if (entitlements_data == NULL) {
fe8ab488 1517 goto fail;
0a7de745 1518 }
fe8ab488
A
1519 memcpy(entitlements_data, ((CS_GenericBlob *)entitlements_blob)->data, len);
1520 entitlements_data[len] = '\0';
1521
1522 entitlements_obj = OSUnserializeXML(entitlements_data, len + 1, &errorString);
1523 if (errorString != NULL) {
f427ee49 1524 IOLog("failed to parse entitlements: %s\n", errorString->getCStringNoCopy());
fe8ab488
A
1525 goto fail;
1526 }
0a7de745 1527 if (entitlements_obj == NULL) {
fe8ab488 1528 goto fail;
0a7de745 1529 }
fe8ab488
A
1530
1531 entitlements = OSDynamicCast(OSDictionary, entitlements_obj);
0a7de745 1532 if (entitlements == NULL) {
fe8ab488 1533 goto fail;
0a7de745 1534 }
cb323159 1535 entitlements_obj = NULL;
fe8ab488
A
1536
1537fail:
0a7de745 1538 if (entitlements_data != NULL) {
fe8ab488 1539 IOFree(entitlements_data, len + 1);
0a7de745
A
1540 }
1541 if (entitlements_obj != NULL) {
fe8ab488 1542 entitlements_obj->release();
0a7de745
A
1543 }
1544 if (errorString != NULL) {
fe8ab488 1545 errorString->release();
0a7de745 1546 }
cb323159
A
1547 return entitlements;
1548}
1549
f427ee49
A
1550OSDictionary *
1551IOUserClient::copyClientEntitlementsVnode(vnode_t vnode, off_t offset)
1552{
1553 size_t len = 0;
1554 void *entitlements_blob = NULL;
1555
1556 if (cs_entitlements_blob_get_vnode(vnode, offset, &entitlements_blob, &len) != 0) {
1557 return NULL;
1558 }
1559 return IOUserClient::copyEntitlementsFromBlob(entitlements_blob, len);
1560}
1561
cb323159
A
1562OSObject *
1563IOUserClient::copyClientEntitlement( task_t task,
1564 const char * entitlement )
1565{
1566 OSDictionary *entitlements;
1567 OSObject *value;
1568
1569 entitlements = copyClientEntitlements(task);
1570 if (entitlements == NULL) {
1571 return NULL;
1572 }
1573
1574 /* Fetch the entitlement value from the dictionary. */
1575 value = entitlements->getObject(entitlement);
1576 if (value != NULL) {
1577 value->retain();
1578 }
1579
1580 entitlements->release();
fe8ab488
A
1581 return value;
1582}
1583
f427ee49
A
1584OSObject *
1585IOUserClient::copyClientEntitlementVnode(
1586 struct vnode *vnode,
1587 off_t offset,
1588 const char *entitlement)
1589{
1590 OSDictionary *entitlements;
1591 OSObject *value;
1592
1593 entitlements = copyClientEntitlementsVnode(vnode, offset);
1594 if (entitlements == NULL) {
1595 return NULL;
1596 }
1597
1598 /* Fetch the entitlement value from the dictionary. */
1599 value = entitlements->getObject(entitlement);
1600 if (value != NULL) {
1601 value->retain();
1602 }
1603
1604 entitlements->release();
1605 return value;
1606}
1607
0a7de745
A
1608bool
1609IOUserClient::init()
0c530ab8 1610{
0a7de745 1611 if (getPropertyTable() || super::init()) {
6d2010ae 1612 return reserve();
0a7de745
A
1613 }
1614
6d2010ae 1615 return false;
0c530ab8
A
1616}
1617
0a7de745
A
1618bool
1619IOUserClient::init(OSDictionary * dictionary)
0c530ab8 1620{
0a7de745 1621 if (getPropertyTable() || super::init(dictionary)) {
6d2010ae 1622 return reserve();
0a7de745
A
1623 }
1624
6d2010ae 1625 return false;
0c530ab8
A
1626}
1627
0a7de745
A
1628bool
1629IOUserClient::initWithTask(task_t owningTask,
1630 void * securityID,
1631 UInt32 type )
1632{
1633 if (getPropertyTable() || super::init()) {
6d2010ae 1634 return reserve();
0a7de745
A
1635 }
1636
6d2010ae 1637 return false;
1c79356b
A
1638}
1639
0a7de745
A
1640bool
1641IOUserClient::initWithTask(task_t owningTask,
1642 void * securityID,
1643 UInt32 type,
1644 OSDictionary * properties )
1c79356b 1645{
0a7de745 1646 bool ok;
1c79356b 1647
0a7de745
A
1648 ok = super::init( properties );
1649 ok &= initWithTask( owningTask, securityID, type );
1c79356b 1650
0a7de745 1651 return ok;
1c79356b
A
1652}
1653
0a7de745
A
1654bool
1655IOUserClient::reserve()
1656{
39236c6e 1657 if (!reserved) {
f427ee49 1658 reserved = IONewZero(ExpansionData, 1);
0a7de745
A
1659 if (!reserved) {
1660 return false;
1661 }
6d2010ae 1662 }
0a7de745
A
1663 setTerminateDefer(NULL, true);
1664 IOStatisticsRegisterCounter();
1665
1666 return true;
6d2010ae
A
1667}
1668
0a7de745
A
1669struct IOUserClientOwner {
1670 task_t task;
1671 queue_chain_t taskLink;
1672 IOUserClient * uc;
1673 queue_chain_t ucLink;
7e41aa88
A
1674};
1675
1676IOReturn
1677IOUserClient::registerOwner(task_t task)
1678{
0a7de745
A
1679 IOUserClientOwner * owner;
1680 IOReturn ret;
1681 bool newOwner;
1682
1683 IOLockLock(gIOUserClientOwnersLock);
1684
1685 newOwner = true;
1686 ret = kIOReturnSuccess;
1687
1688 if (!owners.next) {
1689 queue_init(&owners);
1690 } else {
1691 queue_iterate(&owners, owner, IOUserClientOwner *, ucLink)
1692 {
1693 if (task != owner->task) {
1694 continue;
1695 }
1696 newOwner = false;
1697 break;
1698 }
1699 }
1700 if (newOwner) {
1701 owner = IONew(IOUserClientOwner, 1);
1702 if (!owner) {
1703 ret = kIOReturnNoMemory;
1704 } else {
1705 owner->task = task;
1706 owner->uc = this;
1707 queue_enter_first(&owners, owner, IOUserClientOwner *, ucLink);
1708 queue_enter_first(task_io_user_clients(task), owner, IOUserClientOwner *, taskLink);
cb323159
A
1709 if (messageAppSuspended) {
1710 task_set_message_app_suspended(task, true);
1711 }
0a7de745
A
1712 }
1713 }
1714
1715 IOLockUnlock(gIOUserClientOwnersLock);
1716
1717 return ret;
7e41aa88
A
1718}
1719
1720void
1721IOUserClient::noMoreSenders(void)
1722{
0a7de745 1723 IOUserClientOwner * owner;
cb323159
A
1724 IOUserClientOwner * iter;
1725 queue_head_t * taskque;
1726 bool hasMessageAppSuspended;
7e41aa88 1727
0a7de745 1728 IOLockLock(gIOUserClientOwnersLock);
7e41aa88 1729
0a7de745
A
1730 if (owners.next) {
1731 while (!queue_empty(&owners)) {
1732 owner = (IOUserClientOwner *)(void *) queue_first(&owners);
cb323159
A
1733 taskque = task_io_user_clients(owner->task);
1734 queue_remove(taskque, owner, IOUserClientOwner *, taskLink);
1735 hasMessageAppSuspended = false;
1736 queue_iterate(taskque, iter, IOUserClientOwner *, taskLink) {
1737 hasMessageAppSuspended = iter->uc->messageAppSuspended;
1738 if (hasMessageAppSuspended) {
1739 break;
1740 }
1741 }
1742 task_set_message_app_suspended(owner->task, hasMessageAppSuspended);
0a7de745
A
1743 queue_remove(&owners, owner, IOUserClientOwner *, ucLink);
1744 IODelete(owner, IOUserClientOwner, 1);
1745 }
1746 owners.next = owners.prev = NULL;
1747 }
7e41aa88 1748
0a7de745 1749 IOLockUnlock(gIOUserClientOwnersLock);
7e41aa88
A
1750}
1751
cb323159
A
1752
1753extern "C" void
1754iokit_task_app_suspended_changed(task_t task)
1755{
1756 queue_head_t * taskque;
1757 IOUserClientOwner * owner;
1758 OSSet * set;
1759
1760 IOLockLock(gIOUserClientOwnersLock);
1761
1762 taskque = task_io_user_clients(task);
1763 set = NULL;
1764 queue_iterate(taskque, owner, IOUserClientOwner *, taskLink) {
1765 if (!owner->uc->messageAppSuspended) {
1766 continue;
1767 }
1768 if (!set) {
1769 set = OSSet::withCapacity(4);
1770 if (!set) {
1771 break;
1772 }
1773 }
1774 set->setObject(owner->uc);
1775 }
1776
1777 IOLockUnlock(gIOUserClientOwnersLock);
1778
1779 if (set) {
1780 set->iterateObjects(^bool (OSObject * obj) {
1781 IOUserClient * uc;
1782
1783 uc = (typeof(uc))obj;
1784#if 0
1785 {
1786 OSString * str;
1787 str = IOCopyLogNameForPID(task_pid(task));
1788 IOLog("iokit_task_app_suspended_changed(%s) %s %d\n", str ? str->getCStringNoCopy() : "",
1789 uc->getName(), task_is_app_suspended(task));
1790 OSSafeReleaseNULL(str);
1791 }
1792#endif
1793 uc->message(kIOMessageTaskAppSuspendedChange, NULL);
1794
1795 return false;
1796 });
1797 set->release();
1798 }
1799}
1800
7e41aa88
A
1801extern "C" kern_return_t
1802iokit_task_terminate(task_t task)
1803{
0a7de745
A
1804 IOUserClientOwner * owner;
1805 IOUserClient * dead;
1806 IOUserClient * uc;
1807 queue_head_t * taskque;
1808
1809 IOLockLock(gIOUserClientOwnersLock);
1810
1811 taskque = task_io_user_clients(task);
1812 dead = NULL;
1813 while (!queue_empty(taskque)) {
1814 owner = (IOUserClientOwner *)(void *) queue_first(taskque);
1815 uc = owner->uc;
1816 queue_remove(taskque, owner, IOUserClientOwner *, taskLink);
1817 queue_remove(&uc->owners, owner, IOUserClientOwner *, ucLink);
1818 if (queue_empty(&uc->owners)) {
1819 uc->retain();
1820 IOLog("destroying out of band connect for %s\n", uc->getName());
1821 // now using the uc queue head as a singly linked queue,
1822 // leaving .next as NULL to mark it empty
1823 uc->owners.next = NULL;
1824 uc->owners.prev = (queue_entry_t) dead;
1825 dead = uc;
1826 }
1827 IODelete(owner, IOUserClientOwner, 1);
1828 }
7e41aa88 1829
0a7de745 1830 IOLockUnlock(gIOUserClientOwnersLock);
7e41aa88 1831
0a7de745
A
1832 while (dead) {
1833 uc = dead;
1834 dead = (IOUserClient *)(void *) dead->owners.prev;
1835 uc->owners.prev = NULL;
1836 if (uc->sharedInstance || !uc->closed) {
1837 uc->clientDied();
1838 }
1839 uc->release();
1840 }
7e41aa88 1841
0a7de745 1842 return KERN_SUCCESS;
7e41aa88
A
1843}
1844
f427ee49
A
1845struct IOUCFilterPolicy {
1846 task_t task;
1847 io_filter_policy_t filterPolicy;
1848 IOUCFilterPolicy * next;
1849};
1850
1851io_filter_policy_t
1852IOUserClient::filterForTask(task_t task, io_filter_policy_t addFilterPolicy)
1853{
1854 IOUCFilterPolicy * elem;
1855 io_filter_policy_t filterPolicy;
1856
1857 filterPolicy = 0;
1858 IOLockLock(filterLock);
1859
1860 for (elem = reserved->filterPolicies; elem && (elem->task != task); elem = elem->next) {
1861 }
1862
1863 if (elem) {
1864 if (addFilterPolicy) {
1865 assert(addFilterPolicy == elem->filterPolicy);
1866 }
1867 filterPolicy = elem->filterPolicy;
1868 } else if (addFilterPolicy) {
1869 elem = IONewZero(IOUCFilterPolicy, 1);
1870 if (elem) {
1871 elem->task = task;
1872 elem->filterPolicy = addFilterPolicy;
1873 elem->next = reserved->filterPolicies;
1874 reserved->filterPolicies = elem;
1875 filterPolicy = addFilterPolicy;
1876 }
1877 }
1878
1879 IOLockUnlock(filterLock);
1880 return filterPolicy;
1881}
1882
0a7de745
A
1883void
1884IOUserClient::free()
1c79356b 1885{
0a7de745
A
1886 if (mappings) {
1887 mappings->release();
1888 }
1889 if (lock) {
f427ee49
A
1890 IORWLockFree(lock);
1891 }
1892 if (filterLock) {
1893 IOLockFree(filterLock);
0a7de745
A
1894 }
1895
1896 IOStatisticsUnregisterCounter();
1897
1898 assert(!owners.next);
1899 assert(!owners.prev);
7e41aa88 1900
0a7de745 1901 if (reserved) {
f427ee49
A
1902 IOUCFilterPolicy * elem;
1903 IOUCFilterPolicy * nextElem;
1904 for (elem = reserved->filterPolicies; elem; elem = nextElem) {
1905 nextElem = elem->next;
1906 if (elem->filterPolicy && gIOUCFilterCallbacks->io_filter_release) {
1907 gIOUCFilterCallbacks->io_filter_release(elem->filterPolicy);
1908 }
1909 IODelete(elem, IOUCFilterPolicy, 1);
1910 }
0a7de745
A
1911 IODelete(reserved, ExpansionData, 1);
1912 }
1913
1914 super::free();
1c79356b
A
1915}
1916
0a7de745
A
1917IOReturn
1918IOUserClient::clientDied( void )
1c79356b 1919{
0a7de745 1920 IOReturn ret = kIOReturnNotReady;
c7d2c2c6 1921
0a7de745
A
1922 if (sharedInstance || OSCompareAndSwap8(0, 1, &closed)) {
1923 ret = clientClose();
1924 }
c7d2c2c6 1925
0a7de745 1926 return ret;
1c79356b
A
1927}
1928
0a7de745
A
1929IOReturn
1930IOUserClient::clientClose( void )
1c79356b 1931{
0a7de745 1932 return kIOReturnUnsupported;
1c79356b
A
1933}
1934
0a7de745
A
1935IOService *
1936IOUserClient::getService( void )
1c79356b 1937{
cb323159 1938 return NULL;
1c79356b
A
1939}
1940
0a7de745
A
1941IOReturn
1942IOUserClient::registerNotificationPort(
1943 mach_port_t /* port */,
1944 UInt32 /* type */,
1945 UInt32 /* refCon */)
1c79356b 1946{
0a7de745 1947 return kIOReturnUnsupported;
1c79356b
A
1948}
1949
0a7de745
A
1950IOReturn
1951IOUserClient::registerNotificationPort(
1952 mach_port_t port,
1953 UInt32 type,
1954 io_user_reference_t refCon)
b0d623f7 1955{
0a7de745 1956 return registerNotificationPort(port, type, (UInt32) refCon);
b0d623f7
A
1957}
1958
0a7de745
A
1959IOReturn
1960IOUserClient::getNotificationSemaphore( UInt32 notification_type,
1961 semaphore_t * semaphore )
1c79356b 1962{
0a7de745 1963 return kIOReturnUnsupported;
1c79356b
A
1964}
1965
0a7de745
A
1966IOReturn
1967IOUserClient::connectClient( IOUserClient * /* client */ )
1c79356b 1968{
0a7de745 1969 return kIOReturnUnsupported;
1c79356b
A
1970}
1971
0a7de745
A
1972IOReturn
1973IOUserClient::clientMemoryForType( UInt32 type,
1974 IOOptionBits * options,
1975 IOMemoryDescriptor ** memory )
1c79356b 1976{
0a7de745 1977 return kIOReturnUnsupported;
1c79356b
A
1978}
1979
f427ee49
A
1980IOReturn
1981IOUserClient::clientMemoryForType( UInt32 type,
1982 IOOptionBits * options,
1983 OSSharedPtr<IOMemoryDescriptor>& memory )
1984{
1985 IOMemoryDescriptor* memoryRaw = nullptr;
1986 IOReturn result = clientMemoryForType(type, options, &memoryRaw);
1987 memory.reset(memoryRaw, OSNoRetain);
1988 return result;
1989}
1990
b0d623f7 1991#if !__LP64__
0a7de745
A
1992IOMemoryMap *
1993IOUserClient::mapClientMemory(
1994 IOOptionBits type,
1995 task_t task,
1996 IOOptionBits mapFlags,
1997 IOVirtualAddress atAddress )
1c79356b 1998{
0a7de745 1999 return NULL;
1c79356b 2000}
b0d623f7 2001#endif
1c79356b 2002
0a7de745
A
2003IOMemoryMap *
2004IOUserClient::mapClientMemory64(
2005 IOOptionBits type,
2006 task_t task,
2007 IOOptionBits mapFlags,
2008 mach_vm_address_t atAddress )
2d21ac55 2009{
0a7de745
A
2010 IOReturn err;
2011 IOOptionBits options = 0;
cb323159
A
2012 IOMemoryDescriptor * memory = NULL;
2013 IOMemoryMap * map = NULL;
2d21ac55 2014
0a7de745 2015 err = clientMemoryForType((UInt32) type, &options, &memory );
2d21ac55 2016
0a7de745
A
2017 if (memory && (kIOReturnSuccess == err)) {
2018 FAKE_STACK_FRAME(getMetaClass());
2d21ac55 2019
0a7de745
A
2020 options = (options & ~kIOMapUserOptionsMask)
2021 | (mapFlags & kIOMapUserOptionsMask);
2022 map = memory->createMappingInTask( task, atAddress, options );
2023 memory->release();
39037602 2024
0a7de745
A
2025 FAKE_STACK_FRAME_END();
2026 }
2d21ac55 2027
0a7de745 2028 return map;
2d21ac55
A
2029}
2030
0a7de745
A
2031IOReturn
2032IOUserClient::exportObjectToClient(task_t task,
2033 OSObject *obj, io_object_t *clientObj)
1c79356b 2034{
0a7de745 2035 mach_port_name_t name;
1c79356b 2036
0a7de745 2037 name = IOMachPort::makeSendRightForTask( task, obj, IKOT_IOKIT_OBJECT );
1c79356b 2038
0a7de745 2039 *clientObj = (io_object_t)(uintptr_t) name;
a39ff7e2 2040
0a7de745
A
2041 if (obj) {
2042 obj->release();
2043 }
a39ff7e2 2044
0a7de745 2045 return kIOReturnSuccess;
1c79356b
A
2046}
2047
0a7de745
A
2048IOReturn
2049IOUserClient::copyPortNameForObjectInTask(task_t task,
2050 OSObject *obj, mach_port_name_t * port_name)
a39ff7e2 2051{
0a7de745 2052 mach_port_name_t name;
a39ff7e2 2053
0a7de745 2054 name = IOMachPort::makeSendRightForTask( task, obj, IKOT_IOKIT_IDENT );
a39ff7e2 2055
0a7de745 2056 *(mach_port_name_t *) port_name = name;
a39ff7e2 2057
0a7de745 2058 return kIOReturnSuccess;
a39ff7e2
A
2059}
2060
0a7de745
A
2061IOReturn
2062IOUserClient::copyObjectForPortNameInTask(task_t task, mach_port_name_t port_name,
2063 OSObject **obj)
a39ff7e2 2064{
0a7de745 2065 OSObject * object;
a39ff7e2 2066
0a7de745 2067 object = iokit_lookup_object_with_port_name(port_name, IKOT_IOKIT_IDENT, task);
a39ff7e2 2068
0a7de745 2069 *obj = object;
a39ff7e2 2070
0a7de745 2071 return object ? kIOReturnSuccess : kIOReturnIPCError;
a39ff7e2
A
2072}
2073
f427ee49
A
2074IOReturn
2075IOUserClient::copyObjectForPortNameInTask(task_t task, mach_port_name_t port_name,
2076 OSSharedPtr<OSObject>& obj)
2077{
2078 OSObject* objRaw = NULL;
2079 IOReturn result = copyObjectForPortNameInTask(task, port_name, &objRaw);
2080 obj.reset(objRaw, OSNoRetain);
2081 return result;
2082}
2083
0a7de745
A
2084IOReturn
2085IOUserClient::adjustPortNameReferencesInTask(task_t task, mach_port_name_t port_name, mach_port_delta_t delta)
a39ff7e2 2086{
0a7de745 2087 return iokit_mod_send_right(task, port_name, delta);
a39ff7e2
A
2088}
2089
0a7de745
A
2090IOExternalMethod *
2091IOUserClient::getExternalMethodForIndex( UInt32 /* index */)
1c79356b 2092{
cb323159 2093 return NULL;
1c79356b
A
2094}
2095
0a7de745
A
2096IOExternalAsyncMethod *
2097IOUserClient::getExternalAsyncMethodForIndex( UInt32 /* index */)
1c79356b 2098{
cb323159 2099 return NULL;
1c79356b
A
2100}
2101
0a7de745
A
2102IOExternalTrap *
2103IOUserClient::
39037602
A
2104getExternalTrapForIndex(UInt32 index)
2105{
2106 return NULL;
2107}
2108
2109#pragma clang diagnostic push
2110#pragma clang diagnostic ignored "-Wdeprecated-declarations"
2111
2112// Suppressing the deprecated-declarations warning. Avoiding the use of deprecated
2113// functions can break clients of kexts implementing getExternalMethodForIndex()
0a7de745
A
2114IOExternalMethod *
2115IOUserClient::
1c79356b
A
2116getTargetAndMethodForIndex(IOService **targetP, UInt32 index)
2117{
0a7de745 2118 IOExternalMethod *method = getExternalMethodForIndex(index);
1c79356b 2119
0a7de745
A
2120 if (method) {
2121 *targetP = (IOService *) method->object;
2122 }
1c79356b 2123
0a7de745 2124 return method;
1c79356b
A
2125}
2126
f427ee49
A
2127IOExternalMethod *
2128IOUserClient::
2129getTargetAndMethodForIndex(OSSharedPtr<IOService>& targetP, UInt32 index)
2130{
2131 IOService* targetPRaw = NULL;
2132 IOExternalMethod* result = getTargetAndMethodForIndex(&targetPRaw, index);
2133 targetP.reset(targetPRaw, OSRetain);
2134 return result;
2135}
2136
0a7de745
A
2137IOExternalAsyncMethod *
2138IOUserClient::
1c79356b
A
2139getAsyncTargetAndMethodForIndex(IOService ** targetP, UInt32 index)
2140{
0a7de745 2141 IOExternalAsyncMethod *method = getExternalAsyncMethodForIndex(index);
1c79356b 2142
0a7de745
A
2143 if (method) {
2144 *targetP = (IOService *) method->object;
2145 }
1c79356b 2146
0a7de745 2147 return method;
1c79356b
A
2148}
2149
f427ee49
A
2150IOExternalAsyncMethod *
2151IOUserClient::
2152getAsyncTargetAndMethodForIndex(OSSharedPtr<IOService>& targetP, UInt32 index)
2153{
2154 IOService* targetPRaw = NULL;
2155 IOExternalAsyncMethod* result = getAsyncTargetAndMethodForIndex(&targetPRaw, index);
2156 targetP.reset(targetPRaw, OSRetain);
2157 return result;
2158}
2159
0a7de745
A
2160IOExternalTrap *
2161IOUserClient::
1c79356b
A
2162getTargetAndTrapForIndex(IOService ** targetP, UInt32 index)
2163{
0a7de745 2164 IOExternalTrap *trap = getExternalTrapForIndex(index);
1c79356b 2165
0a7de745
A
2166 if (trap) {
2167 *targetP = trap->object;
2168 }
1c79356b 2169
0a7de745 2170 return trap;
1c79356b 2171}
39037602 2172#pragma clang diagnostic pop
1c79356b 2173
0a7de745
A
2174IOReturn
2175IOUserClient::releaseAsyncReference64(OSAsyncReference64 reference)
b0d623f7 2176{
0a7de745
A
2177 mach_port_t port;
2178 port = (mach_port_t) (reference[0] & ~kIOUCAsync0Flags);
b0d623f7 2179
0a7de745
A
2180 if (MACH_PORT_NULL != port) {
2181 iokit_release_port_send(port);
2182 }
b0d623f7 2183
0a7de745 2184 return kIOReturnSuccess;
b0d623f7
A
2185}
2186
0a7de745
A
2187IOReturn
2188IOUserClient::releaseNotificationPort(mach_port_t port)
b0d623f7 2189{
0a7de745
A
2190 if (MACH_PORT_NULL != port) {
2191 iokit_release_port_send(port);
2192 }
b0d623f7 2193
0a7de745 2194 return kIOReturnSuccess;
b0d623f7
A
2195}
2196
0a7de745
A
2197IOReturn
2198IOUserClient::sendAsyncResult(OSAsyncReference reference,
2199 IOReturn result, void *args[], UInt32 numArgs)
1c79356b 2200{
0a7de745
A
2201 OSAsyncReference64 reference64;
2202 io_user_reference_t args64[kMaxAsyncArgs];
2203 unsigned int idx;
2d21ac55 2204
0a7de745
A
2205 if (numArgs > kMaxAsyncArgs) {
2206 return kIOReturnMessageTooLarge;
2207 }
2d21ac55 2208
0a7de745
A
2209 for (idx = 0; idx < kOSAsyncRef64Count; idx++) {
2210 reference64[idx] = REF64(reference[idx]);
2211 }
2d21ac55 2212
0a7de745
A
2213 for (idx = 0; idx < numArgs; idx++) {
2214 args64[idx] = REF64(args[idx]);
2215 }
2d21ac55 2216
0a7de745 2217 return sendAsyncResult64(reference64, result, args64, numArgs);
2d21ac55
A
2218}
2219
0a7de745
A
2220IOReturn
2221IOUserClient::sendAsyncResult64WithOptions(OSAsyncReference64 reference,
2222 IOReturn result, io_user_reference_t args[], UInt32 numArgs, IOOptionBits options)
39236c6e
A
2223{
2224 return _sendAsyncResult64(reference, result, args, numArgs, options);
2225}
2226
0a7de745
A
2227IOReturn
2228IOUserClient::sendAsyncResult64(OSAsyncReference64 reference,
2229 IOReturn result, io_user_reference_t args[], UInt32 numArgs)
2230{
2231 return _sendAsyncResult64(reference, result, args, numArgs, 0);
2232}
2233
2234IOReturn
2235IOUserClient::_sendAsyncResult64(OSAsyncReference64 reference,
2236 IOReturn result, io_user_reference_t args[], UInt32 numArgs, IOOptionBits options)
2237{
2238 struct ReplyMsg {
2239 mach_msg_header_t msgHdr;
2240 union{
2241 struct{
2242 OSNotificationHeader notifyHdr;
2243 IOAsyncCompletionContent asyncContent;
2244 uint32_t args[kMaxAsyncArgs];
2245 } msg32;
2246 struct{
2247 OSNotificationHeader64 notifyHdr;
2248 IOAsyncCompletionContent asyncContent;
2249 io_user_reference_t args[kMaxAsyncArgs] __attribute__ ((packed));
2250 } msg64;
2251 } m;
2252 };
2253 ReplyMsg replyMsg;
2254 mach_port_t replyPort;
2255 kern_return_t kr;
2256
2257 // If no reply port, do nothing.
2258 replyPort = (mach_port_t) (reference[0] & ~kIOUCAsync0Flags);
2259 if (replyPort == MACH_PORT_NULL) {
2260 return kIOReturnSuccess;
2261 }
2262
2263 if (numArgs > kMaxAsyncArgs) {
2264 return kIOReturnMessageTooLarge;
2265 }
2266
2267 bzero(&replyMsg, sizeof(replyMsg));
2268 replyMsg.msgHdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND /*remote*/,
2269 0 /*local*/);
2270 replyMsg.msgHdr.msgh_remote_port = replyPort;
cb323159 2271 replyMsg.msgHdr.msgh_local_port = NULL;
0a7de745
A
2272 replyMsg.msgHdr.msgh_id = kOSNotificationMessageID;
2273 if (kIOUCAsync64Flag & reference[0]) {
2274 replyMsg.msgHdr.msgh_size =
2275 sizeof(replyMsg.msgHdr) + sizeof(replyMsg.m.msg64)
2276 - (kMaxAsyncArgs - numArgs) * sizeof(io_user_reference_t);
2277 replyMsg.m.msg64.notifyHdr.size = sizeof(IOAsyncCompletionContent)
2278 + numArgs * sizeof(io_user_reference_t);
2279 replyMsg.m.msg64.notifyHdr.type = kIOAsyncCompletionNotificationType;
c6bf4f31
A
2280 /* Copy reference except for reference[0], which is left as 0 from the earlier bzero */
2281 bcopy(&reference[1], &replyMsg.m.msg64.notifyHdr.reference[1], sizeof(OSAsyncReference64) - sizeof(reference[0]));
0a7de745
A
2282
2283 replyMsg.m.msg64.asyncContent.result = result;
2284 if (numArgs) {
2285 bcopy(args, replyMsg.m.msg64.args, numArgs * sizeof(io_user_reference_t));
2286 }
2287 } else {
2288 unsigned int idx;
2289
2290 replyMsg.msgHdr.msgh_size =
2291 sizeof(replyMsg.msgHdr) + sizeof(replyMsg.m.msg32)
2292 - (kMaxAsyncArgs - numArgs) * sizeof(uint32_t);
2293
2294 replyMsg.m.msg32.notifyHdr.size = sizeof(IOAsyncCompletionContent)
2295 + numArgs * sizeof(uint32_t);
2296 replyMsg.m.msg32.notifyHdr.type = kIOAsyncCompletionNotificationType;
2297
c6bf4f31
A
2298 /* Skip reference[0] which is left as 0 from the earlier bzero */
2299 for (idx = 1; idx < kOSAsyncRefCount; idx++) {
0a7de745
A
2300 replyMsg.m.msg32.notifyHdr.reference[idx] = REF32(reference[idx]);
2301 }
2302
2303 replyMsg.m.msg32.asyncContent.result = result;
2304
2305 for (idx = 0; idx < numArgs; idx++) {
2306 replyMsg.m.msg32.args[idx] = REF32(args[idx]);
2307 }
2308 }
2309
2310 if ((options & kIOUserNotifyOptionCanDrop) != 0) {
39236c6e 2311 kr = mach_msg_send_from_kernel_with_options( &replyMsg.msgHdr,
0a7de745 2312 replyMsg.msgHdr.msgh_size, MACH_SEND_TIMEOUT, MACH_MSG_TIMEOUT_NONE);
39236c6e
A
2313 } else {
2314 /* Fail on full queue. */
2315 kr = mach_msg_send_from_kernel_proper( &replyMsg.msgHdr,
0a7de745
A
2316 replyMsg.msgHdr.msgh_size);
2317 }
2318 if ((KERN_SUCCESS != kr) && (MACH_SEND_TIMED_OUT != kr) && !(kIOUCAsyncErrorLoggedFlag & reference[0])) {
2319 reference[0] |= kIOUCAsyncErrorLoggedFlag;
2320 IOLog("%s: mach_msg_send_from_kernel_proper(0x%x)\n", __PRETTY_FUNCTION__, kr );
39236c6e 2321 }
0a7de745 2322 return kr;
1c79356b
A
2323}
2324
2d21ac55 2325
1c79356b
A
2326/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2327
1c79356b 2328extern "C" {
0a7de745
A
2329#define CHECK(cls, obj, out) \
2330 cls * out; \
2331 if( !(out = OSDynamicCast( cls, obj))) \
1c79356b
A
2332 return( kIOReturnBadArgument )
2333
0a7de745
A
2334#define CHECKLOCKED(cls, obj, out) \
2335 IOUserIterator * oIter; \
2336 cls * out; \
2337 if( !(oIter = OSDynamicCast(IOUserIterator, obj))) \
2338 return (kIOReturnBadArgument); \
2339 if( !(out = OSDynamicCast(cls, oIter->userIteratorObject))) \
4bd07ac2
A
2340 return (kIOReturnBadArgument)
2341
fe8ab488
A
2342/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2343
3e170ce0
A
2344// Create a vm_map_copy_t or kalloc'ed data for memory
2345// to be copied out. ipc will free after the copyout.
2346
0a7de745
A
2347static kern_return_t
2348copyoutkdata( const void * data, vm_size_t len,
2349 io_buf_ptr_t * buf )
3e170ce0 2350{
0a7de745
A
2351 kern_return_t err;
2352 vm_map_copy_t copy;
3e170ce0 2353
0a7de745
A
2354 err = vm_map_copyin( kernel_map, CAST_USER_ADDR_T(data), len,
2355 false /* src_destroy */, &copy);
3e170ce0 2356
0a7de745
A
2357 assert( err == KERN_SUCCESS );
2358 if (err == KERN_SUCCESS) {
2359 *buf = (char *) copy;
2360 }
3e170ce0 2361
0a7de745 2362 return err;
3e170ce0
A
2363}
2364
2365/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2366
fe8ab488 2367/* Routine io_server_version */
0a7de745
A
2368kern_return_t
2369is_io_server_version(
fe8ab488
A
2370 mach_port_t master_port,
2371 uint64_t *version)
2372{
0a7de745
A
2373 *version = IOKIT_SERVER_VERSION;
2374 return kIOReturnSuccess;
fe8ab488
A
2375}
2376
1c79356b 2377/* Routine io_object_get_class */
0a7de745
A
2378kern_return_t
2379is_io_object_get_class(
2380 io_object_t object,
2381 io_name_t className )
1c79356b 2382{
0a7de745
A
2383 const OSMetaClass* my_obj = NULL;
2384
2385 if (!object) {
2386 return kIOReturnBadArgument;
2387 }
490019cf 2388
0a7de745
A
2389 my_obj = object->getMetaClass();
2390 if (!my_obj) {
2391 return kIOReturnNotFound;
2392 }
2393
2394 strlcpy( className, my_obj->getClassName(), sizeof(io_name_t));
3e170ce0 2395
0a7de745 2396 return kIOReturnSuccess;
1c79356b
A
2397}
2398
91447636 2399/* Routine io_object_get_superclass */
0a7de745
A
2400kern_return_t
2401is_io_object_get_superclass(
91447636 2402 mach_port_t master_port,
0a7de745 2403 io_name_t obj_name,
91447636
A
2404 io_name_t class_name)
2405{
0a7de745
A
2406 IOReturn ret;
2407 const OSMetaClass * meta;
2408 const OSMetaClass * super;
2409 const OSSymbol * name;
2410 const char * cstr;
2411
2412 if (!obj_name || !class_name) {
2413 return kIOReturnBadArgument;
2414 }
2415 if (master_port != master_device_port) {
2416 return kIOReturnNotPrivileged;
2417 }
2418
2419 ret = kIOReturnNotFound;
cb323159 2420 meta = NULL;
0a7de745
A
2421 do{
2422 name = OSSymbol::withCString(obj_name);
2423 if (!name) {
2424 break;
2425 }
2426 meta = OSMetaClass::copyMetaClassWithName(name);
2427 if (!meta) {
2428 break;
2429 }
2430 super = meta->getSuperClass();
2431 if (!super) {
2432 break;
2433 }
2434 cstr = super->getClassName();
2435 if (!cstr) {
2436 break;
2437 }
2438 strlcpy(class_name, cstr, sizeof(io_name_t));
2439 ret = kIOReturnSuccess;
2440 }while (false);
2441
2442 OSSafeReleaseNULL(name);
2443 if (meta) {
2444 meta->releaseMetaClass();
2445 }
2446
2447 return ret;
91447636
A
2448}
2449
2450/* Routine io_object_get_bundle_identifier */
0a7de745
A
2451kern_return_t
2452is_io_object_get_bundle_identifier(
91447636 2453 mach_port_t master_port,
0a7de745 2454 io_name_t obj_name,
91447636
A
2455 io_name_t bundle_name)
2456{
0a7de745
A
2457 IOReturn ret;
2458 const OSMetaClass * meta;
2459 const OSSymbol * name;
2460 const OSSymbol * identifier;
2461 const char * cstr;
2462
2463 if (!obj_name || !bundle_name) {
2464 return kIOReturnBadArgument;
2465 }
2466 if (master_port != master_device_port) {
2467 return kIOReturnNotPrivileged;
2468 }
2469
2470 ret = kIOReturnNotFound;
cb323159 2471 meta = NULL;
0a7de745
A
2472 do{
2473 name = OSSymbol::withCString(obj_name);
2474 if (!name) {
2475 break;
2476 }
2477 meta = OSMetaClass::copyMetaClassWithName(name);
2478 if (!meta) {
2479 break;
2480 }
2481 identifier = meta->getKmodName();
2482 if (!identifier) {
2483 break;
2484 }
2485 cstr = identifier->getCStringNoCopy();
2486 if (!cstr) {
2487 break;
2488 }
2489 strlcpy(bundle_name, identifier->getCStringNoCopy(), sizeof(io_name_t));
2490 ret = kIOReturnSuccess;
2491 }while (false);
2492
2493 OSSafeReleaseNULL(name);
2494 if (meta) {
2495 meta->releaseMetaClass();
2496 }
2497
2498 return ret;
91447636
A
2499}
2500
1c79356b 2501/* Routine io_object_conforms_to */
0a7de745
A
2502kern_return_t
2503is_io_object_conforms_to(
1c79356b
A
2504 io_object_t object,
2505 io_name_t className,
2506 boolean_t *conforms )
2507{
0a7de745
A
2508 if (!object) {
2509 return kIOReturnBadArgument;
2510 }
1c79356b 2511
cb323159 2512 *conforms = (NULL != object->metaCast( className ));
3e170ce0 2513
0a7de745 2514 return kIOReturnSuccess;
1c79356b
A
2515}
2516
2517/* Routine io_object_get_retain_count */
0a7de745
A
2518kern_return_t
2519is_io_object_get_retain_count(
1c79356b 2520 io_object_t object,
2d21ac55 2521 uint32_t *retainCount )
1c79356b 2522{
0a7de745
A
2523 if (!object) {
2524 return kIOReturnBadArgument;
2525 }
1c79356b 2526
0a7de745
A
2527 *retainCount = object->getRetainCount();
2528 return kIOReturnSuccess;
1c79356b
A
2529}
2530
2531/* Routine io_iterator_next */
0a7de745
A
2532kern_return_t
2533is_io_iterator_next(
1c79356b
A
2534 io_object_t iterator,
2535 io_object_t *object )
2536{
0a7de745
A
2537 IOReturn ret;
2538 OSObject * obj;
2539 OSIterator * iter;
2540 IOUserIterator * uiter;
1c79356b 2541
0a7de745 2542 if ((uiter = OSDynamicCast(IOUserIterator, iterator))) {
d9a64523 2543 obj = uiter->copyNextObject();
0a7de745 2544 } else if ((iter = OSDynamicCast(OSIterator, iterator))) {
d9a64523 2545 obj = iter->getNextObject();
0a7de745
A
2546 if (obj) {
2547 obj->retain();
2548 }
2549 } else {
2550 return kIOReturnBadArgument;
d9a64523 2551 }
1c79356b 2552
0a7de745
A
2553 if (obj) {
2554 *object = obj;
2555 ret = kIOReturnSuccess;
2556 } else {
2557 ret = kIOReturnNoDevice;
2558 }
4bd07ac2 2559
0a7de745 2560 return ret;
1c79356b
A
2561}
2562
2563/* Routine io_iterator_reset */
0a7de745
A
2564kern_return_t
2565is_io_iterator_reset(
1c79356b
A
2566 io_object_t iterator )
2567{
0a7de745 2568 CHECK( OSIterator, iterator, iter );
1c79356b 2569
0a7de745 2570 iter->reset();
1c79356b 2571
0a7de745 2572 return kIOReturnSuccess;
1c79356b
A
2573}
2574
2575/* Routine io_iterator_is_valid */
0a7de745
A
2576kern_return_t
2577is_io_iterator_is_valid(
1c79356b
A
2578 io_object_t iterator,
2579 boolean_t *is_valid )
2580{
0a7de745 2581 CHECK( OSIterator, iterator, iter );
1c79356b 2582
0a7de745 2583 *is_valid = iter->isValid();
1c79356b 2584
0a7de745 2585 return kIOReturnSuccess;
1c79356b
A
2586}
2587
0a7de745
A
2588static kern_return_t
2589internal_io_service_match_property_table(
1c79356b 2590 io_service_t _service,
fe8ab488
A
2591 const char * matching,
2592 mach_msg_type_number_t matching_size,
2593 boolean_t *matches)
1c79356b 2594{
0a7de745 2595 CHECK( IOService, _service, service );
1c79356b 2596
0a7de745
A
2597 kern_return_t kr;
2598 OSObject * obj;
2599 OSDictionary * dict;
1c79356b 2600
0a7de745 2601 assert(matching_size);
f427ee49
A
2602
2603
0a7de745 2604 obj = OSUnserializeXML(matching, matching_size);
39037602 2605
0a7de745 2606 if ((dict = OSDynamicCast( OSDictionary, obj))) {
f427ee49 2607 IOTaskRegistryCompatibilityMatching(current_task(), dict);
0a7de745
A
2608 *matches = service->passiveMatch( dict );
2609 kr = kIOReturnSuccess;
2610 } else {
2611 kr = kIOReturnBadArgument;
2612 }
1c79356b 2613
0a7de745
A
2614 if (obj) {
2615 obj->release();
2616 }
1c79356b 2617
0a7de745 2618 return kr;
1c79356b
A
2619}
2620
fe8ab488 2621/* Routine io_service_match_property_table */
0a7de745
A
2622kern_return_t
2623is_io_service_match_property_table(
fe8ab488
A
2624 io_service_t service,
2625 io_string_t matching,
2626 boolean_t *matches )
2627{
0a7de745 2628 return kIOReturnUnsupported;
fe8ab488
A
2629}
2630
2631
55e303ae 2632/* Routine io_service_match_property_table_ool */
0a7de745
A
2633kern_return_t
2634is_io_service_match_property_table_ool(
55e303ae
A
2635 io_object_t service,
2636 io_buf_ptr_t matching,
2637 mach_msg_type_number_t matchingCnt,
2d21ac55 2638 kern_return_t *result,
55e303ae
A
2639 boolean_t *matches )
2640{
0a7de745
A
2641 kern_return_t kr;
2642 vm_offset_t data;
2643 vm_map_offset_t map_data;
55e303ae 2644
0a7de745
A
2645 kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) matching );
2646 data = CAST_DOWN(vm_offset_t, map_data);
55e303ae 2647
0a7de745
A
2648 if (KERN_SUCCESS == kr) {
2649 // must return success after vm_map_copyout() succeeds
2650 *result = internal_io_service_match_property_table(service,
2651 (const char *)data, matchingCnt, matches );
2652 vm_deallocate( kernel_map, data, matchingCnt );
2653 }
55e303ae 2654
0a7de745 2655 return kr;
55e303ae
A
2656}
2657
fe8ab488 2658/* Routine io_service_match_property_table_bin */
0a7de745
A
2659kern_return_t
2660is_io_service_match_property_table_bin(
fe8ab488
A
2661 io_object_t service,
2662 io_struct_inband_t matching,
2663 mach_msg_type_number_t matchingCnt,
2664 boolean_t *matches)
2665{
0a7de745 2666 return internal_io_service_match_property_table(service, matching, matchingCnt, matches);
fe8ab488
A
2667}
2668
0a7de745
A
2669static kern_return_t
2670internal_io_service_get_matching_services(
1c79356b 2671 mach_port_t master_port,
fe8ab488
A
2672 const char * matching,
2673 mach_msg_type_number_t matching_size,
1c79356b
A
2674 io_iterator_t *existing )
2675{
0a7de745
A
2676 kern_return_t kr;
2677 OSObject * obj;
2678 OSDictionary * dict;
1c79356b 2679
0a7de745
A
2680 if (master_port != master_device_port) {
2681 return kIOReturnNotPrivileged;
2682 }
1c79356b 2683
0a7de745
A
2684 assert(matching_size);
2685 obj = OSUnserializeXML(matching, matching_size);
39037602 2686
0a7de745 2687 if ((dict = OSDynamicCast( OSDictionary, obj))) {
f427ee49 2688 IOTaskRegistryCompatibilityMatching(current_task(), dict);
0a7de745
A
2689 *existing = IOUserIterator::withIterator(IOService::getMatchingServices( dict ));
2690 kr = kIOReturnSuccess;
2691 } else {
2692 kr = kIOReturnBadArgument;
2693 }
1c79356b 2694
0a7de745
A
2695 if (obj) {
2696 obj->release();
2697 }
1c79356b 2698
0a7de745 2699 return kr;
1c79356b
A
2700}
2701
fe8ab488 2702/* Routine io_service_get_matching_services */
0a7de745
A
2703kern_return_t
2704is_io_service_get_matching_services(
fe8ab488
A
2705 mach_port_t master_port,
2706 io_string_t matching,
2707 io_iterator_t *existing )
2708{
0a7de745 2709 return kIOReturnUnsupported;
fe8ab488
A
2710}
2711
55e303ae 2712/* Routine io_service_get_matching_services_ool */
0a7de745
A
2713kern_return_t
2714is_io_service_get_matching_services_ool(
55e303ae
A
2715 mach_port_t master_port,
2716 io_buf_ptr_t matching,
2717 mach_msg_type_number_t matchingCnt,
2d21ac55 2718 kern_return_t *result,
55e303ae
A
2719 io_object_t *existing )
2720{
0a7de745
A
2721 kern_return_t kr;
2722 vm_offset_t data;
2723 vm_map_offset_t map_data;
55e303ae 2724
0a7de745
A
2725 kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) matching );
2726 data = CAST_DOWN(vm_offset_t, map_data);
55e303ae 2727
0a7de745
A
2728 if (KERN_SUCCESS == kr) {
2729 // must return success after vm_map_copyout() succeeds
2730 // and mig will copy out objects on success
cb323159 2731 *existing = NULL;
0a7de745
A
2732 *result = internal_io_service_get_matching_services(master_port,
2733 (const char *) data, matchingCnt, existing);
2734 vm_deallocate( kernel_map, data, matchingCnt );
2735 }
55e303ae 2736
0a7de745 2737 return kr;
55e303ae
A
2738}
2739
fe8ab488 2740/* Routine io_service_get_matching_services_bin */
0a7de745
A
2741kern_return_t
2742is_io_service_get_matching_services_bin(
fe8ab488
A
2743 mach_port_t master_port,
2744 io_struct_inband_t matching,
2745 mach_msg_type_number_t matchingCnt,
2746 io_object_t *existing)
2747{
0a7de745 2748 return internal_io_service_get_matching_services(master_port, matching, matchingCnt, existing);
fe8ab488 2749}
316670eb 2750
fe8ab488 2751
0a7de745
A
2752static kern_return_t
2753internal_io_service_get_matching_service(
316670eb 2754 mach_port_t master_port,
fe8ab488
A
2755 const char * matching,
2756 mach_msg_type_number_t matching_size,
316670eb
A
2757 io_service_t *service )
2758{
0a7de745
A
2759 kern_return_t kr;
2760 OSObject * obj;
2761 OSDictionary * dict;
316670eb 2762
0a7de745
A
2763 if (master_port != master_device_port) {
2764 return kIOReturnNotPrivileged;
2765 }
316670eb 2766
0a7de745
A
2767 assert(matching_size);
2768 obj = OSUnserializeXML(matching, matching_size);
39037602 2769
0a7de745 2770 if ((dict = OSDynamicCast( OSDictionary, obj))) {
f427ee49 2771 IOTaskRegistryCompatibilityMatching(current_task(), dict);
0a7de745
A
2772 *service = IOService::copyMatchingService( dict );
2773 kr = *service ? kIOReturnSuccess : kIOReturnNotFound;
2774 } else {
2775 kr = kIOReturnBadArgument;
2776 }
316670eb 2777
0a7de745
A
2778 if (obj) {
2779 obj->release();
2780 }
316670eb 2781
0a7de745 2782 return kr;
316670eb
A
2783}
2784
fe8ab488 2785/* Routine io_service_get_matching_service */
0a7de745
A
2786kern_return_t
2787is_io_service_get_matching_service(
fe8ab488
A
2788 mach_port_t master_port,
2789 io_string_t matching,
2790 io_service_t *service )
2791{
0a7de745 2792 return kIOReturnUnsupported;
fe8ab488
A
2793}
2794
316670eb 2795/* Routine io_service_get_matching_services_ool */
0a7de745
A
2796kern_return_t
2797is_io_service_get_matching_service_ool(
316670eb
A
2798 mach_port_t master_port,
2799 io_buf_ptr_t matching,
2800 mach_msg_type_number_t matchingCnt,
2801 kern_return_t *result,
2802 io_object_t *service )
2803{
0a7de745
A
2804 kern_return_t kr;
2805 vm_offset_t data;
2806 vm_map_offset_t map_data;
316670eb 2807
0a7de745
A
2808 kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) matching );
2809 data = CAST_DOWN(vm_offset_t, map_data);
316670eb 2810
0a7de745
A
2811 if (KERN_SUCCESS == kr) {
2812 // must return success after vm_map_copyout() succeeds
2813 // and mig will copy out objects on success
cb323159 2814 *service = NULL;
0a7de745
A
2815 *result = internal_io_service_get_matching_service(master_port,
2816 (const char *) data, matchingCnt, service );
2817 vm_deallocate( kernel_map, data, matchingCnt );
2818 }
316670eb 2819
0a7de745 2820 return kr;
316670eb
A
2821}
2822
fe8ab488 2823/* Routine io_service_get_matching_service_bin */
0a7de745
A
2824kern_return_t
2825is_io_service_get_matching_service_bin(
fe8ab488
A
2826 mach_port_t master_port,
2827 io_struct_inband_t matching,
2828 mach_msg_type_number_t matchingCnt,
2829 io_object_t *service)
2830{
0a7de745 2831 return internal_io_service_get_matching_service(master_port, matching, matchingCnt, service);
fe8ab488 2832}
316670eb 2833
0a7de745
A
2834static kern_return_t
2835internal_io_service_add_notification(
1c79356b
A
2836 mach_port_t master_port,
2837 io_name_t notification_type,
fe8ab488
A
2838 const char * matching,
2839 size_t matching_size,
1c79356b 2840 mach_port_t port,
2d21ac55
A
2841 void * reference,
2842 vm_size_t referenceSize,
2843 bool client64,
1c79356b
A
2844 io_object_t * notification )
2845{
cb323159
A
2846 IOServiceUserNotification * userNotify = NULL;
2847 IONotifier * notify = NULL;
0a7de745 2848 const OSSymbol * sym;
f427ee49 2849 OSObject * obj;
0a7de745
A
2850 OSDictionary * dict;
2851 IOReturn err;
f427ee49 2852 natural_t userMsgType;
0a7de745
A
2853
2854 if (master_port != master_device_port) {
2855 return kIOReturnNotPrivileged;
2856 }
2857
2858 do {
2859 err = kIOReturnNoResources;
1c79356b 2860
0a7de745
A
2861 if (matching_size > (sizeof(io_struct_inband_t) * 1024)) {
2862 return kIOReturnMessageTooLarge;
2863 }
2864
2865 if (!(sym = OSSymbol::withCString( notification_type ))) {
2866 err = kIOReturnNoResources;
2867 }
1c79356b 2868
0a7de745 2869 assert(matching_size);
f427ee49
A
2870 obj = OSUnserializeXML(matching, matching_size);
2871 dict = OSDynamicCast(OSDictionary, obj);
0a7de745
A
2872 if (!dict) {
2873 err = kIOReturnBadArgument;
2874 continue;
2875 }
f427ee49 2876 IOTaskRegistryCompatibilityMatching(current_task(), dict);
1c79356b 2877
0a7de745
A
2878 if ((sym == gIOPublishNotification)
2879 || (sym == gIOFirstPublishNotification)) {
2880 userMsgType = kIOServicePublishNotificationType;
2881 } else if ((sym == gIOMatchedNotification)
2882 || (sym == gIOFirstMatchNotification)) {
2883 userMsgType = kIOServiceMatchedNotificationType;
2884 } else if ((sym == gIOTerminatedNotification)
2885 || (sym == gIOWillTerminateNotification)) {
2886 userMsgType = kIOServiceTerminatedNotificationType;
2887 } else {
2888 userMsgType = kLastIOKitNotificationType;
2889 }
cc8bc92a 2890
0a7de745 2891 userNotify = new IOServiceUserNotification;
1c79356b 2892
0a7de745
A
2893 if (userNotify && !userNotify->init( port, userMsgType,
2894 reference, referenceSize, client64)) {
2895 userNotify->release();
cb323159 2896 userNotify = NULL;
0a7de745
A
2897 }
2898 if (!userNotify) {
2899 continue;
2900 }
2901
2902 notify = IOService::addMatchingNotification( sym, dict,
2903 &userNotify->_handler, userNotify );
2904 if (notify) {
2905 *notification = userNotify;
2906 userNotify->setNotification( notify );
2907 err = kIOReturnSuccess;
2908 } else {
2909 err = kIOReturnUnsupported;
2910 }
2911 } while (false);
2912
2913 if ((kIOReturnSuccess != err) && userNotify) {
2914 userNotify->invalidatePort();
2915 userNotify->release();
cb323159 2916 userNotify = NULL;
0a7de745
A
2917 }
2918
2919 if (sym) {
2920 sym->release();
2921 }
f427ee49
A
2922 if (obj) {
2923 obj->release();
0a7de745 2924 }
1c79356b 2925
0a7de745 2926 return err;
1c79356b
A
2927}
2928
2d21ac55
A
2929
2930/* Routine io_service_add_notification */
0a7de745
A
2931kern_return_t
2932is_io_service_add_notification(
2d21ac55
A
2933 mach_port_t master_port,
2934 io_name_t notification_type,
2935 io_string_t matching,
2936 mach_port_t port,
2937 io_async_ref_t reference,
2938 mach_msg_type_number_t referenceCnt,
2939 io_object_t * notification )
2940{
0a7de745 2941 return kIOReturnUnsupported;
2d21ac55
A
2942}
2943
2944/* Routine io_service_add_notification_64 */
0a7de745
A
2945kern_return_t
2946is_io_service_add_notification_64(
2d21ac55
A
2947 mach_port_t master_port,
2948 io_name_t notification_type,
2949 io_string_t matching,
2950 mach_port_t wake_port,
2951 io_async_ref64_t reference,
2952 mach_msg_type_number_t referenceCnt,
2953 io_object_t *notification )
2954{
0a7de745 2955 return kIOReturnUnsupported;
2d21ac55
A
2956}
2957
fe8ab488 2958/* Routine io_service_add_notification_bin */
0a7de745
A
2959kern_return_t
2960is_io_service_add_notification_bin
fe8ab488
A
2961(
2962 mach_port_t master_port,
2963 io_name_t notification_type,
2964 io_struct_inband_t matching,
2965 mach_msg_type_number_t matchingCnt,
2966 mach_port_t wake_port,
2967 io_async_ref_t reference,
2968 mach_msg_type_number_t referenceCnt,
2969 io_object_t *notification)
2970{
0a7de745
A
2971 io_async_ref_t zreference;
2972
2973 if (referenceCnt > ASYNC_REF_COUNT) {
2974 return kIOReturnBadArgument;
2975 }
2976 bcopy(&reference[0], &zreference[0], referenceCnt * sizeof(zreference[0]));
2977 bzero(&zreference[referenceCnt], (ASYNC_REF_COUNT - referenceCnt) * sizeof(zreference[0]));
2978
2979 return internal_io_service_add_notification(master_port, notification_type,
2980 matching, matchingCnt, wake_port, &zreference[0], sizeof(io_async_ref_t),
2981 false, notification);
fe8ab488
A
2982}
2983
2984/* Routine io_service_add_notification_bin_64 */
0a7de745
A
2985kern_return_t
2986is_io_service_add_notification_bin_64
fe8ab488
A
2987(
2988 mach_port_t master_port,
2989 io_name_t notification_type,
2990 io_struct_inband_t matching,
2991 mach_msg_type_number_t matchingCnt,
2992 mach_port_t wake_port,
2993 io_async_ref64_t reference,
2994 mach_msg_type_number_t referenceCnt,
2995 io_object_t *notification)
2996{
0a7de745
A
2997 io_async_ref64_t zreference;
2998
2999 if (referenceCnt > ASYNC_REF64_COUNT) {
3000 return kIOReturnBadArgument;
3001 }
3002 bcopy(&reference[0], &zreference[0], referenceCnt * sizeof(zreference[0]));
3003 bzero(&zreference[referenceCnt], (ASYNC_REF64_COUNT - referenceCnt) * sizeof(zreference[0]));
3004
3005 return internal_io_service_add_notification(master_port, notification_type,
3006 matching, matchingCnt, wake_port, &zreference[0], sizeof(io_async_ref64_t),
3007 true, notification);
fe8ab488 3008}
2d21ac55 3009
0a7de745
A
3010static kern_return_t
3011internal_io_service_add_notification_ool(
55e303ae
A
3012 mach_port_t master_port,
3013 io_name_t notification_type,
3014 io_buf_ptr_t matching,
3015 mach_msg_type_number_t matchingCnt,
3016 mach_port_t wake_port,
2d21ac55
A
3017 void * reference,
3018 vm_size_t referenceSize,
3019 bool client64,
3020 kern_return_t *result,
55e303ae
A
3021 io_object_t *notification )
3022{
0a7de745
A
3023 kern_return_t kr;
3024 vm_offset_t data;
3025 vm_map_offset_t map_data;
55e303ae 3026
0a7de745
A
3027 kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) matching );
3028 data = CAST_DOWN(vm_offset_t, map_data);
55e303ae 3029
0a7de745
A
3030 if (KERN_SUCCESS == kr) {
3031 // must return success after vm_map_copyout() succeeds
3032 // and mig will copy out objects on success
cb323159 3033 *notification = NULL;
0a7de745
A
3034 *result = internal_io_service_add_notification( master_port, notification_type,
3035 (char *) data, matchingCnt, wake_port, reference, referenceSize, client64, notification );
3036 vm_deallocate( kernel_map, data, matchingCnt );
3037 }
55e303ae 3038
0a7de745 3039 return kr;
55e303ae
A
3040}
3041
2d21ac55 3042/* Routine io_service_add_notification_ool */
0a7de745
A
3043kern_return_t
3044is_io_service_add_notification_ool(
2d21ac55
A
3045 mach_port_t master_port,
3046 io_name_t notification_type,
3047 io_buf_ptr_t matching,
3048 mach_msg_type_number_t matchingCnt,
3049 mach_port_t wake_port,
3050 io_async_ref_t reference,
3051 mach_msg_type_number_t referenceCnt,
3052 kern_return_t *result,
3053 io_object_t *notification )
3054{
0a7de745
A
3055 io_async_ref_t zreference;
3056
3057 if (referenceCnt > ASYNC_REF_COUNT) {
3058 return kIOReturnBadArgument;
3059 }
3060 bcopy(&reference[0], &zreference[0], referenceCnt * sizeof(zreference[0]));
3061 bzero(&zreference[referenceCnt], (ASYNC_REF_COUNT - referenceCnt) * sizeof(zreference[0]));
3062
3063 return internal_io_service_add_notification_ool(master_port, notification_type,
3064 matching, matchingCnt, wake_port, &zreference[0], sizeof(io_async_ref_t),
3065 false, result, notification);
2d21ac55
A
3066}
3067
3068/* Routine io_service_add_notification_ool_64 */
0a7de745
A
3069kern_return_t
3070is_io_service_add_notification_ool_64(
2d21ac55
A
3071 mach_port_t master_port,
3072 io_name_t notification_type,
3073 io_buf_ptr_t matching,
3074 mach_msg_type_number_t matchingCnt,
3075 mach_port_t wake_port,
3076 io_async_ref64_t reference,
3077 mach_msg_type_number_t referenceCnt,
3078 kern_return_t *result,
3079 io_object_t *notification )
3080{
0a7de745
A
3081 io_async_ref64_t zreference;
3082
3083 if (referenceCnt > ASYNC_REF64_COUNT) {
3084 return kIOReturnBadArgument;
3085 }
3086 bcopy(&reference[0], &zreference[0], referenceCnt * sizeof(zreference[0]));
3087 bzero(&zreference[referenceCnt], (ASYNC_REF64_COUNT - referenceCnt) * sizeof(zreference[0]));
3088
3089 return internal_io_service_add_notification_ool(master_port, notification_type,
3090 matching, matchingCnt, wake_port, &zreference[0], sizeof(io_async_ref64_t),
3091 true, result, notification);
2d21ac55 3092}
55e303ae 3093
1c79356b 3094/* Routine io_service_add_notification_old */
0a7de745
A
3095kern_return_t
3096is_io_service_add_notification_old(
1c79356b
A
3097 mach_port_t master_port,
3098 io_name_t notification_type,
3099 io_string_t matching,
3100 mach_port_t port,
b0d623f7 3101 // for binary compatibility reasons, this must be natural_t for ILP32
1c79356b
A
3102 natural_t ref,
3103 io_object_t * notification )
3104{
0a7de745
A
3105 return is_io_service_add_notification( master_port, notification_type,
3106 matching, port, &ref, 1, notification );
1c79356b
A
3107}
3108
2d21ac55 3109
0a7de745
A
3110static kern_return_t
3111internal_io_service_add_interest_notification(
3112 io_object_t _service,
3113 io_name_t type_of_interest,
3114 mach_port_t port,
2d21ac55
A
3115 void * reference,
3116 vm_size_t referenceSize,
3117 bool client64,
0a7de745 3118 io_object_t * notification )
1c79356b 3119{
cb323159
A
3120 IOServiceMessageUserNotification * userNotify = NULL;
3121 IONotifier * notify = NULL;
0a7de745
A
3122 const OSSymbol * sym;
3123 IOReturn err;
3124
3125 CHECK( IOService, _service, service );
3126
3127 err = kIOReturnNoResources;
3128 if ((sym = OSSymbol::withCString( type_of_interest ))) {
3129 do {
3130 userNotify = new IOServiceMessageUserNotification;
3131
3132 if (userNotify && !userNotify->init( port, kIOServiceMessageNotificationType,
3133 reference, referenceSize,
3134 kIOUserNotifyMaxMessageSize,
3135 client64 )) {
3136 userNotify->release();
cb323159 3137 userNotify = NULL;
0a7de745
A
3138 }
3139 if (!userNotify) {
3140 continue;
3141 }
3142
3143 notify = service->registerInterest( sym,
3144 &userNotify->_handler, userNotify );
3145 if (notify) {
3146 *notification = userNotify;
3147 userNotify->setNotification( notify );
3148 err = kIOReturnSuccess;
3149 } else {
3150 err = kIOReturnUnsupported;
3151 }
3152
3153 sym->release();
3154 } while (false);
3155 }
1c79356b 3156
0a7de745
A
3157 if ((kIOReturnSuccess != err) && userNotify) {
3158 userNotify->invalidatePort();
3159 userNotify->release();
cb323159 3160 userNotify = NULL;
0a7de745 3161 }
5ba3f43e 3162
0a7de745 3163 return err;
1c79356b
A
3164}
3165
2d21ac55 3166/* Routine io_service_add_message_notification */
0a7de745
A
3167kern_return_t
3168is_io_service_add_interest_notification(
3169 io_object_t service,
3170 io_name_t type_of_interest,
3171 mach_port_t port,
2d21ac55
A
3172 io_async_ref_t reference,
3173 mach_msg_type_number_t referenceCnt,
0a7de745 3174 io_object_t * notification )
2d21ac55 3175{
0a7de745
A
3176 io_async_ref_t zreference;
3177
3178 if (referenceCnt > ASYNC_REF_COUNT) {
3179 return kIOReturnBadArgument;
3180 }
3181 bcopy(&reference[0], &zreference[0], referenceCnt * sizeof(zreference[0]));
3182 bzero(&zreference[referenceCnt], (ASYNC_REF_COUNT - referenceCnt) * sizeof(zreference[0]));
3183
3184 return internal_io_service_add_interest_notification(service, type_of_interest,
3185 port, &zreference[0], sizeof(io_async_ref_t), false, notification);
2d21ac55
A
3186}
3187
3188/* Routine io_service_add_interest_notification_64 */
0a7de745
A
3189kern_return_t
3190is_io_service_add_interest_notification_64(
2d21ac55
A
3191 io_object_t service,
3192 io_name_t type_of_interest,
3193 mach_port_t wake_port,
3194 io_async_ref64_t reference,
3195 mach_msg_type_number_t referenceCnt,
3196 io_object_t *notification )
3197{
0a7de745
A
3198 io_async_ref64_t zreference;
3199
3200 if (referenceCnt > ASYNC_REF64_COUNT) {
3201 return kIOReturnBadArgument;
3202 }
3203 bcopy(&reference[0], &zreference[0], referenceCnt * sizeof(zreference[0]));
3204 bzero(&zreference[referenceCnt], (ASYNC_REF64_COUNT - referenceCnt) * sizeof(zreference[0]));
3205
3206 return internal_io_service_add_interest_notification(service, type_of_interest,
3207 wake_port, &zreference[0], sizeof(io_async_ref64_t), true, notification);
2d21ac55
A
3208}
3209
3210
1c79356b 3211/* Routine io_service_acknowledge_notification */
0a7de745
A
3212kern_return_t
3213is_io_service_acknowledge_notification(
1c79356b
A
3214 io_object_t _service,
3215 natural_t notify_ref,
3216 natural_t response )
3217{
0a7de745 3218 CHECK( IOService, _service, service );
1c79356b 3219
0a7de745
A
3220 return service->acknowledgeNotification((IONotificationRef)(uintptr_t) notify_ref,
3221 (IOOptionBits) response );
1c79356b
A
3222}
3223
3224/* Routine io_connect_get_semaphore */
0a7de745
A
3225kern_return_t
3226is_io_connect_get_notification_semaphore(
1c79356b
A
3227 io_connect_t connection,
3228 natural_t notification_type,
3229 semaphore_t *semaphore )
3230{
f427ee49 3231 IOReturn ret;
0a7de745 3232 CHECK( IOUserClient, connection, client );
1c79356b 3233
0a7de745 3234 IOStatisticsClientCall();
f427ee49
A
3235 IORWLockWrite(client->lock);
3236 ret = client->getNotificationSemaphore((UInt32) notification_type,
3237 semaphore );
3238 IORWLockUnlock(client->lock);
3239
3240 return ret;
1c79356b
A
3241}
3242
3243/* Routine io_registry_get_root_entry */
0a7de745
A
3244kern_return_t
3245is_io_registry_get_root_entry(
1c79356b
A
3246 mach_port_t master_port,
3247 io_object_t *root )
3248{
0a7de745 3249 IORegistryEntry * entry;
1c79356b 3250
0a7de745
A
3251 if (master_port != master_device_port) {
3252 return kIOReturnNotPrivileged;
3253 }
1c79356b 3254
0a7de745
A
3255 entry = IORegistryEntry::getRegistryRoot();
3256 if (entry) {
3257 entry->retain();
3258 }
3259 *root = entry;
1c79356b 3260
0a7de745 3261 return kIOReturnSuccess;
1c79356b
A
3262}
3263
3264/* Routine io_registry_create_iterator */
0a7de745
A
3265kern_return_t
3266is_io_registry_create_iterator(
1c79356b
A
3267 mach_port_t master_port,
3268 io_name_t plane,
2d21ac55 3269 uint32_t options,
1c79356b
A
3270 io_object_t *iterator )
3271{
0a7de745
A
3272 if (master_port != master_device_port) {
3273 return kIOReturnNotPrivileged;
3274 }
1c79356b 3275
0a7de745
A
3276 *iterator = IOUserIterator::withIterator(
3277 IORegistryIterator::iterateOver(
3278 IORegistryEntry::getPlane( plane ), options ));
1c79356b 3279
0a7de745 3280 return *iterator ? kIOReturnSuccess : kIOReturnBadArgument;
1c79356b
A
3281}
3282
3283/* Routine io_registry_entry_create_iterator */
0a7de745
A
3284kern_return_t
3285is_io_registry_entry_create_iterator(
1c79356b
A
3286 io_object_t registry_entry,
3287 io_name_t plane,
2d21ac55 3288 uint32_t options,
1c79356b
A
3289 io_object_t *iterator )
3290{
0a7de745 3291 CHECK( IORegistryEntry, registry_entry, entry );
1c79356b 3292
0a7de745
A
3293 *iterator = IOUserIterator::withIterator(
3294 IORegistryIterator::iterateOver( entry,
4bd07ac2 3295 IORegistryEntry::getPlane( plane ), options ));
1c79356b 3296
0a7de745 3297 return *iterator ? kIOReturnSuccess : kIOReturnBadArgument;
1c79356b
A
3298}
3299
3300/* Routine io_registry_iterator_enter */
0a7de745
A
3301kern_return_t
3302is_io_registry_iterator_enter_entry(
1c79356b
A
3303 io_object_t iterator )
3304{
0a7de745 3305 CHECKLOCKED( IORegistryIterator, iterator, iter );
1c79356b 3306
0a7de745
A
3307 IOLockLock(oIter->lock);
3308 iter->enterEntry();
3309 IOLockUnlock(oIter->lock);
1c79356b 3310
0a7de745 3311 return kIOReturnSuccess;
1c79356b
A
3312}
3313
3314/* Routine io_registry_iterator_exit */
0a7de745
A
3315kern_return_t
3316is_io_registry_iterator_exit_entry(
1c79356b
A
3317 io_object_t iterator )
3318{
0a7de745 3319 bool didIt;
1c79356b 3320
0a7de745 3321 CHECKLOCKED( IORegistryIterator, iterator, iter );
1c79356b 3322
0a7de745
A
3323 IOLockLock(oIter->lock);
3324 didIt = iter->exitEntry();
3325 IOLockUnlock(oIter->lock);
1c79356b 3326
0a7de745 3327 return didIt ? kIOReturnSuccess : kIOReturnNoDevice;
1c79356b
A
3328}
3329
3330/* Routine io_registry_entry_from_path */
0a7de745
A
3331kern_return_t
3332is_io_registry_entry_from_path(
1c79356b
A
3333 mach_port_t master_port,
3334 io_string_t path,
3335 io_object_t *registry_entry )
3336{
0a7de745 3337 IORegistryEntry * entry;
1c79356b 3338
0a7de745
A
3339 if (master_port != master_device_port) {
3340 return kIOReturnNotPrivileged;
3341 }
1c79356b 3342
0a7de745 3343 entry = IORegistryEntry::fromPath( path );
1c79356b 3344
f427ee49
A
3345 if (!entry && IOTaskRegistryCompatibility(current_task())) {
3346 OSDictionary * matching;
3347 const OSObject * objects[2] = { kOSBooleanTrue, NULL };
3348 const OSSymbol * keys[2] = { gIOCompatibilityMatchKey, gIOPathMatchKey };
3349
3350 objects[1] = OSString::withCStringNoCopy(path);
3351 matching = OSDictionary::withObjects(objects, keys, 2, 2);
3352 if (matching) {
3353 entry = IOService::copyMatchingService(matching);
3354 }
3355 OSSafeReleaseNULL(matching);
3356 OSSafeReleaseNULL(objects[1]);
3357 }
3358
0a7de745 3359 *registry_entry = entry;
1c79356b 3360
0a7de745 3361 return kIOReturnSuccess;
1c79356b
A
3362}
3363
3e170ce0
A
3364
3365/* Routine io_registry_entry_from_path */
0a7de745
A
3366kern_return_t
3367is_io_registry_entry_from_path_ool(
3e170ce0
A
3368 mach_port_t master_port,
3369 io_string_inband_t path,
3370 io_buf_ptr_t path_ool,
3371 mach_msg_type_number_t path_oolCnt,
3372 kern_return_t *result,
3373 io_object_t *registry_entry)
3374{
0a7de745
A
3375 IORegistryEntry * entry;
3376 vm_map_offset_t map_data;
3377 const char * cpath;
3378 IOReturn res;
3379 kern_return_t err;
3e170ce0 3380
0a7de745
A
3381 if (master_port != master_device_port) {
3382 return kIOReturnNotPrivileged;
3383 }
3e170ce0 3384
0a7de745 3385 map_data = 0;
cb323159 3386 entry = NULL;
0a7de745
A
3387 res = err = KERN_SUCCESS;
3388 if (path[0]) {
3389 cpath = path;
3390 } else {
3391 if (!path_oolCnt) {
3392 return kIOReturnBadArgument;
3393 }
3394 if (path_oolCnt > (sizeof(io_struct_inband_t) * 1024)) {
3395 return kIOReturnMessageTooLarge;
3396 }
3e170ce0 3397
0a7de745
A
3398 err = vm_map_copyout(kernel_map, &map_data, (vm_map_copy_t) path_ool);
3399 if (KERN_SUCCESS == err) {
3400 // must return success to mig after vm_map_copyout() succeeds, so result is actual
3401 cpath = CAST_DOWN(const char *, map_data);
3402 if (cpath[path_oolCnt - 1]) {
3403 res = kIOReturnBadArgument;
3404 }
3405 }
3e170ce0 3406 }
3e170ce0 3407
0a7de745
A
3408 if ((KERN_SUCCESS == err) && (KERN_SUCCESS == res)) {
3409 entry = IORegistryEntry::fromPath(cpath);
3410 res = entry ? kIOReturnSuccess : kIOReturnNotFound;
3411 }
3e170ce0 3412
0a7de745
A
3413 if (map_data) {
3414 vm_deallocate(kernel_map, map_data, path_oolCnt);
3415 }
3e170ce0 3416
0a7de745
A
3417 if (KERN_SUCCESS != err) {
3418 res = err;
3419 }
3420 *registry_entry = entry;
3421 *result = res;
3e170ce0 3422
0a7de745 3423 return err;
3e170ce0
A
3424}
3425
3426
1c79356b 3427/* Routine io_registry_entry_in_plane */
0a7de745
A
3428kern_return_t
3429is_io_registry_entry_in_plane(
1c79356b
A
3430 io_object_t registry_entry,
3431 io_name_t plane,
3432 boolean_t *inPlane )
3433{
0a7de745 3434 CHECK( IORegistryEntry, registry_entry, entry );
1c79356b 3435
0a7de745 3436 *inPlane = entry->inPlane( IORegistryEntry::getPlane( plane ));
1c79356b 3437
0a7de745 3438 return kIOReturnSuccess;
1c79356b
A
3439}
3440
3441
3442/* Routine io_registry_entry_get_path */
0a7de745
A
3443kern_return_t
3444is_io_registry_entry_get_path(
1c79356b
A
3445 io_object_t registry_entry,
3446 io_name_t plane,
3447 io_string_t path )
3448{
0a7de745
A
3449 int length;
3450 CHECK( IORegistryEntry, registry_entry, entry );
1c79356b 3451
0a7de745
A
3452 length = sizeof(io_string_t);
3453 if (entry->getPath( path, &length, IORegistryEntry::getPlane( plane ))) {
3454 return kIOReturnSuccess;
3455 } else {
3456 return kIOReturnBadArgument;
3457 }
1c79356b
A
3458}
3459
3e170ce0 3460/* Routine io_registry_entry_get_path */
0a7de745
A
3461kern_return_t
3462is_io_registry_entry_get_path_ool(
3e170ce0
A
3463 io_object_t registry_entry,
3464 io_name_t plane,
3465 io_string_inband_t path,
3466 io_buf_ptr_t *path_ool,
3467 mach_msg_type_number_t *path_oolCnt)
3468{
0a7de745
A
3469 enum { kMaxPath = 16384 };
3470 IOReturn err;
3471 int length;
3472 char * buf;
3e170ce0 3473
0a7de745 3474 CHECK( IORegistryEntry, registry_entry, entry );
3e170ce0 3475
0a7de745
A
3476 *path_ool = NULL;
3477 *path_oolCnt = 0;
3478 length = sizeof(io_string_inband_t);
3479 if (entry->getPath(path, &length, IORegistryEntry::getPlane(plane))) {
3480 err = kIOReturnSuccess;
3481 } else {
3482 length = kMaxPath;
3483 buf = IONew(char, length);
3484 if (!buf) {
3485 err = kIOReturnNoMemory;
3486 } else if (!entry->getPath(buf, &length, IORegistryEntry::getPlane(plane))) {
3487 err = kIOReturnError;
3488 } else {
3489 *path_oolCnt = length;
3490 err = copyoutkdata(buf, length, path_ool);
3491 }
3492 if (buf) {
3493 IODelete(buf, char, kMaxPath);
3494 }
3e170ce0 3495 }
3e170ce0 3496
0a7de745 3497 return err;
3e170ce0
A
3498}
3499
1c79356b
A
3500
3501/* Routine io_registry_entry_get_name */
0a7de745
A
3502kern_return_t
3503is_io_registry_entry_get_name(
1c79356b
A
3504 io_object_t registry_entry,
3505 io_name_t name )
3506{
0a7de745 3507 CHECK( IORegistryEntry, registry_entry, entry );
1c79356b 3508
0a7de745 3509 strncpy( name, entry->getName(), sizeof(io_name_t));
1c79356b 3510
0a7de745 3511 return kIOReturnSuccess;
1c79356b
A
3512}
3513
3514/* Routine io_registry_entry_get_name_in_plane */
0a7de745
A
3515kern_return_t
3516is_io_registry_entry_get_name_in_plane(
1c79356b 3517 io_object_t registry_entry,
0b4e3aa0 3518 io_name_t planeName,
1c79356b
A
3519 io_name_t name )
3520{
0a7de745
A
3521 const IORegistryPlane * plane;
3522 CHECK( IORegistryEntry, registry_entry, entry );
1c79356b 3523
0a7de745
A
3524 if (planeName[0]) {
3525 plane = IORegistryEntry::getPlane( planeName );
3526 } else {
cb323159 3527 plane = NULL;
0a7de745 3528 }
0b4e3aa0 3529
0a7de745 3530 strncpy( name, entry->getName( plane), sizeof(io_name_t));
1c79356b 3531
0a7de745 3532 return kIOReturnSuccess;
1c79356b
A
3533}
3534
0b4e3aa0 3535/* Routine io_registry_entry_get_location_in_plane */
0a7de745
A
3536kern_return_t
3537is_io_registry_entry_get_location_in_plane(
0b4e3aa0
A
3538 io_object_t registry_entry,
3539 io_name_t planeName,
3540 io_name_t location )
3541{
0a7de745
A
3542 const IORegistryPlane * plane;
3543 CHECK( IORegistryEntry, registry_entry, entry );
0b4e3aa0 3544
0a7de745
A
3545 if (planeName[0]) {
3546 plane = IORegistryEntry::getPlane( planeName );
3547 } else {
cb323159 3548 plane = NULL;
0a7de745 3549 }
0b4e3aa0 3550
0a7de745 3551 const char * cstr = entry->getLocation( plane );
0b4e3aa0 3552
0a7de745
A
3553 if (cstr) {
3554 strncpy( location, cstr, sizeof(io_name_t));
3555 return kIOReturnSuccess;
3556 } else {
3557 return kIOReturnNotFound;
3558 }
0b4e3aa0
A
3559}
3560
b0d623f7 3561/* Routine io_registry_entry_get_registry_entry_id */
0a7de745
A
3562kern_return_t
3563is_io_registry_entry_get_registry_entry_id(
b0d623f7
A
3564 io_object_t registry_entry,
3565 uint64_t *entry_id )
3566{
0a7de745 3567 CHECK( IORegistryEntry, registry_entry, entry );
b0d623f7 3568
0a7de745 3569 *entry_id = entry->getRegistryEntryID();
b0d623f7 3570
0a7de745 3571 return kIOReturnSuccess;
b0d623f7
A
3572}
3573
f427ee49
A
3574
3575static OSObject *
3576IOCopyPropertyCompatible(IORegistryEntry * regEntry, const char * name)
3577{
3578 OSObject * obj;
3579 OSObject * compatProps;
3580 OSDictionary * props;
3581
3582 obj = regEntry->copyProperty(name);
3583 if (!obj
3584 && IOTaskRegistryCompatibility(current_task())
3585 && (compatProps = regEntry->copyProperty(gIOCompatibilityPropertiesKey))) {
3586 props = OSDynamicCast(OSDictionary, compatProps);
3587 if (props) {
3588 obj = props->getObject(name);
3589 if (obj) {
3590 obj->retain();
3591 }
3592 }
3593 compatProps->release();
3594 }
3595
3596 return obj;
3597}
3598
0b4e3aa0 3599/* Routine io_registry_entry_get_property */
0a7de745
A
3600kern_return_t
3601is_io_registry_entry_get_property_bytes(
0b4e3aa0
A
3602 io_object_t registry_entry,
3603 io_name_t property_name,
2d21ac55 3604 io_struct_inband_t buf,
0b4e3aa0
A
3605 mach_msg_type_number_t *dataCnt )
3606{
0a7de745
A
3607 OSObject * obj;
3608 OSData * data;
3609 OSString * str;
3610 OSBoolean * boo;
3611 OSNumber * off;
3612 UInt64 offsetBytes;
3613 unsigned int len = 0;
cb323159 3614 const void * bytes = NULL;
0a7de745 3615 IOReturn ret = kIOReturnSuccess;
0b4e3aa0 3616
0a7de745 3617 CHECK( IORegistryEntry, registry_entry, entry );
0b4e3aa0 3618
fe8ab488 3619#if CONFIG_MACF
0a7de745
A
3620 if (0 != mac_iokit_check_get_property(kauth_cred_get(), entry, property_name)) {
3621 return kIOReturnNotPermitted;
3622 }
fe8ab488
A
3623#endif
3624
f427ee49 3625 obj = IOCopyPropertyCompatible(entry, property_name);
0a7de745
A
3626 if (!obj) {
3627 return kIOReturnNoResources;
3628 }
3629
3630 // One day OSData will be a common container base class
3631 // until then...
3632 if ((data = OSDynamicCast( OSData, obj ))) {
3633 len = data->getLength();
3634 bytes = data->getBytesNoCopy();
3635 if (!data->isSerializable()) {
3636 len = 0;
3637 }
3638 } else if ((str = OSDynamicCast( OSString, obj ))) {
3639 len = str->getLength() + 1;
3640 bytes = str->getCStringNoCopy();
3641 } else if ((boo = OSDynamicCast( OSBoolean, obj ))) {
3642 len = boo->isTrue() ? sizeof("Yes") : sizeof("No");
3643 bytes = boo->isTrue() ? "Yes" : "No";
3644 } else if ((off = OSDynamicCast( OSNumber, obj ))) {
3645 offsetBytes = off->unsigned64BitValue();
3646 len = off->numberOfBytes();
3647 if (len > sizeof(offsetBytes)) {
3648 len = sizeof(offsetBytes);
3649 }
3650 bytes = &offsetBytes;
55e303ae 3651#ifdef __BIG_ENDIAN__
0a7de745
A
3652 bytes = (const void *)
3653 (((UInt32) bytes) + (sizeof(UInt64) - len));
0b4e3aa0 3654#endif
0a7de745
A
3655 } else {
3656 ret = kIOReturnBadArgument;
3657 }
0b4e3aa0 3658
0a7de745
A
3659 if (bytes) {
3660 if (*dataCnt < len) {
3661 ret = kIOReturnIPCError;
3662 } else {
3663 *dataCnt = len;
3664 bcopy( bytes, buf, len );
3665 }
0b4e3aa0 3666 }
0a7de745 3667 obj->release();
0b4e3aa0 3668
0a7de745 3669 return ret;
0b4e3aa0
A
3670}
3671
0c530ab8 3672
0b4e3aa0 3673/* Routine io_registry_entry_get_property */
0a7de745
A
3674kern_return_t
3675is_io_registry_entry_get_property(
0b4e3aa0
A
3676 io_object_t registry_entry,
3677 io_name_t property_name,
3678 io_buf_ptr_t *properties,
3679 mach_msg_type_number_t *propertiesCnt )
3680{
0a7de745 3681 kern_return_t err;
f427ee49 3682 unsigned int len;
0a7de745 3683 OSObject * obj;
0b4e3aa0 3684
0a7de745 3685 CHECK( IORegistryEntry, registry_entry, entry );
0b4e3aa0 3686
fe8ab488 3687#if CONFIG_MACF
0a7de745
A
3688 if (0 != mac_iokit_check_get_property(kauth_cred_get(), entry, property_name)) {
3689 return kIOReturnNotPermitted;
3690 }
fe8ab488
A
3691#endif
3692
f427ee49 3693 obj = IOCopyPropertyCompatible(entry, property_name);
0a7de745
A
3694 if (!obj) {
3695 return kIOReturnNotFound;
3696 }
0b4e3aa0 3697
0a7de745
A
3698 OSSerialize * s = OSSerialize::withCapacity(4096);
3699 if (!s) {
3700 obj->release();
3701 return kIOReturnNoMemory;
3702 }
0b4e3aa0 3703
0a7de745
A
3704 if (obj->serialize( s )) {
3705 len = s->getLength();
3706 *propertiesCnt = len;
3707 err = copyoutkdata( s->text(), len, properties );
3708 } else {
3709 err = kIOReturnUnsupported;
3710 }
0b4e3aa0 3711
0a7de745
A
3712 s->release();
3713 obj->release();
1c79356b 3714
0a7de745 3715 return err;
1c79356b
A
3716}
3717
0b4e3aa0 3718/* Routine io_registry_entry_get_property_recursively */
0a7de745
A
3719kern_return_t
3720is_io_registry_entry_get_property_recursively(
0b4e3aa0
A
3721 io_object_t registry_entry,
3722 io_name_t plane,
3723 io_name_t property_name,
0a7de745 3724 uint32_t options,
0b4e3aa0
A
3725 io_buf_ptr_t *properties,
3726 mach_msg_type_number_t *propertiesCnt )
3727{
0a7de745 3728 kern_return_t err;
f427ee49 3729 unsigned int len;
0a7de745 3730 OSObject * obj;
0b4e3aa0 3731
0a7de745 3732 CHECK( IORegistryEntry, registry_entry, entry );
0b4e3aa0 3733
fe8ab488 3734#if CONFIG_MACF
0a7de745
A
3735 if (0 != mac_iokit_check_get_property(kauth_cred_get(), entry, property_name)) {
3736 return kIOReturnNotPermitted;
3737 }
fe8ab488
A
3738#endif
3739
0a7de745
A
3740 obj = entry->copyProperty( property_name,
3741 IORegistryEntry::getPlane( plane ), options );
3742 if (!obj) {
3743 return kIOReturnNotFound;
3744 }
0b4e3aa0 3745
0a7de745
A
3746 OSSerialize * s = OSSerialize::withCapacity(4096);
3747 if (!s) {
3748 obj->release();
3749 return kIOReturnNoMemory;
3750 }
0b4e3aa0 3751
0a7de745
A
3752 if (obj->serialize( s )) {
3753 len = s->getLength();
3754 *propertiesCnt = len;
3755 err = copyoutkdata( s->text(), len, properties );
3756 } else {
3757 err = kIOReturnUnsupported;
3758 }
0b4e3aa0 3759
0a7de745
A
3760 s->release();
3761 obj->release();
0b4e3aa0 3762
0a7de745 3763 return err;
0b4e3aa0 3764}
1c79356b
A
3765
3766/* Routine io_registry_entry_get_properties */
0a7de745
A
3767kern_return_t
3768is_io_registry_entry_get_properties(
1c79356b
A
3769 io_object_t registry_entry,
3770 io_buf_ptr_t *properties,
3771 mach_msg_type_number_t *propertiesCnt )
3772{
0a7de745 3773 return kIOReturnUnsupported;
fe8ab488
A
3774}
3775
3776#if CONFIG_MACF
3777
0a7de745
A
3778struct GetPropertiesEditorRef {
3779 kauth_cred_t cred;
3780 IORegistryEntry * entry;
3781 OSCollection * root;
fe8ab488
A
3782};
3783
3784static const OSMetaClassBase *
3785GetPropertiesEditor(void * reference,
0a7de745
A
3786 OSSerialize * s,
3787 OSCollection * container,
3788 const OSSymbol * name,
3789 const OSMetaClassBase * value)
fe8ab488 3790{
0a7de745 3791 GetPropertiesEditorRef * ref = (typeof(ref))reference;
fe8ab488 3792
0a7de745
A
3793 if (!ref->root) {
3794 ref->root = container;
3795 }
3796 if (ref->root == container) {
3797 if (0 != mac_iokit_check_get_property(ref->cred, ref->entry, name->getCStringNoCopy())) {
cb323159 3798 value = NULL;
0a7de745
A
3799 }
3800 }
3801 if (value) {
3802 value->retain();
3803 }
3804 return value;
fe8ab488
A
3805}
3806
3807#endif /* CONFIG_MACF */
3808
4ba76501 3809/* Routine io_registry_entry_get_properties_bin_buf */
0a7de745 3810kern_return_t
4ba76501 3811is_io_registry_entry_get_properties_bin_buf(
fe8ab488 3812 io_object_t registry_entry,
4ba76501
A
3813 mach_vm_address_t buf,
3814 mach_vm_size_t *bufsize,
fe8ab488
A
3815 io_buf_ptr_t *properties,
3816 mach_msg_type_number_t *propertiesCnt)
3817{
f427ee49
A
3818 kern_return_t err = kIOReturnSuccess;
3819 unsigned int len;
3820 OSObject * compatProperties;
0a7de745 3821 OSSerialize * s;
cb323159
A
3822 OSSerialize::Editor editor = NULL;
3823 void * editRef = NULL;
fe8ab488 3824
0a7de745 3825 CHECK(IORegistryEntry, registry_entry, entry);
fe8ab488
A
3826
3827#if CONFIG_MACF
0a7de745
A
3828 GetPropertiesEditorRef ref;
3829 if (mac_iokit_check_filter_properties(kauth_cred_get(), entry)) {
3830 editor = &GetPropertiesEditor;
3831 editRef = &ref;
3832 ref.cred = kauth_cred_get();
3833 ref.entry = entry;
cb323159 3834 ref.root = NULL;
0a7de745 3835 }
fe8ab488
A
3836#endif
3837
0a7de745
A
3838 s = OSSerialize::binaryWithCapacity(4096, editor, editRef);
3839 if (!s) {
3840 return kIOReturnNoMemory;
3841 }
fe8ab488 3842
f427ee49
A
3843 if (IOTaskRegistryCompatibility(current_task())
3844 && (compatProperties = entry->copyProperty(gIOCompatibilityPropertiesKey))) {
3845 OSDictionary * dict;
3846
3847 dict = entry->dictionaryWithProperties();
3848 if (!dict) {
3849 err = kIOReturnNoMemory;
3850 } else {
3851 dict->removeObject(gIOCompatibilityPropertiesKey);
3852 dict->merge(OSDynamicCast(OSDictionary, compatProperties));
3853 if (!dict->serialize(s)) {
3854 err = kIOReturnUnsupported;
3855 }
3856 dict->release();
3857 }
3858 compatProperties->release();
3859 } else if (!entry->serializeProperties(s)) {
0a7de745
A
3860 err = kIOReturnUnsupported;
3861 }
fe8ab488 3862
0a7de745
A
3863 if (kIOReturnSuccess == err) {
3864 len = s->getLength();
4ba76501
A
3865 if (buf && bufsize && len <= *bufsize) {
3866 *bufsize = len;
3867 *propertiesCnt = 0;
3868 *properties = nullptr;
3869 if (copyout(s->text(), buf, len)) {
3870 err = kIOReturnVMError;
3871 } else {
3872 err = kIOReturnSuccess;
3873 }
3874 } else {
3875 if (bufsize) {
3876 *bufsize = 0;
3877 }
3878 *propertiesCnt = len;
3879 err = copyoutkdata( s->text(), len, properties );
3880 }
0a7de745
A
3881 }
3882 s->release();
fe8ab488 3883
0a7de745 3884 return err;
fe8ab488
A
3885}
3886
4ba76501 3887/* Routine io_registry_entry_get_properties_bin */
0a7de745 3888kern_return_t
4ba76501
A
3889is_io_registry_entry_get_properties_bin(
3890 io_object_t registry_entry,
3891 io_buf_ptr_t *properties,
3892 mach_msg_type_number_t *propertiesCnt)
3893{
3894 return is_io_registry_entry_get_properties_bin_buf(registry_entry,
3895 0, NULL, properties, propertiesCnt);
3896}
3897
3898/* Routine io_registry_entry_get_property_bin_buf */
3899kern_return_t
3900is_io_registry_entry_get_property_bin_buf(
fe8ab488
A
3901 io_object_t registry_entry,
3902 io_name_t plane,
3903 io_name_t property_name,
3904 uint32_t options,
4ba76501
A
3905 mach_vm_address_t buf,
3906 mach_vm_size_t *bufsize,
fe8ab488
A
3907 io_buf_ptr_t *properties,
3908 mach_msg_type_number_t *propertiesCnt )
3909{
0a7de745 3910 kern_return_t err;
f427ee49 3911 unsigned int len;
0a7de745
A
3912 OSObject * obj;
3913 const OSSymbol * sym;
fe8ab488 3914
0a7de745 3915 CHECK( IORegistryEntry, registry_entry, entry );
fe8ab488
A
3916
3917#if CONFIG_MACF
0a7de745
A
3918 if (0 != mac_iokit_check_get_property(kauth_cred_get(), entry, property_name)) {
3919 return kIOReturnNotPermitted;
3920 }
fe8ab488
A
3921#endif
3922
0a7de745
A
3923 sym = OSSymbol::withCString(property_name);
3924 if (!sym) {
3925 return kIOReturnNoMemory;
3926 }
fe8ab488 3927
0a7de745
A
3928 if (gIORegistryEntryPropertyKeysKey == sym) {
3929 obj = entry->copyPropertyKeys();
3930 } else {
3931 if ((kIORegistryIterateRecursively & options) && plane[0]) {
f427ee49
A
3932 if (!IOTaskRegistryCompatibility(current_task())) {
3933 obj = entry->copyProperty(property_name,
3934 IORegistryEntry::getPlane(plane), options);
3935 } else {
3936 obj = IOCopyPropertyCompatible(entry, property_name);
3937 if ((NULL == obj) && plane && (options & kIORegistryIterateRecursively)) {
3938 IORegistryIterator * iter;
3939 iter = IORegistryIterator::iterateOver(entry, IORegistryEntry::getPlane(plane), options);
3940 if (iter) {
3941 while ((NULL == obj) && (entry = iter->getNextObject())) {
3942 obj = IOCopyPropertyCompatible(entry, property_name);
3943 }
3944 iter->release();
3945 }
3946 }
3947 }
0a7de745 3948 } else {
f427ee49 3949 obj = IOCopyPropertyCompatible(entry, property_name);
0a7de745
A
3950 }
3951 if (obj && gIORemoveOnReadProperties->containsObject(sym)) {
3952 entry->removeProperty(sym);
3953 }
3954 }
fe8ab488 3955
0a7de745
A
3956 sym->release();
3957 if (!obj) {
3958 return kIOReturnNotFound;
3959 }
1c79356b 3960
0a7de745
A
3961 OSSerialize * s = OSSerialize::binaryWithCapacity(4096);
3962 if (!s) {
3963 obj->release();
3964 return kIOReturnNoMemory;
3965 }
1c79356b 3966
0a7de745
A
3967 if (obj->serialize( s )) {
3968 len = s->getLength();
4ba76501
A
3969 if (buf && bufsize && len <= *bufsize) {
3970 *bufsize = len;
3971 *propertiesCnt = 0;
3972 *properties = nullptr;
3973 if (copyout(s->text(), buf, len)) {
3974 err = kIOReturnVMError;
3975 } else {
3976 err = kIOReturnSuccess;
3977 }
3978 } else {
3979 if (bufsize) {
3980 *bufsize = 0;
3981 }
3982 *propertiesCnt = len;
3983 err = copyoutkdata( s->text(), len, properties );
3984 }
0a7de745
A
3985 } else {
3986 err = kIOReturnUnsupported;
3987 }
1c79356b 3988
0a7de745
A
3989 s->release();
3990 obj->release();
1c79356b 3991
0a7de745 3992 return err;
1c79356b
A
3993}
3994
4ba76501
A
3995/* Routine io_registry_entry_get_property_bin */
3996kern_return_t
3997is_io_registry_entry_get_property_bin(
3998 io_object_t registry_entry,
3999 io_name_t plane,
4000 io_name_t property_name,
4001 uint32_t options,
4002 io_buf_ptr_t *properties,
4003 mach_msg_type_number_t *propertiesCnt )
4004{
4005 return is_io_registry_entry_get_property_bin_buf(registry_entry, plane,
4006 property_name, options, 0, NULL, properties, propertiesCnt);
4007}
4008
3e170ce0 4009
1c79356b 4010/* Routine io_registry_entry_set_properties */
0a7de745
A
4011kern_return_t
4012is_io_registry_entry_set_properties
1c79356b
A
4013(
4014 io_object_t registry_entry,
4015 io_buf_ptr_t properties,
4016 mach_msg_type_number_t propertiesCnt,
0a7de745 4017 kern_return_t * result)
1c79356b 4018{
0a7de745
A
4019 OSObject * obj;
4020 kern_return_t err;
4021 IOReturn res;
4022 vm_offset_t data;
4023 vm_map_offset_t map_data;
1c79356b 4024
0a7de745 4025 CHECK( IORegistryEntry, registry_entry, entry );
39236c6e 4026
0a7de745
A
4027 if (propertiesCnt > sizeof(io_struct_inband_t) * 1024) {
4028 return kIOReturnMessageTooLarge;
4029 }
1c79356b 4030
0a7de745
A
4031 err = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) properties );
4032 data = CAST_DOWN(vm_offset_t, map_data);
1c79356b 4033
0a7de745
A
4034 if (KERN_SUCCESS == err) {
4035 FAKE_STACK_FRAME(entry->getMetaClass());
39037602 4036
0a7de745
A
4037 // must return success after vm_map_copyout() succeeds
4038 obj = OSUnserializeXML((const char *) data, propertiesCnt );
4039 vm_deallocate( kernel_map, data, propertiesCnt );
1c79356b 4040
0a7de745
A
4041 if (!obj) {
4042 res = kIOReturnBadArgument;
4043 }
6d2010ae 4044#if CONFIG_MACF
0a7de745
A
4045 else if (0 != mac_iokit_check_set_properties(kauth_cred_get(),
4046 registry_entry, obj)) {
4047 res = kIOReturnNotPermitted;
4048 }
6d2010ae 4049#endif
0a7de745
A
4050 else {
4051 res = entry->setProperties( obj );
4052 }
39037602 4053
0a7de745
A
4054 if (obj) {
4055 obj->release();
4056 }
39037602 4057
0a7de745
A
4058 FAKE_STACK_FRAME_END();
4059 } else {
4060 res = err;
4061 }
1c79356b 4062
0a7de745
A
4063 *result = res;
4064 return err;
1c79356b
A
4065}
4066
1c79356b 4067/* Routine io_registry_entry_get_child_iterator */
0a7de745
A
4068kern_return_t
4069is_io_registry_entry_get_child_iterator(
1c79356b
A
4070 io_object_t registry_entry,
4071 io_name_t plane,
4072 io_object_t *iterator )
4073{
0a7de745 4074 CHECK( IORegistryEntry, registry_entry, entry );
1c79356b 4075
0a7de745
A
4076 *iterator = IOUserIterator::withIterator(entry->getChildIterator(
4077 IORegistryEntry::getPlane( plane )));
1c79356b 4078
0a7de745 4079 return kIOReturnSuccess;
1c79356b
A
4080}
4081
4082/* Routine io_registry_entry_get_parent_iterator */
0a7de745
A
4083kern_return_t
4084is_io_registry_entry_get_parent_iterator(
1c79356b
A
4085 io_object_t registry_entry,
4086 io_name_t plane,
4087 io_object_t *iterator)
4088{
0a7de745 4089 CHECK( IORegistryEntry, registry_entry, entry );
1c79356b 4090
0a7de745
A
4091 *iterator = IOUserIterator::withIterator(entry->getParentIterator(
4092 IORegistryEntry::getPlane( plane )));
1c79356b 4093
0a7de745 4094 return kIOReturnSuccess;
1c79356b
A
4095}
4096
4097/* Routine io_service_get_busy_state */
0a7de745
A
4098kern_return_t
4099is_io_service_get_busy_state(
1c79356b 4100 io_object_t _service,
2d21ac55 4101 uint32_t *busyState )
1c79356b 4102{
0a7de745 4103 CHECK( IOService, _service, service );
1c79356b 4104
0a7de745 4105 *busyState = service->getBusyState();
1c79356b 4106
0a7de745 4107 return kIOReturnSuccess;
1c79356b
A
4108}
4109
55e303ae 4110/* Routine io_service_get_state */
0a7de745
A
4111kern_return_t
4112is_io_service_get_state(
55e303ae 4113 io_object_t _service,
b0d623f7
A
4114 uint64_t *state,
4115 uint32_t *busy_state,
4116 uint64_t *accumulated_busy_time )
55e303ae 4117{
0a7de745 4118 CHECK( IOService, _service, service );
55e303ae 4119
0a7de745
A
4120 *state = service->getState();
4121 *busy_state = service->getBusyState();
4122 *accumulated_busy_time = service->getAccumulatedBusyTime();
55e303ae 4123
0a7de745 4124 return kIOReturnSuccess;
55e303ae
A
4125}
4126
1c79356b 4127/* Routine io_service_wait_quiet */
0a7de745
A
4128kern_return_t
4129is_io_service_wait_quiet(
1c79356b
A
4130 io_object_t _service,
4131 mach_timespec_t wait_time )
4132{
0a7de745 4133 uint64_t timeoutNS;
1c79356b 4134
0a7de745
A
4135 CHECK( IOService, _service, service );
4136
4137 timeoutNS = wait_time.tv_sec;
4138 timeoutNS *= kSecondScale;
4139 timeoutNS += wait_time.tv_nsec;
4140
4141 return service->waitQuiet(timeoutNS);
1c79356b
A
4142}
4143
4144/* Routine io_service_request_probe */
0a7de745
A
4145kern_return_t
4146is_io_service_request_probe(
1c79356b 4147 io_object_t _service,
2d21ac55 4148 uint32_t options )
1c79356b 4149{
0a7de745 4150 CHECK( IOService, _service, service );
1c79356b 4151
0a7de745 4152 return service->requestProbe( options );
1c79356b
A
4153}
4154
fe8ab488 4155/* Routine io_service_get_authorization_id */
0a7de745
A
4156kern_return_t
4157is_io_service_get_authorization_id(
fe8ab488
A
4158 io_object_t _service,
4159 uint64_t *authorization_id )
4160{
0a7de745 4161 kern_return_t kr;
fe8ab488 4162
0a7de745 4163 CHECK( IOService, _service, service );
fe8ab488 4164
0a7de745
A
4165 kr = IOUserClient::clientHasPrivilege((void *) current_task(),
4166 kIOClientPrivilegeAdministrator );
4167 if (kIOReturnSuccess != kr) {
4168 return kr;
4169 }
fe8ab488 4170
0a7de745 4171 *authorization_id = service->getAuthorizationID();
fe8ab488 4172
0a7de745 4173 return kr;
fe8ab488
A
4174}
4175
4176/* Routine io_service_set_authorization_id */
0a7de745
A
4177kern_return_t
4178is_io_service_set_authorization_id(
fe8ab488
A
4179 io_object_t _service,
4180 uint64_t authorization_id )
4181{
0a7de745 4182 CHECK( IOService, _service, service );
fe8ab488 4183
0a7de745 4184 return service->setAuthorizationID( authorization_id );
fe8ab488
A
4185}
4186
0c530ab8 4187/* Routine io_service_open_ndr */
0a7de745
A
4188kern_return_t
4189is_io_service_open_extended(
0c530ab8
A
4190 io_object_t _service,
4191 task_t owningTask,
2d21ac55 4192 uint32_t connect_type,
0c530ab8
A
4193 NDR_record_t ndr,
4194 io_buf_ptr_t properties,
4195 mach_msg_type_number_t propertiesCnt,
0a7de745 4196 kern_return_t * result,
0c530ab8
A
4197 io_object_t *connection )
4198{
cb323159 4199 IOUserClient * client = NULL;
0a7de745
A
4200 kern_return_t err = KERN_SUCCESS;
4201 IOReturn res = kIOReturnSuccess;
cb323159 4202 OSDictionary * propertiesDict = NULL;
0a7de745
A
4203 bool crossEndian;
4204 bool disallowAccess;
0c530ab8 4205
0a7de745 4206 CHECK( IOService, _service, service );
0c530ab8 4207
0a7de745
A
4208 if (!owningTask) {
4209 return kIOReturnBadArgument;
4210 }
4211 assert(owningTask == current_task());
4212 if (owningTask != current_task()) {
4213 return kIOReturnBadArgument;
4214 }
3e170ce0 4215
c3c9b80d
A
4216#if CONFIG_MACF
4217 if (mac_iokit_check_open_service(kauth_cred_get(), service, connect_type) != 0) {
4218 return kIOReturnNotPermitted;
4219 }
4220#endif
0a7de745
A
4221 do{
4222 if (properties) {
4223 return kIOReturnUnsupported;
4224 }
d190cdc3 4225#if 0
0c530ab8 4226 {
0a7de745
A
4227 OSObject * obj;
4228 vm_offset_t data;
4229 vm_map_offset_t map_data;
4230
4231 if (propertiesCnt > sizeof(io_struct_inband_t)) {
4232 return kIOReturnMessageTooLarge;
4233 }
4234
4235 err = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) properties );
4236 res = err;
4237 data = CAST_DOWN(vm_offset_t, map_data);
4238 if (KERN_SUCCESS == err) {
4239 // must return success after vm_map_copyout() succeeds
4240 obj = OSUnserializeXML((const char *) data, propertiesCnt );
4241 vm_deallocate( kernel_map, data, propertiesCnt );
4242 propertiesDict = OSDynamicCast(OSDictionary, obj);
4243 if (!propertiesDict) {
4244 res = kIOReturnBadArgument;
4245 if (obj) {
4246 obj->release();
4247 }
4248 }
4249 }
4250 if (kIOReturnSuccess != res) {
4251 break;
4252 }
0c530ab8 4253 }
d190cdc3 4254#endif
0a7de745
A
4255 crossEndian = (ndr.int_rep != NDR_record.int_rep);
4256 if (crossEndian) {
4257 if (!propertiesDict) {
4258 propertiesDict = OSDictionary::withCapacity(4);
4259 }
4260 OSData * data = OSData::withBytes(&ndr, sizeof(ndr));
4261 if (data) {
4262 if (propertiesDict) {
4263 propertiesDict->setObject(kIOUserClientCrossEndianKey, data);
4264 }
4265 data->release();
4266 }
4267 }
4268
4269 res = service->newUserClient( owningTask, (void *) owningTask,
0c530ab8
A
4270 connect_type, propertiesDict, &client );
4271
0a7de745
A
4272 if (propertiesDict) {
4273 propertiesDict->release();
4274 }
0c530ab8 4275
0a7de745
A
4276 if (res == kIOReturnSuccess) {
4277 assert( OSDynamicCast(IOUserClient, client));
f427ee49
A
4278 if (!client->reserved) {
4279 if (!client->reserve()) {
4280 client->clientClose();
4281 OSSafeReleaseNULL(client);
4282 res = kIOReturnNoMemory;
4283 }
4284 }
4285 }
0c530ab8 4286
f427ee49 4287 if (res == kIOReturnSuccess) {
cb323159 4288 client->sharedInstance = (NULL != client->getProperty(kIOUserClientSharedInstanceKey));
f427ee49
A
4289 if (client->sharedInstance) {
4290 IOLockLock(gIOUserClientOwnersLock);
4291 }
4292 if (!client->lock) {
4293 client->lock = IORWLockAlloc();
4294 client->filterLock = IOLockAlloc();
4295
4296 client->messageAppSuspended = (NULL != client->getProperty(kIOUserClientMessageAppSuspendedKey));
4297 {
4298 OSObject * obj;
4299 extern const OSSymbol * gIOSurfaceIdentifier;
4300 obj = client->getProperty(kIOUserClientDefaultLockingKey);
4301 if (obj) {
4302 client->defaultLocking = (kOSBooleanFalse != client->getProperty(kIOUserClientDefaultLockingKey));
4303 } else {
4304 const OSMetaClass * meta;
4305 OSKext * kext;
4306 meta = client->getMetaClass();
4307 kext = meta->getKext();
4308 if (!kext || !kext->hasDependency(gIOSurfaceIdentifier)) {
4309 client->defaultLocking = true;
4310 client->setProperty(kIOUserClientDefaultLockingKey, kOSBooleanTrue);
4311 }
4312 }
4313 }
4314 }
4315 if (client->sharedInstance) {
4316 IOLockUnlock(gIOUserClientOwnersLock);
4317 }
7e41aa88 4318
0a7de745
A
4319 disallowAccess = (crossEndian
4320 && (kOSBooleanTrue != service->getProperty(kIOUserClientCrossEndianCompatibleKey))
4321 && (kOSBooleanTrue != client->getProperty(kIOUserClientCrossEndianCompatibleKey)));
4322 if (disallowAccess) {
4323 res = kIOReturnUnsupported;
4324 }
6d2010ae 4325#if CONFIG_MACF
0a7de745
A
4326 else if (0 != mac_iokit_check_open(kauth_cred_get(), client, connect_type)) {
4327 res = kIOReturnNotPermitted;
4328 }
6d2010ae 4329#endif
7e41aa88 4330
f427ee49
A
4331 if ((kIOReturnSuccess == res)
4332 && gIOUCFilterCallbacks
4333 && gIOUCFilterCallbacks->io_filter_resolver) {
4334 io_filter_policy_t filterPolicy;
4335 filterPolicy = client->filterForTask(owningTask, 0);
4336 if (!filterPolicy) {
4337 res = gIOUCFilterCallbacks->io_filter_resolver(owningTask, client, connect_type, &filterPolicy);
4338 if (kIOReturnUnsupported == res) {
4339 res = kIOReturnSuccess;
4340 } else if (kIOReturnSuccess == res) {
4341 client->filterForTask(owningTask, filterPolicy);
4342 }
4343 }
4344 }
4345
0a7de745
A
4346 if (kIOReturnSuccess == res) {
4347 res = client->registerOwner(owningTask);
4348 }
4349
4350 if (kIOReturnSuccess != res) {
4351 IOStatisticsClientCall();
4352 client->clientClose();
4353 client->release();
cb323159 4354 client = NULL;
0a7de745
A
4355 break;
4356 }
4357 OSString * creatorName = IOCopyLogNameForPID(proc_selfpid());
4358 if (creatorName) {
4359 client->setProperty(kIOUserClientCreatorKey, creatorName);
4360 creatorName->release();
4361 }
4362 client->setTerminateDefer(service, false);
4363 }
4364 }while (false);
0c530ab8 4365
0a7de745
A
4366 *connection = client;
4367 *result = res;
0c530ab8 4368
0a7de745 4369 return err;
0c530ab8
A
4370}
4371
1c79356b 4372/* Routine io_service_close */
0a7de745
A
4373kern_return_t
4374is_io_service_close(
1c79356b
A
4375 io_object_t connection )
4376{
0a7de745
A
4377 OSSet * mappings;
4378 if ((mappings = OSDynamicCast(OSSet, connection))) {
4379 return kIOReturnSuccess;
4380 }
43866e37 4381
0a7de745 4382 CHECK( IOUserClient, connection, client );
1c79356b 4383
0a7de745 4384 IOStatisticsClientCall();
c7d2c2c6 4385
0a7de745 4386 if (client->sharedInstance || OSCompareAndSwap8(0, 1, &client->closed)) {
f427ee49 4387 IORWLockWrite(client->lock);
0a7de745 4388 client->clientClose();
f427ee49 4389 IORWLockUnlock(client->lock);
0a7de745
A
4390 } else {
4391 IOLog("ignored is_io_service_close(0x%qx,%s)\n",
4392 client->getRegistryEntryID(), client->getName());
4393 }
1c79356b 4394
0a7de745 4395 return kIOReturnSuccess;
1c79356b
A
4396}
4397
4398/* Routine io_connect_get_service */
0a7de745
A
4399kern_return_t
4400is_io_connect_get_service(
1c79356b
A
4401 io_object_t connection,
4402 io_object_t *service )
4403{
0a7de745 4404 IOService * theService;
1c79356b 4405
0a7de745 4406 CHECK( IOUserClient, connection, client );
1c79356b 4407
0a7de745
A
4408 theService = client->getService();
4409 if (theService) {
4410 theService->retain();
4411 }
1c79356b 4412
0a7de745 4413 *service = theService;
1c79356b 4414
0a7de745 4415 return theService ? kIOReturnSuccess : kIOReturnUnsupported;
1c79356b
A
4416}
4417
4418/* Routine io_connect_set_notification_port */
0a7de745
A
4419kern_return_t
4420is_io_connect_set_notification_port(
1c79356b 4421 io_object_t connection,
2d21ac55 4422 uint32_t notification_type,
1c79356b 4423 mach_port_t port,
2d21ac55 4424 uint32_t reference)
1c79356b 4425{
0a7de745
A
4426 kern_return_t ret;
4427 CHECK( IOUserClient, connection, client );
1c79356b 4428
0a7de745 4429 IOStatisticsClientCall();
f427ee49 4430 IORWLockWrite(client->lock);
0a7de745
A
4431 ret = client->registerNotificationPort( port, notification_type,
4432 (io_user_reference_t) reference );
f427ee49 4433 IORWLockUnlock(client->lock);
0a7de745 4434 return ret;
1c79356b
A
4435}
4436
2d21ac55 4437/* Routine io_connect_set_notification_port */
0a7de745
A
4438kern_return_t
4439is_io_connect_set_notification_port_64(
2d21ac55
A
4440 io_object_t connection,
4441 uint32_t notification_type,
4442 mach_port_t port,
4443 io_user_reference_t reference)
4444{
0a7de745
A
4445 kern_return_t ret;
4446 CHECK( IOUserClient, connection, client );
2d21ac55 4447
0a7de745 4448 IOStatisticsClientCall();
f427ee49 4449 IORWLockWrite(client->lock);
0a7de745
A
4450 ret = client->registerNotificationPort( port, notification_type,
4451 reference );
f427ee49 4452 IORWLockUnlock(client->lock);
0a7de745 4453 return ret;
2d21ac55
A
4454}
4455
4456/* Routine io_connect_map_memory_into_task */
0a7de745
A
4457kern_return_t
4458is_io_connect_map_memory_into_task
2d21ac55
A
4459(
4460 io_connect_t connection,
4461 uint32_t memory_type,
4462 task_t into_task,
4463 mach_vm_address_t *address,
4464 mach_vm_size_t *size,
4465 uint32_t flags
4466)
1c79356b 4467{
0a7de745
A
4468 IOReturn err;
4469 IOMemoryMap * map;
4470
4471 CHECK( IOUserClient, connection, client );
4472
4473 if (!into_task) {
4474 return kIOReturnBadArgument;
4475 }
1c79356b 4476
0a7de745 4477 IOStatisticsClientCall();
f427ee49
A
4478 if (client->defaultLocking) {
4479 IORWLockWrite(client->lock);
4480 }
0a7de745 4481 map = client->mapClientMemory64( memory_type, into_task, flags, *address );
f427ee49
A
4482 if (client->defaultLocking) {
4483 IORWLockUnlock(client->lock);
4484 }
0a7de745
A
4485
4486 if (map) {
4487 *address = map->getAddress();
4488 if (size) {
4489 *size = map->getSize();
4490 }
4491
4492 if (client->sharedInstance
4493 || (into_task != current_task())) {
4494 // push a name out to the task owning the map,
4495 // so we can clean up maps
4496 mach_port_name_t name __unused =
4497 IOMachPort::makeSendRightForTask(
4498 into_task, map, IKOT_IOKIT_OBJECT );
4499 map->release();
4500 } else {
4501 // keep it with the user client
4502 IOLockLock( gIOObjectPortLock);
cb323159 4503 if (NULL == client->mappings) {
0a7de745
A
4504 client->mappings = OSSet::withCapacity(2);
4505 }
4506 if (client->mappings) {
4507 client->mappings->setObject( map);
4508 }
4509 IOLockUnlock( gIOObjectPortLock);
4510 map->release();
4511 }
4512 err = kIOReturnSuccess;
4513 } else {
4514 err = kIOReturnBadArgument;
4515 }
4516
4517 return err;
1c79356b
A
4518}
4519
2d21ac55 4520/* Routine is_io_connect_map_memory */
0a7de745
A
4521kern_return_t
4522is_io_connect_map_memory(
2d21ac55 4523 io_object_t connect,
0a7de745
A
4524 uint32_t type,
4525 task_t task,
4526 uint32_t * mapAddr,
4527 uint32_t * mapSize,
4528 uint32_t flags )
2d21ac55 4529{
0a7de745
A
4530 IOReturn err;
4531 mach_vm_address_t address;
4532 mach_vm_size_t size;
2d21ac55 4533
0a7de745
A
4534 address = SCALAR64(*mapAddr);
4535 size = SCALAR64(*mapSize);
2d21ac55 4536
0a7de745 4537 err = is_io_connect_map_memory_into_task(connect, type, task, &address, &size, flags);
2d21ac55 4538
0a7de745
A
4539 *mapAddr = SCALAR32(address);
4540 *mapSize = SCALAR32(size);
2d21ac55 4541
0a7de745 4542 return err;
2d21ac55 4543}
6d2010ae
A
4544} /* extern "C" */
4545
0a7de745
A
4546IOMemoryMap *
4547IOUserClient::removeMappingForDescriptor(IOMemoryDescriptor * mem)
483a1d10 4548{
0a7de745 4549 OSIterator * iter;
cb323159 4550 IOMemoryMap * map = NULL;
483a1d10 4551
0a7de745 4552 IOLockLock(gIOObjectPortLock);
483a1d10 4553
0a7de745
A
4554 iter = OSCollectionIterator::withCollection(mappings);
4555 if (iter) {
4556 while ((map = OSDynamicCast(IOMemoryMap, iter->getNextObject()))) {
4557 if (mem == map->getMemoryDescriptor()) {
4558 map->retain();
4559 mappings->removeObject(map);
4560 break;
4561 }
4562 }
4563 iter->release();
4564 }
483a1d10 4565
0a7de745 4566 IOLockUnlock(gIOObjectPortLock);
483a1d10 4567
0a7de745 4568 return map;
483a1d10
A
4569}
4570
6d2010ae 4571extern "C" {
2d21ac55 4572/* Routine io_connect_unmap_memory_from_task */
0a7de745
A
4573kern_return_t
4574is_io_connect_unmap_memory_from_task
2d21ac55
A
4575(
4576 io_connect_t connection,
4577 uint32_t memory_type,
4578 task_t from_task,
4579 mach_vm_address_t address)
1c79356b 4580{
0a7de745
A
4581 IOReturn err;
4582 IOOptionBits options = 0;
cb323159 4583 IOMemoryDescriptor * memory = NULL;
0a7de745 4584 IOMemoryMap * map;
1c79356b 4585
0a7de745 4586 CHECK( IOUserClient, connection, client );
1c79356b 4587
0a7de745
A
4588 if (!from_task) {
4589 return kIOReturnBadArgument;
4590 }
a39ff7e2 4591
0a7de745 4592 IOStatisticsClientCall();
f427ee49
A
4593 if (client->defaultLocking) {
4594 IORWLockWrite(client->lock);
4595 }
0a7de745 4596 err = client->clientMemoryForType((UInt32) memory_type, &options, &memory );
f427ee49
A
4597 if (client->defaultLocking) {
4598 IORWLockUnlock(client->lock);
4599 }
0a7de745
A
4600
4601 if (memory && (kIOReturnSuccess == err)) {
4602 options = (options & ~kIOMapUserOptionsMask)
4603 | kIOMapAnywhere | kIOMapReference;
4604
4605 map = memory->createMappingInTask( from_task, address, options );
4606 memory->release();
4607 if (map) {
4608 IOLockLock( gIOObjectPortLock);
4609 if (client->mappings) {
4610 client->mappings->removeObject( map);
4611 }
4612 IOLockUnlock( gIOObjectPortLock);
4613
4614 mach_port_name_t name = 0;
f427ee49
A
4615 bool is_shared_instance_or_from_current_task = from_task != current_task() || client->sharedInstance;
4616 if (is_shared_instance_or_from_current_task) {
0a7de745
A
4617 name = IOMachPort::makeSendRightForTask( from_task, map, IKOT_IOKIT_OBJECT );
4618 map->release();
4619 }
4620
4621 if (name) {
4622 map->userClientUnmap();
4623 err = iokit_mod_send_right( from_task, name, -2 );
4624 err = kIOReturnSuccess;
4625 } else {
4626 IOMachPort::releasePortForObject( map, IKOT_IOKIT_OBJECT );
4627 }
f427ee49 4628 if (!is_shared_instance_or_from_current_task) {
0a7de745
A
4629 map->release();
4630 }
4631 } else {
4632 err = kIOReturnBadArgument;
4633 }
4634 }
1c79356b 4635
0a7de745 4636 return err;
1c79356b
A
4637}
4638
0a7de745
A
4639kern_return_t
4640is_io_connect_unmap_memory(
2d21ac55 4641 io_object_t connect,
0a7de745
A
4642 uint32_t type,
4643 task_t task,
4644 uint32_t mapAddr )
2d21ac55 4645{
0a7de745
A
4646 IOReturn err;
4647 mach_vm_address_t address;
2d21ac55 4648
0a7de745
A
4649 address = SCALAR64(mapAddr);
4650
4651 err = is_io_connect_unmap_memory_from_task(connect, type, task, mapAddr);
4652
4653 return err;
2d21ac55
A
4654}
4655
1c79356b
A
4656
4657/* Routine io_connect_add_client */
0a7de745
A
4658kern_return_t
4659is_io_connect_add_client(
1c79356b
A
4660 io_object_t connection,
4661 io_object_t connect_to)
4662{
0a7de745
A
4663 CHECK( IOUserClient, connection, client );
4664 CHECK( IOUserClient, connect_to, to );
1c79356b 4665
f427ee49
A
4666 IOReturn ret;
4667
0a7de745 4668 IOStatisticsClientCall();
f427ee49
A
4669 if (client->defaultLocking) {
4670 IORWLockWrite(client->lock);
4671 }
4672 ret = client->connectClient( to );
4673 if (client->defaultLocking) {
4674 IORWLockUnlock(client->lock);
4675 }
4676 return ret;
1c79356b
A
4677}
4678
4679
4680/* Routine io_connect_set_properties */
0a7de745
A
4681kern_return_t
4682is_io_connect_set_properties(
1c79356b
A
4683 io_object_t connection,
4684 io_buf_ptr_t properties,
4685 mach_msg_type_number_t propertiesCnt,
0a7de745 4686 kern_return_t * result)
1c79356b 4687{
0a7de745 4688 return is_io_registry_entry_set_properties( connection, properties, propertiesCnt, result );
1c79356b
A
4689}
4690
ebb1b9f4 4691/* Routine io_user_client_method */
0a7de745
A
4692kern_return_t
4693is_io_connect_method_var_output
ebb1b9f4
A
4694(
4695 io_connect_t connection,
4696 uint32_t selector,
4697 io_scalar_inband64_t scalar_input,
4698 mach_msg_type_number_t scalar_inputCnt,
4699 io_struct_inband_t inband_input,
4700 mach_msg_type_number_t inband_inputCnt,
4701 mach_vm_address_t ool_input,
4702 mach_vm_size_t ool_input_size,
4703 io_struct_inband_t inband_output,
4704 mach_msg_type_number_t *inband_outputCnt,
4705 io_scalar_inband64_t scalar_output,
4706 mach_msg_type_number_t *scalar_outputCnt,
4707 io_buf_ptr_t *var_output,
4708 mach_msg_type_number_t *var_outputCnt
4709)
4710{
0a7de745 4711 CHECK( IOUserClient, connection, client );
ebb1b9f4 4712
0a7de745
A
4713 IOExternalMethodArguments args;
4714 IOReturn ret;
cb323159
A
4715 IOMemoryDescriptor * inputMD = NULL;
4716 OSObject * structureVariableOutputData = NULL;
ebb1b9f4 4717
0a7de745
A
4718 bzero(&args.__reserved[0], sizeof(args.__reserved));
4719 args.__reservedA = 0;
4720 args.version = kIOExternalMethodArgumentsCurrentVersion;
ebb1b9f4 4721
0a7de745 4722 args.selector = selector;
ebb1b9f4 4723
0a7de745 4724 args.asyncWakePort = MACH_PORT_NULL;
cb323159 4725 args.asyncReference = NULL;
0a7de745
A
4726 args.asyncReferenceCount = 0;
4727 args.structureVariableOutputData = &structureVariableOutputData;
4d15aeb1 4728
0a7de745
A
4729 args.scalarInput = scalar_input;
4730 args.scalarInputCount = scalar_inputCnt;
4731 args.structureInput = inband_input;
4732 args.structureInputSize = inband_inputCnt;
ebb1b9f4 4733
0a7de745
A
4734 if (ool_input && (ool_input_size <= sizeof(io_struct_inband_t))) {
4735 return kIOReturnIPCError;
4736 }
ebb1b9f4 4737
0a7de745
A
4738 if (ool_input) {
4739 inputMD = IOMemoryDescriptor::withAddressRange(ool_input, ool_input_size,
4740 kIODirectionOut | kIOMemoryMapCopyOnWrite,
4741 current_task());
4742 }
ebb1b9f4 4743
0a7de745
A
4744 args.structureInputDescriptor = inputMD;
4745
4746 args.scalarOutput = scalar_output;
4747 args.scalarOutputCount = *scalar_outputCnt;
4748 bzero(&scalar_output[0], *scalar_outputCnt * sizeof(scalar_output[0]));
4749 args.structureOutput = inband_output;
4750 args.structureOutputSize = *inband_outputCnt;
4751 args.structureOutputDescriptor = NULL;
4752 args.structureOutputDescriptorSize = 0;
4753
4754 IOStatisticsClientCall();
f427ee49
A
4755 ret = kIOReturnSuccess;
4756
4757 io_filter_policy_t filterPolicy = client->filterForTask(current_task(), 0);
4758 if (filterPolicy && gIOUCFilterCallbacks->io_filter_applier) {
4759 ret = gIOUCFilterCallbacks->io_filter_applier(filterPolicy, io_filter_type_external_method, selector);
4760 }
4761 if (kIOReturnSuccess == ret) {
4762 if (client->defaultLocking) {
4763 IORWLockRead(client->lock);
4764 }
4765 ret = client->externalMethod( selector, &args );
4766 if (client->defaultLocking) {
4767 IORWLockUnlock(client->lock);
4768 }
4769 }
0a7de745
A
4770
4771 *scalar_outputCnt = args.scalarOutputCount;
4772 *inband_outputCnt = args.structureOutputSize;
4773
4774 if (var_outputCnt && var_output && (kIOReturnSuccess == ret)) {
4775 OSSerialize * serialize;
4776 OSData * data;
f427ee49 4777 unsigned int len;
0a7de745
A
4778
4779 if ((serialize = OSDynamicCast(OSSerialize, structureVariableOutputData))) {
4780 len = serialize->getLength();
4781 *var_outputCnt = len;
4782 ret = copyoutkdata(serialize->text(), len, var_output);
4783 } else if ((data = OSDynamicCast(OSData, structureVariableOutputData))) {
4784 len = data->getLength();
4785 *var_outputCnt = len;
4786 ret = copyoutkdata(data->getBytesNoCopy(), len, var_output);
4787 } else {
4788 ret = kIOReturnUnderrun;
4789 }
ebb1b9f4 4790 }
0a7de745
A
4791
4792 if (inputMD) {
4793 inputMD->release();
ebb1b9f4 4794 }
0a7de745
A
4795 if (structureVariableOutputData) {
4796 structureVariableOutputData->release();
ebb1b9f4 4797 }
ebb1b9f4 4798
0a7de745 4799 return ret;
ebb1b9f4 4800}
1c79356b 4801
2d21ac55 4802/* Routine io_user_client_method */
0a7de745
A
4803kern_return_t
4804is_io_connect_method
2d21ac55
A
4805(
4806 io_connect_t connection,
4807 uint32_t selector,
4808 io_scalar_inband64_t scalar_input,
4809 mach_msg_type_number_t scalar_inputCnt,
4810 io_struct_inband_t inband_input,
4811 mach_msg_type_number_t inband_inputCnt,
4812 mach_vm_address_t ool_input,
4813 mach_vm_size_t ool_input_size,
2d21ac55
A
4814 io_struct_inband_t inband_output,
4815 mach_msg_type_number_t *inband_outputCnt,
6d2010ae
A
4816 io_scalar_inband64_t scalar_output,
4817 mach_msg_type_number_t *scalar_outputCnt,
2d21ac55 4818 mach_vm_address_t ool_output,
ebb1b9f4 4819 mach_vm_size_t *ool_output_size
2d21ac55 4820)
1c79356b 4821{
0a7de745 4822 CHECK( IOUserClient, connection, client );
1c79356b 4823
0a7de745
A
4824 IOExternalMethodArguments args;
4825 IOReturn ret;
cb323159
A
4826 IOMemoryDescriptor * inputMD = NULL;
4827 IOMemoryDescriptor * outputMD = NULL;
1c79356b 4828
0a7de745
A
4829 bzero(&args.__reserved[0], sizeof(args.__reserved));
4830 args.__reservedA = 0;
4831 args.version = kIOExternalMethodArgumentsCurrentVersion;
1c79356b 4832
0a7de745 4833 args.selector = selector;
1c79356b 4834
0a7de745 4835 args.asyncWakePort = MACH_PORT_NULL;
cb323159 4836 args.asyncReference = NULL;
0a7de745 4837 args.asyncReferenceCount = 0;
cb323159 4838 args.structureVariableOutputData = NULL;
1c79356b 4839
0a7de745
A
4840 args.scalarInput = scalar_input;
4841 args.scalarInputCount = scalar_inputCnt;
4842 args.structureInput = inband_input;
4843 args.structureInputSize = inband_inputCnt;
1c79356b 4844
0a7de745
A
4845 if (ool_input && (ool_input_size <= sizeof(io_struct_inband_t))) {
4846 return kIOReturnIPCError;
4847 }
f427ee49
A
4848 if (ool_output) {
4849 if (*ool_output_size <= sizeof(io_struct_inband_t)) {
4850 return kIOReturnIPCError;
4851 }
4852 if (*ool_output_size > UINT_MAX) {
4853 return kIOReturnIPCError;
4854 }
0a7de745 4855 }
4d15aeb1 4856
0a7de745
A
4857 if (ool_input) {
4858 inputMD = IOMemoryDescriptor::withAddressRange(ool_input, ool_input_size,
4859 kIODirectionOut | kIOMemoryMapCopyOnWrite,
4860 current_task());
4861 }
1c79356b 4862
0a7de745 4863 args.structureInputDescriptor = inputMD;
1c79356b 4864
0a7de745
A
4865 args.scalarOutput = scalar_output;
4866 args.scalarOutputCount = *scalar_outputCnt;
4867 bzero(&scalar_output[0], *scalar_outputCnt * sizeof(scalar_output[0]));
4868 args.structureOutput = inband_output;
4869 args.structureOutputSize = *inband_outputCnt;
1c79356b 4870
0a7de745
A
4871 if (ool_output && ool_output_size) {
4872 outputMD = IOMemoryDescriptor::withAddressRange(ool_output, *ool_output_size,
4873 kIODirectionIn, current_task());
4874 }
1c79356b 4875
0a7de745 4876 args.structureOutputDescriptor = outputMD;
f427ee49
A
4877 args.structureOutputDescriptorSize = ool_output_size
4878 ? ((typeof(args.structureOutputDescriptorSize)) * ool_output_size)
4879 : 0;
1c79356b 4880
0a7de745 4881 IOStatisticsClientCall();
f427ee49
A
4882 ret = kIOReturnSuccess;
4883 io_filter_policy_t filterPolicy = client->filterForTask(current_task(), 0);
4884 if (filterPolicy && gIOUCFilterCallbacks->io_filter_applier) {
4885 ret = gIOUCFilterCallbacks->io_filter_applier(filterPolicy, io_filter_type_external_method, selector);
4886 }
4887 if (kIOReturnSuccess == ret) {
4888 if (client->defaultLocking) {
4889 IORWLockRead(client->lock);
4890 }
4891 ret = client->externalMethod( selector, &args );
4892 if (client->defaultLocking) {
4893 IORWLockUnlock(client->lock);
4894 }
4895 }
1c79356b 4896
0a7de745
A
4897 *scalar_outputCnt = args.scalarOutputCount;
4898 *inband_outputCnt = args.structureOutputSize;
4899 *ool_output_size = args.structureOutputDescriptorSize;
1c79356b 4900
0a7de745
A
4901 if (inputMD) {
4902 inputMD->release();
4903 }
4904 if (outputMD) {
4905 outputMD->release();
4906 }
1c79356b 4907
0a7de745 4908 return ret;
2d21ac55 4909}
1c79356b 4910
2d21ac55 4911/* Routine io_async_user_client_method */
0a7de745
A
4912kern_return_t
4913is_io_connect_async_method
2d21ac55
A
4914(
4915 io_connect_t connection,
4916 mach_port_t wake_port,
4917 io_async_ref64_t reference,
4918 mach_msg_type_number_t referenceCnt,
4919 uint32_t selector,
4920 io_scalar_inband64_t scalar_input,
4921 mach_msg_type_number_t scalar_inputCnt,
4922 io_struct_inband_t inband_input,
4923 mach_msg_type_number_t inband_inputCnt,
4924 mach_vm_address_t ool_input,
4925 mach_vm_size_t ool_input_size,
2d21ac55
A
4926 io_struct_inband_t inband_output,
4927 mach_msg_type_number_t *inband_outputCnt,
6d2010ae
A
4928 io_scalar_inband64_t scalar_output,
4929 mach_msg_type_number_t *scalar_outputCnt,
2d21ac55
A
4930 mach_vm_address_t ool_output,
4931 mach_vm_size_t * ool_output_size
4932)
4933{
0a7de745 4934 CHECK( IOUserClient, connection, client );
1c79356b 4935
0a7de745
A
4936 IOExternalMethodArguments args;
4937 IOReturn ret;
cb323159
A
4938 IOMemoryDescriptor * inputMD = NULL;
4939 IOMemoryDescriptor * outputMD = NULL;
2d21ac55 4940
f427ee49
A
4941 if (referenceCnt < 1) {
4942 return kIOReturnBadArgument;
4943 }
4944
0a7de745
A
4945 bzero(&args.__reserved[0], sizeof(args.__reserved));
4946 args.__reservedA = 0;
4947 args.version = kIOExternalMethodArgumentsCurrentVersion;
2d21ac55 4948
0a7de745
A
4949 reference[0] = (io_user_reference_t) wake_port;
4950 if (vm_map_is_64bit(get_task_map(current_task()))) {
4951 reference[0] |= kIOUCAsync64Flag;
4952 }
2d21ac55 4953
0a7de745 4954 args.selector = selector;
2d21ac55 4955
0a7de745
A
4956 args.asyncWakePort = wake_port;
4957 args.asyncReference = reference;
4958 args.asyncReferenceCount = referenceCnt;
2d21ac55 4959
cb323159 4960 args.structureVariableOutputData = NULL;
5ba3f43e 4961
0a7de745
A
4962 args.scalarInput = scalar_input;
4963 args.scalarInputCount = scalar_inputCnt;
4964 args.structureInput = inband_input;
4965 args.structureInputSize = inband_inputCnt;
2d21ac55 4966
0a7de745
A
4967 if (ool_input && (ool_input_size <= sizeof(io_struct_inband_t))) {
4968 return kIOReturnIPCError;
4969 }
f427ee49
A
4970 if (ool_output) {
4971 if (*ool_output_size <= sizeof(io_struct_inband_t)) {
4972 return kIOReturnIPCError;
4973 }
4974 if (*ool_output_size > UINT_MAX) {
4975 return kIOReturnIPCError;
4976 }
0a7de745 4977 }
4d15aeb1 4978
0a7de745
A
4979 if (ool_input) {
4980 inputMD = IOMemoryDescriptor::withAddressRange(ool_input, ool_input_size,
4981 kIODirectionOut | kIOMemoryMapCopyOnWrite,
4982 current_task());
4983 }
2d21ac55 4984
0a7de745 4985 args.structureInputDescriptor = inputMD;
2d21ac55 4986
0a7de745
A
4987 args.scalarOutput = scalar_output;
4988 args.scalarOutputCount = *scalar_outputCnt;
4989 bzero(&scalar_output[0], *scalar_outputCnt * sizeof(scalar_output[0]));
4990 args.structureOutput = inband_output;
4991 args.structureOutputSize = *inband_outputCnt;
2d21ac55 4992
0a7de745
A
4993 if (ool_output) {
4994 outputMD = IOMemoryDescriptor::withAddressRange(ool_output, *ool_output_size,
4995 kIODirectionIn, current_task());
4996 }
2d21ac55 4997
0a7de745 4998 args.structureOutputDescriptor = outputMD;
f427ee49 4999 args.structureOutputDescriptorSize = ((typeof(args.structureOutputDescriptorSize)) * ool_output_size);
2d21ac55 5000
0a7de745 5001 IOStatisticsClientCall();
f427ee49
A
5002 ret = kIOReturnSuccess;
5003 io_filter_policy_t filterPolicy = client->filterForTask(current_task(), 0);
5004 if (filterPolicy && gIOUCFilterCallbacks->io_filter_applier) {
5005 ret = gIOUCFilterCallbacks->io_filter_applier(filterPolicy, io_filter_type_external_async_method, selector);
5006 }
5007 if (kIOReturnSuccess == ret) {
5008 if (client->defaultLocking) {
5009 IORWLockRead(client->lock);
5010 }
5011 ret = client->externalMethod( selector, &args );
5012 if (client->defaultLocking) {
5013 IORWLockUnlock(client->lock);
5014 }
5015 }
2d21ac55 5016
cb323159 5017 *scalar_outputCnt = args.scalarOutputCount;
0a7de745
A
5018 *inband_outputCnt = args.structureOutputSize;
5019 *ool_output_size = args.structureOutputDescriptorSize;
2d21ac55 5020
0a7de745
A
5021 if (inputMD) {
5022 inputMD->release();
5023 }
5024 if (outputMD) {
5025 outputMD->release();
5026 }
2d21ac55 5027
0a7de745 5028 return ret;
1c79356b
A
5029}
5030
2d21ac55 5031/* Routine io_connect_method_scalarI_scalarO */
0a7de745
A
5032kern_return_t
5033is_io_connect_method_scalarI_scalarO(
5034 io_object_t connect,
5035 uint32_t index,
5036 io_scalar_inband_t input,
5037 mach_msg_type_number_t inputCount,
5038 io_scalar_inband_t output,
5039 mach_msg_type_number_t * outputCount )
5040{
5041 IOReturn err;
5042 uint32_t i;
5043 io_scalar_inband64_t _input;
5044 io_scalar_inband64_t _output;
5045
5046 mach_msg_type_number_t struct_outputCnt = 0;
5047 mach_vm_size_t ool_output_size = 0;
5048
5049 bzero(&_output[0], sizeof(_output));
5050 for (i = 0; i < inputCount; i++) {
5051 _input[i] = SCALAR64(input[i]);
5052 }
5053
5054 err = is_io_connect_method(connect, index,
5055 _input, inputCount,
5056 NULL, 0,
5057 0, 0,
5058 NULL, &struct_outputCnt,
5059 _output, outputCount,
5060 0, &ool_output_size);
1c79356b 5061
0a7de745
A
5062 for (i = 0; i < *outputCount; i++) {
5063 output[i] = SCALAR32(_output[i]);
1c79356b 5064 }
1c79356b 5065
0a7de745
A
5066 return err;
5067}
5068
5069kern_return_t
5070shim_io_connect_method_scalarI_scalarO(
5071 IOExternalMethod * method,
5072 IOService * object,
5073 const io_user_scalar_t * input,
5074 mach_msg_type_number_t inputCount,
5075 io_user_scalar_t * output,
5076 mach_msg_type_number_t * outputCount )
5077{
5078 IOMethod func;
5079 io_scalar_inband_t _output;
5080 IOReturn err;
5081 err = kIOReturnBadArgument;
5082
5083 bzero(&_output[0], sizeof(_output));
5084 do {
5085 if (inputCount != method->count0) {
5086 IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0);
5087 DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0);
5088 continue;
5089 }
5090 if (*outputCount != method->count1) {
5091 IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)*outputCount, (uint64_t)method->count1);
5092 DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1);
5093 continue;
5094 }
1c79356b 5095
0a7de745
A
5096 func = method->func;
5097
5098 switch (inputCount) {
5099 case 6:
5100 err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5101 ARG32(input[3]), ARG32(input[4]), ARG32(input[5]));
5102 break;
5103 case 5:
5104 err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5105 ARG32(input[3]), ARG32(input[4]),
5106 &_output[0] );
5107 break;
5108 case 4:
5109 err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5110 ARG32(input[3]),
5111 &_output[0], &_output[1] );
5112 break;
5113 case 3:
5114 err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5115 &_output[0], &_output[1], &_output[2] );
5116 break;
5117 case 2:
5118 err = (object->*func)( ARG32(input[0]), ARG32(input[1]),
5119 &_output[0], &_output[1], &_output[2],
5120 &_output[3] );
5121 break;
5122 case 1:
5123 err = (object->*func)( ARG32(input[0]),
5124 &_output[0], &_output[1], &_output[2],
5125 &_output[3], &_output[4] );
5126 break;
5127 case 0:
5128 err = (object->*func)( &_output[0], &_output[1], &_output[2],
5129 &_output[3], &_output[4], &_output[5] );
5130 break;
5131
5132 default:
5133 IOLog("%s: Bad method table\n", object->getName());
5134 }
5135 }while (false);
5136
5137 uint32_t i;
5138 for (i = 0; i < *outputCount; i++) {
5139 output[i] = SCALAR32(_output[i]);
5140 }
5141
5142 return err;
1c79356b
A
5143}
5144
2d21ac55 5145/* Routine io_async_method_scalarI_scalarO */
0a7de745
A
5146kern_return_t
5147is_io_async_method_scalarI_scalarO(
5148 io_object_t connect,
2d21ac55
A
5149 mach_port_t wake_port,
5150 io_async_ref_t reference,
5151 mach_msg_type_number_t referenceCnt,
0a7de745
A
5152 uint32_t index,
5153 io_scalar_inband_t input,
5154 mach_msg_type_number_t inputCount,
5155 io_scalar_inband_t output,
5156 mach_msg_type_number_t * outputCount )
5157{
5158 IOReturn err;
5159 uint32_t i;
5160 io_scalar_inband64_t _input;
5161 io_scalar_inband64_t _output;
5162 io_async_ref64_t _reference;
5163
cb323159
A
5164 if (referenceCnt > ASYNC_REF64_COUNT) {
5165 return kIOReturnBadArgument;
5166 }
0a7de745
A
5167 bzero(&_output[0], sizeof(_output));
5168 for (i = 0; i < referenceCnt; i++) {
5169 _reference[i] = REF64(reference[i]);
5170 }
cb323159 5171 bzero(&_reference[referenceCnt], (ASYNC_REF64_COUNT - referenceCnt) * sizeof(_reference[0]));
0a7de745
A
5172
5173 mach_msg_type_number_t struct_outputCnt = 0;
5174 mach_vm_size_t ool_output_size = 0;
5175
5176 for (i = 0; i < inputCount; i++) {
5177 _input[i] = SCALAR64(input[i]);
5178 }
5179
5180 err = is_io_connect_async_method(connect,
5181 wake_port, _reference, referenceCnt,
5182 index,
5183 _input, inputCount,
5184 NULL, 0,
5185 0, 0,
5186 NULL, &struct_outputCnt,
5187 _output, outputCount,
5188 0, &ool_output_size);
5189
5190 for (i = 0; i < *outputCount; i++) {
5191 output[i] = SCALAR32(_output[i]);
5192 }
5193
5194 return err;
2d21ac55
A
5195}
5196/* Routine io_async_method_scalarI_structureO */
0a7de745
A
5197kern_return_t
5198is_io_async_method_scalarI_structureO(
5199 io_object_t connect,
2d21ac55
A
5200 mach_port_t wake_port,
5201 io_async_ref_t reference,
5202 mach_msg_type_number_t referenceCnt,
0a7de745
A
5203 uint32_t index,
5204 io_scalar_inband_t input,
5205 mach_msg_type_number_t inputCount,
5206 io_struct_inband_t output,
5207 mach_msg_type_number_t * outputCount )
5208{
5209 uint32_t i;
5210 io_scalar_inband64_t _input;
5211 io_async_ref64_t _reference;
5212
cb323159
A
5213 if (referenceCnt > ASYNC_REF64_COUNT) {
5214 return kIOReturnBadArgument;
5215 }
0a7de745
A
5216 for (i = 0; i < referenceCnt; i++) {
5217 _reference[i] = REF64(reference[i]);
5218 }
cb323159 5219 bzero(&_reference[referenceCnt], (ASYNC_REF64_COUNT - referenceCnt) * sizeof(_reference[0]));
0a7de745
A
5220
5221 mach_msg_type_number_t scalar_outputCnt = 0;
5222 mach_vm_size_t ool_output_size = 0;
5223
5224 for (i = 0; i < inputCount; i++) {
5225 _input[i] = SCALAR64(input[i]);
5226 }
5227
5228 return is_io_connect_async_method(connect,
5229 wake_port, _reference, referenceCnt,
5230 index,
5231 _input, inputCount,
5232 NULL, 0,
5233 0, 0,
5234 output, outputCount,
5235 NULL, &scalar_outputCnt,
5236 0, &ool_output_size);
2d21ac55 5237}
1c79356b 5238
2d21ac55 5239/* Routine io_async_method_scalarI_structureI */
0a7de745
A
5240kern_return_t
5241is_io_async_method_scalarI_structureI(
5242 io_connect_t connect,
2d21ac55
A
5243 mach_port_t wake_port,
5244 io_async_ref_t reference,
5245 mach_msg_type_number_t referenceCnt,
0a7de745
A
5246 uint32_t index,
5247 io_scalar_inband_t input,
5248 mach_msg_type_number_t inputCount,
5249 io_struct_inband_t inputStruct,
5250 mach_msg_type_number_t inputStructCount )
5251{
5252 uint32_t i;
5253 io_scalar_inband64_t _input;
5254 io_async_ref64_t _reference;
5255
cb323159
A
5256 if (referenceCnt > ASYNC_REF64_COUNT) {
5257 return kIOReturnBadArgument;
5258 }
0a7de745
A
5259 for (i = 0; i < referenceCnt; i++) {
5260 _reference[i] = REF64(reference[i]);
5261 }
cb323159 5262 bzero(&_reference[referenceCnt], (ASYNC_REF64_COUNT - referenceCnt) * sizeof(_reference[0]));
0a7de745
A
5263
5264 mach_msg_type_number_t scalar_outputCnt = 0;
5265 mach_msg_type_number_t inband_outputCnt = 0;
5266 mach_vm_size_t ool_output_size = 0;
5267
5268 for (i = 0; i < inputCount; i++) {
5269 _input[i] = SCALAR64(input[i]);
5270 }
5271
5272 return is_io_connect_async_method(connect,
5273 wake_port, _reference, referenceCnt,
5274 index,
5275 _input, inputCount,
5276 inputStruct, inputStructCount,
5277 0, 0,
5278 NULL, &inband_outputCnt,
5279 NULL, &scalar_outputCnt,
5280 0, &ool_output_size);
1c79356b
A
5281}
5282
2d21ac55 5283/* Routine io_async_method_structureI_structureO */
0a7de745
A
5284kern_return_t
5285is_io_async_method_structureI_structureO(
5286 io_object_t connect,
2d21ac55
A
5287 mach_port_t wake_port,
5288 io_async_ref_t reference,
5289 mach_msg_type_number_t referenceCnt,
0a7de745
A
5290 uint32_t index,
5291 io_struct_inband_t input,
5292 mach_msg_type_number_t inputCount,
5293 io_struct_inband_t output,
5294 mach_msg_type_number_t * outputCount )
5295{
5296 uint32_t i;
5297 mach_msg_type_number_t scalar_outputCnt = 0;
5298 mach_vm_size_t ool_output_size = 0;
5299 io_async_ref64_t _reference;
5300
cb323159
A
5301 if (referenceCnt > ASYNC_REF64_COUNT) {
5302 return kIOReturnBadArgument;
5303 }
0a7de745
A
5304 for (i = 0; i < referenceCnt; i++) {
5305 _reference[i] = REF64(reference[i]);
5306 }
cb323159 5307 bzero(&_reference[referenceCnt], (ASYNC_REF64_COUNT - referenceCnt) * sizeof(_reference[0]));
0a7de745
A
5308
5309 return is_io_connect_async_method(connect,
5310 wake_port, _reference, referenceCnt,
5311 index,
5312 NULL, 0,
5313 input, inputCount,
5314 0, 0,
5315 output, outputCount,
5316 NULL, &scalar_outputCnt,
5317 0, &ool_output_size);
5318}
5319
5320
5321kern_return_t
5322shim_io_async_method_scalarI_scalarO(
5323 IOExternalAsyncMethod * method,
5324 IOService * object,
2d21ac55
A
5325 mach_port_t asyncWakePort,
5326 io_user_reference_t * asyncReference,
5327 uint32_t asyncReferenceCount,
0a7de745
A
5328 const io_user_scalar_t * input,
5329 mach_msg_type_number_t inputCount,
5330 io_user_scalar_t * output,
5331 mach_msg_type_number_t * outputCount )
5332{
5333 IOAsyncMethod func;
5334 uint32_t i;
5335 io_scalar_inband_t _output;
5336 IOReturn err;
5337 io_async_ref_t reference;
5338
5339 bzero(&_output[0], sizeof(_output));
5340 for (i = 0; i < asyncReferenceCount; i++) {
5341 reference[i] = REF32(asyncReference[i]);
5342 }
5343
5344 err = kIOReturnBadArgument;
5345
5346 do {
5347 if (inputCount != method->count0) {
5348 IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0);
5349 DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0);
5350 continue;
5351 }
5352 if (*outputCount != method->count1) {
5353 IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)*outputCount, (uint64_t)method->count1);
5354 DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1);
5355 continue;
5356 }
5357
5358 func = method->func;
5359
5360 switch (inputCount) {
5361 case 6:
5362 err = (object->*func)( reference,
5363 ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5364 ARG32(input[3]), ARG32(input[4]), ARG32(input[5]));
5365 break;
5366 case 5:
5367 err = (object->*func)( reference,
5368 ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5369 ARG32(input[3]), ARG32(input[4]),
5370 &_output[0] );
5371 break;
5372 case 4:
5373 err = (object->*func)( reference,
5374 ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5375 ARG32(input[3]),
5376 &_output[0], &_output[1] );
5377 break;
5378 case 3:
5379 err = (object->*func)( reference,
5380 ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5381 &_output[0], &_output[1], &_output[2] );
5382 break;
5383 case 2:
5384 err = (object->*func)( reference,
5385 ARG32(input[0]), ARG32(input[1]),
5386 &_output[0], &_output[1], &_output[2],
5387 &_output[3] );
5388 break;
5389 case 1:
5390 err = (object->*func)( reference,
5391 ARG32(input[0]),
5392 &_output[0], &_output[1], &_output[2],
5393 &_output[3], &_output[4] );
5394 break;
5395 case 0:
5396 err = (object->*func)( reference,
5397 &_output[0], &_output[1], &_output[2],
5398 &_output[3], &_output[4], &_output[5] );
5399 break;
5400
5401 default:
5402 IOLog("%s: Bad method table\n", object->getName());
5403 }
5404 }while (false);
5405
5406 for (i = 0; i < *outputCount; i++) {
5407 output[i] = SCALAR32(_output[i]);
5408 }
5409
5410 return err;
1c79356b
A
5411}
5412
2d21ac55
A
5413
5414/* Routine io_connect_method_scalarI_structureO */
0a7de745
A
5415kern_return_t
5416is_io_connect_method_scalarI_structureO(
5417 io_object_t connect,
5418 uint32_t index,
5419 io_scalar_inband_t input,
5420 mach_msg_type_number_t inputCount,
5421 io_struct_inband_t output,
5422 mach_msg_type_number_t * outputCount )
5423{
5424 uint32_t i;
5425 io_scalar_inband64_t _input;
5426
5427 mach_msg_type_number_t scalar_outputCnt = 0;
5428 mach_vm_size_t ool_output_size = 0;
2d21ac55 5429
0a7de745
A
5430 for (i = 0; i < inputCount; i++) {
5431 _input[i] = SCALAR64(input[i]);
2d21ac55 5432 }
2d21ac55 5433
0a7de745
A
5434 return is_io_connect_method(connect, index,
5435 _input, inputCount,
5436 NULL, 0,
5437 0, 0,
5438 output, outputCount,
5439 NULL, &scalar_outputCnt,
5440 0, &ool_output_size);
2d21ac55
A
5441}
5442
0a7de745
A
5443kern_return_t
5444shim_io_connect_method_scalarI_structureO(
5445
5446 IOExternalMethod * method,
5447 IOService * object,
5448 const io_user_scalar_t * input,
5449 mach_msg_type_number_t inputCount,
5450 io_struct_inband_t output,
5451 IOByteCount * outputCount )
5452{
5453 IOMethod func;
5454 IOReturn err;
2d21ac55 5455
0a7de745
A
5456 err = kIOReturnBadArgument;
5457
5458 do {
5459 if (inputCount != method->count0) {
5460 IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0);
5461 DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0);
5462 continue;
5463 }
5464 if ((kIOUCVariableStructureSize != method->count1)
5465 && (*outputCount != method->count1)) {
5466 IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)*outputCount, (uint64_t)method->count1, (uint64_t)kIOUCVariableStructureSize);
5467 DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1);
5468 continue;
5469 }
5470
5471 func = method->func;
5472
5473 switch (inputCount) {
5474 case 5:
5475 err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5476 ARG32(input[3]), ARG32(input[4]),
5477 output );
5478 break;
5479 case 4:
5480 err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5481 ARG32(input[3]),
5482 output, (void *)outputCount );
5483 break;
5484 case 3:
5485 err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
cb323159 5486 output, (void *)outputCount, NULL );
0a7de745
A
5487 break;
5488 case 2:
5489 err = (object->*func)( ARG32(input[0]), ARG32(input[1]),
cb323159 5490 output, (void *)outputCount, NULL, NULL );
0a7de745
A
5491 break;
5492 case 1:
5493 err = (object->*func)( ARG32(input[0]),
cb323159 5494 output, (void *)outputCount, NULL, NULL, NULL );
0a7de745
A
5495 break;
5496 case 0:
cb323159 5497 err = (object->*func)( output, (void *)outputCount, NULL, NULL, NULL, NULL );
0a7de745
A
5498 break;
5499
5500 default:
5501 IOLog("%s: Bad method table\n", object->getName());
5502 }
5503 }while (false);
5504
5505 return err;
5506}
5507
5508
5509kern_return_t
5510shim_io_async_method_scalarI_structureO(
5511 IOExternalAsyncMethod * method,
5512 IOService * object,
2d21ac55
A
5513 mach_port_t asyncWakePort,
5514 io_user_reference_t * asyncReference,
5515 uint32_t asyncReferenceCount,
0a7de745
A
5516 const io_user_scalar_t * input,
5517 mach_msg_type_number_t inputCount,
5518 io_struct_inband_t output,
5519 mach_msg_type_number_t * outputCount )
5520{
5521 IOAsyncMethod func;
5522 uint32_t i;
5523 IOReturn err;
5524 io_async_ref_t reference;
5525
5526 for (i = 0; i < asyncReferenceCount; i++) {
5527 reference[i] = REF32(asyncReference[i]);
5528 }
5529
5530 err = kIOReturnBadArgument;
5531 do {
5532 if (inputCount != method->count0) {
5533 IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0);
5534 DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0);
5535 continue;
5536 }
5537 if ((kIOUCVariableStructureSize != method->count1)
5538 && (*outputCount != method->count1)) {
5539 IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)*outputCount, (uint64_t)method->count1, (uint64_t)kIOUCVariableStructureSize);
5540 DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1);
5541 continue;
5542 }
5543
5544 func = method->func;
5545
5546 switch (inputCount) {
5547 case 5:
5548 err = (object->*func)( reference,
5549 ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5550 ARG32(input[3]), ARG32(input[4]),
5551 output );
5552 break;
5553 case 4:
5554 err = (object->*func)( reference,
5555 ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5556 ARG32(input[3]),
5557 output, (void *)outputCount );
5558 break;
5559 case 3:
5560 err = (object->*func)( reference,
5561 ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
cb323159 5562 output, (void *)outputCount, NULL );
0a7de745
A
5563 break;
5564 case 2:
5565 err = (object->*func)( reference,
5566 ARG32(input[0]), ARG32(input[1]),
cb323159 5567 output, (void *)outputCount, NULL, NULL );
0a7de745
A
5568 break;
5569 case 1:
5570 err = (object->*func)( reference,
5571 ARG32(input[0]),
cb323159 5572 output, (void *)outputCount, NULL, NULL, NULL );
0a7de745
A
5573 break;
5574 case 0:
5575 err = (object->*func)( reference,
cb323159 5576 output, (void *)outputCount, NULL, NULL, NULL, NULL );
0a7de745
A
5577 break;
5578
5579 default:
5580 IOLog("%s: Bad method table\n", object->getName());
5581 }
5582 }while (false);
5583
5584 return err;
2d21ac55
A
5585}
5586
5587/* Routine io_connect_method_scalarI_structureI */
0a7de745
A
5588kern_return_t
5589is_io_connect_method_scalarI_structureI(
5590 io_connect_t connect,
5591 uint32_t index,
5592 io_scalar_inband_t input,
5593 mach_msg_type_number_t inputCount,
5594 io_struct_inband_t inputStruct,
5595 mach_msg_type_number_t inputStructCount )
5596{
5597 uint32_t i;
5598 io_scalar_inband64_t _input;
5599
5600 mach_msg_type_number_t scalar_outputCnt = 0;
5601 mach_msg_type_number_t inband_outputCnt = 0;
5602 mach_vm_size_t ool_output_size = 0;
5603
5604 for (i = 0; i < inputCount; i++) {
5605 _input[i] = SCALAR64(input[i]);
2d21ac55 5606 }
1c79356b 5607
0a7de745
A
5608 return is_io_connect_method(connect, index,
5609 _input, inputCount,
5610 inputStruct, inputStructCount,
5611 0, 0,
5612 NULL, &inband_outputCnt,
5613 NULL, &scalar_outputCnt,
5614 0, &ool_output_size);
1c79356b
A
5615}
5616
0a7de745
A
5617kern_return_t
5618shim_io_connect_method_scalarI_structureI(
5619 IOExternalMethod * method,
5620 IOService * object,
5621 const io_user_scalar_t * input,
5622 mach_msg_type_number_t inputCount,
5623 io_struct_inband_t inputStruct,
5624 mach_msg_type_number_t inputStructCount )
5625{
5626 IOMethod func;
5627 IOReturn err = kIOReturnBadArgument;
5628
5629 do{
5630 if (inputCount != method->count0) {
5631 IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0);
5632 DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0);
5633 continue;
5634 }
5635 if ((kIOUCVariableStructureSize != method->count1)
5636 && (inputStructCount != method->count1)) {
5637 IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputStructCount, (uint64_t)method->count1, (uint64_t)kIOUCVariableStructureSize);
5638 DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputStructCount, uint64_t, (uint64_t)method->count1);
5639 continue;
5640 }
5641
5642 func = method->func;
5643
5644 switch (inputCount) {
5645 case 5:
5646 err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5647 ARG32(input[3]), ARG32(input[4]),
5648 inputStruct );
5649 break;
5650 case 4:
5651 err = (object->*func)( ARG32(input[0]), ARG32(input[1]), (void *) input[2],
5652 ARG32(input[3]),
5653 inputStruct, (void *)(uintptr_t)inputStructCount );
5654 break;
5655 case 3:
5656 err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5657 inputStruct, (void *)(uintptr_t)inputStructCount,
cb323159 5658 NULL );
0a7de745
A
5659 break;
5660 case 2:
5661 err = (object->*func)( ARG32(input[0]), ARG32(input[1]),
5662 inputStruct, (void *)(uintptr_t)inputStructCount,
cb323159 5663 NULL, NULL );
0a7de745
A
5664 break;
5665 case 1:
5666 err = (object->*func)( ARG32(input[0]),
5667 inputStruct, (void *)(uintptr_t)inputStructCount,
cb323159 5668 NULL, NULL, NULL );
0a7de745
A
5669 break;
5670 case 0:
5671 err = (object->*func)( inputStruct, (void *)(uintptr_t)inputStructCount,
cb323159 5672 NULL, NULL, NULL, NULL );
0a7de745
A
5673 break;
5674
5675 default:
5676 IOLog("%s: Bad method table\n", object->getName());
5677 }
5678 }while (false);
5679
5680 return err;
5681}
5682
5683kern_return_t
5684shim_io_async_method_scalarI_structureI(
5685 IOExternalAsyncMethod * method,
5686 IOService * object,
2d21ac55
A
5687 mach_port_t asyncWakePort,
5688 io_user_reference_t * asyncReference,
5689 uint32_t asyncReferenceCount,
0a7de745
A
5690 const io_user_scalar_t * input,
5691 mach_msg_type_number_t inputCount,
5692 io_struct_inband_t inputStruct,
5693 mach_msg_type_number_t inputStructCount )
5694{
5695 IOAsyncMethod func;
5696 uint32_t i;
5697 IOReturn err = kIOReturnBadArgument;
5698 io_async_ref_t reference;
5699
5700 for (i = 0; i < asyncReferenceCount; i++) {
5701 reference[i] = REF32(asyncReference[i]);
5702 }
5703
5704 do{
5705 if (inputCount != method->count0) {
5706 IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0);
5707 DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0);
5708 continue;
5709 }
5710 if ((kIOUCVariableStructureSize != method->count1)
5711 && (inputStructCount != method->count1)) {
5712 IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputStructCount, (uint64_t)method->count1, (uint64_t)kIOUCVariableStructureSize);
5713 DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputStructCount, uint64_t, (uint64_t)method->count1);
5714 continue;
5715 }
5716
5717 func = method->func;
5718
5719 switch (inputCount) {
5720 case 5:
5721 err = (object->*func)( reference,
5722 ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5723 ARG32(input[3]), ARG32(input[4]),
5724 inputStruct );
5725 break;
5726 case 4:
5727 err = (object->*func)( reference,
5728 ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5729 ARG32(input[3]),
5730 inputStruct, (void *)(uintptr_t)inputStructCount );
5731 break;
5732 case 3:
5733 err = (object->*func)( reference,
5734 ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
5735 inputStruct, (void *)(uintptr_t)inputStructCount,
cb323159 5736 NULL );
0a7de745
A
5737 break;
5738 case 2:
5739 err = (object->*func)( reference,
5740 ARG32(input[0]), ARG32(input[1]),
5741 inputStruct, (void *)(uintptr_t)inputStructCount,
cb323159 5742 NULL, NULL );
0a7de745
A
5743 break;
5744 case 1:
5745 err = (object->*func)( reference,
5746 ARG32(input[0]),
5747 inputStruct, (void *)(uintptr_t)inputStructCount,
cb323159 5748 NULL, NULL, NULL );
0a7de745
A
5749 break;
5750 case 0:
5751 err = (object->*func)( reference,
5752 inputStruct, (void *)(uintptr_t)inputStructCount,
cb323159 5753 NULL, NULL, NULL, NULL );
0a7de745
A
5754 break;
5755
5756 default:
5757 IOLog("%s: Bad method table\n", object->getName());
5758 }
5759 }while (false);
5760
5761 return err;
2d21ac55
A
5762}
5763
5764/* Routine io_connect_method_structureI_structureO */
0a7de745
A
5765kern_return_t
5766is_io_connect_method_structureI_structureO(
5767 io_object_t connect,
5768 uint32_t index,
5769 io_struct_inband_t input,
5770 mach_msg_type_number_t inputCount,
5771 io_struct_inband_t output,
5772 mach_msg_type_number_t * outputCount )
5773{
5774 mach_msg_type_number_t scalar_outputCnt = 0;
5775 mach_vm_size_t ool_output_size = 0;
5776
5777 return is_io_connect_method(connect, index,
5778 NULL, 0,
5779 input, inputCount,
5780 0, 0,
5781 output, outputCount,
5782 NULL, &scalar_outputCnt,
5783 0, &ool_output_size);
5784}
5785
5786kern_return_t
5787shim_io_connect_method_structureI_structureO(
5788 IOExternalMethod * method,
5789 IOService * object,
5790 io_struct_inband_t input,
5791 mach_msg_type_number_t inputCount,
5792 io_struct_inband_t output,
5793 IOByteCount * outputCount )
5794{
5795 IOMethod func;
5796 IOReturn err = kIOReturnBadArgument;
5797
5798 do{
5799 if ((kIOUCVariableStructureSize != method->count0)
5800 && (inputCount != method->count0)) {
5801 IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0, (uint64_t)kIOUCVariableStructureSize);
5802 DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0);
5803 continue;
5804 }
5805 if ((kIOUCVariableStructureSize != method->count1)
5806 && (*outputCount != method->count1)) {
5807 IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)*outputCount, (uint64_t)method->count1, (uint64_t)kIOUCVariableStructureSize);
5808 DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1);
5809 continue;
5810 }
1c79356b 5811
0a7de745
A
5812 func = method->func;
5813
5814 if (method->count1) {
5815 if (method->count0) {
5816 err = (object->*func)( input, output,
cb323159 5817 (void *)(uintptr_t)inputCount, outputCount, NULL, NULL );
0a7de745 5818 } else {
cb323159 5819 err = (object->*func)( output, outputCount, NULL, NULL, NULL, NULL );
0a7de745
A
5820 }
5821 } else {
cb323159 5822 err = (object->*func)( input, (void *)(uintptr_t)inputCount, NULL, NULL, NULL, NULL );
0a7de745
A
5823 }
5824 }while (false);
1c79356b 5825
0a7de745
A
5826
5827 return err;
1c79356b
A
5828}
5829
0a7de745
A
5830kern_return_t
5831shim_io_async_method_structureI_structureO(
5832 IOExternalAsyncMethod * method,
5833 IOService * object,
2d21ac55
A
5834 mach_port_t asyncWakePort,
5835 io_user_reference_t * asyncReference,
5836 uint32_t asyncReferenceCount,
0a7de745
A
5837 io_struct_inband_t input,
5838 mach_msg_type_number_t inputCount,
5839 io_struct_inband_t output,
5840 mach_msg_type_number_t * outputCount )
5841{
5842 IOAsyncMethod func;
5843 uint32_t i;
5844 IOReturn err;
5845 io_async_ref_t reference;
5846
5847 for (i = 0; i < asyncReferenceCount; i++) {
5848 reference[i] = REF32(asyncReference[i]);
5849 }
5850
5851 err = kIOReturnBadArgument;
5852 do{
5853 if ((kIOUCVariableStructureSize != method->count0)
5854 && (inputCount != method->count0)) {
5855 IOLog("%s:%d %s: IOUserClient inputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)inputCount, (uint64_t)method->count0, (uint64_t)kIOUCVariableStructureSize);
5856 DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)inputCount, uint64_t, (uint64_t)method->count0);
5857 continue;
5858 }
5859 if ((kIOUCVariableStructureSize != method->count1)
5860 && (*outputCount != method->count1)) {
5861 IOLog("%s:%d %s: IOUserClient outputCount count mismatch 0x%llx 0x%llx 0x%llx\n", __FUNCTION__, __LINE__, object->getName(), (uint64_t)*outputCount, (uint64_t)method->count1, (uint64_t)kIOUCVariableStructureSize);
5862 DTRACE_IO2(iokit_count_mismatch, uint64_t, (uint64_t)*outputCount, uint64_t, (uint64_t)method->count1);
5863 continue;
5864 }
5865
5866 func = method->func;
5867
5868 if (method->count1) {
5869 if (method->count0) {
5870 err = (object->*func)( reference,
5871 input, output,
cb323159 5872 (void *)(uintptr_t)inputCount, outputCount, NULL, NULL );
0a7de745
A
5873 } else {
5874 err = (object->*func)( reference,
cb323159 5875 output, outputCount, NULL, NULL, NULL, NULL );
0a7de745
A
5876 }
5877 } else {
5878 err = (object->*func)( reference,
cb323159 5879 input, (void *)(uintptr_t)inputCount, NULL, NULL, NULL, NULL );
0a7de745
A
5880 }
5881 }while (false);
5882
5883 return err;
1c79356b 5884}
2d21ac55 5885
1c79356b 5886/* Routine io_catalog_send_data */
0a7de745
A
5887kern_return_t
5888is_io_catalog_send_data(
5889 mach_port_t master_port,
5890 uint32_t flag,
5891 io_buf_ptr_t inData,
5892 mach_msg_type_number_t inDataCount,
5893 kern_return_t * result)
1c79356b 5894{
4d15aeb1 5895#if NO_KEXTD
0a7de745 5896 return kIOReturnNotPrivileged;
4d15aeb1 5897#else /* NO_KEXTD */
cb323159 5898 OSObject * obj = NULL;
0a7de745
A
5899 vm_offset_t data;
5900 kern_return_t kr = kIOReturnError;
5901
5902 //printf("io_catalog_send_data called. flag: %d\n", flag);
5903
5904 if (master_port != master_device_port) {
5905 return kIOReturnNotPrivileged;
5906 }
5907
cb323159 5908 if ((flag != kIOCatalogRemoveKernelLinker__Removed &&
0a7de745
A
5909 flag != kIOCatalogKextdActive &&
5910 flag != kIOCatalogKextdFinishedLaunching) &&
5911 (!inData || !inDataCount)) {
5912 return kIOReturnBadArgument;
5913 }
5914
f427ee49 5915 if (!IOTaskHasEntitlement(current_task(), kIOCatalogManagementEntitlement)) {
0a7de745
A
5916 OSString * taskName = IOCopyLogNameForPID(proc_selfpid());
5917 IOLog("IOCatalogueSendData(%s): Not entitled\n", taskName ? taskName->getCStringNoCopy() : "");
5918 OSSafeReleaseNULL(taskName);
5919 // For now, fake success to not break applications relying on this function succeeding.
5920 // See <rdar://problem/32554970> for more details.
5921 return kIOReturnSuccess;
5922 }
5923
5924 if (inData) {
5925 vm_map_offset_t map_data;
5926
5927 if (inDataCount > sizeof(io_struct_inband_t) * 1024) {
5928 return kIOReturnMessageTooLarge;
5929 }
5930
5931 kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t)inData);
b0d623f7 5932 data = CAST_DOWN(vm_offset_t, map_data);
91447636 5933
0a7de745
A
5934 if (kr != KERN_SUCCESS) {
5935 return kr;
5936 }
5937
5938 // must return success after vm_map_copyout() succeeds
5939
5940 if (inDataCount) {
5941 obj = (OSObject *)OSUnserializeXML((const char *)data, inDataCount);
5942 vm_deallocate( kernel_map, data, inDataCount );
5943 if (!obj) {
5944 *result = kIOReturnNoMemory;
5945 return KERN_SUCCESS;
5946 }
5947 }
5948 }
5949
5950 switch (flag) {
5951 case kIOCatalogResetDrivers:
5952 case kIOCatalogResetDriversNoMatch: {
5953 OSArray * array;
5954
5955 array = OSDynamicCast(OSArray, obj);
5956 if (array) {
5957 if (!gIOCatalogue->resetAndAddDrivers(array,
5958 flag == kIOCatalogResetDrivers)) {
5959 kr = kIOReturnError;
5960 }
5961 } else {
5962 kr = kIOReturnBadArgument;
5963 }
5964 }
5965 break;
5966
5967 case kIOCatalogAddDrivers:
5968 case kIOCatalogAddDriversNoMatch: {
5969 OSArray * array;
5970
5971 array = OSDynamicCast(OSArray, obj);
5972 if (array) {
5973 if (!gIOCatalogue->addDrivers( array,
5974 flag == kIOCatalogAddDrivers)) {
5975 kr = kIOReturnError;
5976 }
5977 } else {
5978 kr = kIOReturnBadArgument;
5979 }
5980 }
5981 break;
5982
5983 case kIOCatalogRemoveDrivers:
5984 case kIOCatalogRemoveDriversNoMatch: {
5985 OSDictionary * dict;
5986
5987 dict = OSDynamicCast(OSDictionary, obj);
5988 if (dict) {
5989 if (!gIOCatalogue->removeDrivers( dict,
5990 flag == kIOCatalogRemoveDrivers )) {
5991 kr = kIOReturnError;
5992 }
5993 } else {
5994 kr = kIOReturnBadArgument;
5995 }
5996 }
5997 break;
5998
cb323159
A
5999 case kIOCatalogStartMatching__Removed:
6000 case kIOCatalogRemoveKernelLinker__Removed:
0a7de745 6001 case kIOCatalogKextdActive:
f427ee49
A
6002 case kIOCatalogKextdFinishedLaunching:
6003 kr = KERN_NOT_SUPPORTED;
0a7de745 6004 break;
1c79356b 6005
0a7de745
A
6006 default:
6007 kr = kIOReturnBadArgument;
6008 break;
6009 }
1c79356b 6010
0a7de745
A
6011 if (obj) {
6012 obj->release();
6013 }
4d15aeb1 6014
0a7de745
A
6015 *result = kr;
6016 return KERN_SUCCESS;
4d15aeb1 6017#endif /* NO_KEXTD */
1c79356b
A
6018}
6019
6020/* Routine io_catalog_terminate */
0a7de745
A
6021kern_return_t
6022is_io_catalog_terminate(
1c79356b 6023 mach_port_t master_port,
2d21ac55 6024 uint32_t flag,
1c79356b
A
6025 io_name_t name )
6026{
0a7de745 6027 kern_return_t kr;
1c79356b 6028
0a7de745
A
6029 if (master_port != master_device_port) {
6030 return kIOReturnNotPrivileged;
6031 }
1c79356b 6032
0a7de745
A
6033 kr = IOUserClient::clientHasPrivilege((void *) current_task(),
6034 kIOClientPrivilegeAdministrator );
6035 if (kIOReturnSuccess != kr) {
6036 return kr;
6037 }
1c79356b 6038
0a7de745 6039 switch (flag) {
6d2010ae 6040#if !defined(SECURE_KERNEL)
0a7de745 6041 case kIOCatalogServiceTerminate:
ea3f0419 6042 kr = gIOCatalogue->terminateDrivers(NULL, name);
0a7de745
A
6043 break;
6044
6045 case kIOCatalogModuleUnload:
6046 case kIOCatalogModuleTerminate:
6047 kr = gIOCatalogue->terminateDriversForModule(name,
6048 flag == kIOCatalogModuleUnload);
6049 break;
6d2010ae 6050#endif
1c79356b 6051
0a7de745
A
6052 default:
6053 kr = kIOReturnBadArgument;
6054 break;
6055 }
1c79356b 6056
0a7de745 6057 return kr;
1c79356b
A
6058}
6059
6060/* Routine io_catalog_get_data */
0a7de745
A
6061kern_return_t
6062is_io_catalog_get_data(
6063 mach_port_t master_port,
6064 uint32_t flag,
6065 io_buf_ptr_t *outData,
6066 mach_msg_type_number_t *outDataCount)
6067{
6068 kern_return_t kr = kIOReturnSuccess;
6069 OSSerialize * s;
6070
6071 if (master_port != master_device_port) {
6072 return kIOReturnNotPrivileged;
6073 }
6074
6075 //printf("io_catalog_get_data called. flag: %d\n", flag);
6076
6077 s = OSSerialize::withCapacity(4096);
6078 if (!s) {
6079 return kIOReturnNoMemory;
6080 }
6081
6082 kr = gIOCatalogue->serializeData(flag, s);
6083
6084 if (kr == kIOReturnSuccess) {
6085 vm_offset_t data;
6086 vm_map_copy_t copy;
f427ee49 6087 unsigned int size;
0a7de745
A
6088
6089 size = s->getLength();
6090 kr = vm_allocate_kernel(kernel_map, &data, size, VM_FLAGS_ANYWHERE, VM_KERN_MEMORY_IOKIT);
6091 if (kr == kIOReturnSuccess) {
6092 bcopy(s->text(), (void *)data, size);
6093 kr = vm_map_copyin(kernel_map, (vm_map_address_t)data,
f427ee49 6094 size, true, &copy);
0a7de745
A
6095 *outData = (char *)copy;
6096 *outDataCount = size;
6097 }
6098 }
6099
6100 s->release();
6101
6102 return kr;
1c79356b
A
6103}
6104
6105/* Routine io_catalog_get_gen_count */
0a7de745
A
6106kern_return_t
6107is_io_catalog_get_gen_count(
6108 mach_port_t master_port,
6109 uint32_t *genCount)
1c79356b 6110{
0a7de745
A
6111 if (master_port != master_device_port) {
6112 return kIOReturnNotPrivileged;
6113 }
1c79356b 6114
0a7de745
A
6115 //printf("io_catalog_get_gen_count called.\n");
6116
6117 if (!genCount) {
6118 return kIOReturnBadArgument;
6119 }
1c79356b 6120
0a7de745 6121 *genCount = gIOCatalogue->getGenerationCount();
1c79356b 6122
0a7de745 6123 return kIOReturnSuccess;
1c79356b
A
6124}
6125
b0d623f7
A
6126/* Routine io_catalog_module_loaded.
6127 * Is invoked from IOKitLib's IOCatalogueModuleLoaded(). Doesn't seem to be used.
6128 */
0a7de745
A
6129kern_return_t
6130is_io_catalog_module_loaded(
6131 mach_port_t master_port,
6132 io_name_t name)
1c79356b 6133{
0a7de745
A
6134 if (master_port != master_device_port) {
6135 return kIOReturnNotPrivileged;
6136 }
1c79356b 6137
0a7de745
A
6138 //printf("io_catalog_module_loaded called. name %s\n", name);
6139
6140 if (!name) {
6141 return kIOReturnBadArgument;
6142 }
6143
6144 gIOCatalogue->moduleHasLoaded(name);
6145
6146 return kIOReturnSuccess;
1c79356b
A
6147}
6148
0a7de745
A
6149kern_return_t
6150is_io_catalog_reset(
6151 mach_port_t master_port,
6152 uint32_t flag)
1c79356b 6153{
0a7de745
A
6154 if (master_port != master_device_port) {
6155 return kIOReturnNotPrivileged;
6156 }
1c79356b 6157
0a7de745
A
6158 switch (flag) {
6159 case kIOCatalogResetDefault:
6160 gIOCatalogue->reset();
6161 break;
6162
6163 default:
6164 return kIOReturnBadArgument;
6165 }
1c79356b 6166
0a7de745 6167 return kIOReturnSuccess;
1c79356b
A
6168}
6169
0a7de745
A
6170kern_return_t
6171iokit_user_client_trap(struct iokit_user_client_trap_args *args)
1c79356b 6172{
cb323159
A
6173 kern_return_t result = kIOReturnBadArgument;
6174 IOUserClient * userClient;
6175 OSObject * object;
6176 uintptr_t ref;
1c79356b 6177
cb323159
A
6178 ref = (uintptr_t) args->userClientRef;
6179 if ((1ULL << 32) & ref) {
6180 object = iokit_lookup_uext_ref_current_task((mach_port_name_t) ref);
6181 if (object) {
6182 result = IOUserServerUEXTTrap(object, args->p1, args->p2, args->p3, args->p4, args->p5, args->p6);
6183 }
6184 OSSafeReleaseNULL(object);
6185 } else if ((userClient = OSDynamicCast(IOUserClient, iokit_lookup_connect_ref_current_task((mach_port_name_t) ref)))) {
f427ee49 6186 IOExternalTrap *trap = NULL;
0a7de745 6187 IOService *target = NULL;
1c79356b 6188
f427ee49
A
6189 result = kIOReturnSuccess;
6190 io_filter_policy_t filterPolicy = userClient->filterForTask(current_task(), 0);
6191 if (filterPolicy && gIOUCFilterCallbacks->io_filter_applier) {
6192 result = gIOUCFilterCallbacks->io_filter_applier(filterPolicy, io_filter_type_trap, args->index);
6193 }
6194 if (kIOReturnSuccess == result) {
6195 trap = userClient->getTargetAndTrapForIndex(&target, args->index);
6196 }
0a7de745
A
6197 if (trap && target) {
6198 IOTrap func;
1c79356b 6199
0a7de745 6200 func = trap->func;
1c79356b 6201
0a7de745
A
6202 if (func) {
6203 result = (target->*func)(args->p1, args->p2, args->p3, args->p4, args->p5, args->p6);
6204 }
6205 }
1c79356b 6206
0a7de745
A
6207 iokit_remove_connect_reference(userClient);
6208 }
1c79356b 6209
0a7de745 6210 return result;
1c79356b
A
6211}
6212
a39ff7e2 6213/* Routine io_device_tree_entry_exists_with_name */
0a7de745
A
6214kern_return_t
6215is_io_device_tree_entry_exists_with_name(
a39ff7e2
A
6216 mach_port_t master_port,
6217 io_name_t name,
6218 boolean_t *exists )
6219{
6220 OSCollectionIterator *iter;
6221
0a7de745
A
6222 if (master_port != master_device_port) {
6223 return kIOReturnNotPrivileged;
6224 }
a39ff7e2
A
6225
6226 iter = IODTFindMatchingEntries(IORegistryEntry::getRegistryRoot(), kIODTRecursive, name);
6227 *exists = iter && iter->getNextObject();
6228 OSSafeReleaseNULL(iter);
6229
6230 return kIOReturnSuccess;
6231}
6d2010ae
A
6232} /* extern "C" */
6233
0a7de745
A
6234IOReturn
6235IOUserClient::externalMethod( uint32_t selector, IOExternalMethodArguments * args,
6236 IOExternalMethodDispatch * dispatch, OSObject * target, void * reference )
6237{
6238 IOReturn err;
6239 IOService * object;
6240 IOByteCount structureOutputSize;
6241
6242 if (dispatch) {
6243 uint32_t count;
6244 count = dispatch->checkScalarInputCount;
6245 if ((kIOUCVariableStructureSize != count) && (count != args->scalarInputCount)) {
6246 return kIOReturnBadArgument;
6247 }
2d21ac55 6248
0a7de745
A
6249 count = dispatch->checkStructureInputSize;
6250 if ((kIOUCVariableStructureSize != count)
6251 && (count != ((args->structureInputDescriptor)
6252 ? args->structureInputDescriptor->getLength() : args->structureInputSize))) {
6253 return kIOReturnBadArgument;
6254 }
2d21ac55 6255
0a7de745
A
6256 count = dispatch->checkScalarOutputCount;
6257 if ((kIOUCVariableStructureSize != count) && (count != args->scalarOutputCount)) {
6258 return kIOReturnBadArgument;
6259 }
2d21ac55 6260
0a7de745
A
6261 count = dispatch->checkStructureOutputSize;
6262 if ((kIOUCVariableStructureSize != count)
6263 && (count != ((args->structureOutputDescriptor)
6264 ? args->structureOutputDescriptor->getLength() : args->structureOutputSize))) {
6265 return kIOReturnBadArgument;
6266 }
2d21ac55 6267
0a7de745
A
6268 if (dispatch->function) {
6269 err = (*dispatch->function)(target, reference, args);
6270 } else {
6271 err = kIOReturnNoCompletion; /* implementator can dispatch */
6272 }
6273 return err;
6274 }
2d21ac55 6275
0a7de745
A
6276
6277 // pre-Leopard API's don't do ool structs
6278 if (args->structureInputDescriptor || args->structureOutputDescriptor) {
6279 err = kIOReturnIPCError;
6280 return err;
2d21ac55 6281 }
2d21ac55 6282
0a7de745 6283 structureOutputSize = args->structureOutputSize;
2d21ac55 6284
0a7de745
A
6285 if (args->asyncWakePort) {
6286 IOExternalAsyncMethod * method;
cb323159 6287 object = NULL;
0a7de745
A
6288 if (!(method = getAsyncTargetAndMethodForIndex(&object, selector)) || !object) {
6289 return kIOReturnUnsupported;
6290 }
2d21ac55 6291
0a7de745
A
6292 if (kIOUCForegroundOnly & method->flags) {
6293 if (task_is_gpu_denied(current_task())) {
6294 return kIOReturnNotPermitted;
6295 }
6296 }
2d21ac55 6297
0a7de745
A
6298 switch (method->flags & kIOUCTypeMask) {
6299 case kIOUCScalarIStructI:
6300 err = shim_io_async_method_scalarI_structureI( method, object,
6301 args->asyncWakePort, args->asyncReference, args->asyncReferenceCount,
6302 args->scalarInput, args->scalarInputCount,
6303 (char *)args->structureInput, args->structureInputSize );
6304 break;
6305
6306 case kIOUCScalarIScalarO:
6307 err = shim_io_async_method_scalarI_scalarO( method, object,
6308 args->asyncWakePort, args->asyncReference, args->asyncReferenceCount,
6309 args->scalarInput, args->scalarInputCount,
6310 args->scalarOutput, &args->scalarOutputCount );
6311 break;
6312
6313 case kIOUCScalarIStructO:
6314 err = shim_io_async_method_scalarI_structureO( method, object,
6315 args->asyncWakePort, args->asyncReference, args->asyncReferenceCount,
6316 args->scalarInput, args->scalarInputCount,
6317 (char *) args->structureOutput, &args->structureOutputSize );
6318 break;
6319
6320
6321 case kIOUCStructIStructO:
6322 err = shim_io_async_method_structureI_structureO( method, object,
6323 args->asyncWakePort, args->asyncReference, args->asyncReferenceCount,
6324 (char *)args->structureInput, args->structureInputSize,
6325 (char *) args->structureOutput, &args->structureOutputSize );
6326 break;
6327
6328 default:
6329 err = kIOReturnBadArgument;
6330 break;
6331 }
6332 } else {
6333 IOExternalMethod * method;
cb323159 6334 object = NULL;
0a7de745
A
6335 if (!(method = getTargetAndMethodForIndex(&object, selector)) || !object) {
6336 return kIOReturnUnsupported;
6337 }
2d21ac55 6338
0a7de745
A
6339 if (kIOUCForegroundOnly & method->flags) {
6340 if (task_is_gpu_denied(current_task())) {
6341 return kIOReturnNotPermitted;
6342 }
6343 }
6344
6345 switch (method->flags & kIOUCTypeMask) {
6346 case kIOUCScalarIStructI:
6347 err = shim_io_connect_method_scalarI_structureI( method, object,
6348 args->scalarInput, args->scalarInputCount,
6349 (char *) args->structureInput, args->structureInputSize );
6350 break;
6351
6352 case kIOUCScalarIScalarO:
6353 err = shim_io_connect_method_scalarI_scalarO( method, object,
6354 args->scalarInput, args->scalarInputCount,
6355 args->scalarOutput, &args->scalarOutputCount );
6356 break;
6357
6358 case kIOUCScalarIStructO:
6359 err = shim_io_connect_method_scalarI_structureO( method, object,
6360 args->scalarInput, args->scalarInputCount,
6361 (char *) args->structureOutput, &structureOutputSize );
6362 break;
6363
6364
6365 case kIOUCStructIStructO:
6366 err = shim_io_connect_method_structureI_structureO( method, object,
6367 (char *) args->structureInput, args->structureInputSize,
6368 (char *) args->structureOutput, &structureOutputSize );
6369 break;
6370
6371 default:
6372 err = kIOReturnBadArgument;
6373 break;
6374 }
2d21ac55 6375 }
b0d623f7 6376
f427ee49
A
6377 if (structureOutputSize > UINT_MAX) {
6378 structureOutputSize = 0;
6379 err = kIOReturnBadArgument;
6380 }
6381
6382 args->structureOutputSize = ((typeof(args->structureOutputSize))structureOutputSize);
b0d623f7 6383
0a7de745 6384 return err;
2d21ac55
A
6385}
6386
f427ee49
A
6387IOReturn
6388IOUserClient::registerFilterCallbacks(const struct io_filter_callbacks *callbacks, size_t size)
6389{
6390 if (size < sizeof(*callbacks)) {
6391 return kIOReturnBadArgument;
6392 }
6393 if (!OSCompareAndSwapPtr(NULL, __DECONST(void *, callbacks), &gIOUCFilterCallbacks)) {
6394 return kIOReturnBusy;
6395 }
6396 return kIOReturnSuccess;
6397}
6398
b0d623f7
A
6399#if __LP64__
6400OSMetaClassDefineReservedUnused(IOUserClient, 0);
1c79356b 6401OSMetaClassDefineReservedUnused(IOUserClient, 1);
b0d623f7
A
6402#else
6403OSMetaClassDefineReservedUsed(IOUserClient, 0);
6404OSMetaClassDefineReservedUsed(IOUserClient, 1);
6405#endif
1c79356b
A
6406OSMetaClassDefineReservedUnused(IOUserClient, 2);
6407OSMetaClassDefineReservedUnused(IOUserClient, 3);
6408OSMetaClassDefineReservedUnused(IOUserClient, 4);
6409OSMetaClassDefineReservedUnused(IOUserClient, 5);
6410OSMetaClassDefineReservedUnused(IOUserClient, 6);
6411OSMetaClassDefineReservedUnused(IOUserClient, 7);
6412OSMetaClassDefineReservedUnused(IOUserClient, 8);
6413OSMetaClassDefineReservedUnused(IOUserClient, 9);
6414OSMetaClassDefineReservedUnused(IOUserClient, 10);
6415OSMetaClassDefineReservedUnused(IOUserClient, 11);
6416OSMetaClassDefineReservedUnused(IOUserClient, 12);
6417OSMetaClassDefineReservedUnused(IOUserClient, 13);
6418OSMetaClassDefineReservedUnused(IOUserClient, 14);
6419OSMetaClassDefineReservedUnused(IOUserClient, 15);