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