]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOUserClient.cpp
xnu-517.tar.gz
[apple/xnu.git] / iokit / Kernel / IOUserClient.cpp
1 /*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25
26
27 #include <IOKit/IOKitServer.h>
28 #include <IOKit/IOUserClient.h>
29 #include <IOKit/IOService.h>
30 #include <IOKit/IOService.h>
31 #include <IOKit/IORegistryEntry.h>
32 #include <IOKit/IOCatalogue.h>
33 #include <IOKit/IOMemoryDescriptor.h>
34 #include <IOKit/IOLib.h>
35
36 #include <IOKit/assert.h>
37
38 #include "IOServicePrivate.h"
39
40 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
41
42 // definitions we should get from osfmk
43
44 //typedef struct ipc_port * ipc_port_t;
45 typedef natural_t ipc_kobject_type_t;
46
47 #define IKOT_IOKIT_SPARE 27
48 #define IKOT_IOKIT_CONNECT 29
49 #define IKOT_IOKIT_OBJECT 30
50
51 extern "C" {
52
53 extern ipc_port_t iokit_alloc_object_port( io_object_t obj,
54 ipc_kobject_type_t type );
55
56 extern kern_return_t iokit_destroy_object_port( ipc_port_t port );
57
58 extern mach_port_name_t iokit_make_send_right( task_t task,
59 io_object_t obj, ipc_kobject_type_t type );
60
61 extern io_object_t iokit_lookup_connect_ref(io_object_t clientRef, ipc_space_t task);
62
63 extern io_object_t iokit_lookup_connect_ref_current_task(io_object_t clientRef);
64
65 extern ipc_port_t master_device_port;
66
67 extern void iokit_retain_port( ipc_port_t port );
68 extern void iokit_release_port( ipc_port_t port );
69
70 extern kern_return_t iokit_switch_object_port( ipc_port_t port, io_object_t obj, ipc_kobject_type_t type );
71
72 #include <vm/vm_map.h>
73
74 } /* extern "C" */
75
76
77 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
78
79 // IOMachPort maps OSObjects to ports, avoiding adding an ivar to OSObject.
80
81 class IOMachPort : public OSObject
82 {
83 OSDeclareDefaultStructors(IOMachPort)
84 public:
85 OSObject * object;
86 ipc_port_t port;
87 UInt32 mscount;
88 UInt8 holdDestroy;
89
90 static IOMachPort * portForObject( OSObject * obj,
91 ipc_kobject_type_t type );
92 static bool noMoreSendersForObject( OSObject * obj,
93 ipc_kobject_type_t type, mach_port_mscount_t * mscount );
94 static void releasePortForObject( OSObject * obj,
95 ipc_kobject_type_t type );
96 static void setHoldDestroy( OSObject * obj, ipc_kobject_type_t type );
97
98 static OSDictionary * dictForType( ipc_kobject_type_t type );
99
100 static mach_port_name_t makeSendRightForTask( task_t task,
101 io_object_t obj, ipc_kobject_type_t type );
102
103 virtual void free();
104 };
105
106 #define super OSObject
107 OSDefineMetaClassAndStructors(IOMachPort, OSObject)
108
109 static IOLock * gIOObjectPortLock;
110
111 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
112
113 // not in dictForType() for debugging ease
114 static OSDictionary * gIOObjectPorts;
115 static OSDictionary * gIOConnectPorts;
116
117 OSDictionary * IOMachPort::dictForType( ipc_kobject_type_t type )
118 {
119 OSDictionary ** dict;
120
121 if( IKOT_IOKIT_OBJECT == type )
122 dict = &gIOObjectPorts;
123 else if( IKOT_IOKIT_CONNECT == type )
124 dict = &gIOConnectPorts;
125 else
126 return( 0 );
127
128 if( 0 == *dict)
129 *dict = OSDictionary::withCapacity( 1 );
130
131 return( *dict );
132 }
133
134 IOMachPort * IOMachPort::portForObject ( OSObject * obj,
135 ipc_kobject_type_t type )
136 {
137 IOMachPort * inst = 0;
138 OSDictionary * dict;
139
140 IOTakeLock( gIOObjectPortLock);
141
142 do {
143
144 dict = dictForType( type );
145 if( !dict)
146 continue;
147
148 if( (inst = (IOMachPort *)
149 dict->getObject( (const OSSymbol *) obj ))) {
150 inst->mscount++;
151 inst->retain();
152 continue;
153 }
154
155 inst = new IOMachPort;
156 if( inst && !inst->init()) {
157 inst = 0;
158 continue;
159 }
160
161 inst->port = iokit_alloc_object_port( obj, type );
162 if( inst->port) {
163 // retains obj
164 dict->setObject( (const OSSymbol *) obj, inst );
165 inst->mscount++;
166
167 } else {
168 inst->release();
169 inst = 0;
170 }
171
172 } while( false );
173
174 IOUnlock( gIOObjectPortLock);
175
176 return( inst );
177 }
178
179 bool IOMachPort::noMoreSendersForObject( OSObject * obj,
180 ipc_kobject_type_t type, mach_port_mscount_t * mscount )
181 {
182 OSDictionary * dict;
183 IOMachPort * machPort;
184 bool destroyed = true;
185
186 IOTakeLock( gIOObjectPortLock);
187
188 if( (dict = dictForType( type ))) {
189 obj->retain();
190
191 machPort = (IOMachPort *) dict->getObject( (const OSSymbol *) obj );
192 if( machPort) {
193 destroyed = (machPort->mscount == *mscount);
194 if( destroyed)
195 dict->removeObject( (const OSSymbol *) obj );
196 else
197 *mscount = machPort->mscount;
198 }
199 obj->release();
200 }
201
202 IOUnlock( gIOObjectPortLock);
203
204 return( destroyed );
205 }
206
207 void IOMachPort::releasePortForObject( OSObject * obj,
208 ipc_kobject_type_t type )
209 {
210 OSDictionary * dict;
211 IOMachPort * machPort;
212
213 IOTakeLock( gIOObjectPortLock);
214
215 if( (dict = dictForType( type ))) {
216 obj->retain();
217 machPort = (IOMachPort *) dict->getObject( (const OSSymbol *) obj );
218 if( machPort && !machPort->holdDestroy)
219 dict->removeObject( (const OSSymbol *) obj );
220 obj->release();
221 }
222
223 IOUnlock( gIOObjectPortLock);
224 }
225
226 void IOMachPort::setHoldDestroy( OSObject * obj, ipc_kobject_type_t type )
227 {
228 OSDictionary * dict;
229 IOMachPort * machPort;
230
231 IOLockLock( gIOObjectPortLock );
232
233 if( (dict = dictForType( type ))) {
234 machPort = (IOMachPort *) dict->getObject( (const OSSymbol *) obj );
235 if( machPort)
236 machPort->holdDestroy = true;
237 }
238
239 IOLockUnlock( gIOObjectPortLock );
240 }
241
242 void IOUserClient::destroyUserReferences( OSObject * obj )
243 {
244 IOMachPort::releasePortForObject( obj, IKOT_IOKIT_OBJECT );
245
246 // panther, 3160200
247 // IOMachPort::releasePortForObject( obj, IKOT_IOKIT_CONNECT );
248
249 OSDictionary * dict;
250
251 IOTakeLock( gIOObjectPortLock);
252 obj->retain();
253
254 if( (dict = IOMachPort::dictForType( IKOT_IOKIT_CONNECT )))
255 {
256 IOMachPort * port;
257 port = (IOMachPort *) dict->getObject( (const OSSymbol *) obj );
258 if (port)
259 {
260 IOUserClient * uc;
261 if ((uc = OSDynamicCast(IOUserClient, obj)) && uc->mappings)
262 {
263 dict->setObject((const OSSymbol *) uc->mappings, port);
264 iokit_switch_object_port(port->port, uc->mappings, IKOT_IOKIT_CONNECT);
265
266 uc->mappings->release();
267 uc->mappings = 0;
268 }
269 dict->removeObject( (const OSSymbol *) obj );
270 }
271 }
272 obj->release();
273 IOUnlock( gIOObjectPortLock);
274 }
275
276 mach_port_name_t IOMachPort::makeSendRightForTask( task_t task,
277 io_object_t obj, ipc_kobject_type_t type )
278 {
279 return( iokit_make_send_right( task, obj, type ));
280 }
281
282 void IOMachPort::free( void )
283 {
284 if( port)
285 iokit_destroy_object_port( port );
286 super::free();
287 }
288
289 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
290
291 class IOUserNotification : public OSIterator
292 {
293 OSDeclareDefaultStructors(IOUserNotification)
294
295 IONotifier * holdNotify;
296 IOLock * lock;
297
298 public:
299
300 virtual bool init( void );
301 virtual void free();
302
303 virtual void setNotification( IONotifier * obj );
304
305 virtual void reset();
306 virtual bool isValid();
307 };
308
309 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
310
311 extern "C" {
312
313 // functions called from osfmk/device/iokit_rpc.c
314
315 void
316 iokit_add_reference( io_object_t obj )
317 {
318 if( obj)
319 obj->retain();
320 }
321
322 void
323 iokit_remove_reference( io_object_t obj )
324 {
325 if( obj)
326 obj->release();
327 }
328
329 ipc_port_t
330 iokit_port_for_object( io_object_t obj, ipc_kobject_type_t type )
331 {
332 IOMachPort * machPort;
333 ipc_port_t port;
334
335 if( (machPort = IOMachPort::portForObject( obj, type ))) {
336
337 port = machPort->port;
338 if( port)
339 iokit_retain_port( port );
340
341 machPort->release();
342
343 } else
344 port = NULL;
345
346 return( port );
347 }
348
349 kern_return_t
350 iokit_client_died( io_object_t obj, ipc_port_t /* port */,
351 ipc_kobject_type_t type, mach_port_mscount_t * mscount )
352 {
353 IOUserClient * client;
354 IOMemoryMap * map;
355 IOUserNotification * notify;
356
357 if( !IOMachPort::noMoreSendersForObject( obj, type, mscount ))
358 return( kIOReturnNotReady );
359
360 if( IKOT_IOKIT_CONNECT == type)
361 {
362 if( (client = OSDynamicCast( IOUserClient, obj )))
363 client->clientDied();
364 }
365 else if( IKOT_IOKIT_OBJECT == type)
366 {
367 if( (map = OSDynamicCast( IOMemoryMap, obj )))
368 map->taskDied();
369 else if( (notify = OSDynamicCast( IOUserNotification, obj )))
370 notify->setNotification( 0 );
371 }
372
373 return( kIOReturnSuccess );
374 }
375
376 }; /* extern "C" */
377
378 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
379
380 class IOServiceUserNotification : public IOUserNotification
381 {
382 OSDeclareDefaultStructors(IOServiceUserNotification)
383
384 struct PingMsg {
385 mach_msg_header_t msgHdr;
386 OSNotificationHeader notifyHeader;
387 };
388
389 enum { kMaxOutstanding = 256 };
390
391 PingMsg * pingMsg;
392 vm_size_t msgSize;
393 OSArray * newSet;
394 OSObject * lastEntry;
395 bool armed;
396
397 public:
398
399 virtual bool init( mach_port_t port, natural_t type,
400 OSAsyncReference reference );
401 virtual void free();
402
403 static bool _handler( void * target,
404 void * ref, IOService * newService );
405 virtual bool handler( void * ref, IOService * newService );
406
407 virtual OSObject * getNextObject();
408 };
409
410 class IOServiceMessageUserNotification : public IOUserNotification
411 {
412 OSDeclareDefaultStructors(IOServiceMessageUserNotification)
413
414 struct PingMsg {
415 mach_msg_header_t msgHdr;
416 mach_msg_body_t msgBody;
417 mach_msg_port_descriptor_t ports[1];
418 OSNotificationHeader notifyHeader;
419 };
420
421 PingMsg * pingMsg;
422 vm_size_t msgSize;
423
424 public:
425
426 virtual bool init( mach_port_t port, natural_t type,
427 OSAsyncReference reference, vm_size_t extraSize );
428 virtual void free();
429
430 static IOReturn _handler( void * target, void * ref,
431 UInt32 messageType, IOService * provider,
432 void * messageArgument, vm_size_t argSize );
433 virtual IOReturn handler( void * ref,
434 UInt32 messageType, IOService * provider,
435 void * messageArgument, vm_size_t argSize );
436
437 virtual OSObject * getNextObject();
438 };
439
440 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
441
442 #undef super
443 #define super OSIterator
444 OSDefineMetaClass( IOUserNotification, OSIterator )
445 OSDefineAbstractStructors( IOUserNotification, OSIterator )
446
447 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
448
449 bool IOUserNotification::init( void )
450 {
451 if( !super::init())
452 return( false );
453
454 lock = IOLockAlloc();
455 if( !lock)
456 return( false );
457
458 return( true );
459 }
460
461 void IOUserNotification::free( void )
462 {
463 if( holdNotify)
464 holdNotify->remove();
465 // can't be in handler now
466
467 if( lock)
468 IOLockFree( lock );
469
470 super::free();
471 }
472
473
474 void IOUserNotification::setNotification( IONotifier * notify )
475 {
476 IONotifier * previousNotify;
477
478 IOLockLock( gIOObjectPortLock);
479
480 previousNotify = holdNotify;
481 holdNotify = notify;
482
483 IOLockUnlock( gIOObjectPortLock);
484
485 if( previousNotify)
486 previousNotify->remove();
487 }
488
489 void IOUserNotification::reset()
490 {
491 // ?
492 }
493
494 bool IOUserNotification::isValid()
495 {
496 return( true );
497 }
498
499 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
500
501 #undef super
502 #define super IOUserNotification
503 OSDefineMetaClassAndStructors(IOServiceUserNotification, IOUserNotification)
504
505 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
506
507 bool IOServiceUserNotification::init( mach_port_t port, natural_t type,
508 OSAsyncReference reference )
509 {
510 newSet = OSArray::withCapacity( 1 );
511 if( !newSet)
512 return( false );
513
514 msgSize = sizeof( PingMsg) + 0;
515 pingMsg = (PingMsg *) IOMalloc( msgSize);
516 if( !pingMsg)
517 return( false );
518
519 bzero( pingMsg, msgSize);
520
521 pingMsg->msgHdr.msgh_remote_port = port;
522 pingMsg->msgHdr.msgh_bits = MACH_MSGH_BITS(
523 MACH_MSG_TYPE_COPY_SEND /*remote*/,
524 MACH_MSG_TYPE_MAKE_SEND /*local*/);
525 pingMsg->msgHdr.msgh_size = msgSize;
526 pingMsg->msgHdr.msgh_id = kOSNotificationMessageID;
527
528 pingMsg->notifyHeader.size = 0;
529 pingMsg->notifyHeader.type = type;
530 bcopy( reference, pingMsg->notifyHeader.reference, sizeof(OSAsyncReference) );
531
532 return( super::init() );
533 }
534
535 void IOServiceUserNotification::free( void )
536 {
537 PingMsg * _pingMsg;
538 vm_size_t _msgSize;
539 OSArray * _newSet;
540 OSObject * _lastEntry;
541
542 _pingMsg = pingMsg;
543 _msgSize = msgSize;
544 _lastEntry = lastEntry;
545 _newSet = newSet;
546
547 super::free();
548
549 if( _pingMsg && _msgSize)
550 IOFree( _pingMsg, _msgSize);
551
552 if( _lastEntry)
553 _lastEntry->release();
554
555 if( _newSet)
556 _newSet->release();
557 }
558
559 bool IOServiceUserNotification::_handler( void * target,
560 void * ref, IOService * newService )
561 {
562 return( ((IOServiceUserNotification *) target)->handler( ref, newService ));
563 }
564
565 bool IOServiceUserNotification::handler( void * ref,
566 IOService * newService )
567 {
568 unsigned int count;
569 kern_return_t kr;
570 ipc_port_t port = NULL;
571 bool sendPing = false;
572
573 IOTakeLock( lock );
574
575 count = newSet->getCount();
576 if( count < kMaxOutstanding) {
577
578 newSet->setObject( newService );
579 if( (sendPing = (armed && (0 == count))))
580 armed = false;
581 }
582
583 IOUnlock( lock );
584
585 if( kIOServiceTerminatedNotificationType == pingMsg->notifyHeader.type)
586 IOMachPort::setHoldDestroy( newService, IKOT_IOKIT_OBJECT );
587
588 if( sendPing) {
589 if( (port = iokit_port_for_object( this, IKOT_IOKIT_OBJECT ) ))
590 pingMsg->msgHdr.msgh_local_port = port;
591 else
592 pingMsg->msgHdr.msgh_local_port = NULL;
593
594 kr = mach_msg_send_from_kernel( &pingMsg->msgHdr,
595 pingMsg->msgHdr.msgh_size);
596 if( port)
597 iokit_release_port( port );
598
599 if( KERN_SUCCESS != kr)
600 IOLog("%s: mach_msg_send_from_kernel {%x}\n", __FILE__, kr );
601 }
602
603 return( true );
604 }
605
606 OSObject * IOServiceUserNotification::getNextObject()
607 {
608 unsigned int count;
609 OSObject * result;
610
611 IOTakeLock( lock );
612
613 if( lastEntry)
614 lastEntry->release();
615
616 count = newSet->getCount();
617 if( count ) {
618 result = newSet->getObject( count - 1 );
619 result->retain();
620 newSet->removeObject( count - 1);
621 } else {
622 result = 0;
623 armed = true;
624 }
625 lastEntry = result;
626
627 IOUnlock( lock );
628
629 return( result );
630 }
631
632 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
633
634 OSDefineMetaClassAndStructors(IOServiceMessageUserNotification, IOUserNotification)
635
636 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
637
638 bool IOServiceMessageUserNotification::init( mach_port_t port, natural_t type,
639 OSAsyncReference reference, vm_size_t extraSize )
640 {
641
642 extraSize += sizeof(IOServiceInterestContent);
643 msgSize = sizeof( PingMsg) + extraSize;
644 pingMsg = (PingMsg *) IOMalloc( msgSize);
645 if( !pingMsg)
646 return( false );
647
648 bzero( pingMsg, msgSize);
649
650 pingMsg->msgHdr.msgh_remote_port = port;
651 pingMsg->msgHdr.msgh_bits = MACH_MSGH_BITS_COMPLEX
652 | MACH_MSGH_BITS(
653 MACH_MSG_TYPE_COPY_SEND /*remote*/,
654 MACH_MSG_TYPE_MAKE_SEND /*local*/);
655 pingMsg->msgHdr.msgh_size = msgSize;
656 pingMsg->msgHdr.msgh_id = kOSNotificationMessageID;
657
658 pingMsg->msgBody.msgh_descriptor_count = 1;
659
660 pingMsg->ports[0].name = 0;
661 pingMsg->ports[0].disposition = MACH_MSG_TYPE_MAKE_SEND;
662 pingMsg->ports[0].type = MACH_MSG_PORT_DESCRIPTOR;
663
664 pingMsg->notifyHeader.size = extraSize;
665 pingMsg->notifyHeader.type = type;
666 bcopy( reference, pingMsg->notifyHeader.reference, sizeof(OSAsyncReference) );
667
668 return( super::init() );
669 }
670
671 void IOServiceMessageUserNotification::free( void )
672 {
673 PingMsg * _pingMsg;
674 vm_size_t _msgSize;
675
676 _pingMsg = pingMsg;
677 _msgSize = msgSize;
678
679 super::free();
680
681 if( _pingMsg && _msgSize)
682 IOFree( _pingMsg, _msgSize);
683 }
684
685 IOReturn IOServiceMessageUserNotification::_handler( void * target, void * ref,
686 UInt32 messageType, IOService * provider,
687 void * argument, vm_size_t argSize )
688 {
689 return( ((IOServiceMessageUserNotification *) target)->handler(
690 ref, messageType, provider, argument, argSize));
691 }
692
693 IOReturn IOServiceMessageUserNotification::handler( void * ref,
694 UInt32 messageType, IOService * provider,
695 void * messageArgument, vm_size_t argSize )
696 {
697 kern_return_t kr;
698 ipc_port_t thisPort, providerPort;
699 IOServiceInterestContent * data = (IOServiceInterestContent *)
700 pingMsg->notifyHeader.content;
701
702 data->messageType = messageType;
703 if( argSize == 0) {
704 argSize = sizeof( messageArgument);
705 data->messageArgument[0] = messageArgument;
706 } else {
707 if( argSize > kIOUserNotifyMaxMessageSize)
708 argSize = kIOUserNotifyMaxMessageSize;
709 bcopy( messageArgument, data->messageArgument, argSize );
710 }
711 pingMsg->msgHdr.msgh_size = sizeof( PingMsg)
712 + sizeof( IOServiceInterestContent )
713 - sizeof( data->messageArgument)
714 + argSize;
715
716 providerPort = iokit_port_for_object( provider, IKOT_IOKIT_OBJECT );
717 pingMsg->ports[0].name = providerPort;
718 thisPort = iokit_port_for_object( this, IKOT_IOKIT_OBJECT );
719 pingMsg->msgHdr.msgh_local_port = thisPort;
720 kr = mach_msg_send_from_kernel( &pingMsg->msgHdr,
721 pingMsg->msgHdr.msgh_size);
722 if( thisPort)
723 iokit_release_port( thisPort );
724 if( providerPort)
725 iokit_release_port( providerPort );
726
727 if( KERN_SUCCESS != kr)
728 IOLog("%s: mach_msg_send_from_kernel {%x}\n", __FILE__, kr );
729
730 return( kIOReturnSuccess );
731 }
732
733 OSObject * IOServiceMessageUserNotification::getNextObject()
734 {
735 return( 0 );
736 }
737
738 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
739
740 #undef super
741 #define super IOService
742 OSDefineMetaClassAndAbstractStructors( IOUserClient, IOService )
743
744 void IOUserClient::initialize( void )
745 {
746 gIOObjectPortLock = IOLockAlloc();
747
748 assert( gIOObjectPortLock );
749 }
750
751 void IOUserClient::setAsyncReference(OSAsyncReference asyncRef,
752 mach_port_t wakePort,
753 void *callback, void *refcon)
754 {
755 asyncRef[kIOAsyncReservedIndex] = (natural_t) wakePort;
756 asyncRef[kIOAsyncCalloutFuncIndex] = (natural_t) callback;
757 asyncRef[kIOAsyncCalloutRefconIndex] = (natural_t) refcon;
758 }
759
760 IOReturn IOUserClient::clientHasPrivilege( void * securityToken,
761 const char * privilegeName )
762 {
763 kern_return_t kr;
764 security_token_t token;
765 mach_msg_type_number_t count;
766
767 count = TASK_SECURITY_TOKEN_COUNT;
768 kr = task_info( (task_t) securityToken, TASK_SECURITY_TOKEN,
769 (task_info_t) &token, &count );
770
771 if (KERN_SUCCESS != kr)
772 {}
773 else if (!strcmp(privilegeName, kIOClientPrivilegeAdministrator))
774 {
775 if (0 != token.val[0])
776 kr = kIOReturnNotPrivileged;
777 }
778 else if (!strcmp(privilegeName, kIOClientPrivilegeLocalUser))
779 {
780 OSArray * array;
781 OSDictionary * user = 0;
782
783 if ((array = OSDynamicCast(OSArray,
784 IORegistryEntry::getRegistryRoot()->copyProperty(gIOConsoleUsersKey))))
785 {
786 for (unsigned int idx = 0;
787 (user = OSDynamicCast(OSDictionary, array->getObject(idx)));
788 idx++)
789 {
790 OSNumber * num;
791 if ((num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionUIDKey)))
792 && (token.val[0] == num->unsigned32BitValue()))
793 break;
794 }
795 array->release();
796 }
797 if (!user)
798 kr = kIOReturnNotPrivileged;
799 }
800 else
801 kr = kIOReturnUnsupported;
802
803 return (kr);
804 }
805
806 bool IOUserClient::initWithTask(task_t owningTask,
807 void * securityID,
808 UInt32 type )
809 {
810 if( getPropertyTable())
811 return true;
812 else
813 return super::init();
814 }
815
816 bool IOUserClient::initWithTask(task_t owningTask,
817 void * securityID,
818 UInt32 type,
819 OSDictionary * properties )
820 {
821 bool ok;
822
823 ok = super::init( properties );
824 ok &= initWithTask( owningTask, securityID, type );
825
826 return( ok );
827 }
828
829 void IOUserClient::free()
830 {
831 if( mappings)
832 mappings->release();
833
834 super::free();
835 }
836
837 IOReturn IOUserClient::clientDied( void )
838 {
839 return( clientClose());
840 }
841
842 IOReturn IOUserClient::clientClose( void )
843 {
844 return( kIOReturnUnsupported );
845 }
846
847 IOService * IOUserClient::getService( void )
848 {
849 return( 0 );
850 }
851
852 IOReturn IOUserClient::registerNotificationPort(
853 mach_port_t /* port */,
854 UInt32 /* type */,
855 UInt32 /* refCon */)
856 {
857 return( kIOReturnUnsupported);
858 }
859
860 IOReturn IOUserClient::getNotificationSemaphore( UInt32 notification_type,
861 semaphore_t * semaphore )
862 {
863 return( kIOReturnUnsupported);
864 }
865
866 IOReturn IOUserClient::connectClient( IOUserClient * /* client */ )
867 {
868 return( kIOReturnUnsupported);
869 }
870
871 IOReturn IOUserClient::clientMemoryForType( UInt32 type,
872 IOOptionBits * options,
873 IOMemoryDescriptor ** memory )
874 {
875 return( kIOReturnUnsupported);
876 }
877
878 IOMemoryMap * IOUserClient::mapClientMemory(
879 IOOptionBits type,
880 task_t task,
881 IOOptionBits mapFlags,
882 IOVirtualAddress atAddress )
883 {
884 IOReturn err;
885 IOOptionBits options = 0;
886 IOMemoryDescriptor * memory;
887 IOMemoryMap * map = 0;
888
889 err = clientMemoryForType( (UInt32) type, &options, &memory );
890
891 if( memory && (kIOReturnSuccess == err)) {
892
893 options = (options & ~kIOMapUserOptionsMask)
894 | (mapFlags & kIOMapUserOptionsMask);
895 map = memory->map( task, atAddress, options );
896 memory->release();
897 }
898
899 return( map );
900 }
901
902 IOReturn IOUserClient::exportObjectToClient(task_t task,
903 OSObject *obj, io_object_t *clientObj)
904 {
905 mach_port_name_t name;
906
907 name = IOMachPort::makeSendRightForTask( task, obj, IKOT_IOKIT_OBJECT );
908 assert( name );
909
910 *(mach_port_name_t *)clientObj = name;
911 return kIOReturnSuccess;
912 }
913
914 IOExternalMethod * IOUserClient::getExternalMethodForIndex( UInt32 /* index */)
915 {
916 return( 0 );
917 }
918
919 IOExternalAsyncMethod * IOUserClient::getExternalAsyncMethodForIndex( UInt32 /* index */)
920 {
921 return( 0 );
922 }
923
924 IOExternalMethod * IOUserClient::
925 getTargetAndMethodForIndex(IOService **targetP, UInt32 index)
926 {
927 IOExternalMethod *method = getExternalMethodForIndex(index);
928
929 if (method)
930 *targetP = (IOService *) method->object;
931
932 return method;
933 }
934
935 IOExternalAsyncMethod * IOUserClient::
936 getAsyncTargetAndMethodForIndex(IOService ** targetP, UInt32 index)
937 {
938 IOExternalAsyncMethod *method = getExternalAsyncMethodForIndex(index);
939
940 if (method)
941 *targetP = (IOService *) method->object;
942
943 return method;
944 }
945
946 IOExternalTrap * IOUserClient::
947 getExternalTrapForIndex(UInt32 index)
948 {
949 return NULL;
950 }
951
952 IOExternalTrap * IOUserClient::
953 getTargetAndTrapForIndex(IOService ** targetP, UInt32 index)
954 {
955 IOExternalTrap *trap = getExternalTrapForIndex(index);
956
957 if (trap) {
958 *targetP = trap->object;
959 }
960
961 return trap;
962 }
963
964 IOReturn IOUserClient::sendAsyncResult(OSAsyncReference reference,
965 IOReturn result, void *args[], UInt32 numArgs)
966 {
967 struct ReplyMsg {
968 mach_msg_header_t msgHdr;
969 OSNotificationHeader notifyHdr;
970 IOAsyncCompletionContent asyncContent;
971 void * args[kMaxAsyncArgs];
972 };
973 ReplyMsg replyMsg;
974 mach_port_t replyPort;
975 kern_return_t kr;
976
977 // If no reply port, do nothing.
978 replyPort = (mach_port_t) reference[0];
979 if(replyPort == MACH_PORT_NULL)
980 return kIOReturnSuccess;
981
982 if(numArgs > kMaxAsyncArgs)
983 return kIOReturnMessageTooLarge;
984 replyMsg.msgHdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND /*remote*/,
985 0 /*local*/);
986 replyMsg.msgHdr.msgh_size =
987 sizeof(replyMsg) - (kMaxAsyncArgs-numArgs)*sizeof(void *);
988 replyMsg.msgHdr.msgh_remote_port = replyPort;
989 replyMsg.msgHdr.msgh_local_port = 0;
990 replyMsg.msgHdr.msgh_id = kOSNotificationMessageID;
991
992 replyMsg.notifyHdr.size = sizeof(IOAsyncCompletionContent)
993 + numArgs*sizeof(void *);
994 replyMsg.notifyHdr.type = kIOAsyncCompletionNotificationType;
995 bcopy( reference, replyMsg.notifyHdr.reference, sizeof(OSAsyncReference));
996
997 replyMsg.asyncContent.result = result;
998 if(numArgs > 0)
999 bcopy(args, replyMsg.args, sizeof(void *)*numArgs);
1000 kr = mach_msg_send_from_kernel( &replyMsg.msgHdr,
1001 replyMsg.msgHdr.msgh_size);
1002 if( KERN_SUCCESS != kr)
1003 IOLog("%s: mach_msg_send_from_kernel {%x}\n", __FILE__, kr );
1004 return kr;
1005 }
1006
1007 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1008
1009 extern "C" {
1010
1011 #define CHECK(cls,obj,out) \
1012 cls * out; \
1013 if( !(out = OSDynamicCast( cls, obj))) \
1014 return( kIOReturnBadArgument )
1015
1016 /* Routine io_object_get_class */
1017 kern_return_t is_io_object_get_class(
1018 io_object_t object,
1019 io_name_t className )
1020 {
1021 if( !object)
1022 return( kIOReturnBadArgument );
1023
1024 strcpy( className, object->getMetaClass()->getClassName());
1025 return( kIOReturnSuccess );
1026 }
1027
1028 /* Routine io_object_conforms_to */
1029 kern_return_t is_io_object_conforms_to(
1030 io_object_t object,
1031 io_name_t className,
1032 boolean_t *conforms )
1033 {
1034 if( !object)
1035 return( kIOReturnBadArgument );
1036
1037 *conforms = (0 != object->metaCast( className ));
1038 return( kIOReturnSuccess );
1039 }
1040
1041 /* Routine io_object_get_retain_count */
1042 kern_return_t is_io_object_get_retain_count(
1043 io_object_t object,
1044 int *retainCount )
1045 {
1046 if( !object)
1047 return( kIOReturnBadArgument );
1048
1049 *retainCount = object->getRetainCount();
1050 return( kIOReturnSuccess );
1051 }
1052
1053 /* Routine io_iterator_next */
1054 kern_return_t is_io_iterator_next(
1055 io_object_t iterator,
1056 io_object_t *object )
1057 {
1058 OSObject * obj;
1059
1060 CHECK( OSIterator, iterator, iter );
1061
1062 obj = iter->getNextObject();
1063 if( obj) {
1064 obj->retain();
1065 *object = obj;
1066 return( kIOReturnSuccess );
1067 } else
1068 return( kIOReturnNoDevice );
1069 }
1070
1071 /* Routine io_iterator_reset */
1072 kern_return_t is_io_iterator_reset(
1073 io_object_t iterator )
1074 {
1075 CHECK( OSIterator, iterator, iter );
1076
1077 iter->reset();
1078
1079 return( kIOReturnSuccess );
1080 }
1081
1082 /* Routine io_iterator_is_valid */
1083 kern_return_t is_io_iterator_is_valid(
1084 io_object_t iterator,
1085 boolean_t *is_valid )
1086 {
1087 CHECK( OSIterator, iterator, iter );
1088
1089 *is_valid = iter->isValid();
1090
1091 return( kIOReturnSuccess );
1092 }
1093
1094 /* Routine io_service_match_property_table */
1095 kern_return_t is_io_service_match_property_table(
1096 io_service_t _service,
1097 io_string_t matching,
1098 boolean_t *matches )
1099 {
1100 CHECK( IOService, _service, service );
1101
1102 kern_return_t kr;
1103 OSObject * obj;
1104 OSDictionary * dict;
1105
1106 obj = OSUnserializeXML( matching );
1107
1108 if( (dict = OSDynamicCast( OSDictionary, obj))) {
1109 *matches = service->passiveMatch( dict );
1110 kr = kIOReturnSuccess;
1111 } else
1112 kr = kIOReturnBadArgument;
1113
1114 if( obj)
1115 obj->release();
1116
1117 return( kr );
1118 }
1119
1120 /* Routine io_service_match_property_table_ool */
1121 kern_return_t is_io_service_match_property_table_ool(
1122 io_object_t service,
1123 io_buf_ptr_t matching,
1124 mach_msg_type_number_t matchingCnt,
1125 natural_t *result,
1126 boolean_t *matches )
1127 {
1128 kern_return_t kr;
1129 vm_offset_t data;
1130
1131 kr = vm_map_copyout( kernel_map, &data, (vm_map_copy_t) matching );
1132
1133 if( KERN_SUCCESS == kr) {
1134 // must return success after vm_map_copyout() succeeds
1135 *result = is_io_service_match_property_table( service,
1136 (char *) data, matches );
1137 vm_deallocate( kernel_map, data, matchingCnt );
1138 }
1139
1140 return( kr );
1141 }
1142
1143 /* Routine io_service_get_matching_services */
1144 kern_return_t is_io_service_get_matching_services(
1145 mach_port_t master_port,
1146 io_string_t matching,
1147 io_iterator_t *existing )
1148 {
1149 kern_return_t kr;
1150 OSObject * obj;
1151 OSDictionary * dict;
1152
1153 if( master_port != master_device_port)
1154 return( kIOReturnNotPrivileged);
1155
1156 obj = OSUnserializeXML( matching );
1157
1158 if( (dict = OSDynamicCast( OSDictionary, obj))) {
1159 *existing = IOService::getMatchingServices( dict );
1160 kr = kIOReturnSuccess;
1161 } else
1162 kr = kIOReturnBadArgument;
1163
1164 if( obj)
1165 obj->release();
1166
1167 return( kr );
1168 }
1169
1170 /* Routine io_service_get_matching_services_ool */
1171 kern_return_t is_io_service_get_matching_services_ool(
1172 mach_port_t master_port,
1173 io_buf_ptr_t matching,
1174 mach_msg_type_number_t matchingCnt,
1175 natural_t *result,
1176 io_object_t *existing )
1177 {
1178 kern_return_t kr;
1179 vm_offset_t data;
1180
1181 kr = vm_map_copyout( kernel_map, &data, (vm_map_copy_t) matching );
1182
1183 if( KERN_SUCCESS == kr) {
1184 // must return success after vm_map_copyout() succeeds
1185 *result = is_io_service_get_matching_services( master_port,
1186 (char *) data, existing );
1187 vm_deallocate( kernel_map, data, matchingCnt );
1188 }
1189
1190 return( kr );
1191 }
1192
1193 /* Routine io_service_add_notification */
1194 kern_return_t is_io_service_add_notification(
1195 mach_port_t master_port,
1196 io_name_t notification_type,
1197 io_string_t matching,
1198 mach_port_t port,
1199 io_async_ref_t reference,
1200 mach_msg_type_number_t referenceCnt,
1201 io_object_t * notification )
1202 {
1203 IOServiceUserNotification * userNotify = 0;
1204 IONotifier * notify = 0;
1205 const OSSymbol * sym;
1206 OSDictionary * dict;
1207 IOReturn err;
1208 unsigned long int userMsgType;
1209
1210
1211 if( master_port != master_device_port)
1212 return( kIOReturnNotPrivileged);
1213
1214 do {
1215 err = kIOReturnNoResources;
1216
1217 if( !(sym = OSSymbol::withCString( notification_type )))
1218 err = kIOReturnNoResources;
1219
1220 if( !(dict = OSDynamicCast( OSDictionary,
1221 OSUnserializeXML( matching )))) {
1222 err = kIOReturnBadArgument;
1223 continue;
1224 }
1225
1226 if( (sym == gIOPublishNotification)
1227 || (sym == gIOFirstPublishNotification))
1228 userMsgType = kIOServicePublishNotificationType;
1229 else if( (sym == gIOMatchedNotification)
1230 || (sym == gIOFirstMatchNotification))
1231 userMsgType = kIOServiceMatchedNotificationType;
1232 else if( sym == gIOTerminatedNotification)
1233 userMsgType = kIOServiceTerminatedNotificationType;
1234 else
1235 userMsgType = kLastIOKitNotificationType;
1236
1237 userNotify = new IOServiceUserNotification;
1238
1239 if( userNotify && !userNotify->init( port, userMsgType,
1240 reference)) {
1241 userNotify->release();
1242 userNotify = 0;
1243 }
1244 if( !userNotify)
1245 continue;
1246
1247 notify = IOService::addNotification( sym, dict,
1248 &userNotify->_handler, userNotify );
1249 if( notify) {
1250 dict = 0;
1251 *notification = userNotify;
1252 userNotify->setNotification( notify );
1253 err = kIOReturnSuccess;
1254 } else
1255 err = kIOReturnUnsupported;
1256
1257 } while( false );
1258
1259 if( sym)
1260 sym->release();
1261 if( dict)
1262 dict->release();
1263
1264 return( err );
1265 }
1266
1267 /* Routine io_service_add_notification_ool */
1268 kern_return_t is_io_service_add_notification_ool(
1269 mach_port_t master_port,
1270 io_name_t notification_type,
1271 io_buf_ptr_t matching,
1272 mach_msg_type_number_t matchingCnt,
1273 mach_port_t wake_port,
1274 io_async_ref_t reference,
1275 mach_msg_type_number_t referenceCnt,
1276 natural_t *result,
1277 io_object_t *notification )
1278 {
1279 kern_return_t kr;
1280 vm_offset_t data;
1281
1282 kr = vm_map_copyout( kernel_map, &data, (vm_map_copy_t) matching );
1283
1284 if( KERN_SUCCESS == kr) {
1285 // must return success after vm_map_copyout() succeeds
1286 *result = is_io_service_add_notification( master_port, notification_type,
1287 (char *) data, wake_port, reference, referenceCnt, notification );
1288 vm_deallocate( kernel_map, data, matchingCnt );
1289 }
1290
1291 return( kr );
1292 }
1293
1294
1295 /* Routine io_service_add_notification_old */
1296 kern_return_t is_io_service_add_notification_old(
1297 mach_port_t master_port,
1298 io_name_t notification_type,
1299 io_string_t matching,
1300 mach_port_t port,
1301 natural_t ref,
1302 io_object_t * notification )
1303 {
1304 return( is_io_service_add_notification( master_port, notification_type,
1305 matching, port, &ref, 1, notification ));
1306 }
1307
1308 /* Routine io_service_add_message_notification */
1309 kern_return_t is_io_service_add_interest_notification(
1310 io_object_t _service,
1311 io_name_t type_of_interest,
1312 mach_port_t port,
1313 io_async_ref_t reference,
1314 mach_msg_type_number_t referenceCnt,
1315 io_object_t * notification )
1316 {
1317
1318 IOServiceMessageUserNotification * userNotify = 0;
1319 IONotifier * notify = 0;
1320 const OSSymbol * sym;
1321 IOReturn err;
1322
1323 CHECK( IOService, _service, service );
1324
1325 err = kIOReturnNoResources;
1326 if( (sym = OSSymbol::withCString( type_of_interest ))) do {
1327
1328 userNotify = new IOServiceMessageUserNotification;
1329
1330 if( userNotify && !userNotify->init( port, kIOServiceMessageNotificationType,
1331 reference, kIOUserNotifyMaxMessageSize )) {
1332 userNotify->release();
1333 userNotify = 0;
1334 }
1335 if( !userNotify)
1336 continue;
1337
1338 notify = service->registerInterest( sym,
1339 &userNotify->_handler, userNotify );
1340 if( notify) {
1341 *notification = userNotify;
1342 userNotify->setNotification( notify );
1343 err = kIOReturnSuccess;
1344 } else
1345 err = kIOReturnUnsupported;
1346
1347 sym->release();
1348
1349 } while( false );
1350
1351 return( err );
1352 }
1353
1354 /* Routine io_service_acknowledge_notification */
1355 kern_return_t is_io_service_acknowledge_notification(
1356 io_object_t _service,
1357 natural_t notify_ref,
1358 natural_t response )
1359 {
1360 CHECK( IOService, _service, service );
1361
1362 return( service->acknowledgeNotification( (IONotificationRef) notify_ref,
1363 (IOOptionBits) response ));
1364
1365 }
1366
1367 /* Routine io_connect_get_semaphore */
1368 kern_return_t is_io_connect_get_notification_semaphore(
1369 io_connect_t connection,
1370 natural_t notification_type,
1371 semaphore_t *semaphore )
1372 {
1373 CHECK( IOUserClient, connection, client );
1374
1375 return( client->getNotificationSemaphore( (UInt32) notification_type,
1376 semaphore ));
1377 }
1378
1379 /* Routine io_registry_get_root_entry */
1380 kern_return_t is_io_registry_get_root_entry(
1381 mach_port_t master_port,
1382 io_object_t *root )
1383 {
1384 IORegistryEntry * entry;
1385
1386 if( master_port != master_device_port)
1387 return( kIOReturnNotPrivileged);
1388
1389 entry = IORegistryEntry::getRegistryRoot();
1390 if( entry)
1391 entry->retain();
1392 *root = entry;
1393
1394 return( kIOReturnSuccess );
1395 }
1396
1397 /* Routine io_registry_create_iterator */
1398 kern_return_t is_io_registry_create_iterator(
1399 mach_port_t master_port,
1400 io_name_t plane,
1401 int options,
1402 io_object_t *iterator )
1403 {
1404 if( master_port != master_device_port)
1405 return( kIOReturnNotPrivileged);
1406
1407 *iterator = IORegistryIterator::iterateOver(
1408 IORegistryEntry::getPlane( plane ), options );
1409
1410 return( *iterator ? kIOReturnSuccess : kIOReturnBadArgument );
1411 }
1412
1413 /* Routine io_registry_entry_create_iterator */
1414 kern_return_t is_io_registry_entry_create_iterator(
1415 io_object_t registry_entry,
1416 io_name_t plane,
1417 int options,
1418 io_object_t *iterator )
1419 {
1420 CHECK( IORegistryEntry, registry_entry, entry );
1421
1422 *iterator = IORegistryIterator::iterateOver( entry,
1423 IORegistryEntry::getPlane( plane ), options );
1424
1425 return( *iterator ? kIOReturnSuccess : kIOReturnBadArgument );
1426 }
1427
1428 /* Routine io_registry_iterator_enter */
1429 kern_return_t is_io_registry_iterator_enter_entry(
1430 io_object_t iterator )
1431 {
1432 CHECK( IORegistryIterator, iterator, iter );
1433
1434 iter->enterEntry();
1435
1436 return( kIOReturnSuccess );
1437 }
1438
1439 /* Routine io_registry_iterator_exit */
1440 kern_return_t is_io_registry_iterator_exit_entry(
1441 io_object_t iterator )
1442 {
1443 bool didIt;
1444
1445 CHECK( IORegistryIterator, iterator, iter );
1446
1447 didIt = iter->exitEntry();
1448
1449 return( didIt ? kIOReturnSuccess : kIOReturnNoDevice );
1450 }
1451
1452 /* Routine io_registry_entry_from_path */
1453 kern_return_t is_io_registry_entry_from_path(
1454 mach_port_t master_port,
1455 io_string_t path,
1456 io_object_t *registry_entry )
1457 {
1458 IORegistryEntry * entry;
1459
1460 if( master_port != master_device_port)
1461 return( kIOReturnNotPrivileged);
1462
1463 entry = IORegistryEntry::fromPath( path );
1464
1465 *registry_entry = entry;
1466
1467 return( kIOReturnSuccess );
1468 }
1469
1470 /* Routine io_registry_entry_in_plane */
1471 kern_return_t is_io_registry_entry_in_plane(
1472 io_object_t registry_entry,
1473 io_name_t plane,
1474 boolean_t *inPlane )
1475 {
1476 CHECK( IORegistryEntry, registry_entry, entry );
1477
1478 *inPlane = entry->inPlane( IORegistryEntry::getPlane( plane ));
1479
1480 return( kIOReturnSuccess );
1481 }
1482
1483
1484 /* Routine io_registry_entry_get_path */
1485 kern_return_t is_io_registry_entry_get_path(
1486 io_object_t registry_entry,
1487 io_name_t plane,
1488 io_string_t path )
1489 {
1490 int length;
1491 CHECK( IORegistryEntry, registry_entry, entry );
1492
1493 length = sizeof( io_string_t);
1494 if( entry->getPath( path, &length, IORegistryEntry::getPlane( plane )))
1495 return( kIOReturnSuccess );
1496 else
1497 return( kIOReturnBadArgument );
1498 }
1499
1500
1501 /* Routine io_registry_entry_get_name */
1502 kern_return_t is_io_registry_entry_get_name(
1503 io_object_t registry_entry,
1504 io_name_t name )
1505 {
1506 CHECK( IORegistryEntry, registry_entry, entry );
1507
1508 strncpy( name, entry->getName(), sizeof( io_name_t));
1509
1510 return( kIOReturnSuccess );
1511 }
1512
1513 /* Routine io_registry_entry_get_name_in_plane */
1514 kern_return_t is_io_registry_entry_get_name_in_plane(
1515 io_object_t registry_entry,
1516 io_name_t planeName,
1517 io_name_t name )
1518 {
1519 const IORegistryPlane * plane;
1520 CHECK( IORegistryEntry, registry_entry, entry );
1521
1522 if( planeName[0])
1523 plane = IORegistryEntry::getPlane( planeName );
1524 else
1525 plane = 0;
1526
1527 strncpy( name, entry->getName( plane), sizeof( io_name_t));
1528
1529 return( kIOReturnSuccess );
1530 }
1531
1532 /* Routine io_registry_entry_get_location_in_plane */
1533 kern_return_t is_io_registry_entry_get_location_in_plane(
1534 io_object_t registry_entry,
1535 io_name_t planeName,
1536 io_name_t location )
1537 {
1538 const IORegistryPlane * plane;
1539 CHECK( IORegistryEntry, registry_entry, entry );
1540
1541 if( planeName[0])
1542 plane = IORegistryEntry::getPlane( planeName );
1543 else
1544 plane = 0;
1545
1546 const char * cstr = entry->getLocation( plane );
1547
1548 if( cstr) {
1549 strncpy( location, cstr, sizeof( io_name_t));
1550 return( kIOReturnSuccess );
1551 } else
1552 return( kIOReturnNotFound );
1553 }
1554
1555 // Create a vm_map_copy_t or kalloc'ed data for memory
1556 // to be copied out. ipc will free after the copyout.
1557
1558 static kern_return_t copyoutkdata( void * data, vm_size_t len,
1559 io_buf_ptr_t * buf )
1560 {
1561 kern_return_t err;
1562 vm_map_copy_t copy;
1563
1564 err = vm_map_copyin( kernel_map, (vm_offset_t) data, len,
1565 false /* src_destroy */, &copy);
1566
1567 assert( err == KERN_SUCCESS );
1568 if( err == KERN_SUCCESS )
1569 *buf = (char *) copy;
1570
1571 return( err );
1572 }
1573
1574 /* Routine io_registry_entry_get_property */
1575 kern_return_t is_io_registry_entry_get_property_bytes(
1576 io_object_t registry_entry,
1577 io_name_t property_name,
1578 io_scalar_inband_t buf,
1579 mach_msg_type_number_t *dataCnt )
1580 {
1581 OSObject * obj;
1582 OSData * data;
1583 OSString * str;
1584 OSBoolean * boo;
1585 OSNumber * off;
1586 UInt64 offsetBytes;
1587 unsigned int len = 0;
1588 const void * bytes = 0;
1589 IOReturn ret = kIOReturnSuccess;
1590
1591 CHECK( IORegistryEntry, registry_entry, entry );
1592
1593 obj = entry->copyProperty(property_name);
1594 if( !obj)
1595 return( kIOReturnNoResources );
1596
1597 // One day OSData will be a common container base class
1598 // until then...
1599 if( (data = OSDynamicCast( OSData, obj ))) {
1600 len = data->getLength();
1601 bytes = data->getBytesNoCopy();
1602
1603 } else if( (str = OSDynamicCast( OSString, obj ))) {
1604 len = str->getLength() + 1;
1605 bytes = str->getCStringNoCopy();
1606
1607 } else if( (boo = OSDynamicCast( OSBoolean, obj ))) {
1608 len = boo->isTrue() ? sizeof("Yes") : sizeof("No");
1609 bytes = boo->isTrue() ? "Yes" : "No";
1610
1611 } else if( (off = OSDynamicCast( OSNumber, obj ))) {
1612 offsetBytes = off->unsigned64BitValue();
1613 len = off->numberOfBytes();
1614 bytes = &offsetBytes;
1615 #ifdef __BIG_ENDIAN__
1616 bytes = (const void *)
1617 (((UInt32) bytes) + (sizeof( UInt64) - len));
1618 #endif
1619
1620 } else
1621 ret = kIOReturnBadArgument;
1622
1623 if( bytes) {
1624 if( *dataCnt < len)
1625 ret = kIOReturnIPCError;
1626 else {
1627 *dataCnt = len;
1628 bcopy( bytes, buf, len );
1629 }
1630 }
1631 obj->release();
1632
1633 return( ret );
1634 }
1635
1636 /* Routine io_registry_entry_get_property */
1637 kern_return_t is_io_registry_entry_get_property(
1638 io_object_t registry_entry,
1639 io_name_t property_name,
1640 io_buf_ptr_t *properties,
1641 mach_msg_type_number_t *propertiesCnt )
1642 {
1643 kern_return_t err;
1644 vm_size_t len;
1645 OSObject * obj;
1646
1647 CHECK( IORegistryEntry, registry_entry, entry );
1648
1649 obj = entry->copyProperty(property_name);
1650 if( !obj)
1651 return( kIOReturnNotFound );
1652
1653 OSSerialize * s = OSSerialize::withCapacity(4096);
1654 if( !s) {
1655 obj->release();
1656 return( kIOReturnNoMemory );
1657 }
1658 s->clearText();
1659
1660 if( obj->serialize( s )) {
1661 len = s->getLength();
1662 *propertiesCnt = len;
1663 err = copyoutkdata( s->text(), len, properties );
1664
1665 } else
1666 err = kIOReturnUnsupported;
1667
1668 s->release();
1669 obj->release();
1670
1671 return( err );
1672 }
1673
1674 /* Routine io_registry_entry_get_property_recursively */
1675 kern_return_t is_io_registry_entry_get_property_recursively(
1676 io_object_t registry_entry,
1677 io_name_t plane,
1678 io_name_t property_name,
1679 int options,
1680 io_buf_ptr_t *properties,
1681 mach_msg_type_number_t *propertiesCnt )
1682 {
1683 kern_return_t err;
1684 vm_size_t len;
1685 OSObject * obj;
1686
1687 CHECK( IORegistryEntry, registry_entry, entry );
1688
1689 obj = entry->copyProperty( property_name,
1690 IORegistryEntry::getPlane( plane ), options);
1691 if( !obj)
1692 return( kIOReturnNotFound );
1693
1694 OSSerialize * s = OSSerialize::withCapacity(4096);
1695 if( !s) {
1696 obj->release();
1697 return( kIOReturnNoMemory );
1698 }
1699
1700 s->clearText();
1701
1702 if( obj->serialize( s )) {
1703 len = s->getLength();
1704 *propertiesCnt = len;
1705 err = copyoutkdata( s->text(), len, properties );
1706
1707 } else
1708 err = kIOReturnUnsupported;
1709
1710 s->release();
1711 obj->release();
1712
1713 return( err );
1714 }
1715
1716 /* Routine io_registry_entry_get_properties */
1717 kern_return_t is_io_registry_entry_get_properties(
1718 io_object_t registry_entry,
1719 io_buf_ptr_t *properties,
1720 mach_msg_type_number_t *propertiesCnt )
1721 {
1722 kern_return_t err;
1723 vm_size_t len;
1724
1725 CHECK( IORegistryEntry, registry_entry, entry );
1726
1727 OSSerialize * s = OSSerialize::withCapacity(4096);
1728 if( !s)
1729 return( kIOReturnNoMemory );
1730
1731 s->clearText();
1732
1733 if( entry->serializeProperties( s )) {
1734 len = s->getLength();
1735 *propertiesCnt = len;
1736 err = copyoutkdata( s->text(), len, properties );
1737
1738 } else
1739 err = kIOReturnUnsupported;
1740
1741 s->release();
1742
1743 return( err );
1744 }
1745
1746 /* Routine io_registry_entry_set_properties */
1747 kern_return_t is_io_registry_entry_set_properties
1748 (
1749 io_object_t registry_entry,
1750 io_buf_ptr_t properties,
1751 mach_msg_type_number_t propertiesCnt,
1752 natural_t * result)
1753 {
1754 OSObject * obj;
1755 kern_return_t err;
1756 IOReturn res;
1757 vm_offset_t data;
1758
1759 CHECK( IORegistryEntry, registry_entry, entry );
1760
1761 err = vm_map_copyout( kernel_map, &data, (vm_map_copy_t) properties );
1762
1763 if( KERN_SUCCESS == err) {
1764
1765 // must return success after vm_map_copyout() succeeds
1766 obj = OSUnserializeXML( (const char *) data );
1767 vm_deallocate( kernel_map, data, propertiesCnt );
1768
1769 if( obj) {
1770 res = entry->setProperties( obj );
1771 obj->release();
1772 } else
1773 res = kIOReturnBadArgument;
1774 } else
1775 res = err;
1776
1777 *result = res;
1778 return( err );
1779 }
1780
1781 /* Routine io_registry_entry_get_child_iterator */
1782 kern_return_t is_io_registry_entry_get_child_iterator(
1783 io_object_t registry_entry,
1784 io_name_t plane,
1785 io_object_t *iterator )
1786 {
1787 CHECK( IORegistryEntry, registry_entry, entry );
1788
1789 *iterator = entry->getChildIterator(
1790 IORegistryEntry::getPlane( plane ));
1791
1792 return( kIOReturnSuccess );
1793 }
1794
1795 /* Routine io_registry_entry_get_parent_iterator */
1796 kern_return_t is_io_registry_entry_get_parent_iterator(
1797 io_object_t registry_entry,
1798 io_name_t plane,
1799 io_object_t *iterator)
1800 {
1801 CHECK( IORegistryEntry, registry_entry, entry );
1802
1803 *iterator = entry->getParentIterator(
1804 IORegistryEntry::getPlane( plane ));
1805
1806 return( kIOReturnSuccess );
1807 }
1808
1809 /* Routine io_service_get_busy_state */
1810 kern_return_t is_io_service_get_busy_state(
1811 io_object_t _service,
1812 int *busyState )
1813 {
1814 CHECK( IOService, _service, service );
1815
1816 *busyState = service->getBusyState();
1817
1818 return( kIOReturnSuccess );
1819 }
1820
1821 /* Routine io_service_get_state */
1822 kern_return_t is_io_service_get_state(
1823 io_object_t _service,
1824 uint64_t *state )
1825 {
1826 CHECK( IOService, _service, service );
1827
1828 *state = service->getState();
1829
1830 return( kIOReturnSuccess );
1831 }
1832
1833 /* Routine io_service_wait_quiet */
1834 kern_return_t is_io_service_wait_quiet(
1835 io_object_t _service,
1836 mach_timespec_t wait_time )
1837 {
1838 CHECK( IOService, _service, service );
1839
1840 return( service->waitQuiet( &wait_time ));
1841 }
1842
1843 /* Routine io_service_request_probe */
1844 kern_return_t is_io_service_request_probe(
1845 io_object_t _service,
1846 int options )
1847 {
1848 CHECK( IOService, _service, service );
1849
1850 return( service->requestProbe( options ));
1851 }
1852
1853
1854 /* Routine io_service_open */
1855 kern_return_t is_io_service_open(
1856 io_object_t _service,
1857 task_t owningTask,
1858 int connect_type,
1859 io_object_t *connection )
1860 {
1861 IOUserClient * client;
1862 IOReturn err;
1863
1864 CHECK( IOService, _service, service );
1865
1866 err = service->newUserClient( owningTask, (void *) owningTask,
1867 connect_type, &client );
1868
1869 if( err == kIOReturnSuccess) {
1870 assert( OSDynamicCast(IOUserClient, client) );
1871 *connection = client;
1872 }
1873
1874 return( err);
1875 }
1876
1877 /* Routine io_service_close */
1878 kern_return_t is_io_service_close(
1879 io_object_t connection )
1880 {
1881 OSSet * mappings;
1882 if ((mappings = OSDynamicCast(OSSet, connection)))
1883 return( kIOReturnSuccess );
1884
1885 CHECK( IOUserClient, connection, client );
1886
1887 client->clientClose();
1888
1889 return( kIOReturnSuccess );
1890 }
1891
1892 /* Routine io_connect_get_service */
1893 kern_return_t is_io_connect_get_service(
1894 io_object_t connection,
1895 io_object_t *service )
1896 {
1897 IOService * theService;
1898
1899 CHECK( IOUserClient, connection, client );
1900
1901 theService = client->getService();
1902 if( theService)
1903 theService->retain();
1904
1905 *service = theService;
1906
1907 return( theService ? kIOReturnSuccess : kIOReturnUnsupported );
1908 }
1909
1910 /* Routine io_connect_set_notification_port */
1911 kern_return_t is_io_connect_set_notification_port(
1912 io_object_t connection,
1913 int notification_type,
1914 mach_port_t port,
1915 int reference)
1916 {
1917 CHECK( IOUserClient, connection, client );
1918
1919 return( client->registerNotificationPort( port, notification_type,
1920 reference ));
1921 }
1922
1923 kern_return_t is_io_connect_map_memory(
1924 io_object_t connect,
1925 int type,
1926 task_t task,
1927 vm_address_t * mapAddr,
1928 vm_size_t * mapSize,
1929 int flags )
1930 {
1931 IOReturn err;
1932 IOMemoryMap * map;
1933
1934 CHECK( IOUserClient, connect, client );
1935
1936 map = client->mapClientMemory( type, task, flags, *mapAddr );
1937
1938 if( map) {
1939 *mapAddr = map->getVirtualAddress();
1940 if( mapSize)
1941 *mapSize = map->getLength();
1942
1943 if( task != current_task()) {
1944 // push a name out to the task owning the map,
1945 // so we can clean up maps
1946 #if IOASSERT
1947 mach_port_name_t name =
1948 #endif
1949 IOMachPort::makeSendRightForTask(
1950 task, map, IKOT_IOKIT_OBJECT );
1951 assert( name );
1952
1953 } else {
1954 // keep it with the user client
1955 IOLockLock( gIOObjectPortLock);
1956 if( 0 == client->mappings)
1957 client->mappings = OSSet::withCapacity(2);
1958 if( client->mappings)
1959 client->mappings->setObject( map);
1960 IOLockUnlock( gIOObjectPortLock);
1961 map->release();
1962 }
1963 err = kIOReturnSuccess;
1964
1965 } else
1966 err = kIOReturnBadArgument;
1967
1968 return( err );
1969 }
1970
1971 kern_return_t is_io_connect_unmap_memory(
1972 io_object_t connect,
1973 int type,
1974 task_t task,
1975 vm_address_t mapAddr )
1976 {
1977 IOReturn err;
1978 IOOptionBits options = 0;
1979 IOMemoryDescriptor * memory;
1980 IOMemoryMap * map;
1981
1982 CHECK( IOUserClient, connect, client );
1983
1984 err = client->clientMemoryForType( (UInt32) type, &options, &memory );
1985
1986 if( memory && (kIOReturnSuccess == err)) {
1987
1988 options = (options & ~kIOMapUserOptionsMask)
1989 | kIOMapAnywhere | kIOMapReference;
1990
1991 map = memory->map( task, mapAddr, options );
1992 memory->release();
1993 if( map) {
1994 IOLockLock( gIOObjectPortLock);
1995 if( client->mappings)
1996 client->mappings->removeObject( map);
1997 IOLockUnlock( gIOObjectPortLock);
1998 IOMachPort::releasePortForObject( map, IKOT_IOKIT_OBJECT );
1999 map->release();
2000 } else
2001 err = kIOReturnBadArgument;
2002 }
2003
2004 return( err );
2005 }
2006
2007
2008 /* Routine io_connect_add_client */
2009 kern_return_t is_io_connect_add_client(
2010 io_object_t connection,
2011 io_object_t connect_to)
2012 {
2013 CHECK( IOUserClient, connection, client );
2014 CHECK( IOUserClient, connect_to, to );
2015
2016 return( client->connectClient( to ) );
2017 }
2018
2019
2020 /* Routine io_connect_set_properties */
2021 kern_return_t is_io_connect_set_properties(
2022 io_object_t connection,
2023 io_buf_ptr_t properties,
2024 mach_msg_type_number_t propertiesCnt,
2025 natural_t * result)
2026 {
2027 return( is_io_registry_entry_set_properties( connection, properties, propertiesCnt, result ));
2028 }
2029
2030
2031 /* Routine io_connect_method_scalarI_scalarO */
2032 kern_return_t is_io_connect_method_scalarI_scalarO(
2033 io_object_t connect,
2034 UInt32 index,
2035 void * input[],
2036 IOByteCount inputCount,
2037 void * output[],
2038 IOByteCount * outputCount )
2039 {
2040 IOReturn err;
2041 IOExternalMethod * method;
2042 IOService * object;
2043 IOMethod func;
2044
2045 CHECK( IOUserClient, connect, client);
2046 if( (method = client->getTargetAndMethodForIndex(&object, index))) {
2047 do {
2048 err = kIOReturnBadArgument;
2049 if( kIOUCScalarIScalarO != (method->flags & kIOUCTypeMask))
2050 continue;
2051 if( inputCount != method->count0)
2052 continue;
2053 if( *outputCount != method->count1)
2054 continue;
2055
2056 func = method->func;
2057
2058 switch( inputCount) {
2059
2060 case 6:
2061 err = (object->*func)( input[0], input[1], input[2],
2062 input[3], input[4], input[5] );
2063 break;
2064 case 5:
2065 err = (object->*func)( input[0], input[1], input[2],
2066 input[3], input[4],
2067 &output[0] );
2068 break;
2069 case 4:
2070 err = (object->*func)( input[0], input[1], input[2],
2071 input[3],
2072 &output[0], &output[1] );
2073 break;
2074 case 3:
2075 err = (object->*func)( input[0], input[1], input[2],
2076 &output[0], &output[1], &output[2] );
2077 break;
2078 case 2:
2079 err = (object->*func)( input[0], input[1],
2080 &output[0], &output[1], &output[2],
2081 &output[3] );
2082 break;
2083 case 1:
2084 err = (object->*func)( input[0],
2085 &output[0], &output[1], &output[2],
2086 &output[3], &output[4] );
2087 break;
2088 case 0:
2089 err = (object->*func)( &output[0], &output[1], &output[2],
2090 &output[3], &output[4], &output[5] );
2091 break;
2092
2093 default:
2094 IOLog("%s: Bad method table\n", client->getName());
2095 }
2096 } while( false);
2097
2098 } else
2099 err = kIOReturnUnsupported;
2100
2101 return( err);
2102 }
2103
2104 /* Routine io_connect_method_scalarI_structureO */
2105 kern_return_t is_io_connect_method_scalarI_structureO(
2106 io_object_t connect,
2107 UInt32 index,
2108 void * input[],
2109 IOByteCount inputCount,
2110 void * output,
2111 IOByteCount * outputCount )
2112 {
2113 IOReturn err;
2114 IOExternalMethod * method;
2115 IOService * object;
2116 IOMethod func;
2117
2118 CHECK( IOUserClient, connect, client);
2119
2120 if( (method = client->getTargetAndMethodForIndex(&object, index)) ) {
2121 do {
2122 err = kIOReturnBadArgument;
2123 if( kIOUCScalarIStructO != (method->flags & kIOUCTypeMask))
2124 continue;
2125 if( inputCount != method->count0)
2126 continue;
2127 if( (0xffffffff != method->count1)
2128 && (*outputCount != method->count1))
2129 continue;
2130
2131 func = method->func;
2132
2133 switch( inputCount) {
2134
2135 case 5:
2136 err = (object->*func)( input[0], input[1], input[2],
2137 input[3], input[4],
2138 output );
2139 break;
2140 case 4:
2141 err = (object->*func)( input[0], input[1], input[2],
2142 input[3],
2143 output, (void *)outputCount );
2144 break;
2145 case 3:
2146 err = (object->*func)( input[0], input[1], input[2],
2147 output, (void *)outputCount, 0 );
2148 break;
2149 case 2:
2150 err = (object->*func)( input[0], input[1],
2151 output, (void *)outputCount, 0, 0 );
2152 break;
2153 case 1:
2154 err = (object->*func)( input[0],
2155 output, (void *)outputCount, 0, 0, 0 );
2156 break;
2157 case 0:
2158 err = (object->*func)( output, (void *)outputCount, 0, 0, 0, 0 );
2159 break;
2160
2161 default:
2162 IOLog("%s: Bad method table\n", client->getName());
2163 }
2164 } while( false);
2165
2166 } else
2167 err = kIOReturnUnsupported;
2168
2169 return( err);
2170 }
2171
2172 /* Routine io_connect_method_scalarI_structureI */
2173 kern_return_t is_io_connect_method_scalarI_structureI(
2174 io_connect_t connect,
2175 UInt32 index,
2176 void * input[],
2177 IOByteCount inputCount,
2178 UInt8 * inputStruct,
2179 IOByteCount inputStructCount )
2180 {
2181 IOReturn err;
2182 IOExternalMethod * method;
2183 IOService * object;
2184 IOMethod func;
2185
2186 CHECK( IOUserClient, connect, client);
2187
2188 if( (method = client->getTargetAndMethodForIndex(&object, index)) ) {
2189 do {
2190 err = kIOReturnBadArgument;
2191 if( kIOUCScalarIStructI != (method->flags & kIOUCTypeMask))
2192 continue;
2193 if( (0xffffffff != method->count0)
2194 && (inputCount != method->count0))
2195 continue;
2196 if( (0xffffffff != method->count1)
2197 && (inputStructCount != method->count1))
2198 continue;
2199
2200 func = method->func;
2201
2202 switch( inputCount) {
2203
2204 case 5:
2205 err = (object->*func)( input[0], input[1], input[2],
2206 input[3], input[4],
2207 inputStruct );
2208 break;
2209 case 4:
2210 err = (object->*func)( input[0], input[1], input[2],
2211 input[3],
2212 inputStruct, (void *)inputStructCount );
2213 break;
2214 case 3:
2215 err = (object->*func)( input[0], input[1], input[2],
2216 inputStruct, (void *)inputStructCount,
2217 0 );
2218 break;
2219 case 2:
2220 err = (object->*func)( input[0], input[1],
2221 inputStruct, (void *)inputStructCount,
2222 0, 0 );
2223 break;
2224 case 1:
2225 err = (object->*func)( input[0],
2226 inputStruct, (void *)inputStructCount,
2227 0, 0, 0 );
2228 break;
2229 case 0:
2230 err = (object->*func)( inputStruct, (void *)inputStructCount,
2231 0, 0, 0, 0 );
2232 break;
2233
2234 default:
2235 IOLog("%s: Bad method table\n", client->getName());
2236 }
2237 } while( false);
2238
2239 } else
2240 err = kIOReturnUnsupported;
2241
2242 return( err);
2243 }
2244
2245 /* Routine io_connect_method_structureI_structureO */
2246 kern_return_t is_io_connect_method_structureI_structureO(
2247 io_object_t connect,
2248 UInt32 index,
2249 UInt8 * input,
2250 IOByteCount inputCount,
2251 UInt8 * output,
2252 IOByteCount * outputCount )
2253 {
2254 IOReturn err;
2255 IOExternalMethod * method;
2256 IOService * object;
2257 IOMethod func;
2258
2259 CHECK( IOUserClient, connect, client);
2260
2261 if( (method = client->getTargetAndMethodForIndex(&object, index)) ) {
2262 do {
2263 err = kIOReturnBadArgument;
2264 if( kIOUCStructIStructO != (method->flags & kIOUCTypeMask))
2265 continue;
2266 if( (0xffffffff != method->count0)
2267 && (inputCount != method->count0))
2268 continue;
2269 if( (0xffffffff != method->count1)
2270 && (*outputCount != method->count1))
2271 continue;
2272
2273 func = method->func;
2274
2275 if( method->count1) {
2276 if( method->count0) {
2277 err = (object->*func)( input, output,
2278 (void *)inputCount, outputCount, 0, 0 );
2279 } else {
2280 err = (object->*func)( output, outputCount, 0, 0, 0, 0 );
2281 }
2282 } else {
2283 err = (object->*func)( input, (void *)inputCount, 0, 0, 0, 0 );
2284 }
2285
2286 } while( false);
2287
2288 } else
2289 err = kIOReturnUnsupported;
2290
2291 return( err);
2292 }
2293
2294 kern_return_t is_io_async_method_scalarI_scalarO(
2295 io_object_t connect,
2296 mach_port_t wakePort,
2297 io_async_ref_t reference,
2298 mach_msg_type_number_t referenceCnt,
2299 UInt32 index,
2300 void * input[],
2301 IOByteCount inputCount,
2302 void * output[],
2303 IOByteCount * outputCount )
2304 {
2305 IOReturn err;
2306 IOExternalAsyncMethod *method;
2307 IOService * object;
2308 IOAsyncMethod func;
2309
2310 CHECK( IOUserClient, connect, client);
2311 if( (method = client->getAsyncTargetAndMethodForIndex(&object, index)) ) {
2312 do {
2313 err = kIOReturnBadArgument;
2314 if( kIOUCScalarIScalarO != (method->flags & kIOUCTypeMask))
2315 continue;
2316 if( inputCount != method->count0)
2317 continue;
2318 if( *outputCount != method->count1)
2319 continue;
2320
2321 reference[0] = (natural_t) wakePort;
2322 func = method->func;
2323
2324 switch( inputCount) {
2325
2326 case 6:
2327 err = (object->*func)( reference,
2328 input[0], input[1], input[2],
2329 input[3], input[4], input[5] );
2330 break;
2331 case 5:
2332 err = (object->*func)( reference,
2333 input[0], input[1], input[2],
2334 input[3], input[4],
2335 &output[0] );
2336 break;
2337 case 4:
2338 err = (object->*func)( reference,
2339 input[0], input[1], input[2],
2340 input[3],
2341 &output[0], &output[1] );
2342 break;
2343 case 3:
2344 err = (object->*func)( reference,
2345 input[0], input[1], input[2],
2346 &output[0], &output[1], &output[2] );
2347 break;
2348 case 2:
2349 err = (object->*func)( reference,
2350 input[0], input[1],
2351 &output[0], &output[1], &output[2],
2352 &output[3] );
2353 break;
2354 case 1:
2355 err = (object->*func)( reference,
2356 input[0],
2357 &output[0], &output[1], &output[2],
2358 &output[3], &output[4] );
2359 break;
2360 case 0:
2361 err = (object->*func)( reference,
2362 &output[0], &output[1], &output[2],
2363 &output[3], &output[4], &output[5] );
2364 break;
2365
2366 default:
2367 IOLog("%s: Bad method table\n", client->getName());
2368 }
2369 } while( false);
2370
2371 } else
2372 err = kIOReturnUnsupported;
2373
2374 return( err);
2375 }
2376
2377 kern_return_t is_io_async_method_scalarI_structureO(
2378 io_object_t connect,
2379 mach_port_t wakePort,
2380 io_async_ref_t reference,
2381 mach_msg_type_number_t referenceCnt,
2382 UInt32 index,
2383 void * input[],
2384 IOByteCount inputCount,
2385 void * output,
2386 IOByteCount * outputCount )
2387 {
2388 IOReturn err;
2389 IOExternalAsyncMethod *method;
2390 IOService * object;
2391 IOAsyncMethod func;
2392
2393 CHECK( IOUserClient, connect, client);
2394
2395 if( (method = client->getAsyncTargetAndMethodForIndex(&object, index)) ) {
2396 do {
2397 err = kIOReturnBadArgument;
2398 if( kIOUCScalarIStructO != (method->flags & kIOUCTypeMask))
2399 continue;
2400 if( inputCount != method->count0)
2401 continue;
2402 if( (0xffffffff != method->count1)
2403 && (*outputCount != method->count1))
2404 continue;
2405
2406 reference[0] = (natural_t) wakePort;
2407 func = method->func;
2408
2409 switch( inputCount) {
2410
2411 case 5:
2412 err = (object->*func)( reference,
2413 input[0], input[1], input[2],
2414 input[3], input[4],
2415 output );
2416 break;
2417 case 4:
2418 err = (object->*func)( reference,
2419 input[0], input[1], input[2],
2420 input[3],
2421 output, (void *)outputCount );
2422 break;
2423 case 3:
2424 err = (object->*func)( reference,
2425 input[0], input[1], input[2],
2426 output, (void *)outputCount, 0 );
2427 break;
2428 case 2:
2429 err = (object->*func)( reference,
2430 input[0], input[1],
2431 output, (void *)outputCount, 0, 0 );
2432 break;
2433 case 1:
2434 err = (object->*func)( reference,
2435 input[0],
2436 output, (void *)outputCount, 0, 0, 0 );
2437 break;
2438 case 0:
2439 err = (object->*func)( reference,
2440 output, (void *)outputCount, 0, 0, 0, 0 );
2441 break;
2442
2443 default:
2444 IOLog("%s: Bad method table\n", client->getName());
2445 }
2446 } while( false);
2447
2448 } else
2449 err = kIOReturnUnsupported;
2450
2451 return( err);
2452 }
2453
2454 kern_return_t is_io_async_method_scalarI_structureI(
2455 io_connect_t connect,
2456 mach_port_t wakePort,
2457 io_async_ref_t reference,
2458 mach_msg_type_number_t referenceCnt,
2459 UInt32 index,
2460 void * input[],
2461 IOByteCount inputCount,
2462 UInt8 * inputStruct,
2463 IOByteCount inputStructCount )
2464 {
2465 IOReturn err;
2466 IOExternalAsyncMethod *method;
2467 IOService * object;
2468 IOAsyncMethod func;
2469
2470 CHECK( IOUserClient, connect, client);
2471
2472 if( (method = client->getAsyncTargetAndMethodForIndex(&object, index)) ) {
2473 do {
2474 err = kIOReturnBadArgument;
2475 if( kIOUCScalarIStructI != (method->flags & kIOUCTypeMask))
2476 continue;
2477 if( (0xffffffff != method->count0)
2478 && (inputCount != method->count0))
2479 continue;
2480 if( (0xffffffff != method->count1)
2481 && (inputStructCount != method->count1))
2482 continue;
2483
2484 reference[0] = (natural_t) wakePort;
2485 func = method->func;
2486
2487 switch( inputCount) {
2488
2489 case 5:
2490 err = (object->*func)( reference,
2491 input[0], input[1], input[2],
2492 input[3], input[4],
2493 inputStruct );
2494 break;
2495 case 4:
2496 err = (object->*func)( reference,
2497 input[0], input[1], input[2],
2498 input[3],
2499 inputStruct, (void *)inputStructCount );
2500 break;
2501 case 3:
2502 err = (object->*func)( reference,
2503 input[0], input[1], input[2],
2504 inputStruct, (void *)inputStructCount,
2505 0 );
2506 break;
2507 case 2:
2508 err = (object->*func)( reference,
2509 input[0], input[1],
2510 inputStruct, (void *)inputStructCount,
2511 0, 0 );
2512 break;
2513 case 1:
2514 err = (object->*func)( reference,
2515 input[0],
2516 inputStruct, (void *)inputStructCount,
2517 0, 0, 0 );
2518 break;
2519 case 0:
2520 err = (object->*func)( reference,
2521 inputStruct, (void *)inputStructCount,
2522 0, 0, 0, 0 );
2523 break;
2524
2525 default:
2526 IOLog("%s: Bad method table\n", client->getName());
2527 }
2528 } while( false);
2529
2530 } else
2531 err = kIOReturnUnsupported;
2532
2533 return( err);
2534 }
2535
2536 kern_return_t is_io_async_method_structureI_structureO(
2537 io_object_t connect,
2538 mach_port_t wakePort,
2539 io_async_ref_t reference,
2540 mach_msg_type_number_t referenceCnt,
2541 UInt32 index,
2542 UInt8 * input,
2543 IOByteCount inputCount,
2544 UInt8 * output,
2545 IOByteCount * outputCount )
2546 {
2547 IOReturn err;
2548 IOExternalAsyncMethod *method;
2549 IOService * object;
2550 IOAsyncMethod func;
2551
2552 CHECK( IOUserClient, connect, client);
2553
2554 if( (method = client->getAsyncTargetAndMethodForIndex(&object, index)) ) {
2555 do {
2556 err = kIOReturnBadArgument;
2557 if( kIOUCStructIStructO != (method->flags & kIOUCTypeMask))
2558 continue;
2559 if( (0xffffffff != method->count0)
2560 && (inputCount != method->count0))
2561 continue;
2562 if( (0xffffffff != method->count1)
2563 && (*outputCount != method->count1))
2564 continue;
2565
2566 reference[0] = (natural_t) wakePort;
2567 func = method->func;
2568
2569 if( method->count1) {
2570 if( method->count0) {
2571 err = (object->*func)( reference,
2572 input, output,
2573 (void *)inputCount, outputCount, 0, 0 );
2574 } else {
2575 err = (object->*func)( reference,
2576 output, outputCount, 0, 0, 0, 0 );
2577 }
2578 } else {
2579 err = (object->*func)( reference,
2580 input, (void *)inputCount, 0, 0, 0, 0 );
2581 }
2582
2583 } while( false);
2584
2585 } else
2586 err = kIOReturnUnsupported;
2587
2588 return( err);
2589 }
2590 /* Routine io_make_matching */
2591 kern_return_t is_io_make_matching(
2592 mach_port_t master_port,
2593 UInt32 type,
2594 IOOptionBits options,
2595 UInt8 * input,
2596 IOByteCount inputCount,
2597 io_string_t matching )
2598 {
2599 OSSerialize * s;
2600 IOReturn err = kIOReturnSuccess;
2601 OSDictionary * dict;
2602
2603 if( master_port != master_device_port)
2604 return( kIOReturnNotPrivileged);
2605
2606 switch( type) {
2607
2608 case kIOServiceMatching:
2609 dict = IOService::serviceMatching( gIOServiceKey );
2610 break;
2611
2612 case kIOBSDNameMatching:
2613 dict = IOBSDNameMatching( (const char *) input );
2614 break;
2615
2616 case kIOOFPathMatching:
2617 dict = IOOFPathMatching( (const char *) input,
2618 matching, sizeof( io_string_t));
2619 break;
2620
2621 default:
2622 dict = 0;
2623 }
2624
2625 if( !dict)
2626 return( kIOReturnUnsupported);
2627
2628 do {
2629 s = OSSerialize::withCapacity(4096);
2630 if( !s) {
2631 err = kIOReturnNoMemory;
2632 continue;
2633 }
2634 s->clearText();
2635 if( !dict->serialize( s )) {
2636 err = kIOReturnUnsupported;
2637 continue;
2638 }
2639
2640 if( s->getLength() > sizeof( io_string_t)) {
2641 err = kIOReturnNoMemory;
2642 continue;
2643 } else
2644 strcpy( matching, s->text());
2645
2646 } while( false);
2647
2648 if( s)
2649 s->release();
2650 if( dict)
2651 dict->release();
2652
2653 return( err);
2654 }
2655
2656 /* Routine io_catalog_send_data */
2657 kern_return_t is_io_catalog_send_data(
2658 mach_port_t master_port,
2659 int flag,
2660 io_buf_ptr_t inData,
2661 mach_msg_type_number_t inDataCount,
2662 natural_t * result)
2663 {
2664 OSObject * obj = 0;
2665 vm_offset_t data;
2666 kern_return_t kr = kIOReturnError;
2667
2668 //printf("io_catalog_send_data called. flag: %d\n", flag);
2669
2670 if( master_port != master_device_port)
2671 return kIOReturnNotPrivileged;
2672
2673 // FIXME: This is a hack. Should have own function for removeKernelLinker()
2674 if(flag != kIOCatalogRemoveKernelLinker && ( !inData || !inDataCount) )
2675 return kIOReturnBadArgument;
2676
2677 if (data) {
2678 kr = vm_map_copyout( kernel_map, &data, (vm_map_copy_t)inData);
2679 if( kr != KERN_SUCCESS)
2680 return kr;
2681
2682 // must return success after vm_map_copyout() succeeds
2683
2684 if( inDataCount ) {
2685 obj = (OSObject *)OSUnserializeXML((const char *)data);
2686 vm_deallocate( kernel_map, data, inDataCount );
2687 if( !obj) {
2688 *result = kIOReturnNoMemory;
2689 return( KERN_SUCCESS);
2690 }
2691 }
2692 }
2693
2694 switch ( flag ) {
2695 case kIOCatalogAddDrivers:
2696 case kIOCatalogAddDriversNoMatch: {
2697 OSArray * array;
2698
2699 array = OSDynamicCast(OSArray, obj);
2700 if ( array ) {
2701 if ( !gIOCatalogue->addDrivers( array ,
2702 flag == kIOCatalogAddDrivers) ) {
2703 kr = kIOReturnError;
2704 }
2705 }
2706 else {
2707 kr = kIOReturnBadArgument;
2708 }
2709 }
2710 break;
2711
2712 case kIOCatalogRemoveDrivers:
2713 case kIOCatalogRemoveDriversNoMatch: {
2714 OSDictionary * dict;
2715
2716 dict = OSDynamicCast(OSDictionary, obj);
2717 if ( dict ) {
2718 if ( !gIOCatalogue->removeDrivers( dict,
2719 flag == kIOCatalogRemoveDrivers ) ) {
2720 kr = kIOReturnError;
2721 }
2722 }
2723 else {
2724 kr = kIOReturnBadArgument;
2725 }
2726 }
2727 break;
2728
2729 case kIOCatalogStartMatching: {
2730 OSDictionary * dict;
2731
2732 dict = OSDynamicCast(OSDictionary, obj);
2733 if ( dict ) {
2734 if ( !gIOCatalogue->startMatching( dict ) ) {
2735 kr = kIOReturnError;
2736 }
2737 }
2738 else {
2739 kr = kIOReturnBadArgument;
2740 }
2741 }
2742 break;
2743
2744 case kIOCatalogRemoveKernelLinker: {
2745 if (gIOCatalogue->removeKernelLinker() != KERN_SUCCESS) {
2746 kr = kIOReturnError;
2747 } else {
2748 kr = kIOReturnSuccess;
2749 }
2750 }
2751 break;
2752
2753 default:
2754 kr = kIOReturnBadArgument;
2755 break;
2756 }
2757
2758 if (obj) obj->release();
2759
2760 *result = kr;
2761 return( KERN_SUCCESS);
2762 }
2763
2764 /* Routine io_catalog_terminate */
2765 kern_return_t is_io_catalog_terminate(
2766 mach_port_t master_port,
2767 int flag,
2768 io_name_t name )
2769 {
2770 kern_return_t kr;
2771
2772 if( master_port != master_device_port )
2773 return kIOReturnNotPrivileged;
2774
2775 kr = IOUserClient::clientHasPrivilege( (void *) current_task(),
2776 kIOClientPrivilegeAdministrator );
2777 if( kIOReturnSuccess != kr)
2778 return( kr );
2779
2780 switch ( flag ) {
2781 case kIOCatalogServiceTerminate:
2782 OSIterator * iter;
2783 IOService * service;
2784
2785 iter = IORegistryIterator::iterateOver(gIOServicePlane,
2786 kIORegistryIterateRecursively);
2787 if ( !iter )
2788 return kIOReturnNoMemory;
2789
2790 do {
2791 iter->reset();
2792 while( (service = (IOService *)iter->getNextObject()) ) {
2793 if( service->metaCast(name)) {
2794 if ( !service->terminate( kIOServiceRequired
2795 | kIOServiceSynchronous) ) {
2796 kr = kIOReturnUnsupported;
2797 break;
2798 }
2799 }
2800 }
2801 } while( !service && !iter->isValid());
2802 iter->release();
2803 break;
2804
2805 case kIOCatalogModuleUnload:
2806 case kIOCatalogModuleTerminate:
2807 kr = gIOCatalogue->terminateDriversForModule(name,
2808 flag == kIOCatalogModuleUnload);
2809 break;
2810
2811 default:
2812 kr = kIOReturnBadArgument;
2813 break;
2814 }
2815
2816 return( kr );
2817 }
2818
2819 /* Routine io_catalog_get_data */
2820 kern_return_t is_io_catalog_get_data(
2821 mach_port_t master_port,
2822 int flag,
2823 io_buf_ptr_t *outData,
2824 mach_msg_type_number_t *outDataCount)
2825 {
2826 kern_return_t kr = kIOReturnSuccess;
2827 OSSerialize * s;
2828
2829 if( master_port != master_device_port)
2830 return kIOReturnNotPrivileged;
2831
2832 //printf("io_catalog_get_data called. flag: %d\n", flag);
2833
2834 s = OSSerialize::withCapacity(4096);
2835 if ( !s )
2836 return kIOReturnNoMemory;
2837
2838 s->clearText();
2839
2840 kr = gIOCatalogue->serializeData(flag, s);
2841
2842 if ( kr == kIOReturnSuccess ) {
2843 vm_offset_t data;
2844 vm_map_copy_t copy;
2845 vm_size_t size;
2846
2847 size = s->getLength();
2848 kr = vm_allocate(kernel_map, &data, size, true);
2849 if ( kr == kIOReturnSuccess ) {
2850 bcopy(s->text(), (void *)data, size);
2851 kr = vm_map_copyin(kernel_map, data, size, true, &copy);
2852 *outData = (char *)copy;
2853 *outDataCount = size;
2854 }
2855 }
2856
2857 s->release();
2858
2859 return kr;
2860 }
2861
2862 /* Routine io_catalog_get_gen_count */
2863 kern_return_t is_io_catalog_get_gen_count(
2864 mach_port_t master_port,
2865 int *genCount)
2866 {
2867 if( master_port != master_device_port)
2868 return kIOReturnNotPrivileged;
2869
2870 //printf("io_catalog_get_gen_count called.\n");
2871
2872 if ( !genCount )
2873 return kIOReturnBadArgument;
2874
2875 *genCount = gIOCatalogue->getGenerationCount();
2876
2877 return kIOReturnSuccess;
2878 }
2879
2880 /* Routine io_catalog_module_loaded */
2881 kern_return_t is_io_catalog_module_loaded(
2882 mach_port_t master_port,
2883 io_name_t name)
2884 {
2885 if( master_port != master_device_port)
2886 return kIOReturnNotPrivileged;
2887
2888 //printf("io_catalog_module_loaded called. name %s\n", name);
2889
2890 if ( !name )
2891 return kIOReturnBadArgument;
2892
2893 gIOCatalogue->moduleHasLoaded(name);
2894
2895 return kIOReturnSuccess;
2896 }
2897
2898 kern_return_t is_io_catalog_reset(
2899 mach_port_t master_port,
2900 int flag)
2901 {
2902 if( master_port != master_device_port)
2903 return kIOReturnNotPrivileged;
2904
2905 switch ( flag ) {
2906 case kIOCatalogResetDefault:
2907 gIOCatalogue->reset();
2908 break;
2909
2910 default:
2911 return kIOReturnBadArgument;
2912 }
2913
2914 return kIOReturnSuccess;
2915 }
2916
2917 kern_return_t iokit_user_client_trap(io_object_t userClientRef, UInt32 index,
2918 void *p1, void *p2, void *p3,
2919 void *p4, void *p5, void *p6)
2920 {
2921 kern_return_t result = kIOReturnBadArgument;
2922 IOUserClient *userClient;
2923
2924 if ((userClient = OSDynamicCast(IOUserClient,
2925 iokit_lookup_connect_ref_current_task(userClientRef)))) {
2926 IOExternalTrap *trap;
2927 IOService *target = NULL;
2928
2929 trap = userClient->getTargetAndTrapForIndex(&target, index);
2930
2931 if (trap && target) {
2932 IOTrap func;
2933
2934 func = trap->func;
2935
2936 if (func) {
2937 result = (target->*func)(p1, p2, p3, p4, p5, p6);
2938 }
2939 }
2940
2941 userClient->release();
2942 }
2943
2944 return result;
2945 }
2946
2947 }; /* extern "C" */
2948
2949 OSMetaClassDefineReservedUnused(IOUserClient, 0);
2950 OSMetaClassDefineReservedUnused(IOUserClient, 1);
2951 OSMetaClassDefineReservedUnused(IOUserClient, 2);
2952 OSMetaClassDefineReservedUnused(IOUserClient, 3);
2953 OSMetaClassDefineReservedUnused(IOUserClient, 4);
2954 OSMetaClassDefineReservedUnused(IOUserClient, 5);
2955 OSMetaClassDefineReservedUnused(IOUserClient, 6);
2956 OSMetaClassDefineReservedUnused(IOUserClient, 7);
2957 OSMetaClassDefineReservedUnused(IOUserClient, 8);
2958 OSMetaClassDefineReservedUnused(IOUserClient, 9);
2959 OSMetaClassDefineReservedUnused(IOUserClient, 10);
2960 OSMetaClassDefineReservedUnused(IOUserClient, 11);
2961 OSMetaClassDefineReservedUnused(IOUserClient, 12);
2962 OSMetaClassDefineReservedUnused(IOUserClient, 13);
2963 OSMetaClassDefineReservedUnused(IOUserClient, 14);
2964 OSMetaClassDefineReservedUnused(IOUserClient, 15);
2965