1/*
2 * Copyright (c) 1998-2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29
30#include <libkern/c++/OSKext.h>
31#include <IOKit/IOKitServer.h>
32#include <IOKit/IOKitKeysPrivate.h>
33#include <IOKit/IOUserClient.h>
34#include <IOKit/IOService.h>
35#include <IOKit/IORegistryEntry.h>
36#include <IOKit/IOCatalogue.h>
37#include <IOKit/IOMemoryDescriptor.h>
38#include <IOKit/IOBufferMemoryDescriptor.h>
39#include <IOKit/IOLib.h>
40#include <IOKit/IOStatisticsPrivate.h>
41#include <IOKit/IOTimeStamp.h>
42#include <IOKit/system.h>
43#include <libkern/OSDebug.h>
44#include <sys/proc.h>
45#include <sys/kauth.h>
46
47#if CONFIG_MACF
48
49extern "C" {
50#include <security/mac_framework.h>
51};
52#include <sys/kauth.h>
53
54#define IOMACF_LOG 0
55
56#endif /* CONFIG_MACF */
57
58#include <IOKit/assert.h>
59
60#include "IOServicePrivate.h"
61#include "IOKitKernelInternal.h"
62
63#define SCALAR64(x) ((io_user_scalar_t)((unsigned int)x))
64#define SCALAR32(x) ((uint32_t )x)
65#define ARG32(x)    ((void *)(uintptr_t)SCALAR32(x))
66#define REF64(x)    ((io_user_reference_t)((UInt64)(x)))
67#define REF32(x)    ((int)(x))
68
69enum
70{
71    kIOUCAsync0Flags = 3ULL,
72    kIOUCAsync64Flag = 1ULL
73};
74
75#if IOKITSTATS
76
77#define IOStatisticsRegisterCounter() \
78do { \
79	reserved->counter = IOStatistics::registerUserClient(this); \
80} while (0)
81
82#define IOStatisticsUnregisterCounter() \
83do { \
84	if (reserved) \
85		IOStatistics::unregisterUserClient(reserved->counter); \
86} while (0)
87
88#define IOStatisticsClientCall() \
89do { \
90	IOStatistics::countUserClientCall(client); \
91} while (0)
92
93#else
94
95#define IOStatisticsRegisterCounter()
96#define IOStatisticsUnregisterCounter()
97#define IOStatisticsClientCall()
98
99#endif /* IOKITSTATS */
100
101/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
102
103// definitions we should get from osfmk
104
105//typedef struct ipc_port * ipc_port_t;
106typedef natural_t ipc_kobject_type_t;
107
108#define IKOT_IOKIT_SPARE	27
109#define IKOT_IOKIT_CONNECT	29
110#define IKOT_IOKIT_OBJECT	30
111
112extern "C" {
113
114extern ipc_port_t iokit_alloc_object_port( io_object_t obj,
115			ipc_kobject_type_t type );
116
117extern kern_return_t iokit_destroy_object_port( ipc_port_t port );
118
119extern mach_port_name_t iokit_make_send_right( task_t task,
120				io_object_t obj, ipc_kobject_type_t type );
121
122extern kern_return_t iokit_mod_send_right( task_t task, mach_port_name_t name, mach_port_delta_t delta );
123
124extern io_object_t iokit_lookup_connect_ref(io_object_t clientRef, ipc_space_t task);
125
126extern io_object_t iokit_lookup_connect_ref_current_task(io_object_t clientRef);
127
128extern ipc_port_t master_device_port;
129
130extern void iokit_retain_port( ipc_port_t port );
131extern void iokit_release_port( ipc_port_t port );
132extern void iokit_release_port_send( ipc_port_t port );
133
134extern kern_return_t iokit_switch_object_port( ipc_port_t port, io_object_t obj, ipc_kobject_type_t type );
135
136#include <mach/mach_traps.h>
137#include <vm/vm_map.h>
138
139} /* extern "C" */
140
141
142/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
143
144// IOMachPort maps OSObjects to ports, avoiding adding an ivar to OSObject.
145
146class IOMachPort : public OSObject
147{
148    OSDeclareDefaultStructors(IOMachPort)
149public:
150    OSObject *	object;
151    ipc_port_t	port;
152    UInt32      mscount;
153    UInt8	holdDestroy;
154
155    static IOMachPort * portForObject( OSObject * obj,
156				ipc_kobject_type_t type );
157    static bool noMoreSendersForObject( OSObject * obj,
158				ipc_kobject_type_t type, mach_port_mscount_t * mscount );
159    static void releasePortForObject( OSObject * obj,
160				ipc_kobject_type_t type );
161    static void setHoldDestroy( OSObject * obj, ipc_kobject_type_t type );
162
163    static OSDictionary * dictForType( ipc_kobject_type_t type );
164
165    static mach_port_name_t makeSendRightForTask( task_t task,
166				io_object_t obj, ipc_kobject_type_t type );
167
168    virtual void free();
169};
170
171#define super OSObject
172OSDefineMetaClassAndStructors(IOMachPort, OSObject)
173
174static IOLock *		gIOObjectPortLock;
175
176/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
177
178// not in dictForType() for debugging ease
179static OSDictionary *	gIOObjectPorts;
180static OSDictionary *	gIOConnectPorts;
181
182OSDictionary * IOMachPort::dictForType( ipc_kobject_type_t type )
183{
184    OSDictionary **	 	dict;
185
186    if( IKOT_IOKIT_OBJECT == type )
187	dict = &gIOObjectPorts;
188    else if( IKOT_IOKIT_CONNECT == type )
189	dict = &gIOConnectPorts;
190    else
191	return( 0 );
192
193    if( 0 == *dict)
194        *dict = OSDictionary::withCapacity( 1 );
195
196    return( *dict );
197}
198
199IOMachPort * IOMachPort::portForObject ( OSObject * obj,
200				ipc_kobject_type_t type )
201{
202    IOMachPort * 	inst = 0;
203    OSDictionary *	dict;
204
205    IOTakeLock( gIOObjectPortLock);
206
207    do {
208
209	dict = dictForType( type );
210	if( !dict)
211	    continue;
212
213        if( (inst = (IOMachPort *)
214                dict->getObject( (const OSSymbol *) obj ))) {
215	    inst->mscount++;
216	    inst->retain();
217            continue;
218	}
219
220        inst = new IOMachPort;
221        if( inst && !inst->init()) {
222            inst = 0;
223            continue;
224	}
225
226        inst->port = iokit_alloc_object_port( obj, type );
227        if( inst->port) {
228	    // retains obj
229            dict->setObject( (const OSSymbol *) obj, inst );
230	    inst->mscount++;
231
232        } else {
233            inst->release();
234            inst = 0;
235        }
236
237    } while( false );
238
239    IOUnlock( gIOObjectPortLock);
240
241    return( inst );
242}
243
244bool IOMachPort::noMoreSendersForObject( OSObject * obj,
245				ipc_kobject_type_t type, mach_port_mscount_t * mscount )
246{
247    OSDictionary *	dict;
248    IOMachPort *	machPort;
249    bool		destroyed = true;
250
251    IOTakeLock( gIOObjectPortLock);
252
253    if( (dict = dictForType( type ))) {
254        obj->retain();
255
256	machPort = (IOMachPort *) dict->getObject( (const OSSymbol *) obj );
257	if( machPort) {
258	    destroyed = (machPort->mscount <= *mscount);
259	    if( destroyed)
260		dict->removeObject( (const OSSymbol *) obj );
261	    else
262		*mscount = machPort->mscount;
263	}
264	obj->release();
265    }
266
267    IOUnlock( gIOObjectPortLock);
268
269    return( destroyed );
270}
271
272void IOMachPort::releasePortForObject( OSObject * obj,
273				ipc_kobject_type_t type )
274{
275    OSDictionary *	dict;
276    IOMachPort *	machPort;
277
278    IOTakeLock( gIOObjectPortLock);
279
280    if( (dict = dictForType( type ))) {
281        obj->retain();
282	machPort = (IOMachPort *) dict->getObject( (const OSSymbol *) obj );
283	if( machPort && !machPort->holdDestroy)
284            dict->removeObject( (const OSSymbol *) obj );
285        obj->release();
286    }
287
288    IOUnlock( gIOObjectPortLock);
289}
290
291void IOMachPort::setHoldDestroy( OSObject * obj, ipc_kobject_type_t type )
292{
293    OSDictionary *	dict;
294    IOMachPort * 	machPort;
295
296    IOLockLock( gIOObjectPortLock );
297
298    if( (dict = dictForType( type ))) {
299        machPort = (IOMachPort *) dict->getObject( (const OSSymbol *) obj );
300        if( machPort)
301            machPort->holdDestroy = true;
302    }
303
304    IOLockUnlock( gIOObjectPortLock );
305}
306
307void IOUserClient::destroyUserReferences( OSObject * obj )
308{
309    IOMachPort::releasePortForObject( obj, IKOT_IOKIT_OBJECT );
310
311    // panther, 3160200
312    // IOMachPort::releasePortForObject( obj, IKOT_IOKIT_CONNECT );
313
314    OSDictionary * dict;
315
316    IOTakeLock( gIOObjectPortLock);
317    obj->retain();
318
319    if( (dict = IOMachPort::dictForType( IKOT_IOKIT_CONNECT )))
320    {
321	IOMachPort * port;
322	port = (IOMachPort *) dict->getObject( (const OSSymbol *) obj );
323	if (port)
324	{
325	    IOUserClient * uc;
326	    if ((uc = OSDynamicCast(IOUserClient, obj)) && uc->mappings)
327	    {
328		dict->setObject((const OSSymbol *) uc->mappings, port);
329		iokit_switch_object_port(port->port, uc->mappings, IKOT_IOKIT_CONNECT);
330
331		uc->mappings->release();
332		uc->mappings = 0;
333	    }
334	    dict->removeObject( (const OSSymbol *) obj );
335	}
336    }
337    obj->release();
338    IOUnlock( gIOObjectPortLock);
339}
340
341mach_port_name_t IOMachPort::makeSendRightForTask( task_t task,
342				io_object_t obj, ipc_kobject_type_t type )
343{
344    return( iokit_make_send_right( task, obj, type ));
345}
346
347void IOMachPort::free( void )
348{
349    if( port)
350	iokit_destroy_object_port( port );
351    super::free();
352}
353
354/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
355
356class IOUserNotification : public OSIterator
357{
358    OSDeclareDefaultStructors(IOUserNotification)
359
360    IONotifier 	* 	holdNotify;
361    IOLock 	*	lock;
362
363public:
364
365    virtual bool init( void );
366    virtual void free();
367
368    virtual void setNotification( IONotifier * obj );
369
370    virtual void reset();
371    virtual bool isValid();
372};
373
374/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
375
376extern "C" {
377
378// functions called from osfmk/device/iokit_rpc.c
379
380void
381iokit_add_reference( io_object_t obj )
382{
383    if( obj)
384	obj->retain();
385}
386
387void
388iokit_remove_reference( io_object_t obj )
389{
390    if( obj)
391	obj->release();
392}
393
394ipc_port_t
395iokit_port_for_object( io_object_t obj, ipc_kobject_type_t type )
396{
397    IOMachPort * machPort;
398    ipc_port_t	 port;
399
400    if( (machPort = IOMachPort::portForObject( obj, type ))) {
401
402	port = machPort->port;
403	if( port)
404	    iokit_retain_port( port );
405
406	machPort->release();
407
408    } else
409	port = NULL;
410
411    return( port );
412}
413
414kern_return_t
415iokit_client_died( io_object_t obj, ipc_port_t /* port */,
416			ipc_kobject_type_t type, mach_port_mscount_t * mscount )
417{
418    IOUserClient *	client;
419    IOMemoryMap *	map;
420    IOUserNotification * notify;
421
422    if( !IOMachPort::noMoreSendersForObject( obj, type, mscount ))
423	return( kIOReturnNotReady );
424
425    if( IKOT_IOKIT_CONNECT == type)
426    {
427	if( (client = OSDynamicCast( IOUserClient, obj ))) {
428		IOStatisticsClientCall();
429	    client->clientDied();
430    }
431    }
432    else if( IKOT_IOKIT_OBJECT == type)
433    {
434	if( (map = OSDynamicCast( IOMemoryMap, obj )))
435	    map->taskDied();
436	else if( (notify = OSDynamicCast( IOUserNotification, obj )))
437	    notify->setNotification( 0 );
438    }
439
440    return( kIOReturnSuccess );
441}
442
443};	/* extern "C" */
444
445/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
446
447class IOServiceUserNotification : public IOUserNotification
448{
449    OSDeclareDefaultStructors(IOServiceUserNotification)
450
451    struct PingMsg {
452        mach_msg_header_t		msgHdr;
453        OSNotificationHeader64		notifyHeader;
454    };
455
456    enum { kMaxOutstanding = 1024 };
457
458    PingMsg	*	pingMsg;
459    vm_size_t		msgSize;
460    OSArray 	*	newSet;
461    OSObject	*	lastEntry;
462    bool		armed;
463
464public:
465
466    virtual bool init( mach_port_t port, natural_t type,
467                       void * reference, vm_size_t referenceSize,
468		       bool clientIs64 );
469    virtual void free();
470
471    static bool _handler( void * target,
472                          void * ref, IOService * newService, IONotifier * notifier );
473    virtual bool handler( void * ref, IOService * newService );
474
475    virtual OSObject * getNextObject();
476};
477
478class IOServiceMessageUserNotification : public IOUserNotification
479{
480    OSDeclareDefaultStructors(IOServiceMessageUserNotification)
481
482    struct PingMsg {
483        mach_msg_header_t		msgHdr;
484	mach_msg_body_t			msgBody;
485	mach_msg_port_descriptor_t	ports[1];
486        OSNotificationHeader64		notifyHeader __attribute__ ((packed));
487    };
488
489    PingMsg *		pingMsg;
490    vm_size_t		msgSize;
491    uint8_t		clientIs64;
492    int			owningPID;
493
494public:
495
496    virtual bool init( mach_port_t port, natural_t type,
497		       void * reference, vm_size_t referenceSize,
498		       vm_size_t extraSize,
499		       bool clientIs64 );
500
501    virtual void free();
502
503    static IOReturn _handler( void * target, void * ref,
504                              UInt32 messageType, IOService * provider,
505                              void * messageArgument, vm_size_t argSize );
506    virtual IOReturn handler( void * ref,
507                              UInt32 messageType, IOService * provider,
508                              void * messageArgument, vm_size_t argSize );
509
510    virtual OSObject * getNextObject();
511};
512
513/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
514
515#undef super
516#define super OSIterator
517OSDefineMetaClass( IOUserNotification, OSIterator )
518OSDefineAbstractStructors( IOUserNotification, OSIterator )
519
520/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
521
522bool IOUserNotification::init( void )
523{
524    if( !super::init())
525	return( false );
526
527    lock = IOLockAlloc();
528    if( !lock)
529        return( false );
530
531    return( true );
532}
533
534void IOUserNotification::free( void )
535{
536    if( holdNotify)
537	holdNotify->remove();
538    // can't be in handler now
539
540    if( lock)
541	IOLockFree( lock );
542
543    super::free();
544}
545
546
547void IOUserNotification::setNotification( IONotifier * notify )
548{
549    IONotifier * previousNotify;
550
551    IOLockLock( gIOObjectPortLock);
552
553    previousNotify = holdNotify;
554    holdNotify = notify;
555
556    IOLockUnlock( gIOObjectPortLock);
557
558    if( previousNotify)
559	previousNotify->remove();
560}
561
562void IOUserNotification::reset()
563{
564    // ?
565}
566
567bool IOUserNotification::isValid()
568{
569    return( true );
570}
571
572/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
573
574#undef super
575#define super IOUserNotification
576OSDefineMetaClassAndStructors(IOServiceUserNotification, IOUserNotification)
577
578/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
579
580bool IOServiceUserNotification::init( mach_port_t port, natural_t type,
581				       void * reference, vm_size_t referenceSize,
582				       bool clientIs64 )
583{
584    if( !super::init())
585        return( false );
586
587    newSet = OSArray::withCapacity( 1 );
588    if( !newSet)
589        return( false );
590
591    if (referenceSize > sizeof(OSAsyncReference64))
592        return( false );
593
594    msgSize = sizeof(PingMsg) - sizeof(OSAsyncReference64) + referenceSize;
595    pingMsg = (PingMsg *) IOMalloc( msgSize);
596    if( !pingMsg)
597        return( false );
598
599    bzero( pingMsg, msgSize);
600
601    pingMsg->msgHdr.msgh_remote_port	= port;
602    pingMsg->msgHdr.msgh_bits 		= MACH_MSGH_BITS(
603                                            MACH_MSG_TYPE_COPY_SEND /*remote*/,
604                                            MACH_MSG_TYPE_MAKE_SEND /*local*/);
605    pingMsg->msgHdr.msgh_size 		= msgSize;
606    pingMsg->msgHdr.msgh_id		= kOSNotificationMessageID;
607
608    pingMsg->notifyHeader.size = 0;
609    pingMsg->notifyHeader.type = type;
610    bcopy( reference, pingMsg->notifyHeader.reference, referenceSize );
611
612    return( true );
613}
614
615void IOServiceUserNotification::free( void )
616{
617    PingMsg   *	_pingMsg;
618    vm_size_t	_msgSize;
619    OSArray   *	_newSet;
620    OSObject  *	_lastEntry;
621
622    _pingMsg   = pingMsg;
623    _msgSize   = msgSize;
624    _lastEntry = lastEntry;
625    _newSet    = newSet;
626
627    super::free();
628
629    if( _pingMsg && _msgSize) {
630		if (_pingMsg->msgHdr.msgh_remote_port) {
631			iokit_release_port_send(_pingMsg->msgHdr.msgh_remote_port);
632		}
633        IOFree(_pingMsg, _msgSize);
634	}
635
636    if( _lastEntry)
637        _lastEntry->release();
638
639    if( _newSet)
640        _newSet->release();
641}
642
643bool IOServiceUserNotification::_handler( void * target,
644                                    void * ref, IOService * newService, IONotifier * notifier )
645{
646    return( ((IOServiceUserNotification *) target)->handler( ref, newService ));
647}
648
649bool IOServiceUserNotification::handler( void * ref,
650                                IOService * newService )
651{
652    unsigned int	count;
653    kern_return_t	kr;
654    ipc_port_t		port = NULL;
655    bool		sendPing = false;
656
657    IOTakeLock( lock );
658
659    count = newSet->getCount();
660    if( count < kMaxOutstanding) {
661
662        newSet->setObject( newService );
663        if( (sendPing = (armed && (0 == count))))
664            armed = false;
665    }
666
667    IOUnlock( lock );
668
669    if( kIOServiceTerminatedNotificationType == pingMsg->notifyHeader.type)
670        IOMachPort::setHoldDestroy( newService, IKOT_IOKIT_OBJECT );
671
672    if( sendPing) {
673	if( (port = iokit_port_for_object( this, IKOT_IOKIT_OBJECT ) ))
674            pingMsg->msgHdr.msgh_local_port = port;
675	else
676            pingMsg->msgHdr.msgh_local_port = NULL;
677
678        kr = mach_msg_send_from_kernel_with_options( &pingMsg->msgHdr,
679						     pingMsg->msgHdr.msgh_size,
680						     (MACH_SEND_MSG | MACH_SEND_ALWAYS | MACH_SEND_IMPORTANCE),
681						     0);
682	if( port)
683	    iokit_release_port( port );
684
685        if( KERN_SUCCESS != kr)
686            IOLog("%s: mach_msg_send_from_kernel_proper {%x}\n", __FILE__, kr );
687    }
688
689    return( true );
690}
691
692OSObject * IOServiceUserNotification::getNextObject()
693{
694    unsigned int	count;
695    OSObject *		result;
696
697    IOTakeLock( lock );
698
699    if( lastEntry)
700        lastEntry->release();
701
702    count = newSet->getCount();
703    if( count ) {
704        result = newSet->getObject( count - 1 );
705        result->retain();
706        newSet->removeObject( count - 1);
707    } else {
708        result = 0;
709        armed = true;
710    }
711    lastEntry = result;
712
713    IOUnlock( lock );
714
715    return( result );
716}
717
718/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
719
720OSDefineMetaClassAndStructors(IOServiceMessageUserNotification, IOUserNotification)
721
722/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
723
724bool IOServiceMessageUserNotification::init( mach_port_t port, natural_t type,
725				void * reference, vm_size_t referenceSize, vm_size_t extraSize,
726				bool client64 )
727{
728    if( !super::init())
729        return( false );
730
731    if (referenceSize > sizeof(OSAsyncReference64))
732        return( false );
733
734    clientIs64 = client64;
735
736    owningPID = proc_selfpid();
737
738    extraSize += sizeof(IOServiceInterestContent64);
739    msgSize = sizeof(PingMsg) - sizeof(OSAsyncReference64) + referenceSize + extraSize;
740    pingMsg = (PingMsg *) IOMalloc( msgSize);
741    if( !pingMsg)
742        return( false );
743
744    bzero( pingMsg, msgSize);
745
746    pingMsg->msgHdr.msgh_remote_port	= port;
747    pingMsg->msgHdr.msgh_bits 		= MACH_MSGH_BITS_COMPLEX
748					|  MACH_MSGH_BITS(
749                                            MACH_MSG_TYPE_COPY_SEND /*remote*/,
750                                            MACH_MSG_TYPE_MAKE_SEND /*local*/);
751    pingMsg->msgHdr.msgh_size 		= msgSize;
752    pingMsg->msgHdr.msgh_id		= kOSNotificationMessageID;
753
754    pingMsg->msgBody.msgh_descriptor_count = 1;
755
756    pingMsg->ports[0].name 		= 0;
757    pingMsg->ports[0].disposition 	= MACH_MSG_TYPE_MAKE_SEND;
758    pingMsg->ports[0].type 		= MACH_MSG_PORT_DESCRIPTOR;
759
760    pingMsg->notifyHeader.size 		= extraSize;
761    pingMsg->notifyHeader.type 		= type;
762    bcopy( reference, pingMsg->notifyHeader.reference, referenceSize );
763
764    return( true );
765}
766
767void IOServiceMessageUserNotification::free( void )
768{
769    PingMsg *	_pingMsg;
770    vm_size_t	_msgSize;
771
772    _pingMsg   = pingMsg;
773    _msgSize   = msgSize;
774
775    super::free();
776
777    if( _pingMsg && _msgSize) {
778		if (_pingMsg->msgHdr.msgh_remote_port) {
779			iokit_release_port_send(_pingMsg->msgHdr.msgh_remote_port);
780		}
781        IOFree( _pingMsg, _msgSize);
782	}
783}
784
785IOReturn IOServiceMessageUserNotification::_handler( void * target, void * ref,
786                                            UInt32 messageType, IOService * provider,
787                                            void * argument, vm_size_t argSize )
788{
789    return( ((IOServiceMessageUserNotification *) target)->handler(
790                                ref, messageType, provider, argument, argSize));
791}
792
793IOReturn IOServiceMessageUserNotification::handler( void * ref,
794                                    UInt32 messageType, IOService * provider,
795                                    void * messageArgument, vm_size_t argSize )
796{
797    kern_return_t		 kr;
798    ipc_port_t 			 thisPort, providerPort;
799    IOServiceInterestContent64 * data = (IOServiceInterestContent64 *)
800					((((uint8_t *) pingMsg) + msgSize) - pingMsg->notifyHeader.size);
801                                        // == pingMsg->notifyHeader.content;
802
803    if (kIOMessageCopyClientID == messageType)
804    {
805        *((void **) messageArgument) = OSNumber::withNumber(owningPID, 32);
806        return (kIOReturnSuccess);
807    }
808
809    data->messageType = messageType;
810
811    if( argSize == 0)
812    {
813	data->messageArgument[0] = (io_user_reference_t) messageArgument;
814	if (clientIs64)
815	    argSize = sizeof(data->messageArgument[0]);
816	else
817	{
818	    data->messageArgument[0] |= (data->messageArgument[0] << 32);
819	    argSize = sizeof(uint32_t);
820	}
821    }
822    else
823    {
824        if( argSize > kIOUserNotifyMaxMessageSize)
825            argSize = kIOUserNotifyMaxMessageSize;
826        bcopy( messageArgument, data->messageArgument, argSize );
827    }
828    pingMsg->msgHdr.msgh_size = msgSize - pingMsg->notifyHeader.size
829        + sizeof( IOServiceInterestContent64 )
830        - sizeof( data->messageArgument)
831        + argSize;
832
833    providerPort = iokit_port_for_object( provider, IKOT_IOKIT_OBJECT );
834    pingMsg->ports[0].name = providerPort;
835    thisPort = iokit_port_for_object( this, IKOT_IOKIT_OBJECT );
836    pingMsg->msgHdr.msgh_local_port = thisPort;
837    kr = mach_msg_send_from_kernel_with_options( &pingMsg->msgHdr,
838						 pingMsg->msgHdr.msgh_size,
839						 (MACH_SEND_MSG | MACH_SEND_ALWAYS | MACH_SEND_IMPORTANCE),
840						 0);
841    if( thisPort)
842	iokit_release_port( thisPort );
843    if( providerPort)
844	iokit_release_port( providerPort );
845
846    if( KERN_SUCCESS != kr)
847        IOLog("%s: mach_msg_send_from_kernel_proper {%x}\n", __FILE__, kr );
848
849    return( kIOReturnSuccess );
850}
851
852OSObject * IOServiceMessageUserNotification::getNextObject()
853{
854    return( 0 );
855}
856
857/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
858
859#undef super
860#define super IOService
861OSDefineMetaClassAndAbstractStructors( IOUserClient, IOService )
862
863void IOUserClient::initialize( void )
864{
865    gIOObjectPortLock = IOLockAlloc();
866
867    assert( gIOObjectPortLock );
868}
869
870void IOUserClient::setAsyncReference(OSAsyncReference asyncRef,
871                                     mach_port_t wakePort,
872                                     void *callback, void *refcon)
873{
874    asyncRef[kIOAsyncReservedIndex]      = ((uintptr_t) wakePort)
875					 | (kIOUCAsync0Flags & asyncRef[kIOAsyncReservedIndex]);
876    asyncRef[kIOAsyncCalloutFuncIndex]   = (uintptr_t) callback;
877    asyncRef[kIOAsyncCalloutRefconIndex] = (uintptr_t) refcon;
878}
879
880void IOUserClient::setAsyncReference64(OSAsyncReference64 asyncRef,
881					mach_port_t wakePort,
882					mach_vm_address_t callback, io_user_reference_t refcon)
883{
884    asyncRef[kIOAsyncReservedIndex]      = ((io_user_reference_t) wakePort)
885					 | (kIOUCAsync0Flags & asyncRef[kIOAsyncReservedIndex]);
886    asyncRef[kIOAsyncCalloutFuncIndex]   = (io_user_reference_t) callback;
887    asyncRef[kIOAsyncCalloutRefconIndex] = refcon;
888}
889
890void IOUserClient::setAsyncReference64(OSAsyncReference64 asyncRef,
891					mach_port_t wakePort,
892					mach_vm_address_t callback, io_user_reference_t refcon, task_t task)
893{
894    setAsyncReference64(asyncRef, wakePort, callback, refcon);
895    if (vm_map_is_64bit(get_task_map(task))) {
896            asyncRef[kIOAsyncReservedIndex] |= kIOUCAsync64Flag;
897    }
898}
899
900static OSDictionary * CopyConsoleUser(UInt32 uid)
901{
902	OSArray * array;
903	OSDictionary * user = 0;
904
905	if ((array = OSDynamicCast(OSArray,
906	    IORegistryEntry::getRegistryRoot()->copyProperty(gIOConsoleUsersKey))))
907	{
908	    for (unsigned int idx = 0;
909		    (user = OSDynamicCast(OSDictionary, array->getObject(idx)));
910		    idx++) {
911            OSNumber * num;
912
913            if ((num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionUIDKey)))
914              && (uid == num->unsigned32BitValue())) {
915                user->retain();
916                break;
917            }
918	    }
919	    array->release();
920	}
921    return user;
922}
923
924static OSDictionary * CopyUserOnConsole(void)
925{
926    OSArray * array;
927    OSDictionary * user = 0;
928
929    if ((array = OSDynamicCast(OSArray,
930	IORegistryEntry::getRegistryRoot()->copyProperty(gIOConsoleUsersKey))))
931    {
932	for (unsigned int idx = 0;
933		(user = OSDynamicCast(OSDictionary, array->getObject(idx)));
934		idx++)
935	{
936	    if (kOSBooleanTrue == user->getObject(gIOConsoleSessionOnConsoleKey))
937	    {
938		user->retain();
939		break;
940	    }
941	}
942	array->release();
943    }
944    return (user);
945}
946
947IOReturn IOUserClient::clientHasPrivilege( void * securityToken,
948                                            const char * privilegeName )
949{
950    kern_return_t           kr;
951    security_token_t        token;
952    mach_msg_type_number_t  count;
953    task_t                  task;
954    OSDictionary *          user;
955    bool                    secureConsole;
956
957
958    if (!strncmp(privilegeName, kIOClientPrivilegeForeground,
959                sizeof(kIOClientPrivilegeForeground)))
960    {
961	/* is graphics access denied for current task? */
962	if (proc_get_effective_task_policy(current_task(), TASK_POLICY_GPU_DENY) != 0)
963		return (kIOReturnNotPrivileged);
964	else
965		return (kIOReturnSuccess);
966    }
967
968    if (!strncmp(privilegeName, kIOClientPrivilegeConsoleSession,
969                                sizeof(kIOClientPrivilegeConsoleSession)))
970    {
971	kauth_cred_t cred;
972	proc_t       p;
973
974        task = (task_t) securityToken;
975	if (!task)
976	    task = current_task();
977	p = (proc_t) get_bsdtask_info(task);
978	kr = kIOReturnNotPrivileged;
979
980	if (p && (cred = kauth_cred_proc_ref(p)))
981	{
982	    user = CopyUserOnConsole();
983	    if (user)
984	    {
985		OSNumber * num;
986		if ((num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionAuditIDKey)))
987		  && (cred->cr_audit.as_aia_p->ai_asid == (au_asid_t) num->unsigned32BitValue()))
988		{
989		    kr = kIOReturnSuccess;
990		}
991		user->release();
992	    }
993	    kauth_cred_unref(&cred);
994	}
995	return (kr);
996    }
997
998    if ((secureConsole = !strncmp(privilegeName, kIOClientPrivilegeSecureConsoleProcess,
999            sizeof(kIOClientPrivilegeSecureConsoleProcess))))
1000        task = (task_t)((IOUCProcessToken *)securityToken)->token;
1001    else
1002        task = (task_t)securityToken;
1003
1004    count = TASK_SECURITY_TOKEN_COUNT;
1005    kr = task_info( task, TASK_SECURITY_TOKEN, (task_info_t) &token, &count );
1006
1007    if (KERN_SUCCESS != kr)
1008    {}
1009    else if (!strncmp(privilegeName, kIOClientPrivilegeAdministrator,
1010                sizeof(kIOClientPrivilegeAdministrator))) {
1011        if (0 != token.val[0])
1012            kr = kIOReturnNotPrivileged;
1013    } else if (!strncmp(privilegeName, kIOClientPrivilegeLocalUser,
1014                sizeof(kIOClientPrivilegeLocalUser))) {
1015        user = CopyConsoleUser(token.val[0]);
1016        if ( user )
1017            user->release();
1018        else
1019            kr = kIOReturnNotPrivileged;
1020    } else if (secureConsole || !strncmp(privilegeName, kIOClientPrivilegeConsoleUser,
1021                                    sizeof(kIOClientPrivilegeConsoleUser))) {
1022        user = CopyConsoleUser(token.val[0]);
1023        if ( user ) {
1024            if (user->getObject(gIOConsoleSessionOnConsoleKey) != kOSBooleanTrue)
1025                kr = kIOReturnNotPrivileged;
1026            else if ( secureConsole ) {
1027                OSNumber * pid = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionSecureInputPIDKey));
1028                if ( pid && pid->unsigned32BitValue() != ((IOUCProcessToken *)securityToken)->pid)
1029                    kr = kIOReturnNotPrivileged;
1030            }
1031            user->release();
1032        }
1033        else
1034            kr = kIOReturnNotPrivileged;
1035    } else
1036        kr = kIOReturnUnsupported;
1037
1038    return (kr);
1039}
1040
1041bool IOUserClient::init()
1042{
1043	if (getPropertyTable() || super::init())
1044		return reserve();
1045
1046	return false;
1047}
1048
1049bool IOUserClient::init(OSDictionary * dictionary)
1050{
1051	if (getPropertyTable() || super::init(dictionary))
1052		return reserve();
1053
1054	return false;
1055}
1056
1057bool IOUserClient::initWithTask(task_t owningTask,
1058                                void * securityID,
1059                                UInt32 type )
1060{
1061	if (getPropertyTable() || super::init())
1062		return reserve();
1063
1064	return false;
1065}
1066
1067bool IOUserClient::initWithTask(task_t owningTask,
1068                                void * securityID,
1069                                UInt32 type,
1070                                OSDictionary * properties )
1071{
1072    bool ok;
1073
1074    ok = super::init( properties );
1075    ok &= initWithTask( owningTask, securityID, type );
1076
1077    return( ok );
1078}
1079
1080bool IOUserClient::reserve()
1081{
1082    if(!reserved) {
1083	reserved = IONew(ExpansionData, 1);
1084	if (!reserved) {
1085	    return false;
1086	}
1087    }
1088    setTerminateDefer(NULL, true);
1089    IOStatisticsRegisterCounter();
1090
1091    return true;
1092}
1093
1094void IOUserClient::free()
1095{
1096    if( mappings)
1097        mappings->release();
1098
1099    IOStatisticsUnregisterCounter();
1100
1101    if (reserved)
1102        IODelete(reserved, ExpansionData, 1);
1103
1104    super::free();
1105}
1106
1107IOReturn IOUserClient::clientDied( void )
1108{
1109    return( clientClose());
1110}
1111
1112IOReturn IOUserClient::clientClose( void )
1113{
1114    return( kIOReturnUnsupported );
1115}
1116
1117IOService * IOUserClient::getService( void )
1118{
1119    return( 0 );
1120}
1121
1122IOReturn IOUserClient::registerNotificationPort(
1123		mach_port_t 	/* port */,
1124		UInt32		/* type */,
1125                UInt32		/* refCon */)
1126{
1127    return( kIOReturnUnsupported);
1128}
1129
1130IOReturn IOUserClient::registerNotificationPort(
1131		mach_port_t port,
1132		UInt32		type,
1133		io_user_reference_t refCon)
1134{
1135    return (registerNotificationPort(port, type, (UInt32) refCon));
1136}
1137
1138IOReturn IOUserClient::getNotificationSemaphore( UInt32 notification_type,
1139                                    semaphore_t * semaphore )
1140{
1141    return( kIOReturnUnsupported);
1142}
1143
1144IOReturn IOUserClient::connectClient( IOUserClient * /* client */ )
1145{
1146    return( kIOReturnUnsupported);
1147}
1148
1149IOReturn IOUserClient::clientMemoryForType( UInt32 type,
1150			        IOOptionBits * options,
1151				IOMemoryDescriptor ** memory )
1152{
1153    return( kIOReturnUnsupported);
1154}
1155
1156#if !__LP64__
1157IOMemoryMap * IOUserClient::mapClientMemory(
1158	IOOptionBits		type,
1159	task_t			task,
1160	IOOptionBits		mapFlags,
1161	IOVirtualAddress	atAddress )
1162{
1163    return (NULL);
1164}
1165#endif
1166
1167IOMemoryMap * IOUserClient::mapClientMemory64(
1168	IOOptionBits		type,
1169	task_t			task,
1170	IOOptionBits		mapFlags,
1171	mach_vm_address_t	atAddress )
1172{
1173    IOReturn		err;
1174    IOOptionBits	options = 0;
1175    IOMemoryDescriptor * memory;
1176    IOMemoryMap *	map = 0;
1177
1178    err = clientMemoryForType( (UInt32) type, &options, &memory );
1179
1180    if( memory && (kIOReturnSuccess == err)) {
1181
1182        options = (options & ~kIOMapUserOptionsMask)
1183		| (mapFlags & kIOMapUserOptionsMask);
1184	map = memory->createMappingInTask( task, atAddress, options );
1185	memory->release();
1186    }
1187
1188    return( map );
1189}
1190
1191IOReturn IOUserClient::exportObjectToClient(task_t task,
1192			OSObject *obj, io_object_t *clientObj)
1193{
1194    mach_port_name_t	name;
1195
1196    name = IOMachPort::makeSendRightForTask( task, obj, IKOT_IOKIT_OBJECT );
1197
1198    *(mach_port_name_t *)clientObj = name;
1199    return kIOReturnSuccess;
1200}
1201
1202IOExternalMethod * IOUserClient::getExternalMethodForIndex( UInt32 /* index */)
1203{
1204    return( 0 );
1205}
1206
1207IOExternalAsyncMethod * IOUserClient::getExternalAsyncMethodForIndex( UInt32 /* index */)
1208{
1209    return( 0 );
1210}
1211
1212IOExternalMethod * IOUserClient::
1213getTargetAndMethodForIndex(IOService **targetP, UInt32 index)
1214{
1215    IOExternalMethod *method = getExternalMethodForIndex(index);
1216
1217    if (method)
1218        *targetP = (IOService *) method->object;
1219
1220    return method;
1221}
1222
1223IOExternalAsyncMethod * IOUserClient::
1224getAsyncTargetAndMethodForIndex(IOService ** targetP, UInt32 index)
1225{
1226    IOExternalAsyncMethod *method = getExternalAsyncMethodForIndex(index);
1227
1228    if (method)
1229        *targetP = (IOService *) method->object;
1230
1231    return method;
1232}
1233
1234IOExternalTrap * IOUserClient::
1235getExternalTrapForIndex(UInt32 index)
1236{
1237	return NULL;
1238}
1239
1240IOExternalTrap * IOUserClient::
1241getTargetAndTrapForIndex(IOService ** targetP, UInt32 index)
1242{
1243      IOExternalTrap *trap = getExternalTrapForIndex(index);
1244
1245      if (trap) {
1246              *targetP = trap->object;
1247      }
1248
1249      return trap;
1250}
1251
1252IOReturn IOUserClient::releaseAsyncReference64(OSAsyncReference64 reference)
1253{
1254    mach_port_t port;
1255    port = (mach_port_t) (reference[0] & ~kIOUCAsync0Flags);
1256
1257    if (MACH_PORT_NULL != port)
1258	iokit_release_port_send(port);
1259
1260    return (kIOReturnSuccess);
1261}
1262
1263IOReturn IOUserClient::releaseNotificationPort(mach_port_t port)
1264{
1265    if (MACH_PORT_NULL != port)
1266	iokit_release_port_send(port);
1267
1268    return (kIOReturnSuccess);
1269}
1270
1271IOReturn IOUserClient::sendAsyncResult(OSAsyncReference reference,
1272                                       IOReturn result, void *args[], UInt32 numArgs)
1273{
1274    OSAsyncReference64  reference64;
1275    io_user_reference_t args64[kMaxAsyncArgs];
1276    unsigned int        idx;
1277
1278    if (numArgs > kMaxAsyncArgs)
1279        return kIOReturnMessageTooLarge;
1280
1281    for (idx = 0; idx < kOSAsyncRef64Count; idx++)
1282	reference64[idx] = REF64(reference[idx]);
1283
1284    for (idx = 0; idx < numArgs; idx++)
1285	args64[idx] = REF64(args[idx]);
1286
1287    return (sendAsyncResult64(reference64, result, args64, numArgs));
1288}
1289
1290IOReturn IOUserClient::sendAsyncResult64WithOptions(OSAsyncReference64 reference,
1291                                        IOReturn result, io_user_reference_t args[], UInt32 numArgs, IOOptionBits options)
1292{
1293	return _sendAsyncResult64(reference, result, args, numArgs, options);
1294}
1295
1296IOReturn IOUserClient::sendAsyncResult64(OSAsyncReference64 reference,
1297                                        IOReturn result, io_user_reference_t args[], UInt32 numArgs)
1298{
1299        return _sendAsyncResult64(reference, result, args, numArgs, 0);
1300}
1301
1302IOReturn IOUserClient::_sendAsyncResult64(OSAsyncReference64 reference,
1303                                        IOReturn result, io_user_reference_t args[], UInt32 numArgs, IOOptionBits options)
1304{
1305    struct ReplyMsg
1306    {
1307	mach_msg_header_t msgHdr;
1308	union
1309	{
1310	    struct
1311	    {
1312		OSNotificationHeader	 notifyHdr;
1313		IOAsyncCompletionContent asyncContent;
1314		uint32_t		 args[kMaxAsyncArgs];
1315	    } msg32;
1316	    struct
1317	    {
1318		OSNotificationHeader64	 notifyHdr;
1319		IOAsyncCompletionContent asyncContent;
1320		io_user_reference_t	 args[kMaxAsyncArgs] __attribute__ ((packed));
1321	    } msg64;
1322	} m;
1323    };
1324    ReplyMsg      replyMsg;
1325    mach_port_t	  replyPort;
1326    kern_return_t kr;
1327
1328    // If no reply port, do nothing.
1329    replyPort = (mach_port_t) (reference[0] & ~kIOUCAsync0Flags);
1330    if (replyPort == MACH_PORT_NULL)
1331        return kIOReturnSuccess;
1332
1333    if (numArgs > kMaxAsyncArgs)
1334        return kIOReturnMessageTooLarge;
1335
1336    replyMsg.msgHdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND /*remote*/,
1337						0 /*local*/);
1338    replyMsg.msgHdr.msgh_remote_port = replyPort;
1339    replyMsg.msgHdr.msgh_local_port  = 0;
1340    replyMsg.msgHdr.msgh_id          = kOSNotificationMessageID;
1341    if (kIOUCAsync64Flag & reference[0])
1342    {
1343	replyMsg.msgHdr.msgh_size =
1344	    sizeof(replyMsg.msgHdr) + sizeof(replyMsg.m.msg64)
1345	    - (kMaxAsyncArgs - numArgs) * sizeof(io_user_reference_t);
1346	replyMsg.m.msg64.notifyHdr.size = sizeof(IOAsyncCompletionContent)
1347					+ numArgs * sizeof(io_user_reference_t);
1348	replyMsg.m.msg64.notifyHdr.type = kIOAsyncCompletionNotificationType;
1349	bcopy(reference, replyMsg.m.msg64.notifyHdr.reference, sizeof(OSAsyncReference64));
1350
1351	replyMsg.m.msg64.asyncContent.result = result;
1352	if (numArgs)
1353	    bcopy(args, replyMsg.m.msg64.args, numArgs * sizeof(io_user_reference_t));
1354    }
1355    else
1356    {
1357	unsigned int idx;
1358
1359	replyMsg.msgHdr.msgh_size =
1360	    sizeof(replyMsg.msgHdr) + sizeof(replyMsg.m.msg32)
1361	    - (kMaxAsyncArgs - numArgs) * sizeof(uint32_t);
1362
1363	replyMsg.m.msg32.notifyHdr.size = sizeof(IOAsyncCompletionContent)
1364					+ numArgs * sizeof(uint32_t);
1365	replyMsg.m.msg32.notifyHdr.type = kIOAsyncCompletionNotificationType;
1366
1367	for (idx = 0; idx < kOSAsyncRefCount; idx++)
1368	    replyMsg.m.msg32.notifyHdr.reference[idx] = REF32(reference[idx]);
1369
1370	replyMsg.m.msg32.asyncContent.result = result;
1371
1372	for (idx = 0; idx < numArgs; idx++)
1373	    replyMsg.m.msg32.args[idx] = REF32(args[idx]);
1374    }
1375
1376	if ((options & kIOUserNotifyOptionCanDrop) != 0) {
1377		kr = mach_msg_send_from_kernel_with_options( &replyMsg.msgHdr,
1378										 replyMsg.msgHdr.msgh_size, MACH_SEND_TIMEOUT, MACH_MSG_TIMEOUT_NONE);
1379	} else {
1380		/* Fail on full queue. */
1381		kr = mach_msg_send_from_kernel_proper( &replyMsg.msgHdr,
1382										 replyMsg.msgHdr.msgh_size);
1383	}
1384    if ((KERN_SUCCESS != kr) && (MACH_SEND_TIMED_OUT != kr))
1385        IOLog("%s: mach_msg_send_from_kernel_proper {%x}\n", __FILE__, kr );
1386    return kr;
1387}
1388
1389
1390/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1391
1392extern "C" {
1393
1394#define CHECK(cls,obj,out)			\
1395	cls * out;				\
1396	if( !(out = OSDynamicCast( cls, obj)))	\
1397	    return( kIOReturnBadArgument )
1398
1399/* Routine io_object_get_class */
1400kern_return_t is_io_object_get_class(
1401	io_object_t object,
1402	io_name_t className )
1403{
1404	const OSMetaClass* my_obj = NULL;
1405
1406	if( !object)
1407		return( kIOReturnBadArgument );
1408
1409	my_obj = object->getMetaClass();
1410	if (!my_obj) {
1411		return (kIOReturnNotFound);
1412	}
1413
1414    strlcpy( className, my_obj->getClassName(), sizeof(io_name_t));
1415    return( kIOReturnSuccess );
1416}
1417
1418/* Routine io_object_get_superclass */
1419kern_return_t is_io_object_get_superclass(
1420	mach_port_t master_port,
1421	io_name_t obj_name,
1422	io_name_t class_name)
1423{
1424	const OSMetaClass* my_obj = NULL;
1425	const OSMetaClass* superclass = NULL;
1426	const OSSymbol *my_name = NULL;
1427	const char *my_cstr = NULL;
1428
1429	if (!obj_name || !class_name)
1430		return (kIOReturnBadArgument);
1431
1432    if( master_port != master_device_port)
1433        return( kIOReturnNotPrivileged);
1434
1435	my_name = OSSymbol::withCString(obj_name);
1436
1437	if (my_name) {
1438		my_obj = OSMetaClass::getMetaClassWithName(my_name);
1439		my_name->release();
1440	}
1441	if (my_obj) {
1442		superclass = my_obj->getSuperClass();
1443	}
1444
1445	if (!superclass)  {
1446		return( kIOReturnNotFound );
1447	}
1448
1449	my_cstr = superclass->getClassName();
1450
1451	if (my_cstr) {
1452		strlcpy(class_name, my_cstr, sizeof(io_name_t));
1453		return( kIOReturnSuccess );
1454	}
1455	return (kIOReturnNotFound);
1456}
1457
1458/* Routine io_object_get_bundle_identifier */
1459kern_return_t is_io_object_get_bundle_identifier(
1460	mach_port_t master_port,
1461	io_name_t obj_name,
1462	io_name_t bundle_name)
1463{
1464	const OSMetaClass* my_obj = NULL;
1465	const OSSymbol *my_name = NULL;
1466	const OSSymbol *identifier = NULL;
1467	const char *my_cstr = NULL;
1468
1469	if (!obj_name || !bundle_name)
1470		return (kIOReturnBadArgument);
1471
1472    if( master_port != master_device_port)
1473        return( kIOReturnNotPrivileged);
1474
1475	my_name = OSSymbol::withCString(obj_name);
1476
1477	if (my_name) {
1478		my_obj = OSMetaClass::getMetaClassWithName(my_name);
1479		my_name->release();
1480	}
1481
1482	if (my_obj) {
1483		identifier = my_obj->getKmodName();
1484	}
1485	if (!identifier) {
1486		return( kIOReturnNotFound );
1487	}
1488
1489	my_cstr = identifier->getCStringNoCopy();
1490	if (my_cstr) {
1491		strlcpy(bundle_name, identifier->getCStringNoCopy(), sizeof(io_name_t));
1492		return( kIOReturnSuccess );
1493	}
1494
1495	return (kIOReturnBadArgument);
1496}
1497
1498/* Routine io_object_conforms_to */
1499kern_return_t is_io_object_conforms_to(
1500	io_object_t object,
1501	io_name_t className,
1502	boolean_t *conforms )
1503{
1504    if( !object)
1505        return( kIOReturnBadArgument );
1506
1507    *conforms = (0 != object->metaCast( className ));
1508    return( kIOReturnSuccess );
1509}
1510
1511/* Routine io_object_get_retain_count */
1512kern_return_t is_io_object_get_retain_count(
1513	io_object_t object,
1514	uint32_t *retainCount )
1515{
1516    if( !object)
1517        return( kIOReturnBadArgument );
1518
1519    *retainCount = object->getRetainCount();
1520    return( kIOReturnSuccess );
1521}
1522
1523/* Routine io_iterator_next */
1524kern_return_t is_io_iterator_next(
1525	io_object_t iterator,
1526	io_object_t *object )
1527{
1528    OSObject *	obj;
1529
1530    CHECK( OSIterator, iterator, iter );
1531
1532    obj = iter->getNextObject();
1533    if( obj) {
1534	obj->retain();
1535	*object = obj;
1536        return( kIOReturnSuccess );
1537    } else
1538        return( kIOReturnNoDevice );
1539}
1540
1541/* Routine io_iterator_reset */
1542kern_return_t is_io_iterator_reset(
1543	io_object_t iterator )
1544{
1545    CHECK( OSIterator, iterator, iter );
1546
1547    iter->reset();
1548
1549    return( kIOReturnSuccess );
1550}
1551
1552/* Routine io_iterator_is_valid */
1553kern_return_t is_io_iterator_is_valid(
1554	io_object_t iterator,
1555	boolean_t *is_valid )
1556{
1557    CHECK( OSIterator, iterator, iter );
1558
1559    *is_valid = iter->isValid();
1560
1561    return( kIOReturnSuccess );
1562}
1563
1564/* Routine io_service_match_property_table */
1565kern_return_t is_io_service_match_property_table(
1566	io_service_t _service,
1567	io_string_t matching,
1568	boolean_t *matches )
1569{
1570    CHECK( IOService, _service, service );
1571
1572    kern_return_t	kr;
1573    OSObject *		obj;
1574    OSDictionary *	dict;
1575
1576    obj = OSUnserializeXML( matching );
1577
1578    if( (dict = OSDynamicCast( OSDictionary, obj))) {
1579        *matches = service->passiveMatch( dict );
1580	kr = kIOReturnSuccess;
1581    } else
1582	kr = kIOReturnBadArgument;
1583
1584    if( obj)
1585        obj->release();
1586
1587    return( kr );
1588}
1589
1590/* Routine io_service_match_property_table_ool */
1591kern_return_t is_io_service_match_property_table_ool(
1592	io_object_t service,
1593	io_buf_ptr_t matching,
1594	mach_msg_type_number_t matchingCnt,
1595	kern_return_t *result,
1596	boolean_t *matches )
1597{
1598    kern_return_t	  kr;
1599    vm_offset_t 	  data;
1600    vm_map_offset_t	  map_data;
1601
1602    kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) matching );
1603    data = CAST_DOWN(vm_offset_t, map_data);
1604
1605    if( KERN_SUCCESS == kr) {
1606        // must return success after vm_map_copyout() succeeds
1607	*result = is_io_service_match_property_table( service,
1608		(char *) data, matches );
1609	vm_deallocate( kernel_map, data, matchingCnt );
1610    }
1611
1612    return( kr );
1613}
1614
1615/* Routine io_service_get_matching_services */
1616kern_return_t is_io_service_get_matching_services(
1617	mach_port_t master_port,
1618	io_string_t matching,
1619	io_iterator_t *existing )
1620{
1621    kern_return_t	kr;
1622    OSObject *		obj;
1623    OSDictionary *	dict;
1624
1625    if( master_port != master_device_port)
1626        return( kIOReturnNotPrivileged);
1627
1628    obj = OSUnserializeXML( matching );
1629
1630    if( (dict = OSDynamicCast( OSDictionary, obj))) {
1631        *existing = IOService::getMatchingServices( dict );
1632	kr = kIOReturnSuccess;
1633    } else
1634	kr = kIOReturnBadArgument;
1635
1636    if( obj)
1637        obj->release();
1638
1639    return( kr );
1640}
1641
1642/* Routine io_service_get_matching_services_ool */
1643kern_return_t is_io_service_get_matching_services_ool(
1644	mach_port_t master_port,
1645	io_buf_ptr_t matching,
1646	mach_msg_type_number_t matchingCnt,
1647	kern_return_t *result,
1648	io_object_t *existing )
1649{
1650    kern_return_t	kr;
1651    vm_offset_t 	data;
1652    vm_map_offset_t	map_data;
1653
1654    kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) matching );
1655    data = CAST_DOWN(vm_offset_t, map_data);
1656
1657    if( KERN_SUCCESS == kr) {
1658        // must return success after vm_map_copyout() succeeds
1659	*result = is_io_service_get_matching_services( master_port,
1660			(char *) data, existing );
1661	vm_deallocate( kernel_map, data, matchingCnt );
1662    }
1663
1664    return( kr );
1665}
1666
1667
1668/* Routine io_service_get_matching_service */
1669kern_return_t is_io_service_get_matching_service(
1670	mach_port_t master_port,
1671	io_string_t matching,
1672	io_service_t *service )
1673{
1674    kern_return_t	kr;
1675    OSObject *		obj;
1676    OSDictionary *	dict;
1677
1678    if( master_port != master_device_port)
1679        return( kIOReturnNotPrivileged);
1680
1681    obj = OSUnserializeXML( matching );
1682
1683    if( (dict = OSDynamicCast( OSDictionary, obj))) {
1684        *service = IOService::copyMatchingService( dict );
1685	kr = *service ? kIOReturnSuccess : kIOReturnNotFound;
1686    } else
1687	kr = kIOReturnBadArgument;
1688
1689    if( obj)
1690        obj->release();
1691
1692    return( kr );
1693}
1694
1695/* Routine io_service_get_matching_services_ool */
1696kern_return_t is_io_service_get_matching_service_ool(
1697	mach_port_t master_port,
1698	io_buf_ptr_t matching,
1699	mach_msg_type_number_t matchingCnt,
1700	kern_return_t *result,
1701	io_object_t *service )
1702{
1703    kern_return_t	kr;
1704    vm_offset_t 	data;
1705    vm_map_offset_t	map_data;
1706
1707    kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) matching );
1708    data = CAST_DOWN(vm_offset_t, map_data);
1709
1710    if( KERN_SUCCESS == kr) {
1711        // must return success after vm_map_copyout() succeeds
1712	*result = is_io_service_get_matching_service( master_port,
1713			(char *) data, service );
1714	vm_deallocate( kernel_map, data, matchingCnt );
1715    }
1716
1717    return( kr );
1718}
1719
1720
1721static kern_return_t internal_io_service_add_notification(
1722	mach_port_t master_port,
1723	io_name_t notification_type,
1724	io_string_t matching,
1725	mach_port_t port,
1726	void * reference,
1727	vm_size_t referenceSize,
1728	bool client64,
1729	io_object_t * notification )
1730{
1731    IOServiceUserNotification *	userNotify = 0;
1732    IONotifier *		notify = 0;
1733    const OSSymbol *		sym;
1734    OSDictionary *		dict;
1735    IOReturn			err;
1736    unsigned long int		userMsgType;
1737
1738
1739    if( master_port != master_device_port)
1740        return( kIOReturnNotPrivileged);
1741
1742    do {
1743        err = kIOReturnNoResources;
1744
1745        if( !(sym = OSSymbol::withCString( notification_type )))
1746	    err = kIOReturnNoResources;
1747
1748        if( !(dict = OSDynamicCast( OSDictionary,
1749                    OSUnserializeXML( matching )))) {
1750            err = kIOReturnBadArgument;
1751	    continue;
1752	}
1753
1754	if( (sym == gIOPublishNotification)
1755	 || (sym == gIOFirstPublishNotification))
1756	    userMsgType = kIOServicePublishNotificationType;
1757	else if( (sym == gIOMatchedNotification)
1758	      || (sym == gIOFirstMatchNotification))
1759	    userMsgType = kIOServiceMatchedNotificationType;
1760	else if( sym == gIOTerminatedNotification)
1761	    userMsgType = kIOServiceTerminatedNotificationType;
1762	else
1763	    userMsgType = kLastIOKitNotificationType;
1764
1765        userNotify = new IOServiceUserNotification;
1766
1767        if( userNotify && !userNotify->init( port, userMsgType,
1768                                             reference, referenceSize, client64)) {
1769			iokit_release_port_send(port);
1770            userNotify->release();
1771            userNotify = 0;
1772        }
1773        if( !userNotify)
1774	    continue;
1775
1776        notify = IOService::addMatchingNotification( sym, dict,
1777                                             &userNotify->_handler, userNotify );
1778	if( notify) {
1779            *notification = userNotify;
1780	    userNotify->setNotification( notify );
1781	    err = kIOReturnSuccess;
1782	} else
1783	    err = kIOReturnUnsupported;
1784
1785    } while( false );
1786
1787    if( sym)
1788	sym->release();
1789    if( dict)
1790	dict->release();
1791
1792    return( err );
1793}
1794
1795
1796/* Routine io_service_add_notification */
1797kern_return_t is_io_service_add_notification(
1798	mach_port_t master_port,
1799	io_name_t notification_type,
1800	io_string_t matching,
1801	mach_port_t port,
1802	io_async_ref_t reference,
1803	mach_msg_type_number_t referenceCnt,
1804	io_object_t * notification )
1805{
1806    return (internal_io_service_add_notification(master_port, notification_type,
1807		matching, port, &reference[0], sizeof(io_async_ref_t),
1808		false, notification));
1809}
1810
1811/* Routine io_service_add_notification_64 */
1812kern_return_t is_io_service_add_notification_64(
1813	mach_port_t master_port,
1814	io_name_t notification_type,
1815	io_string_t matching,
1816	mach_port_t wake_port,
1817	io_async_ref64_t reference,
1818	mach_msg_type_number_t referenceCnt,
1819	io_object_t *notification )
1820{
1821    return (internal_io_service_add_notification(master_port, notification_type,
1822		matching, wake_port, &reference[0], sizeof(io_async_ref64_t),
1823		true, notification));
1824}
1825
1826
1827static kern_return_t internal_io_service_add_notification_ool(
1828	mach_port_t master_port,
1829	io_name_t notification_type,
1830	io_buf_ptr_t matching,
1831	mach_msg_type_number_t matchingCnt,
1832	mach_port_t wake_port,
1833	void * reference,
1834	vm_size_t referenceSize,
1835	bool client64,
1836	kern_return_t *result,
1837	io_object_t *notification )
1838{
1839    kern_return_t	kr;
1840    vm_offset_t 	data;
1841    vm_map_offset_t	map_data;
1842
1843    kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) matching );
1844    data = CAST_DOWN(vm_offset_t, map_data);
1845
1846    if( KERN_SUCCESS == kr) {
1847        // must return success after vm_map_copyout() succeeds
1848	*result = internal_io_service_add_notification( master_port, notification_type,
1849			(char *) data, wake_port, reference, referenceSize, client64, notification );
1850	vm_deallocate( kernel_map, data, matchingCnt );
1851    }
1852
1853    return( kr );
1854}
1855
1856/* Routine io_service_add_notification_ool */
1857kern_return_t is_io_service_add_notification_ool(
1858	mach_port_t master_port,
1859	io_name_t notification_type,
1860	io_buf_ptr_t matching,
1861	mach_msg_type_number_t matchingCnt,
1862	mach_port_t wake_port,
1863	io_async_ref_t reference,
1864	mach_msg_type_number_t referenceCnt,
1865	kern_return_t *result,
1866	io_object_t *notification )
1867{
1868    return (internal_io_service_add_notification_ool(master_port, notification_type,
1869		matching, matchingCnt, wake_port, &reference[0], sizeof(io_async_ref_t),
1870		false, result, notification));
1871}
1872
1873/* Routine io_service_add_notification_ool_64 */
1874kern_return_t is_io_service_add_notification_ool_64(
1875	mach_port_t master_port,
1876	io_name_t notification_type,
1877	io_buf_ptr_t matching,
1878	mach_msg_type_number_t matchingCnt,
1879	mach_port_t wake_port,
1880	io_async_ref64_t reference,
1881	mach_msg_type_number_t referenceCnt,
1882	kern_return_t *result,
1883	io_object_t *notification )
1884{
1885    return (internal_io_service_add_notification_ool(master_port, notification_type,
1886		matching, matchingCnt, wake_port, &reference[0], sizeof(io_async_ref64_t),
1887		true, result, notification));
1888}
1889
1890/* Routine io_service_add_notification_old */
1891kern_return_t is_io_service_add_notification_old(
1892	mach_port_t master_port,
1893	io_name_t notification_type,
1894	io_string_t matching,
1895	mach_port_t port,
1896	// for binary compatibility reasons, this must be natural_t for ILP32
1897	natural_t ref,
1898	io_object_t * notification )
1899{
1900    return( is_io_service_add_notification( master_port, notification_type,
1901            matching, port, &ref, 1, notification ));
1902}
1903
1904
1905static kern_return_t internal_io_service_add_interest_notification(
1906        io_object_t _service,
1907        io_name_t type_of_interest,
1908        mach_port_t port,
1909	void * reference,
1910	vm_size_t referenceSize,
1911	bool client64,
1912        io_object_t * notification )
1913{
1914
1915    IOServiceMessageUserNotification *	userNotify = 0;
1916    IONotifier *			notify = 0;
1917    const OSSymbol *			sym;
1918    IOReturn				err;
1919
1920    CHECK( IOService, _service, service );
1921
1922    err = kIOReturnNoResources;
1923    if( (sym = OSSymbol::withCString( type_of_interest ))) do {
1924
1925        userNotify = new IOServiceMessageUserNotification;
1926
1927        if( userNotify && !userNotify->init( port, kIOServiceMessageNotificationType,
1928                                             reference, referenceSize,
1929					     kIOUserNotifyMaxMessageSize,
1930					     client64 )) {
1931			iokit_release_port_send(port);
1932            userNotify->release();
1933            userNotify = 0;
1934        }
1935        if( !userNotify)
1936            continue;
1937
1938        notify = service->registerInterest( sym,
1939                                    &userNotify->_handler, userNotify );
1940        if( notify) {
1941            *notification = userNotify;
1942            userNotify->setNotification( notify );
1943            err = kIOReturnSuccess;
1944        } else
1945            err = kIOReturnUnsupported;
1946
1947	sym->release();
1948
1949    } while( false );
1950
1951    return( err );
1952}
1953
1954/* Routine io_service_add_message_notification */
1955kern_return_t is_io_service_add_interest_notification(
1956        io_object_t service,
1957        io_name_t type_of_interest,
1958        mach_port_t port,
1959	io_async_ref_t reference,
1960	mach_msg_type_number_t referenceCnt,
1961        io_object_t * notification )
1962{
1963    return (internal_io_service_add_interest_notification(service, type_of_interest,
1964		    port, &reference[0], sizeof(io_async_ref_t), false, notification));
1965}
1966
1967/* Routine io_service_add_interest_notification_64 */
1968kern_return_t is_io_service_add_interest_notification_64(
1969	io_object_t service,
1970	io_name_t type_of_interest,
1971	mach_port_t wake_port,
1972	io_async_ref64_t reference,
1973	mach_msg_type_number_t referenceCnt,
1974	io_object_t *notification )
1975{
1976    return (internal_io_service_add_interest_notification(service, type_of_interest,
1977		    wake_port, &reference[0], sizeof(io_async_ref64_t), true, notification));
1978}
1979
1980
1981/* Routine io_service_acknowledge_notification */
1982kern_return_t is_io_service_acknowledge_notification(
1983	io_object_t _service,
1984	natural_t notify_ref,
1985	natural_t response )
1986{
1987    CHECK( IOService, _service, service );
1988
1989    return( service->acknowledgeNotification( (IONotificationRef)(uintptr_t) notify_ref,
1990                                              (IOOptionBits) response ));
1991
1992}
1993
1994/* Routine io_connect_get_semaphore */
1995kern_return_t is_io_connect_get_notification_semaphore(
1996	io_connect_t connection,
1997	natural_t notification_type,
1998	semaphore_t *semaphore )
1999{
2000    CHECK( IOUserClient, connection, client );
2001
2002    IOStatisticsClientCall();
2003    return( client->getNotificationSemaphore( (UInt32) notification_type,
2004                                              semaphore ));
2005}
2006
2007/* Routine io_registry_get_root_entry */
2008kern_return_t is_io_registry_get_root_entry(
2009	mach_port_t master_port,
2010	io_object_t *root )
2011{
2012    IORegistryEntry *	entry;
2013
2014    if( master_port != master_device_port)
2015        return( kIOReturnNotPrivileged);
2016
2017    entry = IORegistryEntry::getRegistryRoot();
2018    if( entry)
2019	entry->retain();
2020    *root = entry;
2021
2022    return( kIOReturnSuccess );
2023}
2024
2025/* Routine io_registry_create_iterator */
2026kern_return_t is_io_registry_create_iterator(
2027	mach_port_t master_port,
2028	io_name_t plane,
2029	uint32_t options,
2030	io_object_t *iterator )
2031{
2032    if( master_port != master_device_port)
2033        return( kIOReturnNotPrivileged);
2034
2035    *iterator = IORegistryIterator::iterateOver(
2036	IORegistryEntry::getPlane( plane ), options );
2037
2038    return( *iterator ? kIOReturnSuccess : kIOReturnBadArgument );
2039}
2040
2041/* Routine io_registry_entry_create_iterator */
2042kern_return_t is_io_registry_entry_create_iterator(
2043	io_object_t registry_entry,
2044	io_name_t plane,
2045	uint32_t options,
2046	io_object_t *iterator )
2047{
2048    CHECK( IORegistryEntry, registry_entry, entry );
2049
2050    *iterator = IORegistryIterator::iterateOver( entry,
2051	IORegistryEntry::getPlane( plane ), options );
2052
2053    return( *iterator ? kIOReturnSuccess : kIOReturnBadArgument );
2054}
2055
2056/* Routine io_registry_iterator_enter */
2057kern_return_t is_io_registry_iterator_enter_entry(
2058	io_object_t iterator )
2059{
2060    CHECK( IORegistryIterator, iterator, iter );
2061
2062    iter->enterEntry();
2063
2064    return( kIOReturnSuccess );
2065}
2066
2067/* Routine io_registry_iterator_exit */
2068kern_return_t is_io_registry_iterator_exit_entry(
2069	io_object_t iterator )
2070{
2071    bool	didIt;
2072
2073    CHECK( IORegistryIterator, iterator, iter );
2074
2075    didIt = iter->exitEntry();
2076
2077    return( didIt ? kIOReturnSuccess : kIOReturnNoDevice );
2078}
2079
2080/* Routine io_registry_entry_from_path */
2081kern_return_t is_io_registry_entry_from_path(
2082	mach_port_t master_port,
2083	io_string_t path,
2084	io_object_t *registry_entry )
2085{
2086    IORegistryEntry *	entry;
2087
2088    if( master_port != master_device_port)
2089        return( kIOReturnNotPrivileged);
2090
2091    entry = IORegistryEntry::fromPath( path );
2092
2093    *registry_entry = entry;
2094
2095    return( kIOReturnSuccess );
2096}
2097
2098/* Routine io_registry_entry_in_plane */
2099kern_return_t is_io_registry_entry_in_plane(
2100	io_object_t registry_entry,
2101	io_name_t plane,
2102	boolean_t *inPlane )
2103{
2104    CHECK( IORegistryEntry, registry_entry, entry );
2105
2106    *inPlane = entry->inPlane( IORegistryEntry::getPlane( plane ));
2107
2108    return( kIOReturnSuccess );
2109}
2110
2111
2112/* Routine io_registry_entry_get_path */
2113kern_return_t is_io_registry_entry_get_path(
2114	io_object_t registry_entry,
2115	io_name_t plane,
2116	io_string_t path )
2117{
2118    int		length;
2119    CHECK( IORegistryEntry, registry_entry, entry );
2120
2121    length = sizeof( io_string_t);
2122    if( entry->getPath( path, &length, IORegistryEntry::getPlane( plane )))
2123	return( kIOReturnSuccess );
2124    else
2125	return( kIOReturnBadArgument );
2126}
2127
2128
2129/* Routine io_registry_entry_get_name */
2130kern_return_t is_io_registry_entry_get_name(
2131	io_object_t registry_entry,
2132	io_name_t name )
2133{
2134    CHECK( IORegistryEntry, registry_entry, entry );
2135
2136    strncpy( name, entry->getName(), sizeof( io_name_t));
2137
2138    return( kIOReturnSuccess );
2139}
2140
2141/* Routine io_registry_entry_get_name_in_plane */
2142kern_return_t is_io_registry_entry_get_name_in_plane(
2143	io_object_t registry_entry,
2144	io_name_t planeName,
2145	io_name_t name )
2146{
2147    const IORegistryPlane * plane;
2148    CHECK( IORegistryEntry, registry_entry, entry );
2149
2150    if( planeName[0])
2151        plane = IORegistryEntry::getPlane( planeName );
2152    else
2153        plane = 0;
2154
2155    strncpy( name, entry->getName( plane), sizeof( io_name_t));
2156
2157    return( kIOReturnSuccess );
2158}
2159
2160/* Routine io_registry_entry_get_location_in_plane */
2161kern_return_t is_io_registry_entry_get_location_in_plane(
2162	io_object_t registry_entry,
2163	io_name_t planeName,
2164	io_name_t location )
2165{
2166    const IORegistryPlane * plane;
2167    CHECK( IORegistryEntry, registry_entry, entry );
2168
2169    if( planeName[0])
2170        plane = IORegistryEntry::getPlane( planeName );
2171    else
2172        plane = 0;
2173
2174    const char * cstr = entry->getLocation( plane );
2175
2176    if( cstr) {
2177        strncpy( location, cstr, sizeof( io_name_t));
2178        return( kIOReturnSuccess );
2179    } else
2180        return( kIOReturnNotFound );
2181}
2182
2183/* Routine io_registry_entry_get_registry_entry_id */
2184kern_return_t is_io_registry_entry_get_registry_entry_id(
2185	io_object_t registry_entry,
2186	uint64_t *entry_id )
2187{
2188    CHECK( IORegistryEntry, registry_entry, entry );
2189
2190    *entry_id = entry->getRegistryEntryID();
2191
2192    return (kIOReturnSuccess);
2193}
2194
2195// Create a vm_map_copy_t or kalloc'ed data for memory
2196// to be copied out. ipc will free after the copyout.
2197
2198static kern_return_t copyoutkdata( const void * data, vm_size_t len,
2199                                    io_buf_ptr_t * buf )
2200{
2201    kern_return_t	err;
2202    vm_map_copy_t	copy;
2203
2204    err = vm_map_copyin( kernel_map, CAST_USER_ADDR_T(data), len,
2205                    false /* src_destroy */, &copy);
2206
2207    assert( err == KERN_SUCCESS );
2208    if( err == KERN_SUCCESS )
2209        *buf = (char *) copy;
2210
2211    return( err );
2212}
2213
2214/* Routine io_registry_entry_get_property */
2215kern_return_t is_io_registry_entry_get_property_bytes(
2216	io_object_t registry_entry,
2217	io_name_t property_name,
2218	io_struct_inband_t buf,
2219	mach_msg_type_number_t *dataCnt )
2220{
2221    OSObject	*	obj;
2222    OSData 	*	data;
2223    OSString 	*	str;
2224    OSBoolean	*	boo;
2225    OSNumber 	*	off;
2226    UInt64		offsetBytes;
2227    unsigned int	len = 0;
2228    const void *	bytes = 0;
2229    IOReturn		ret = kIOReturnSuccess;
2230
2231    CHECK( IORegistryEntry, registry_entry, entry );
2232
2233    obj = entry->copyProperty(property_name);
2234    if( !obj)
2235        return( kIOReturnNoResources );
2236
2237    // One day OSData will be a common container base class
2238    // until then...
2239    if( (data = OSDynamicCast( OSData, obj ))) {
2240	len = data->getLength();
2241	bytes = data->getBytesNoCopy();
2242
2243    } else if( (str = OSDynamicCast( OSString, obj ))) {
2244	len = str->getLength() + 1;
2245	bytes = str->getCStringNoCopy();
2246
2247    } else if( (boo = OSDynamicCast( OSBoolean, obj ))) {
2248	len = boo->isTrue() ? sizeof("Yes") : sizeof("No");
2249	bytes = boo->isTrue() ? "Yes" : "No";
2250
2251    } else if( (off = OSDynamicCast( OSNumber, obj ))) {
2252	offsetBytes = off->unsigned64BitValue();
2253	len = off->numberOfBytes();
2254	bytes = &offsetBytes;
2255#ifdef __BIG_ENDIAN__
2256	bytes = (const void *)
2257		(((UInt32) bytes) + (sizeof( UInt64) - len));
2258#endif
2259
2260    } else
2261	ret = kIOReturnBadArgument;
2262
2263    if( bytes) {
2264	if( *dataCnt < len)
2265	    ret = kIOReturnIPCError;
2266	else {
2267            *dataCnt = len;
2268            bcopy( bytes, buf, len );
2269	}
2270    }
2271    obj->release();
2272
2273    return( ret );
2274}
2275
2276
2277/* Routine io_registry_entry_get_property */
2278kern_return_t is_io_registry_entry_get_property(
2279	io_object_t registry_entry,
2280	io_name_t property_name,
2281	io_buf_ptr_t *properties,
2282	mach_msg_type_number_t *propertiesCnt )
2283{
2284    kern_return_t	err;
2285    vm_size_t 		len;
2286    OSObject *		obj;
2287
2288    CHECK( IORegistryEntry, registry_entry, entry );
2289
2290    obj = entry->copyProperty(property_name);
2291    if( !obj)
2292        return( kIOReturnNotFound );
2293
2294    OSSerialize * s = OSSerialize::withCapacity(4096);
2295    if( !s) {
2296        obj->release();
2297	return( kIOReturnNoMemory );
2298    }
2299    s->clearText();
2300
2301    if( obj->serialize( s )) {
2302        len = s->getLength();
2303        *propertiesCnt = len;
2304        err = copyoutkdata( s->text(), len, properties );
2305
2306    } else
2307        err = kIOReturnUnsupported;
2308
2309    s->release();
2310    obj->release();
2311
2312    return( err );
2313}
2314
2315/* Routine io_registry_entry_get_property_recursively */
2316kern_return_t is_io_registry_entry_get_property_recursively(
2317	io_object_t registry_entry,
2318	io_name_t plane,
2319	io_name_t property_name,
2320        uint32_t options,
2321	io_buf_ptr_t *properties,
2322	mach_msg_type_number_t *propertiesCnt )
2323{
2324    kern_return_t	err;
2325    vm_size_t 		len;
2326    OSObject *		obj;
2327
2328    CHECK( IORegistryEntry, registry_entry, entry );
2329
2330    obj = entry->copyProperty( property_name,
2331                               IORegistryEntry::getPlane( plane ), options);
2332    if( !obj)
2333        return( kIOReturnNotFound );
2334
2335    OSSerialize * s = OSSerialize::withCapacity(4096);
2336    if( !s) {
2337        obj->release();
2338	return( kIOReturnNoMemory );
2339    }
2340
2341    s->clearText();
2342
2343    if( obj->serialize( s )) {
2344        len = s->getLength();
2345        *propertiesCnt = len;
2346        err = copyoutkdata( s->text(), len, properties );
2347
2348    } else
2349        err = kIOReturnUnsupported;
2350
2351    s->release();
2352    obj->release();
2353
2354    return( err );
2355}
2356
2357/* Routine io_registry_entry_get_properties */
2358kern_return_t is_io_registry_entry_get_properties(
2359	io_object_t registry_entry,
2360	io_buf_ptr_t *properties,
2361	mach_msg_type_number_t *propertiesCnt )
2362{
2363    kern_return_t	err;
2364    vm_size_t 		len;
2365
2366    CHECK( IORegistryEntry, registry_entry, entry );
2367
2368    OSSerialize * s = OSSerialize::withCapacity(4096);
2369    if( !s)
2370	return( kIOReturnNoMemory );
2371
2372    s->clearText();
2373
2374    if( entry->serializeProperties( s )) {
2375        len = s->getLength();
2376        *propertiesCnt = len;
2377        err = copyoutkdata( s->text(), len, properties );
2378
2379    } else
2380        err = kIOReturnUnsupported;
2381
2382    s->release();
2383
2384    return( err );
2385}
2386
2387/* Routine io_registry_entry_set_properties */
2388kern_return_t is_io_registry_entry_set_properties
2389(
2390	io_object_t registry_entry,
2391	io_buf_ptr_t properties,
2392	mach_msg_type_number_t propertiesCnt,
2393        kern_return_t * result)
2394{
2395    OSObject *		obj;
2396    kern_return_t	err;
2397    IOReturn		res;
2398    vm_offset_t 	data;
2399    vm_map_offset_t	map_data;
2400
2401    CHECK( IORegistryEntry, registry_entry, entry );
2402
2403    if( propertiesCnt > sizeof(io_struct_inband_t) * 1024)
2404        return( kIOReturnMessageTooLarge);
2405
2406    err = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) properties );
2407    data = CAST_DOWN(vm_offset_t, map_data);
2408
2409    if( KERN_SUCCESS == err) {
2410
2411        // must return success after vm_map_copyout() succeeds
2412        obj = OSUnserializeXML( (const char *) data, propertiesCnt );
2413	vm_deallocate( kernel_map, data, propertiesCnt );
2414
2415	if (!obj)
2416	    res = kIOReturnBadArgument;
2417#if CONFIG_MACF
2418	else if (0 != mac_iokit_check_set_properties(kauth_cred_get(),
2419	    registry_entry, obj))
2420	    res = kIOReturnNotPermitted;
2421#endif
2422	else
2423            res = entry->setProperties( obj );
2424	if (obj)
2425	    obj->release();
2426    } else
2427        res = err;
2428
2429    *result = res;
2430    return( err );
2431}
2432
2433/* Routine io_registry_entry_get_child_iterator */
2434kern_return_t is_io_registry_entry_get_child_iterator(
2435	io_object_t registry_entry,
2436	io_name_t plane,
2437	io_object_t *iterator )
2438{
2439    CHECK( IORegistryEntry, registry_entry, entry );
2440
2441    *iterator = entry->getChildIterator(
2442	IORegistryEntry::getPlane( plane ));
2443
2444    return( kIOReturnSuccess );
2445}
2446
2447/* Routine io_registry_entry_get_parent_iterator */
2448kern_return_t is_io_registry_entry_get_parent_iterator(
2449	io_object_t registry_entry,
2450	io_name_t plane,
2451	io_object_t *iterator)
2452{
2453    CHECK( IORegistryEntry, registry_entry, entry );
2454
2455    *iterator = entry->getParentIterator(
2456	IORegistryEntry::getPlane( plane ));
2457
2458    return( kIOReturnSuccess );
2459}
2460
2461/* Routine io_service_get_busy_state */
2462kern_return_t is_io_service_get_busy_state(
2463	io_object_t _service,
2464	uint32_t *busyState )
2465{
2466    CHECK( IOService, _service, service );
2467
2468    *busyState = service->getBusyState();
2469
2470    return( kIOReturnSuccess );
2471}
2472
2473/* Routine io_service_get_state */
2474kern_return_t is_io_service_get_state(
2475	io_object_t _service,
2476	uint64_t *state,
2477	uint32_t *busy_state,
2478	uint64_t *accumulated_busy_time )
2479{
2480    CHECK( IOService, _service, service );
2481
2482    *state                 = service->getState();
2483    *busy_state            = service->getBusyState();
2484    *accumulated_busy_time = service->getAccumulatedBusyTime();
2485
2486    return( kIOReturnSuccess );
2487}
2488
2489/* Routine io_service_wait_quiet */
2490kern_return_t is_io_service_wait_quiet(
2491	io_object_t _service,
2492	mach_timespec_t wait_time )
2493{
2494    uint64_t    timeoutNS;
2495
2496    CHECK( IOService, _service, service );
2497
2498    timeoutNS = wait_time.tv_sec;
2499    timeoutNS *= kSecondScale;
2500    timeoutNS += wait_time.tv_nsec;
2501
2502    return( service->waitQuiet(timeoutNS) );
2503}
2504
2505/* Routine io_service_request_probe */
2506kern_return_t is_io_service_request_probe(
2507	io_object_t _service,
2508	uint32_t options )
2509{
2510    CHECK( IOService, _service, service );
2511
2512    return( service->requestProbe( options ));
2513}
2514
2515/* Routine io_service_open_ndr */
2516kern_return_t is_io_service_open_extended(
2517	io_object_t _service,
2518	task_t owningTask,
2519	uint32_t connect_type,
2520	NDR_record_t ndr,
2521	io_buf_ptr_t properties,
2522	mach_msg_type_number_t propertiesCnt,
2523        kern_return_t * result,
2524	io_object_t *connection )
2525{
2526    IOUserClient * client = 0;
2527    kern_return_t  err = KERN_SUCCESS;
2528    IOReturn	   res = kIOReturnSuccess;
2529    OSDictionary * propertiesDict = 0;
2530    bool	   crossEndian;
2531    bool	   disallowAccess;
2532
2533    CHECK( IOService, _service, service );
2534
2535    do
2536    {
2537	if (properties)
2538	{
2539	    OSObject *	    obj;
2540	    vm_offset_t     data;
2541	    vm_map_offset_t map_data;
2542
2543	    if( propertiesCnt > sizeof(io_struct_inband_t))
2544		return( kIOReturnMessageTooLarge);
2545
2546	    err = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) properties );
2547	    res = err;
2548	    data = CAST_DOWN(vm_offset_t, map_data);
2549	    if (KERN_SUCCESS == err)
2550	    {
2551		// must return success after vm_map_copyout() succeeds
2552		obj = OSUnserializeXML( (const char *) data, propertiesCnt );
2553		vm_deallocate( kernel_map, data, propertiesCnt );
2554		propertiesDict = OSDynamicCast(OSDictionary, obj);
2555		if (!propertiesDict)
2556		{
2557		    res = kIOReturnBadArgument;
2558		    if (obj)
2559			obj->release();
2560		}
2561	    }
2562	    if (kIOReturnSuccess != res)
2563		break;
2564	}
2565
2566	crossEndian = (ndr.int_rep != NDR_record.int_rep);
2567	if (crossEndian)
2568	{
2569	    if (!propertiesDict)
2570		propertiesDict = OSDictionary::withCapacity(4);
2571	    OSData * data = OSData::withBytes(&ndr, sizeof(ndr));
2572	    if (data)
2573	    {
2574		if (propertiesDict)
2575		    propertiesDict->setObject(kIOUserClientCrossEndianKey, data);
2576		data->release();
2577	    }
2578	}
2579
2580	res = service->newUserClient( owningTask, (void *) owningTask,
2581		    connect_type, propertiesDict, &client );
2582
2583	if (propertiesDict)
2584	    propertiesDict->release();
2585
2586	if (res == kIOReturnSuccess)
2587	{
2588	    assert( OSDynamicCast(IOUserClient, client) );
2589
2590	    disallowAccess = (crossEndian
2591		&& (kOSBooleanTrue != service->getProperty(kIOUserClientCrossEndianCompatibleKey))
2592		&& (kOSBooleanTrue != client->getProperty(kIOUserClientCrossEndianCompatibleKey)));
2593            if (disallowAccess) res = kIOReturnUnsupported;
2594#if CONFIG_MACF
2595	    else if (0 != mac_iokit_check_open(kauth_cred_get(), client, connect_type))
2596		res = kIOReturnNotPermitted;
2597#endif
2598	    if (kIOReturnSuccess != res)
2599	    {
2600		IOStatisticsClientCall();
2601		client->clientClose();
2602		client->release();
2603		client = 0;
2604		break;
2605	    }
2606	    client->sharedInstance = (0 != client->getProperty(kIOUserClientSharedInstanceKey));
2607	    OSString * creatorName = IOCopyLogNameForPID(proc_selfpid());
2608	    if (creatorName)
2609	    {
2610		client->setProperty(kIOUserClientCreatorKey, creatorName);
2611		creatorName->release();
2612	    }
2613	    client->setTerminateDefer(service, false);
2614	}
2615    }
2616    while (false);
2617
2618    *connection = client;
2619    *result = res;
2620
2621    return (err);
2622}
2623
2624/* Routine io_service_close */
2625kern_return_t is_io_service_close(
2626	io_object_t connection )
2627{
2628    OSSet * mappings;
2629    if ((mappings = OSDynamicCast(OSSet, connection)))
2630	return( kIOReturnSuccess );
2631
2632    CHECK( IOUserClient, connection, client );
2633
2634    IOStatisticsClientCall();
2635    client->clientClose();
2636
2637    return( kIOReturnSuccess );
2638}
2639
2640/* Routine io_connect_get_service */
2641kern_return_t is_io_connect_get_service(
2642	io_object_t connection,
2643	io_object_t *service )
2644{
2645    IOService * theService;
2646
2647    CHECK( IOUserClient, connection, client );
2648
2649    theService = client->getService();
2650    if( theService)
2651	theService->retain();
2652
2653    *service = theService;
2654
2655    return( theService ? kIOReturnSuccess : kIOReturnUnsupported );
2656}
2657
2658/* Routine io_connect_set_notification_port */
2659kern_return_t is_io_connect_set_notification_port(
2660	io_object_t connection,
2661	uint32_t notification_type,
2662	mach_port_t port,
2663	uint32_t reference)
2664{
2665    CHECK( IOUserClient, connection, client );
2666
2667    IOStatisticsClientCall();
2668    return( client->registerNotificationPort( port, notification_type,
2669						(io_user_reference_t) reference ));
2670}
2671
2672/* Routine io_connect_set_notification_port */
2673kern_return_t is_io_connect_set_notification_port_64(
2674	io_object_t connection,
2675	uint32_t notification_type,
2676	mach_port_t port,
2677	io_user_reference_t reference)
2678{
2679    CHECK( IOUserClient, connection, client );
2680
2681    IOStatisticsClientCall();
2682    return( client->registerNotificationPort( port, notification_type,
2683						reference ));
2684}
2685
2686/* Routine io_connect_map_memory_into_task */
2687kern_return_t is_io_connect_map_memory_into_task
2688(
2689	io_connect_t connection,
2690	uint32_t memory_type,
2691	task_t into_task,
2692	mach_vm_address_t *address,
2693	mach_vm_size_t *size,
2694	uint32_t flags
2695)
2696{
2697    IOReturn		err;
2698    IOMemoryMap *	map;
2699
2700    CHECK( IOUserClient, connection, client );
2701
2702    IOStatisticsClientCall();
2703    map = client->mapClientMemory64( memory_type, into_task, flags, *address );
2704
2705    if( map) {
2706        *address = map->getAddress();
2707        if( size)
2708            *size = map->getSize();
2709
2710        if( client->sharedInstance
2711	    || (into_task != current_task())) {
2712            // push a name out to the task owning the map,
2713            // so we can clean up maps
2714	    mach_port_name_t name __unused =
2715		IOMachPort::makeSendRightForTask(
2716                                    into_task, map, IKOT_IOKIT_OBJECT );
2717
2718        } else {
2719            // keep it with the user client
2720            IOLockLock( gIOObjectPortLock);
2721            if( 0 == client->mappings)
2722                client->mappings = OSSet::withCapacity(2);
2723            if( client->mappings)
2724                client->mappings->setObject( map);
2725            IOLockUnlock( gIOObjectPortLock);
2726            map->release();
2727        }
2728        err = kIOReturnSuccess;
2729
2730    } else
2731	err = kIOReturnBadArgument;
2732
2733    return( err );
2734}
2735
2736/* Routine is_io_connect_map_memory */
2737kern_return_t is_io_connect_map_memory(
2738	io_object_t     connect,
2739	uint32_t	type,
2740	task_t		task,
2741	vm_address_t *	mapAddr,
2742	vm_size_t    *	mapSize,
2743	uint32_t	flags )
2744{
2745    IOReturn	      err;
2746    mach_vm_address_t address;
2747    mach_vm_size_t    size;
2748
2749    address = SCALAR64(*mapAddr);
2750    size    = SCALAR64(*mapSize);
2751
2752    err = is_io_connect_map_memory_into_task(connect, type, task, &address, &size, flags);
2753
2754    *mapAddr = SCALAR32(address);
2755    *mapSize = SCALAR32(size);
2756
2757    return (err);
2758}
2759
2760} /* extern "C" */
2761
2762IOMemoryMap * IOUserClient::removeMappingForDescriptor(IOMemoryDescriptor * mem)
2763{
2764    OSIterator *  iter;
2765    IOMemoryMap * map = 0;
2766
2767    IOLockLock(gIOObjectPortLock);
2768
2769    iter = OSCollectionIterator::withCollection(mappings);
2770    if(iter)
2771    {
2772        while ((map = OSDynamicCast(IOMemoryMap, iter->getNextObject())))
2773        {
2774            if(mem == map->getMemoryDescriptor())
2775            {
2776                map->retain();
2777                mappings->removeObject(map);
2778                break;
2779            }
2780        }
2781        iter->release();
2782    }
2783
2784    IOLockUnlock(gIOObjectPortLock);
2785
2786    return (map);
2787}
2788
2789extern "C" {
2790
2791/* Routine io_connect_unmap_memory_from_task */
2792kern_return_t is_io_connect_unmap_memory_from_task
2793(
2794	io_connect_t connection,
2795	uint32_t memory_type,
2796	task_t from_task,
2797	mach_vm_address_t address)
2798{
2799    IOReturn		err;
2800    IOOptionBits	options = 0;
2801    IOMemoryDescriptor * memory;
2802    IOMemoryMap *	map;
2803
2804    CHECK( IOUserClient, connection, client );
2805
2806    IOStatisticsClientCall();
2807    err = client->clientMemoryForType( (UInt32) memory_type, &options, &memory );
2808
2809    if( memory && (kIOReturnSuccess == err)) {
2810
2811        options = (options & ~kIOMapUserOptionsMask)
2812		| kIOMapAnywhere | kIOMapReference;
2813
2814	map = memory->createMappingInTask( from_task, address, options );
2815	memory->release();
2816        if( map)
2817	{
2818            IOLockLock( gIOObjectPortLock);
2819            if( client->mappings)
2820                client->mappings->removeObject( map);
2821            IOLockUnlock( gIOObjectPortLock);
2822
2823	    mach_port_name_t name = 0;
2824	    if (from_task != current_task())
2825		name = IOMachPort::makeSendRightForTask( from_task, map, IKOT_IOKIT_OBJECT );
2826	    if (name)
2827	    {
2828		map->userClientUnmap();
2829		err = iokit_mod_send_right( from_task, name, -2 );
2830		err = kIOReturnSuccess;
2831	    }
2832	    else
2833		IOMachPort::releasePortForObject( map, IKOT_IOKIT_OBJECT );
2834	    if (from_task == current_task())
2835		map->release();
2836        }
2837	else
2838            err = kIOReturnBadArgument;
2839    }
2840
2841    return( err );
2842}
2843
2844kern_return_t is_io_connect_unmap_memory(
2845	io_object_t     connect,
2846	uint32_t	type,
2847	task_t		task,
2848	vm_address_t 	mapAddr )
2849{
2850    IOReturn		err;
2851    mach_vm_address_t   address;
2852
2853    address = SCALAR64(mapAddr);
2854
2855    err = is_io_connect_unmap_memory_from_task(connect, type, task, mapAddr);
2856
2857    return (err);
2858}
2859
2860
2861/* Routine io_connect_add_client */
2862kern_return_t is_io_connect_add_client(
2863	io_object_t connection,
2864	io_object_t connect_to)
2865{
2866    CHECK( IOUserClient, connection, client );
2867    CHECK( IOUserClient, connect_to, to );
2868
2869    IOStatisticsClientCall();
2870    return( client->connectClient( to ) );
2871}
2872
2873
2874/* Routine io_connect_set_properties */
2875kern_return_t is_io_connect_set_properties(
2876	io_object_t connection,
2877	io_buf_ptr_t properties,
2878	mach_msg_type_number_t propertiesCnt,
2879        kern_return_t * result)
2880{
2881    return( is_io_registry_entry_set_properties( connection, properties, propertiesCnt, result ));
2882}
2883
2884/* Routine io_user_client_method */
2885kern_return_t is_io_connect_method_var_output
2886(
2887	io_connect_t connection,
2888	uint32_t selector,
2889	io_scalar_inband64_t scalar_input,
2890	mach_msg_type_number_t scalar_inputCnt,
2891	io_struct_inband_t inband_input,
2892	mach_msg_type_number_t inband_inputCnt,
2893	mach_vm_address_t ool_input,
2894	mach_vm_size_t ool_input_size,
2895	io_struct_inband_t inband_output,
2896	mach_msg_type_number_t *inband_outputCnt,
2897	io_scalar_inband64_t scalar_output,
2898	mach_msg_type_number_t *scalar_outputCnt,
2899	io_buf_ptr_t *var_output,
2900	mach_msg_type_number_t *var_outputCnt
2901)
2902{
2903    CHECK( IOUserClient, connection, client );
2904
2905    IOExternalMethodArguments args;
2906    IOReturn ret;
2907    IOMemoryDescriptor * inputMD  = 0;
2908    OSObject *           structureVariableOutputData = 0;
2909
2910    bzero(&args.__reserved[0], sizeof(args.__reserved));
2911    args.version = kIOExternalMethodArgumentsCurrentVersion;
2912
2913    args.selector = selector;
2914
2915    args.asyncWakePort               = MACH_PORT_NULL;
2916    args.asyncReference              = 0;
2917    args.asyncReferenceCount         = 0;
2918    args.structureVariableOutputData = &structureVariableOutputData;
2919
2920    args.scalarInput = scalar_input;
2921    args.scalarInputCount = scalar_inputCnt;
2922    args.structureInput = inband_input;
2923    args.structureInputSize = inband_inputCnt;
2924
2925    if (ool_input)
2926	inputMD = IOMemoryDescriptor::withAddressRange(ool_input, ool_input_size,
2927						    kIODirectionOut, current_task());
2928
2929    args.structureInputDescriptor = inputMD;
2930
2931    args.scalarOutput = scalar_output;
2932    args.scalarOutputCount = *scalar_outputCnt;
2933    args.structureOutput = inband_output;
2934    args.structureOutputSize = *inband_outputCnt;
2935    args.structureOutputDescriptor = NULL;
2936    args.structureOutputDescriptorSize = 0;
2937
2938    IOStatisticsClientCall();
2939    ret = client->externalMethod( selector, &args );
2940
2941    *scalar_outputCnt = args.scalarOutputCount;
2942    *inband_outputCnt = args.structureOutputSize;
2943
2944    if (var_outputCnt && var_output && (kIOReturnSuccess == ret))
2945    {
2946    	OSSerialize * serialize;
2947    	OSData      * data;
2948	vm_size_t     len;
2949
2950	if ((serialize = OSDynamicCast(OSSerialize, structureVariableOutputData)))
2951	{
2952	    len = serialize->getLength();
2953	    *var_outputCnt = len;
2954	    ret = copyoutkdata(serialize->text(), len, var_output);
2955	}
2956	else if ((data = OSDynamicCast(OSData, structureVariableOutputData)))
2957	{
2958	    len = data->getLength();
2959	    *var_outputCnt = len;
2960	    ret = copyoutkdata(data->getBytesNoCopy(), len, var_output);
2961	}
2962	else
2963	{
2964	    ret = kIOReturnUnderrun;
2965	}
2966    }
2967
2968    if (inputMD)
2969	inputMD->release();
2970    if (structureVariableOutputData)
2971    	structureVariableOutputData->release();
2972
2973    return (ret);
2974}
2975
2976/* Routine io_user_client_method */
2977kern_return_t is_io_connect_method
2978(
2979	io_connect_t connection,
2980	uint32_t selector,
2981	io_scalar_inband64_t scalar_input,
2982	mach_msg_type_number_t scalar_inputCnt,
2983	io_struct_inband_t inband_input,
2984	mach_msg_type_number_t inband_inputCnt,
2985	mach_vm_address_t ool_input,
2986	mach_vm_size_t ool_input_size,
2987	io_struct_inband_t inband_output,
2988	mach_msg_type_number_t *inband_outputCnt,
2989	io_scalar_inband64_t scalar_output,
2990	mach_msg_type_number_t *scalar_outputCnt,
2991	mach_vm_address_t ool_output,
2992	mach_vm_size_t *ool_output_size
2993)
2994{
2995    CHECK( IOUserClient, connection, client );
2996
2997    IOExternalMethodArguments args;
2998    IOReturn ret;
2999    IOMemoryDescriptor * inputMD  = 0;
3000    IOMemoryDescriptor * outputMD = 0;
3001
3002    bzero(&args.__reserved[0], sizeof(args.__reserved));
3003    args.version = kIOExternalMethodArgumentsCurrentVersion;
3004
3005    args.selector = selector;
3006
3007    args.asyncWakePort               = MACH_PORT_NULL;
3008    args.asyncReference              = 0;
3009    args.asyncReferenceCount         = 0;
3010    args.structureVariableOutputData = 0;
3011
3012    args.scalarInput = scalar_input;
3013    args.scalarInputCount = scalar_inputCnt;
3014    args.structureInput = inband_input;
3015    args.structureInputSize = inband_inputCnt;
3016
3017    if (ool_input)
3018	inputMD = IOMemoryDescriptor::withAddressRange(ool_input, ool_input_size,
3019						    kIODirectionOut, current_task());
3020
3021    args.structureInputDescriptor = inputMD;
3022
3023    args.scalarOutput = scalar_output;
3024    args.scalarOutputCount = *scalar_outputCnt;
3025    args.structureOutput = inband_output;
3026    args.structureOutputSize = *inband_outputCnt;
3027
3028    if (ool_output && ool_output_size)
3029    {
3030	outputMD = IOMemoryDescriptor::withAddressRange(ool_output, *ool_output_size,
3031						    kIODirectionIn, current_task());
3032    }
3033
3034    args.structureOutputDescriptor = outputMD;
3035    args.structureOutputDescriptorSize = ool_output_size ? *ool_output_size : 0;
3036
3037    IOStatisticsClientCall();
3038    ret = client->externalMethod( selector, &args );
3039
3040    *scalar_outputCnt = args.scalarOutputCount;
3041    *inband_outputCnt = args.structureOutputSize;
3042    *ool_output_size  = args.structureOutputDescriptorSize;
3043
3044    if (inputMD)
3045	inputMD->release();
3046    if (outputMD)
3047	outputMD->release();
3048
3049    return (ret);
3050}
3051
3052/* Routine io_async_user_client_method */
3053kern_return_t is_io_connect_async_method
3054(
3055	io_connect_t connection,
3056	mach_port_t wake_port,
3057	io_async_ref64_t reference,
3058	mach_msg_type_number_t referenceCnt,
3059	uint32_t selector,
3060	io_scalar_inband64_t scalar_input,
3061	mach_msg_type_number_t scalar_inputCnt,
3062	io_struct_inband_t inband_input,
3063	mach_msg_type_number_t inband_inputCnt,
3064	mach_vm_address_t ool_input,
3065	mach_vm_size_t ool_input_size,
3066	io_struct_inband_t inband_output,
3067	mach_msg_type_number_t *inband_outputCnt,
3068	io_scalar_inband64_t scalar_output,
3069	mach_msg_type_number_t *scalar_outputCnt,
3070	mach_vm_address_t ool_output,
3071	mach_vm_size_t * ool_output_size
3072)
3073{
3074    CHECK( IOUserClient, connection, client );
3075
3076    IOExternalMethodArguments args;
3077    IOReturn ret;
3078    IOMemoryDescriptor * inputMD  = 0;
3079    IOMemoryDescriptor * outputMD = 0;
3080
3081    bzero(&args.__reserved[0], sizeof(args.__reserved));
3082    args.version = kIOExternalMethodArgumentsCurrentVersion;
3083
3084    reference[0]	     = (io_user_reference_t) wake_port;
3085    if (vm_map_is_64bit(get_task_map(current_task())))
3086	reference[0]	     |= kIOUCAsync64Flag;
3087
3088    args.selector = selector;
3089
3090    args.asyncWakePort       = wake_port;
3091    args.asyncReference      = reference;
3092    args.asyncReferenceCount = referenceCnt;
3093
3094    args.scalarInput = scalar_input;
3095    args.scalarInputCount = scalar_inputCnt;
3096    args.structureInput = inband_input;
3097    args.structureInputSize = inband_inputCnt;
3098
3099    if (ool_input)
3100	inputMD = IOMemoryDescriptor::withAddressRange(ool_input, ool_input_size,
3101						    kIODirectionOut, current_task());
3102
3103    args.structureInputDescriptor = inputMD;
3104
3105    args.scalarOutput = scalar_output;
3106    args.scalarOutputCount = *scalar_outputCnt;
3107    args.structureOutput = inband_output;
3108    args.structureOutputSize = *inband_outputCnt;
3109
3110    if (ool_output)
3111    {
3112	outputMD = IOMemoryDescriptor::withAddressRange(ool_output, *ool_output_size,
3113						    kIODirectionIn, current_task());
3114    }
3115
3116    args.structureOutputDescriptor = outputMD;
3117    args.structureOutputDescriptorSize = *ool_output_size;
3118
3119    IOStatisticsClientCall();
3120    ret = client->externalMethod( selector, &args );
3121
3122    *inband_outputCnt = args.structureOutputSize;
3123    *ool_output_size  = args.structureOutputDescriptorSize;
3124
3125    if (inputMD)
3126	inputMD->release();
3127    if (outputMD)
3128	outputMD->release();
3129
3130    return (ret);
3131}
3132
3133/* Routine io_connect_method_scalarI_scalarO */
3134kern_return_t is_io_connect_method_scalarI_scalarO(
3135	io_object_t	   connect,
3136	uint32_t	   index,
3137        io_scalar_inband_t       input,
3138        mach_msg_type_number_t	 inputCount,
3139        io_scalar_inband_t       output,
3140        mach_msg_type_number_t * outputCount )
3141{
3142    IOReturn err;
3143    uint32_t i;
3144    io_scalar_inband64_t _input;
3145    io_scalar_inband64_t _output;
3146
3147    mach_msg_type_number_t struct_outputCnt = 0;
3148    mach_vm_size_t ool_output_size = 0;
3149
3150    for (i = 0; i < inputCount; i++)
3151	_input[i] = SCALAR64(input[i]);
3152
3153    err = is_io_connect_method(connect, index,
3154		    _input, inputCount,
3155		    NULL, 0,
3156		    0, 0,
3157		    NULL, &struct_outputCnt,
3158		    _output, outputCount,
3159		    0, &ool_output_size);
3160
3161    for (i = 0; i < *outputCount; i++)
3162	output[i] = SCALAR32(_output[i]);
3163
3164    return (err);
3165}
3166
3167kern_return_t shim_io_connect_method_scalarI_scalarO(
3168	IOExternalMethod *	method,
3169	IOService *		object,
3170        const io_user_scalar_t * input,
3171        mach_msg_type_number_t	 inputCount,
3172        io_user_scalar_t * output,
3173        mach_msg_type_number_t * outputCount )
3174{
3175    IOMethod		func;
3176    io_scalar_inband_t  _output;
3177    IOReturn 		err;
3178    err = kIOReturnBadArgument;
3179
3180    do {
3181
3182	if( inputCount != method->count0)
3183	{
3184	    IOLog("%s: IOUserClient inputCount count mismatch\n", object->getName());
3185	    continue;
3186	}
3187	if( *outputCount != method->count1)
3188	{
3189	    IOLog("%s: IOUserClient outputCount count mismatch\n", object->getName());
3190	    continue;
3191	}
3192
3193	func = method->func;
3194
3195	switch( inputCount) {
3196
3197	    case 6:
3198		err = (object->*func)(  ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
3199					ARG32(input[3]), ARG32(input[4]), ARG32(input[5]) );
3200		break;
3201	    case 5:
3202		err = (object->*func)(  ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
3203					ARG32(input[3]), ARG32(input[4]),
3204					&_output[0] );
3205		break;
3206	    case 4:
3207		err = (object->*func)(  ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
3208					ARG32(input[3]),
3209					&_output[0], &_output[1] );
3210		break;
3211	    case 3:
3212		err = (object->*func)(  ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
3213					&_output[0], &_output[1], &_output[2] );
3214		break;
3215	    case 2:
3216		err = (object->*func)(  ARG32(input[0]), ARG32(input[1]),
3217					&_output[0], &_output[1], &_output[2],
3218					&_output[3] );
3219		break;
3220	    case 1:
3221		err = (object->*func)(  ARG32(input[0]),
3222					&_output[0], &_output[1], &_output[2],
3223					&_output[3], &_output[4] );
3224		break;
3225	    case 0:
3226		err = (object->*func)(  &_output[0], &_output[1], &_output[2],
3227					&_output[3], &_output[4], &_output[5] );
3228		break;
3229
3230	    default:
3231		IOLog("%s: Bad method table\n", object->getName());
3232	}
3233    }
3234    while( false);
3235
3236    uint32_t i;
3237    for (i = 0; i < *outputCount; i++)
3238	output[i] = SCALAR32(_output[i]);
3239
3240    return( err);
3241}
3242
3243/* Routine io_async_method_scalarI_scalarO */
3244kern_return_t is_io_async_method_scalarI_scalarO(
3245	io_object_t	   connect,
3246	mach_port_t wake_port,
3247	io_async_ref_t reference,
3248	mach_msg_type_number_t referenceCnt,
3249	uint32_t	   index,
3250        io_scalar_inband_t       input,
3251        mach_msg_type_number_t	 inputCount,
3252        io_scalar_inband_t       output,
3253        mach_msg_type_number_t * outputCount )
3254{
3255    IOReturn err;
3256    uint32_t i;
3257    io_scalar_inband64_t _input;
3258    io_scalar_inband64_t _output;
3259    io_async_ref64_t _reference;
3260
3261    for (i = 0; i < referenceCnt; i++)
3262	_reference[i] = REF64(reference[i]);
3263
3264    mach_msg_type_number_t struct_outputCnt = 0;
3265    mach_vm_size_t ool_output_size = 0;
3266
3267    for (i = 0; i < inputCount; i++)
3268	_input[i] = SCALAR64(input[i]);
3269
3270    err = is_io_connect_async_method(connect,
3271		    wake_port, _reference, referenceCnt,
3272		    index,
3273		    _input, inputCount,
3274		    NULL, 0,
3275		    0, 0,
3276		    NULL, &struct_outputCnt,
3277		    _output, outputCount,
3278		    0, &ool_output_size);
3279
3280    for (i = 0; i < *outputCount; i++)
3281	output[i] = SCALAR32(_output[i]);
3282
3283    return (err);
3284}
3285/* Routine io_async_method_scalarI_structureO */
3286kern_return_t is_io_async_method_scalarI_structureO(
3287	io_object_t	connect,
3288	mach_port_t wake_port,
3289	io_async_ref_t reference,
3290	mach_msg_type_number_t referenceCnt,
3291	uint32_t	index,
3292        io_scalar_inband_t input,
3293        mach_msg_type_number_t	inputCount,
3294        io_struct_inband_t		output,
3295        mach_msg_type_number_t *	outputCount )
3296{
3297    uint32_t i;
3298    io_scalar_inband64_t _input;
3299    io_async_ref64_t _reference;
3300
3301    for (i = 0; i < referenceCnt; i++)
3302	_reference[i] = REF64(reference[i]);
3303
3304    mach_msg_type_number_t scalar_outputCnt = 0;
3305    mach_vm_size_t ool_output_size = 0;
3306
3307    for (i = 0; i < inputCount; i++)
3308	_input[i] = SCALAR64(input[i]);
3309
3310    return (is_io_connect_async_method(connect,
3311		    wake_port, _reference, referenceCnt,
3312		    index,
3313		    _input, inputCount,
3314		    NULL, 0,
3315		    0, 0,
3316		    output, outputCount,
3317		    NULL, &scalar_outputCnt,
3318		    0, &ool_output_size));
3319}
3320
3321/* Routine io_async_method_scalarI_structureI */
3322kern_return_t is_io_async_method_scalarI_structureI(
3323	io_connect_t		connect,
3324	mach_port_t wake_port,
3325	io_async_ref_t reference,
3326	mach_msg_type_number_t referenceCnt,
3327	uint32_t		index,
3328        io_scalar_inband_t	input,
3329        mach_msg_type_number_t	inputCount,
3330        io_struct_inband_t	inputStruct,
3331        mach_msg_type_number_t	inputStructCount )
3332{
3333    uint32_t i;
3334    io_scalar_inband64_t _input;
3335    io_async_ref64_t _reference;
3336
3337    for (i = 0; i < referenceCnt; i++)
3338	_reference[i] = REF64(reference[i]);
3339
3340    mach_msg_type_number_t scalar_outputCnt = 0;
3341    mach_msg_type_number_t inband_outputCnt = 0;
3342    mach_vm_size_t ool_output_size = 0;
3343
3344    for (i = 0; i < inputCount; i++)
3345	_input[i] = SCALAR64(input[i]);
3346
3347    return (is_io_connect_async_method(connect,
3348		    wake_port, _reference, referenceCnt,
3349		    index,
3350		    _input, inputCount,
3351		    inputStruct, inputStructCount,
3352		    0, 0,
3353		    NULL, &inband_outputCnt,
3354		    NULL, &scalar_outputCnt,
3355		    0, &ool_output_size));
3356}
3357
3358/* Routine io_async_method_structureI_structureO */
3359kern_return_t is_io_async_method_structureI_structureO(
3360	io_object_t	connect,
3361	mach_port_t wake_port,
3362	io_async_ref_t reference,
3363	mach_msg_type_number_t referenceCnt,
3364	uint32_t	index,
3365        io_struct_inband_t		input,
3366        mach_msg_type_number_t	inputCount,
3367        io_struct_inband_t		output,
3368        mach_msg_type_number_t *	outputCount )
3369{
3370    uint32_t i;
3371    mach_msg_type_number_t scalar_outputCnt = 0;
3372    mach_vm_size_t ool_output_size = 0;
3373    io_async_ref64_t _reference;
3374
3375    for (i = 0; i < referenceCnt; i++)
3376	_reference[i] = REF64(reference[i]);
3377
3378    return (is_io_connect_async_method(connect,
3379		    wake_port, _reference, referenceCnt,
3380		    index,
3381		    NULL, 0,
3382		    input, inputCount,
3383		    0, 0,
3384		    output, outputCount,
3385		    NULL, &scalar_outputCnt,
3386		    0, &ool_output_size));
3387}
3388
3389
3390kern_return_t shim_io_async_method_scalarI_scalarO(
3391	IOExternalAsyncMethod *	method,
3392	IOService *		object,
3393	mach_port_t             asyncWakePort,
3394	io_user_reference_t *   asyncReference,
3395	uint32_t                asyncReferenceCount,
3396        const io_user_scalar_t * input,
3397        mach_msg_type_number_t	 inputCount,
3398        io_user_scalar_t * output,
3399        mach_msg_type_number_t * outputCount )
3400{
3401    IOAsyncMethod	func;
3402    uint32_t		i;
3403    io_scalar_inband_t  _output;
3404    IOReturn 		err;
3405    io_async_ref_t	reference;
3406
3407    for (i = 0; i < asyncReferenceCount; i++)
3408	reference[i] = REF32(asyncReference[i]);
3409
3410    err = kIOReturnBadArgument;
3411
3412    do {
3413
3414	if( inputCount != method->count0)
3415	{
3416	    IOLog("%s: IOUserClient inputCount count mismatch\n", object->getName());
3417	    continue;
3418	}
3419	if( *outputCount != method->count1)
3420	{
3421	    IOLog("%s: IOUserClient outputCount count mismatch\n", object->getName());
3422	    continue;
3423	}
3424
3425	func = method->func;
3426
3427        switch( inputCount) {
3428
3429            case 6:
3430                err = (object->*func)(	reference,
3431                                        ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
3432                                        ARG32(input[3]), ARG32(input[4]), ARG32(input[5]) );
3433                break;
3434            case 5:
3435                err = (object->*func)(  reference,
3436                                        ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
3437                                        ARG32(input[3]), ARG32(input[4]),
3438                                        &_output[0] );
3439                break;
3440            case 4:
3441                err = (object->*func)(  reference,
3442                                        ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
3443                                        ARG32(input[3]),
3444                                        &_output[0], &_output[1] );
3445                break;
3446            case 3:
3447                err = (object->*func)(  reference,
3448                                        ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
3449                                        &_output[0], &_output[1], &_output[2] );
3450                break;
3451            case 2:
3452                err = (object->*func)(  reference,
3453                                        ARG32(input[0]), ARG32(input[1]),
3454                                        &_output[0], &_output[1], &_output[2],
3455                                        &_output[3] );
3456                break;
3457            case 1:
3458                err = (object->*func)(  reference,
3459                                        ARG32(input[0]),
3460					&_output[0], &_output[1], &_output[2],
3461                                        &_output[3], &_output[4] );
3462                break;
3463            case 0:
3464                err = (object->*func)(  reference,
3465                                        &_output[0], &_output[1], &_output[2],
3466                                        &_output[3], &_output[4], &_output[5] );
3467                break;
3468
3469            default:
3470                IOLog("%s: Bad method table\n", object->getName());
3471        }
3472    }
3473    while( false);
3474
3475    for (i = 0; i < *outputCount; i++)
3476	output[i] = SCALAR32(_output[i]);
3477
3478    return( err);
3479}
3480
3481
3482/* Routine io_connect_method_scalarI_structureO */
3483kern_return_t is_io_connect_method_scalarI_structureO(
3484	io_object_t	connect,
3485	uint32_t	index,
3486        io_scalar_inband_t input,
3487        mach_msg_type_number_t	inputCount,
3488        io_struct_inband_t		output,
3489        mach_msg_type_number_t *	outputCount )
3490{
3491    uint32_t i;
3492    io_scalar_inband64_t _input;
3493
3494    mach_msg_type_number_t scalar_outputCnt = 0;
3495    mach_vm_size_t ool_output_size = 0;
3496
3497    for (i = 0; i < inputCount; i++)
3498	_input[i] = SCALAR64(input[i]);
3499
3500    return (is_io_connect_method(connect, index,
3501		    _input, inputCount,
3502		    NULL, 0,
3503		    0, 0,
3504		    output, outputCount,
3505		    NULL, &scalar_outputCnt,
3506		    0, &ool_output_size));
3507}
3508
3509kern_return_t shim_io_connect_method_scalarI_structureO(
3510
3511	IOExternalMethod *	method,
3512	IOService *		object,
3513        const io_user_scalar_t * input,
3514        mach_msg_type_number_t	inputCount,
3515        io_struct_inband_t		output,
3516        IOByteCount *	outputCount )
3517{
3518    IOMethod		func;
3519    IOReturn 		err;
3520
3521    err = kIOReturnBadArgument;
3522
3523    do {
3524	if( inputCount != method->count0)
3525	{
3526	    IOLog("%s: IOUserClient inputCount count mismatch\n", object->getName());
3527	    continue;
3528	}
3529	if( (kIOUCVariableStructureSize != method->count1)
3530		&& (*outputCount != method->count1))
3531	{
3532	    IOLog("%s: IOUserClient outputCount count mismatch\n", object->getName());
3533	    continue;
3534	}
3535
3536	func = method->func;
3537
3538	switch( inputCount) {
3539
3540	    case 5:
3541		err = (object->*func)(  ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
3542                                        ARG32(input[3]), ARG32(input[4]),
3543                                        output );
3544		break;
3545	    case 4:
3546		err = (object->*func)(  ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
3547					ARG32(input[3]),
3548					output, (void *)outputCount );
3549		break;
3550	    case 3:
3551		err = (object->*func)(  ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
3552					output, (void *)outputCount, 0 );
3553		break;
3554	    case 2:
3555		err = (object->*func)(  ARG32(input[0]), ARG32(input[1]),
3556					output, (void *)outputCount, 0, 0 );
3557		break;
3558	    case 1:
3559		err = (object->*func)(  ARG32(input[0]),
3560					output, (void *)outputCount, 0, 0, 0 );
3561		break;
3562	    case 0:
3563		err = (object->*func)(  output, (void *)outputCount, 0, 0, 0, 0 );
3564		break;
3565
3566	    default:
3567		IOLog("%s: Bad method table\n", object->getName());
3568	}
3569    }
3570    while( false);
3571
3572    return( err);
3573}
3574
3575
3576kern_return_t shim_io_async_method_scalarI_structureO(
3577	IOExternalAsyncMethod *	method,
3578	IOService *		object,
3579	mach_port_t             asyncWakePort,
3580	io_user_reference_t *   asyncReference,
3581	uint32_t                asyncReferenceCount,
3582        const io_user_scalar_t * input,
3583        mach_msg_type_number_t	inputCount,
3584        io_struct_inband_t		output,
3585        mach_msg_type_number_t *	outputCount )
3586{
3587    IOAsyncMethod	func;
3588    uint32_t		i;
3589    IOReturn 		err;
3590    io_async_ref_t	reference;
3591
3592    for (i = 0; i < asyncReferenceCount; i++)
3593	reference[i] = REF32(asyncReference[i]);
3594
3595    err = kIOReturnBadArgument;
3596    do {
3597	if( inputCount != method->count0)
3598	{
3599	    IOLog("%s: IOUserClient inputCount count mismatch\n", object->getName());
3600	    continue;
3601	}
3602	if( (kIOUCVariableStructureSize != method->count1)
3603		&& (*outputCount != method->count1))
3604	{
3605	    IOLog("%s: IOUserClient outputCount count mismatch\n", object->getName());
3606	    continue;
3607	}
3608
3609	func = method->func;
3610
3611        switch( inputCount) {
3612
3613            case 5:
3614                err = (object->*func)(	reference,
3615                                        ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
3616                                        ARG32(input[3]), ARG32(input[4]),
3617                                        output );
3618                break;
3619            case 4:
3620                err = (object->*func)(	reference,
3621                                        ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
3622                                        ARG32(input[3]),
3623                                        output, (void *)outputCount );
3624                break;
3625            case 3:
3626                err = (object->*func)(	reference,
3627                                        ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
3628                                        output, (void *)outputCount, 0 );
3629                break;
3630            case 2:
3631                err = (object->*func)(	reference,
3632                                        ARG32(input[0]), ARG32(input[1]),
3633                                        output, (void *)outputCount, 0, 0 );
3634                break;
3635            case 1:
3636                err = (object->*func)(	reference,
3637                                        ARG32(input[0]),
3638                                        output, (void *)outputCount, 0, 0, 0 );
3639                break;
3640            case 0:
3641                err = (object->*func)(	reference,
3642                                        output, (void *)outputCount, 0, 0, 0, 0 );
3643                break;
3644
3645            default:
3646                IOLog("%s: Bad method table\n", object->getName());
3647        }
3648    }
3649    while( false);
3650
3651    return( err);
3652}
3653
3654/* Routine io_connect_method_scalarI_structureI */
3655kern_return_t is_io_connect_method_scalarI_structureI(
3656	io_connect_t		connect,
3657	uint32_t		index,
3658        io_scalar_inband_t	input,
3659        mach_msg_type_number_t	inputCount,
3660        io_struct_inband_t	inputStruct,
3661        mach_msg_type_number_t	inputStructCount )
3662{
3663    uint32_t i;
3664    io_scalar_inband64_t _input;
3665
3666    mach_msg_type_number_t scalar_outputCnt = 0;
3667    mach_msg_type_number_t inband_outputCnt = 0;
3668    mach_vm_size_t ool_output_size = 0;
3669
3670    for (i = 0; i < inputCount; i++)
3671	_input[i] = SCALAR64(input[i]);
3672
3673    return (is_io_connect_method(connect, index,
3674		    _input, inputCount,
3675		    inputStruct, inputStructCount,
3676		    0, 0,
3677		    NULL, &inband_outputCnt,
3678		    NULL, &scalar_outputCnt,
3679		    0, &ool_output_size));
3680}
3681
3682kern_return_t shim_io_connect_method_scalarI_structureI(
3683    IOExternalMethod *	method,
3684    IOService *		object,
3685        const io_user_scalar_t * input,
3686        mach_msg_type_number_t	inputCount,
3687        io_struct_inband_t		inputStruct,
3688        mach_msg_type_number_t	inputStructCount )
3689{
3690    IOMethod		func;
3691    IOReturn		err = kIOReturnBadArgument;
3692
3693    do
3694    {
3695	if( (kIOUCVariableStructureSize != method->count0)
3696		&& (inputCount != method->count0))
3697	{
3698	    IOLog("%s: IOUserClient inputCount count mismatch\n", object->getName());
3699	    continue;
3700	}
3701	if( (kIOUCVariableStructureSize != method->count1)
3702		&& (inputStructCount != method->count1))
3703	{
3704	    IOLog("%s: IOUserClient outputCount count mismatch\n", object->getName());
3705	    continue;
3706	}
3707
3708	func = method->func;
3709
3710	switch( inputCount) {
3711
3712	    case 5:
3713		err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
3714					ARG32(input[3]), ARG32(input[4]),
3715					inputStruct );
3716		break;
3717	    case 4:
3718		err = (object->*func)( ARG32(input[0]), ARG32(input[1]), (void *)  input[2],
3719					ARG32(input[3]),
3720					inputStruct, (void *)(uintptr_t)inputStructCount );
3721		break;
3722	    case 3:
3723		err = (object->*func)( ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
3724					inputStruct, (void *)(uintptr_t)inputStructCount,
3725					0 );
3726		break;
3727	    case 2:
3728		err = (object->*func)( ARG32(input[0]), ARG32(input[1]),
3729					inputStruct, (void *)(uintptr_t)inputStructCount,
3730					0, 0 );
3731		break;
3732	    case 1:
3733		err = (object->*func)( ARG32(input[0]),
3734					inputStruct, (void *)(uintptr_t)inputStructCount,
3735					0, 0, 0 );
3736		break;
3737	    case 0:
3738		err = (object->*func)( inputStruct, (void *)(uintptr_t)inputStructCount,
3739					0, 0, 0, 0 );
3740		break;
3741
3742	    default:
3743		IOLog("%s: Bad method table\n", object->getName());
3744	}
3745    }
3746    while (false);
3747
3748    return( err);
3749}
3750
3751kern_return_t shim_io_async_method_scalarI_structureI(
3752	IOExternalAsyncMethod *	method,
3753	IOService *		object,
3754	mach_port_t             asyncWakePort,
3755	io_user_reference_t *   asyncReference,
3756	uint32_t                asyncReferenceCount,
3757        const io_user_scalar_t * input,
3758        mach_msg_type_number_t	inputCount,
3759        io_struct_inband_t		inputStruct,
3760        mach_msg_type_number_t	inputStructCount )
3761{
3762    IOAsyncMethod	func;
3763    uint32_t		i;
3764    IOReturn		err = kIOReturnBadArgument;
3765    io_async_ref_t	reference;
3766
3767    for (i = 0; i < asyncReferenceCount; i++)
3768	reference[i] = REF32(asyncReference[i]);
3769
3770    do
3771    {
3772	if( (kIOUCVariableStructureSize != method->count0)
3773		&& (inputCount != method->count0))
3774	{
3775	    IOLog("%s: IOUserClient inputCount count mismatch\n", object->getName());
3776	    continue;
3777	}
3778	if( (kIOUCVariableStructureSize != method->count1)
3779		&& (inputStructCount != method->count1))
3780	{
3781	    IOLog("%s: IOUserClient outputCount count mismatch\n", object->getName());
3782	    continue;
3783	}
3784
3785        func = method->func;
3786
3787        switch( inputCount) {
3788
3789            case 5:
3790                err = (object->*func)(	reference,
3791                                        ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
3792                                        ARG32(input[3]), ARG32(input[4]),
3793                                        inputStruct );
3794                break;
3795            case 4:
3796                err = (object->*func)(	reference,
3797                                        ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
3798                                        ARG32(input[3]),
3799                                        inputStruct, (void *)(uintptr_t)inputStructCount );
3800                break;
3801            case 3:
3802                err = (object->*func)(	reference,
3803                                        ARG32(input[0]), ARG32(input[1]), ARG32(input[2]),
3804                                        inputStruct, (void *)(uintptr_t)inputStructCount,
3805                                        0 );
3806                break;
3807            case 2:
3808                err = (object->*func)(	reference,
3809                                        ARG32(input[0]), ARG32(input[1]),
3810                                        inputStruct, (void *)(uintptr_t)inputStructCount,
3811                                        0, 0 );
3812                break;
3813            case 1:
3814                err = (object->*func)(	reference,
3815                                        ARG32(input[0]),
3816                                        inputStruct, (void *)(uintptr_t)inputStructCount,
3817                                        0, 0, 0 );
3818                break;
3819            case 0:
3820                err = (object->*func)(	reference,
3821                                        inputStruct, (void *)(uintptr_t)inputStructCount,
3822                                        0, 0, 0, 0 );
3823                break;
3824
3825            default:
3826                IOLog("%s: Bad method table\n", object->getName());
3827        }
3828    }
3829    while (false);
3830
3831    return( err);
3832}
3833
3834/* Routine io_connect_method_structureI_structureO */
3835kern_return_t is_io_connect_method_structureI_structureO(
3836	io_object_t	connect,
3837	uint32_t	index,
3838        io_struct_inband_t		input,
3839        mach_msg_type_number_t	inputCount,
3840        io_struct_inband_t		output,
3841        mach_msg_type_number_t *	outputCount )
3842{
3843    mach_msg_type_number_t scalar_outputCnt = 0;
3844    mach_vm_size_t ool_output_size = 0;
3845
3846    return (is_io_connect_method(connect, index,
3847		    NULL, 0,
3848		    input, inputCount,
3849		    0, 0,
3850		    output, outputCount,
3851		    NULL, &scalar_outputCnt,
3852		    0, &ool_output_size));
3853}
3854
3855kern_return_t shim_io_connect_method_structureI_structureO(
3856    IOExternalMethod *	method,
3857    IOService *		object,
3858        io_struct_inband_t		input,
3859        mach_msg_type_number_t	inputCount,
3860        io_struct_inband_t		output,
3861        IOByteCount *	outputCount )
3862{
3863    IOMethod		func;
3864    IOReturn 		err = kIOReturnBadArgument;
3865
3866    do
3867    {
3868	if( (kIOUCVariableStructureSize != method->count0)
3869		&& (inputCount != method->count0))
3870	{
3871	    IOLog("%s: IOUserClient inputCount count mismatch\n", object->getName());
3872	    continue;
3873	}
3874	if( (kIOUCVariableStructureSize != method->count1)
3875		&& (*outputCount != method->count1))
3876	{
3877	    IOLog("%s: IOUserClient outputCount count mismatch\n", object->getName());
3878	    continue;
3879	}
3880
3881	func = method->func;
3882
3883	if( method->count1) {
3884	    if( method->count0) {
3885		err = (object->*func)( input, output,
3886					(void *)(uintptr_t)inputCount, outputCount, 0, 0 );
3887	    } else {
3888		err = (object->*func)( output, outputCount, 0, 0, 0, 0 );
3889	    }
3890	} else {
3891		err = (object->*func)( input, (void *)(uintptr_t)inputCount, 0, 0, 0, 0 );
3892	}
3893    }
3894    while( false);
3895
3896
3897    return( err);
3898}
3899
3900kern_return_t shim_io_async_method_structureI_structureO(
3901	IOExternalAsyncMethod *	method,
3902	IOService *		object,
3903	mach_port_t           asyncWakePort,
3904	io_user_reference_t * asyncReference,
3905	uint32_t              asyncReferenceCount,
3906        io_struct_inband_t		input,
3907        mach_msg_type_number_t	inputCount,
3908        io_struct_inband_t		output,
3909        mach_msg_type_number_t *	outputCount )
3910{
3911    IOAsyncMethod	func;
3912    uint32_t            i;
3913    IOReturn 		err;
3914    io_async_ref_t	reference;
3915
3916    for (i = 0; i < asyncReferenceCount; i++)
3917	reference[i] = REF32(asyncReference[i]);
3918
3919    err = kIOReturnBadArgument;
3920    do
3921    {
3922	if( (kIOUCVariableStructureSize != method->count0)
3923		&& (inputCount != method->count0))
3924	{
3925	    IOLog("%s: IOUserClient inputCount count mismatch\n", object->getName());
3926	    continue;
3927	}
3928	if( (kIOUCVariableStructureSize != method->count1)
3929		&& (*outputCount != method->count1))
3930	{
3931	    IOLog("%s: IOUserClient outputCount count mismatch\n", object->getName());
3932	    continue;
3933	}
3934
3935        func = method->func;
3936
3937        if( method->count1) {
3938            if( method->count0) {
3939                err = (object->*func)( reference,
3940                                       input, output,
3941                                        (void *)(uintptr_t)inputCount, outputCount, 0, 0 );
3942            } else {
3943                err = (object->*func)( reference,
3944                                       output, outputCount, 0, 0, 0, 0 );
3945            }
3946        } else {
3947                err = (object->*func)( reference,
3948                                       input, (void *)(uintptr_t)inputCount, 0, 0, 0, 0 );
3949        }
3950    }
3951    while( false);
3952
3953    return( err);
3954}
3955
3956/* Routine io_catalog_send_data */
3957kern_return_t is_io_catalog_send_data(
3958        mach_port_t		master_port,
3959        uint32_t                flag,
3960        io_buf_ptr_t 		inData,
3961        mach_msg_type_number_t 	inDataCount,
3962        kern_return_t *		result)
3963{
3964    OSObject * obj = 0;
3965    vm_offset_t data;
3966    kern_return_t kr = kIOReturnError;
3967
3968    //printf("io_catalog_send_data called. flag: %d\n", flag);
3969
3970    if( master_port != master_device_port)
3971        return kIOReturnNotPrivileged;
3972
3973    if( (flag != kIOCatalogRemoveKernelLinker &&
3974            flag != kIOCatalogKextdActive &&
3975            flag != kIOCatalogKextdFinishedLaunching) &&
3976        ( !inData || !inDataCount) )
3977    {
3978        return kIOReturnBadArgument;
3979    }
3980
3981    if (inData) {
3982        vm_map_offset_t map_data;
3983
3984        if( inDataCount > sizeof(io_struct_inband_t) * 1024)
3985            return( kIOReturnMessageTooLarge);
3986
3987        kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t)inData);
3988		data = CAST_DOWN(vm_offset_t, map_data);
3989
3990        if( kr != KERN_SUCCESS)
3991            return kr;
3992
3993        // must return success after vm_map_copyout() succeeds
3994
3995        if( inDataCount ) {
3996            obj = (OSObject *)OSUnserializeXML((const char *)data, inDataCount);
3997            vm_deallocate( kernel_map, data, inDataCount );
3998            if( !obj) {
3999                *result = kIOReturnNoMemory;
4000                return( KERN_SUCCESS);
4001            }
4002        }
4003    }
4004
4005    switch ( flag ) {
4006        case kIOCatalogResetDrivers:
4007        case kIOCatalogResetDriversNoMatch: {
4008                OSArray * array;
4009
4010                array = OSDynamicCast(OSArray, obj);
4011                if (array) {
4012                   if ( !gIOCatalogue->resetAndAddDrivers(array,
4013                        flag == kIOCatalogResetDrivers) ) {
4014
4015                        kr = kIOReturnError;
4016                    }
4017                } else {
4018                    kr = kIOReturnBadArgument;
4019                }
4020            }
4021            break;
4022
4023        case kIOCatalogAddDrivers:
4024        case kIOCatalogAddDriversNoMatch: {
4025                OSArray * array;
4026
4027                array = OSDynamicCast(OSArray, obj);
4028                if ( array ) {
4029                    if ( !gIOCatalogue->addDrivers( array ,
4030                                          flag == kIOCatalogAddDrivers) ) {
4031                        kr = kIOReturnError;
4032                    }
4033                }
4034                else {
4035                    kr = kIOReturnBadArgument;
4036                }
4037            }
4038            break;
4039
4040        case kIOCatalogRemoveDrivers:
4041        case kIOCatalogRemoveDriversNoMatch: {
4042                OSDictionary * dict;
4043
4044                dict = OSDynamicCast(OSDictionary, obj);
4045                if ( dict ) {
4046                    if ( !gIOCatalogue->removeDrivers( dict,
4047                                          flag == kIOCatalogRemoveDrivers ) ) {
4048                        kr = kIOReturnError;
4049                    }
4050                }
4051                else {
4052                    kr = kIOReturnBadArgument;
4053                }
4054            }
4055            break;
4056
4057        case kIOCatalogStartMatching: {
4058                OSDictionary * dict;
4059
4060                dict = OSDynamicCast(OSDictionary, obj);
4061                if ( dict ) {
4062                    if ( !gIOCatalogue->startMatching( dict ) ) {
4063                        kr = kIOReturnError;
4064                    }
4065                }
4066                else {
4067                    kr = kIOReturnBadArgument;
4068                }
4069            }
4070            break;
4071
4072        case kIOCatalogRemoveKernelLinker:
4073            kr = KERN_NOT_SUPPORTED;
4074            break;
4075
4076        case kIOCatalogKextdActive:
4077#if !NO_KEXTD
4078            IOServiceTrace(IOSERVICE_KEXTD_ALIVE, 0, 0, 0, 0);
4079            OSKext::setKextdActive();
4080
4081           /* Dump all nonloaded startup extensions; kextd will now send them
4082            * down on request.
4083            */
4084            OSKext::flushNonloadedKexts( /* flushPrelinkedKexts */ false);
4085#endif
4086            kr = kIOReturnSuccess;
4087            break;
4088
4089        case kIOCatalogKextdFinishedLaunching: {
4090#if !NO_KEXTD
4091                static bool clearedBusy = false;
4092
4093                if (!clearedBusy) {
4094                    IOService * serviceRoot = IOService::getServiceRoot();
4095                    if (serviceRoot) {
4096                        IOServiceTrace(IOSERVICE_KEXTD_READY, 0, 0, 0, 0);
4097                        serviceRoot->adjustBusy(-1);
4098                        clearedBusy = true;
4099                    }
4100                }
4101#endif
4102                kr = kIOReturnSuccess;
4103            }
4104            break;
4105
4106        default:
4107            kr = kIOReturnBadArgument;
4108            break;
4109    }
4110
4111    if (obj) obj->release();
4112
4113    *result = kr;
4114    return( KERN_SUCCESS);
4115}
4116
4117/* Routine io_catalog_terminate */
4118kern_return_t is_io_catalog_terminate(
4119	mach_port_t master_port,
4120	uint32_t flag,
4121	io_name_t name )
4122{
4123    kern_return_t	   kr;
4124
4125    if( master_port != master_device_port )
4126        return kIOReturnNotPrivileged;
4127
4128    kr = IOUserClient::clientHasPrivilege( (void *) current_task(),
4129                                            kIOClientPrivilegeAdministrator );
4130    if( kIOReturnSuccess != kr)
4131        return( kr );
4132
4133    switch ( flag ) {
4134#if !defined(SECURE_KERNEL)
4135        case kIOCatalogServiceTerminate:
4136            OSIterator *	iter;
4137            IOService *		service;
4138
4139            iter = IORegistryIterator::iterateOver(gIOServicePlane,
4140                                        kIORegistryIterateRecursively);
4141            if ( !iter )
4142                return kIOReturnNoMemory;
4143
4144            do {
4145                iter->reset();
4146                while( (service = (IOService *)iter->getNextObject()) ) {
4147                    if( service->metaCast(name)) {
4148                        if ( !service->terminate( kIOServiceRequired
4149                                                | kIOServiceSynchronous) ) {
4150                            kr = kIOReturnUnsupported;
4151                            break;
4152                        }
4153                    }
4154                }
4155            } while( !service && !iter->isValid());
4156            iter->release();
4157            break;
4158
4159        case kIOCatalogModuleUnload:
4160        case kIOCatalogModuleTerminate:
4161            kr = gIOCatalogue->terminateDriversForModule(name,
4162                                        flag == kIOCatalogModuleUnload);
4163            break;
4164#endif
4165
4166        default:
4167            kr = kIOReturnBadArgument;
4168            break;
4169    }
4170
4171    return( kr );
4172}
4173
4174/* Routine io_catalog_get_data */
4175kern_return_t is_io_catalog_get_data(
4176        mach_port_t		master_port,
4177        uint32_t                flag,
4178        io_buf_ptr_t 		*outData,
4179        mach_msg_type_number_t 	*outDataCount)
4180{
4181    kern_return_t kr = kIOReturnSuccess;
4182    OSSerialize * s;
4183
4184    if( master_port != master_device_port)
4185        return kIOReturnNotPrivileged;
4186
4187    //printf("io_catalog_get_data called. flag: %d\n", flag);
4188
4189    s = OSSerialize::withCapacity(4096);
4190    if ( !s )
4191        return kIOReturnNoMemory;
4192
4193    s->clearText();
4194
4195    kr = gIOCatalogue->serializeData(flag, s);
4196
4197    if ( kr == kIOReturnSuccess ) {
4198        vm_offset_t data;
4199        vm_map_copy_t copy;
4200        vm_size_t size;
4201
4202        size = s->getLength();
4203        kr = vm_allocate(kernel_map, &data, size, VM_FLAGS_ANYWHERE);
4204        if ( kr == kIOReturnSuccess ) {
4205            bcopy(s->text(), (void *)data, size);
4206            kr = vm_map_copyin(kernel_map, (vm_map_address_t)data,
4207			       (vm_map_size_t)size, true, &copy);
4208            *outData = (char *)copy;
4209            *outDataCount = size;
4210        }
4211    }
4212
4213    s->release();
4214
4215    return kr;
4216}
4217
4218/* Routine io_catalog_get_gen_count */
4219kern_return_t is_io_catalog_get_gen_count(
4220        mach_port_t		master_port,
4221        uint32_t                *genCount)
4222{
4223    if( master_port != master_device_port)
4224        return kIOReturnNotPrivileged;
4225
4226    //printf("io_catalog_get_gen_count called.\n");
4227
4228    if ( !genCount )
4229        return kIOReturnBadArgument;
4230
4231    *genCount = gIOCatalogue->getGenerationCount();
4232
4233    return kIOReturnSuccess;
4234}
4235
4236/* Routine io_catalog_module_loaded.
4237 * Is invoked from IOKitLib's IOCatalogueModuleLoaded(). Doesn't seem to be used.
4238 */
4239kern_return_t is_io_catalog_module_loaded(
4240        mach_port_t		master_port,
4241        io_name_t               name)
4242{
4243    if( master_port != master_device_port)
4244        return kIOReturnNotPrivileged;
4245
4246    //printf("io_catalog_module_loaded called. name %s\n", name);
4247
4248    if ( !name )
4249        return kIOReturnBadArgument;
4250
4251    gIOCatalogue->moduleHasLoaded(name);
4252
4253    return kIOReturnSuccess;
4254}
4255
4256kern_return_t is_io_catalog_reset(
4257	mach_port_t		master_port,
4258	uint32_t		flag)
4259{
4260    if( master_port != master_device_port)
4261        return kIOReturnNotPrivileged;
4262
4263    switch ( flag ) {
4264        case kIOCatalogResetDefault:
4265            gIOCatalogue->reset();
4266            break;
4267
4268        default:
4269            return kIOReturnBadArgument;
4270    }
4271
4272    return kIOReturnSuccess;
4273}
4274
4275kern_return_t iokit_user_client_trap(struct iokit_user_client_trap_args *args)
4276{
4277    kern_return_t result = kIOReturnBadArgument;
4278    IOUserClient *userClient;
4279
4280    if ((userClient = OSDynamicCast(IOUserClient,
4281            iokit_lookup_connect_ref_current_task((OSObject *)(args->userClientRef))))) {
4282        IOExternalTrap *trap;
4283        IOService *target = NULL;
4284
4285        trap = userClient->getTargetAndTrapForIndex(&target, args->index);
4286
4287        if (trap && target) {
4288            IOTrap func;
4289
4290            func = trap->func;
4291
4292            if (func) {
4293                result = (target->*func)(args->p1, args->p2, args->p3, args->p4, args->p5, args->p6);
4294            }
4295        }
4296
4297        userClient->release();
4298    }
4299
4300    return result;
4301}
4302
4303} /* extern "C" */
4304
4305IOReturn IOUserClient::externalMethod( uint32_t selector, IOExternalMethodArguments * args,
4306					IOExternalMethodDispatch * dispatch, OSObject * target, void * reference )
4307{
4308    IOReturn    err;
4309    IOService * object;
4310    IOByteCount structureOutputSize;
4311
4312    if (dispatch)
4313    {
4314	uint32_t count;
4315	count = dispatch->checkScalarInputCount;
4316	if ((kIOUCVariableStructureSize != count) && (count != args->scalarInputCount))
4317	{
4318	    return (kIOReturnBadArgument);
4319	}
4320
4321	count = dispatch->checkStructureInputSize;
4322	if ((kIOUCVariableStructureSize != count)
4323	    && (count != ((args->structureInputDescriptor)
4324			    ? args->structureInputDescriptor->getLength() : args->structureInputSize)))
4325	{
4326	    return (kIOReturnBadArgument);
4327	}
4328
4329	count = dispatch->checkScalarOutputCount;
4330	if ((kIOUCVariableStructureSize != count) && (count != args->scalarOutputCount))
4331	{
4332	    return (kIOReturnBadArgument);
4333	}
4334
4335	count = dispatch->checkStructureOutputSize;
4336	if ((kIOUCVariableStructureSize != count)
4337	    && (count != ((args->structureOutputDescriptor)
4338			    ? args->structureOutputDescriptor->getLength() : args->structureOutputSize)))
4339	{
4340	    return (kIOReturnBadArgument);
4341	}
4342
4343	if (dispatch->function)
4344	    err = (*dispatch->function)(target, reference, args);
4345	else
4346	    err = kIOReturnNoCompletion;	    /* implementator can dispatch */
4347
4348	return (err);
4349    }
4350
4351
4352    // pre-Leopard API's don't do ool structs
4353    if (args->structureInputDescriptor || args->structureOutputDescriptor)
4354    {
4355       err = kIOReturnIPCError;
4356       return (err);
4357    }
4358
4359    structureOutputSize = args->structureOutputSize;
4360
4361    if (args->asyncWakePort)
4362    {
4363	IOExternalAsyncMethod *	method;
4364
4365	if( !(method = getAsyncTargetAndMethodForIndex(&object, selector)) )
4366	    return (kIOReturnUnsupported);
4367
4368    if (kIOUCForegroundOnly & method->flags)
4369    {
4370	/* is graphics access denied for current task? */
4371	if (proc_get_effective_task_policy(current_task(), TASK_POLICY_GPU_DENY) != 0)
4372            return (kIOReturnNotPermitted);
4373    }
4374
4375	switch (method->flags & kIOUCTypeMask)
4376	{
4377	    case kIOUCScalarIStructI:
4378		err = shim_io_async_method_scalarI_structureI( method, object,
4379					args->asyncWakePort, args->asyncReference, args->asyncReferenceCount,
4380					args->scalarInput, args->scalarInputCount,
4381					(char *)args->structureInput, args->structureInputSize );
4382		break;
4383
4384	    case kIOUCScalarIScalarO:
4385		err = shim_io_async_method_scalarI_scalarO( method, object,
4386					args->asyncWakePort, args->asyncReference, args->asyncReferenceCount,
4387					args->scalarInput, args->scalarInputCount,
4388					args->scalarOutput, &args->scalarOutputCount );
4389		break;
4390
4391	    case kIOUCScalarIStructO:
4392		err = shim_io_async_method_scalarI_structureO( method, object,
4393					args->asyncWakePort, args->asyncReference, args->asyncReferenceCount,
4394					args->scalarInput, args->scalarInputCount,
4395					(char *) args->structureOutput, &args->structureOutputSize );
4396		break;
4397
4398
4399	    case kIOUCStructIStructO:
4400		err = shim_io_async_method_structureI_structureO( method, object,
4401					args->asyncWakePort, args->asyncReference, args->asyncReferenceCount,
4402					(char *)args->structureInput, args->structureInputSize,
4403					(char *) args->structureOutput, &args->structureOutputSize );
4404		break;
4405
4406	    default:
4407		err = kIOReturnBadArgument;
4408		break;
4409	}
4410    }
4411    else
4412    {
4413	IOExternalMethod *	method;
4414
4415	if( !(method = getTargetAndMethodForIndex(&object, selector)) )
4416	    return (kIOReturnUnsupported);
4417
4418    if (kIOUCForegroundOnly & method->flags)
4419    {
4420	/* is graphics access denied for current task? */
4421	if (proc_get_effective_task_policy(current_task(), TASK_POLICY_GPU_DENY) != 0)
4422            return (kIOReturnNotPermitted);
4423
4424    }
4425
4426	switch (method->flags & kIOUCTypeMask)
4427	{
4428	    case kIOUCScalarIStructI:
4429		err = shim_io_connect_method_scalarI_structureI( method, object,
4430					args->scalarInput, args->scalarInputCount,
4431					(char *) args->structureInput, args->structureInputSize );
4432		break;
4433
4434	    case kIOUCScalarIScalarO:
4435		err = shim_io_connect_method_scalarI_scalarO( method, object,
4436					args->scalarInput, args->scalarInputCount,
4437					args->scalarOutput, &args->scalarOutputCount );
4438		break;
4439
4440	    case kIOUCScalarIStructO:
4441		err = shim_io_connect_method_scalarI_structureO( method, object,
4442					args->scalarInput, args->scalarInputCount,
4443					(char *) args->structureOutput, &structureOutputSize );
4444		break;
4445
4446
4447	    case kIOUCStructIStructO:
4448		err = shim_io_connect_method_structureI_structureO( method, object,
4449					(char *) args->structureInput, args->structureInputSize,
4450					(char *) args->structureOutput, &structureOutputSize );
4451		break;
4452
4453	    default:
4454		err = kIOReturnBadArgument;
4455		break;
4456	}
4457    }
4458
4459    args->structureOutputSize = structureOutputSize;
4460
4461    return (err);
4462}
4463
4464
4465#if __LP64__
4466OSMetaClassDefineReservedUnused(IOUserClient, 0);
4467OSMetaClassDefineReservedUnused(IOUserClient, 1);
4468#else
4469OSMetaClassDefineReservedUsed(IOUserClient, 0);
4470OSMetaClassDefineReservedUsed(IOUserClient, 1);
4471#endif
4472OSMetaClassDefineReservedUnused(IOUserClient, 2);
4473OSMetaClassDefineReservedUnused(IOUserClient, 3);
4474OSMetaClassDefineReservedUnused(IOUserClient, 4);
4475OSMetaClassDefineReservedUnused(IOUserClient, 5);
4476OSMetaClassDefineReservedUnused(IOUserClient, 6);
4477OSMetaClassDefineReservedUnused(IOUserClient, 7);
4478OSMetaClassDefineReservedUnused(IOUserClient, 8);
4479OSMetaClassDefineReservedUnused(IOUserClient, 9);
4480OSMetaClassDefineReservedUnused(IOUserClient, 10);
4481OSMetaClassDefineReservedUnused(IOUserClient, 11);
4482OSMetaClassDefineReservedUnused(IOUserClient, 12);
4483OSMetaClassDefineReservedUnused(IOUserClient, 13);
4484OSMetaClassDefineReservedUnused(IOUserClient, 14);
4485OSMetaClassDefineReservedUnused(IOUserClient, 15);
4486
4487