+ return NULL;
+}
+
+IOReturn
+IOUserClient::registerNotificationPort(
+ mach_port_t /* port */,
+ UInt32 /* type */,
+ UInt32 /* refCon */)
+{
+ return kIOReturnUnsupported;
+}
+
+IOReturn
+IOUserClient::registerNotificationPort(
+ mach_port_t port,
+ UInt32 type,
+ io_user_reference_t refCon)
+{
+ return registerNotificationPort(port, type, (UInt32) refCon);
+}
+
+IOReturn
+IOUserClient::getNotificationSemaphore( UInt32 notification_type,
+ semaphore_t * semaphore )
+{
+ return kIOReturnUnsupported;
+}
+
+IOReturn
+IOUserClient::connectClient( IOUserClient * /* client */ )
+{
+ return kIOReturnUnsupported;
+}
+
+IOReturn
+IOUserClient::clientMemoryForType( UInt32 type,
+ IOOptionBits * options,
+ IOMemoryDescriptor ** memory )
+{
+ return kIOReturnUnsupported;
+}
+
+IOReturn
+IOUserClient::clientMemoryForType( UInt32 type,
+ IOOptionBits * options,
+ OSSharedPtr<IOMemoryDescriptor>& memory )
+{
+ IOMemoryDescriptor* memoryRaw = nullptr;
+ IOReturn result = clientMemoryForType(type, options, &memoryRaw);
+ memory.reset(memoryRaw, OSNoRetain);
+ return result;
+}
+
+#if !__LP64__
+IOMemoryMap *
+IOUserClient::mapClientMemory(
+ IOOptionBits type,
+ task_t task,
+ IOOptionBits mapFlags,
+ IOVirtualAddress atAddress )
+{
+ return NULL;
+}
+#endif
+
+IOMemoryMap *
+IOUserClient::mapClientMemory64(
+ IOOptionBits type,
+ task_t task,
+ IOOptionBits mapFlags,
+ mach_vm_address_t atAddress )
+{
+ IOReturn err;
+ IOOptionBits options = 0;
+ IOMemoryDescriptor * memory = NULL;
+ IOMemoryMap * map = NULL;
+
+ err = clientMemoryForType((UInt32) type, &options, &memory );
+
+ if (memory && (kIOReturnSuccess == err)) {
+ FAKE_STACK_FRAME(getMetaClass());
+
+ options = (options & ~kIOMapUserOptionsMask)
+ | (mapFlags & kIOMapUserOptionsMask);
+ map = memory->createMappingInTask( task, atAddress, options );
+ memory->release();
+
+ FAKE_STACK_FRAME_END();
+ }
+
+ return map;
+}
+
+IOReturn
+IOUserClient::exportObjectToClient(task_t task,
+ OSObject *obj, io_object_t *clientObj)
+{
+ mach_port_name_t name;
+
+ name = IOMachPort::makeSendRightForTask( task, obj, IKOT_IOKIT_OBJECT );
+
+ *clientObj = (io_object_t)(uintptr_t) name;
+
+ if (obj) {
+ obj->release();
+ }
+
+ return kIOReturnSuccess;
+}
+
+IOReturn
+IOUserClient::copyPortNameForObjectInTask(task_t task,
+ OSObject *obj, mach_port_name_t * port_name)
+{
+ mach_port_name_t name;
+
+ name = IOMachPort::makeSendRightForTask( task, obj, IKOT_IOKIT_IDENT );
+
+ *(mach_port_name_t *) port_name = name;
+
+ return kIOReturnSuccess;
+}
+
+IOReturn
+IOUserClient::copyObjectForPortNameInTask(task_t task, mach_port_name_t port_name,
+ OSObject **obj)
+{
+ OSObject * object;
+
+ object = iokit_lookup_object_with_port_name(port_name, IKOT_IOKIT_IDENT, task);
+
+ *obj = object;
+
+ return object ? kIOReturnSuccess : kIOReturnIPCError;
+}
+
+IOReturn
+IOUserClient::copyObjectForPortNameInTask(task_t task, mach_port_name_t port_name,
+ OSSharedPtr<OSObject>& obj)
+{
+ OSObject* objRaw = NULL;
+ IOReturn result = copyObjectForPortNameInTask(task, port_name, &objRaw);
+ obj.reset(objRaw, OSNoRetain);
+ return result;
+}
+
+IOReturn
+IOUserClient::adjustPortNameReferencesInTask(task_t task, mach_port_name_t port_name, mach_port_delta_t delta)
+{
+ return iokit_mod_send_right(task, port_name, delta);
+}
+
+IOExternalMethod *
+IOUserClient::getExternalMethodForIndex( UInt32 /* index */)
+{
+ return NULL;
+}
+
+IOExternalAsyncMethod *
+IOUserClient::getExternalAsyncMethodForIndex( UInt32 /* index */)
+{
+ return NULL;
+}
+
+IOExternalTrap *
+IOUserClient::
+getExternalTrapForIndex(UInt32 index)
+{
+ return NULL;
+}
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+// Suppressing the deprecated-declarations warning. Avoiding the use of deprecated
+// functions can break clients of kexts implementing getExternalMethodForIndex()
+IOExternalMethod *
+IOUserClient::
+getTargetAndMethodForIndex(IOService **targetP, UInt32 index)
+{
+ IOExternalMethod *method = getExternalMethodForIndex(index);
+
+ if (method) {
+ *targetP = (IOService *) method->object;
+ }
+
+ return method;
+}
+
+IOExternalMethod *
+IOUserClient::
+getTargetAndMethodForIndex(OSSharedPtr<IOService>& targetP, UInt32 index)
+{
+ IOService* targetPRaw = NULL;
+ IOExternalMethod* result = getTargetAndMethodForIndex(&targetPRaw, index);
+ targetP.reset(targetPRaw, OSRetain);
+ return result;
+}
+
+IOExternalAsyncMethod *
+IOUserClient::
+getAsyncTargetAndMethodForIndex(IOService ** targetP, UInt32 index)
+{
+ IOExternalAsyncMethod *method = getExternalAsyncMethodForIndex(index);
+
+ if (method) {
+ *targetP = (IOService *) method->object;
+ }
+
+ return method;
+}
+
+IOExternalAsyncMethod *
+IOUserClient::
+getAsyncTargetAndMethodForIndex(OSSharedPtr<IOService>& targetP, UInt32 index)
+{
+ IOService* targetPRaw = NULL;
+ IOExternalAsyncMethod* result = getAsyncTargetAndMethodForIndex(&targetPRaw, index);
+ targetP.reset(targetPRaw, OSRetain);
+ return result;
+}
+
+IOExternalTrap *
+IOUserClient::
+getTargetAndTrapForIndex(IOService ** targetP, UInt32 index)
+{
+ IOExternalTrap *trap = getExternalTrapForIndex(index);
+
+ if (trap) {
+ *targetP = trap->object;
+ }
+
+ return trap;
+}
+#pragma clang diagnostic pop
+
+IOReturn
+IOUserClient::releaseAsyncReference64(OSAsyncReference64 reference)
+{
+ mach_port_t port;
+ port = (mach_port_t) (reference[0] & ~kIOUCAsync0Flags);
+
+ if (MACH_PORT_NULL != port) {
+ iokit_release_port_send(port);
+ }
+
+ return kIOReturnSuccess;
+}
+
+IOReturn
+IOUserClient::releaseNotificationPort(mach_port_t port)
+{
+ if (MACH_PORT_NULL != port) {
+ iokit_release_port_send(port);
+ }
+
+ return kIOReturnSuccess;
+}
+
+IOReturn
+IOUserClient::sendAsyncResult(OSAsyncReference reference,
+ IOReturn result, void *args[], UInt32 numArgs)
+{
+ OSAsyncReference64 reference64;
+ io_user_reference_t args64[kMaxAsyncArgs];
+ unsigned int idx;
+
+ if (numArgs > kMaxAsyncArgs) {
+ return kIOReturnMessageTooLarge;
+ }
+
+ for (idx = 0; idx < kOSAsyncRef64Count; idx++) {
+ reference64[idx] = REF64(reference[idx]);
+ }
+
+ for (idx = 0; idx < numArgs; idx++) {
+ args64[idx] = REF64(args[idx]);
+ }
+
+ return sendAsyncResult64(reference64, result, args64, numArgs);
+}
+
+IOReturn
+IOUserClient::sendAsyncResult64WithOptions(OSAsyncReference64 reference,
+ IOReturn result, io_user_reference_t args[], UInt32 numArgs, IOOptionBits options)
+{
+ return _sendAsyncResult64(reference, result, args, numArgs, options);
+}
+
+IOReturn
+IOUserClient::sendAsyncResult64(OSAsyncReference64 reference,
+ IOReturn result, io_user_reference_t args[], UInt32 numArgs)
+{
+ return _sendAsyncResult64(reference, result, args, numArgs, 0);
+}
+
+IOReturn
+IOUserClient::_sendAsyncResult64(OSAsyncReference64 reference,
+ IOReturn result, io_user_reference_t args[], UInt32 numArgs, IOOptionBits options)
+{
+ struct ReplyMsg {
+ mach_msg_header_t msgHdr;
+ union{
+ struct{
+ OSNotificationHeader notifyHdr;
+ IOAsyncCompletionContent asyncContent;
+ uint32_t args[kMaxAsyncArgs];
+ } msg32;
+ struct{
+ OSNotificationHeader64 notifyHdr;
+ IOAsyncCompletionContent asyncContent;
+ io_user_reference_t args[kMaxAsyncArgs] __attribute__ ((packed));
+ } msg64;
+ } m;
+ };
+ ReplyMsg replyMsg;
+ mach_port_t replyPort;
+ kern_return_t kr;
+
+ // If no reply port, do nothing.
+ replyPort = (mach_port_t) (reference[0] & ~kIOUCAsync0Flags);
+ if (replyPort == MACH_PORT_NULL) {
+ return kIOReturnSuccess;
+ }
+
+ if (numArgs > kMaxAsyncArgs) {
+ return kIOReturnMessageTooLarge;
+ }
+
+ bzero(&replyMsg, sizeof(replyMsg));
+ replyMsg.msgHdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND /*remote*/,
+ 0 /*local*/);
+ replyMsg.msgHdr.msgh_remote_port = replyPort;
+ replyMsg.msgHdr.msgh_local_port = NULL;
+ replyMsg.msgHdr.msgh_id = kOSNotificationMessageID;
+ if (kIOUCAsync64Flag & reference[0]) {
+ replyMsg.msgHdr.msgh_size =
+ sizeof(replyMsg.msgHdr) + sizeof(replyMsg.m.msg64)
+ - (kMaxAsyncArgs - numArgs) * sizeof(io_user_reference_t);
+ replyMsg.m.msg64.notifyHdr.size = sizeof(IOAsyncCompletionContent)
+ + numArgs * sizeof(io_user_reference_t);
+ replyMsg.m.msg64.notifyHdr.type = kIOAsyncCompletionNotificationType;
+ /* Copy reference except for reference[0], which is left as 0 from the earlier bzero */
+ bcopy(&reference[1], &replyMsg.m.msg64.notifyHdr.reference[1], sizeof(OSAsyncReference64) - sizeof(reference[0]));
+
+ replyMsg.m.msg64.asyncContent.result = result;
+ if (numArgs) {
+ bcopy(args, replyMsg.m.msg64.args, numArgs * sizeof(io_user_reference_t));
+ }
+ } else {
+ unsigned int idx;
+
+ replyMsg.msgHdr.msgh_size =
+ sizeof(replyMsg.msgHdr) + sizeof(replyMsg.m.msg32)
+ - (kMaxAsyncArgs - numArgs) * sizeof(uint32_t);
+
+ replyMsg.m.msg32.notifyHdr.size = sizeof(IOAsyncCompletionContent)
+ + numArgs * sizeof(uint32_t);
+ replyMsg.m.msg32.notifyHdr.type = kIOAsyncCompletionNotificationType;
+
+ /* Skip reference[0] which is left as 0 from the earlier bzero */
+ for (idx = 1; idx < kOSAsyncRefCount; idx++) {
+ replyMsg.m.msg32.notifyHdr.reference[idx] = REF32(reference[idx]);
+ }
+
+ replyMsg.m.msg32.asyncContent.result = result;
+
+ for (idx = 0; idx < numArgs; idx++) {
+ replyMsg.m.msg32.args[idx] = REF32(args[idx]);
+ }
+ }
+
+ if ((options & kIOUserNotifyOptionCanDrop) != 0) {
+ kr = mach_msg_send_from_kernel_with_options( &replyMsg.msgHdr,
+ replyMsg.msgHdr.msgh_size, MACH_SEND_TIMEOUT, MACH_MSG_TIMEOUT_NONE);
+ } else {
+ /* Fail on full queue. */
+ kr = mach_msg_send_from_kernel_proper( &replyMsg.msgHdr,
+ replyMsg.msgHdr.msgh_size);
+ }
+ if ((KERN_SUCCESS != kr) && (MACH_SEND_TIMED_OUT != kr) && !(kIOUCAsyncErrorLoggedFlag & reference[0])) {
+ reference[0] |= kIOUCAsyncErrorLoggedFlag;
+ IOLog("%s: mach_msg_send_from_kernel_proper(0x%x)\n", __PRETTY_FUNCTION__, kr );
+ }
+ return kr;
+}
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+extern "C" {
+#define CHECK(cls, obj, out) \
+ cls * out; \
+ if( !(out = OSDynamicCast( cls, obj))) \
+ return( kIOReturnBadArgument )
+
+#define CHECKLOCKED(cls, obj, out) \
+ IOUserIterator * oIter; \
+ cls * out; \
+ if( !(oIter = OSDynamicCast(IOUserIterator, obj))) \
+ return (kIOReturnBadArgument); \
+ if( !(out = OSDynamicCast(cls, oIter->userIteratorObject))) \
+ return (kIOReturnBadArgument)
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+// Create a vm_map_copy_t or kalloc'ed data for memory
+// to be copied out. ipc will free after the copyout.
+
+static kern_return_t
+copyoutkdata( const void * data, vm_size_t len,
+ io_buf_ptr_t * buf )
+{
+ kern_return_t err;
+ vm_map_copy_t copy;
+
+ err = vm_map_copyin( kernel_map, CAST_USER_ADDR_T(data), len,
+ false /* src_destroy */, ©);
+
+ assert( err == KERN_SUCCESS );
+ if (err == KERN_SUCCESS) {
+ *buf = (char *) copy;
+ }
+
+ return err;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* Routine io_server_version */
+kern_return_t
+is_io_server_version(
+ mach_port_t master_port,
+ uint64_t *version)
+{
+ *version = IOKIT_SERVER_VERSION;
+ return kIOReturnSuccess;
+}
+
+/* Routine io_object_get_class */
+kern_return_t
+is_io_object_get_class(
+ io_object_t object,
+ io_name_t className )
+{
+ const OSMetaClass* my_obj = NULL;
+
+ if (!object) {
+ return kIOReturnBadArgument;
+ }
+
+ my_obj = object->getMetaClass();
+ if (!my_obj) {
+ return kIOReturnNotFound;
+ }
+
+ strlcpy( className, my_obj->getClassName(), sizeof(io_name_t));
+
+ return kIOReturnSuccess;
+}
+
+/* Routine io_object_get_superclass */
+kern_return_t
+is_io_object_get_superclass(
+ mach_port_t master_port,
+ io_name_t obj_name,
+ io_name_t class_name)
+{
+ IOReturn ret;
+ const OSMetaClass * meta;
+ const OSMetaClass * super;
+ const OSSymbol * name;
+ const char * cstr;
+
+ if (!obj_name || !class_name) {
+ return kIOReturnBadArgument;
+ }
+ if (master_port != master_device_port) {
+ return kIOReturnNotPrivileged;
+ }
+
+ ret = kIOReturnNotFound;
+ meta = NULL;
+ do{
+ name = OSSymbol::withCString(obj_name);
+ if (!name) {
+ break;
+ }
+ meta = OSMetaClass::copyMetaClassWithName(name);
+ if (!meta) {
+ break;
+ }
+ super = meta->getSuperClass();
+ if (!super) {
+ break;
+ }
+ cstr = super->getClassName();
+ if (!cstr) {
+ break;
+ }
+ strlcpy(class_name, cstr, sizeof(io_name_t));
+ ret = kIOReturnSuccess;
+ }while (false);
+
+ OSSafeReleaseNULL(name);
+ if (meta) {
+ meta->releaseMetaClass();
+ }
+
+ return ret;
+}
+
+/* Routine io_object_get_bundle_identifier */
+kern_return_t
+is_io_object_get_bundle_identifier(
+ mach_port_t master_port,
+ io_name_t obj_name,
+ io_name_t bundle_name)
+{
+ IOReturn ret;
+ const OSMetaClass * meta;
+ const OSSymbol * name;
+ const OSSymbol * identifier;
+ const char * cstr;
+
+ if (!obj_name || !bundle_name) {
+ return kIOReturnBadArgument;
+ }
+ if (master_port != master_device_port) {
+ return kIOReturnNotPrivileged;
+ }
+
+ ret = kIOReturnNotFound;
+ meta = NULL;
+ do{
+ name = OSSymbol::withCString(obj_name);
+ if (!name) {
+ break;
+ }
+ meta = OSMetaClass::copyMetaClassWithName(name);
+ if (!meta) {
+ break;
+ }
+ identifier = meta->getKmodName();
+ if (!identifier) {
+ break;
+ }
+ cstr = identifier->getCStringNoCopy();
+ if (!cstr) {
+ break;
+ }
+ strlcpy(bundle_name, identifier->getCStringNoCopy(), sizeof(io_name_t));
+ ret = kIOReturnSuccess;
+ }while (false);
+
+ OSSafeReleaseNULL(name);
+ if (meta) {
+ meta->releaseMetaClass();
+ }
+
+ return ret;
+}
+
+/* Routine io_object_conforms_to */
+kern_return_t
+is_io_object_conforms_to(
+ io_object_t object,
+ io_name_t className,
+ boolean_t *conforms )
+{
+ if (!object) {
+ return kIOReturnBadArgument;
+ }
+
+ *conforms = (NULL != object->metaCast( className ));
+
+ return kIOReturnSuccess;
+}
+
+/* Routine io_object_get_retain_count */
+kern_return_t
+is_io_object_get_retain_count(
+ io_object_t object,
+ uint32_t *retainCount )
+{
+ if (!object) {
+ return kIOReturnBadArgument;
+ }
+
+ *retainCount = object->getRetainCount();
+ return kIOReturnSuccess;
+}
+
+/* Routine io_iterator_next */
+kern_return_t
+is_io_iterator_next(
+ io_object_t iterator,
+ io_object_t *object )
+{
+ IOReturn ret;
+ OSObject * obj;
+ OSIterator * iter;
+ IOUserIterator * uiter;
+
+ if ((uiter = OSDynamicCast(IOUserIterator, iterator))) {
+ obj = uiter->copyNextObject();
+ } else if ((iter = OSDynamicCast(OSIterator, iterator))) {
+ obj = iter->getNextObject();
+ if (obj) {
+ obj->retain();
+ }
+ } else {
+ return kIOReturnBadArgument;
+ }
+
+ if (obj) {
+ *object = obj;
+ ret = kIOReturnSuccess;
+ } else {
+ ret = kIOReturnNoDevice;
+ }
+
+ return ret;
+}
+
+/* Routine io_iterator_reset */
+kern_return_t
+is_io_iterator_reset(
+ io_object_t iterator )
+{
+ CHECK( OSIterator, iterator, iter );
+
+ iter->reset();
+
+ return kIOReturnSuccess;
+}
+
+/* Routine io_iterator_is_valid */
+kern_return_t
+is_io_iterator_is_valid(
+ io_object_t iterator,
+ boolean_t *is_valid )
+{
+ CHECK( OSIterator, iterator, iter );
+
+ *is_valid = iter->isValid();
+
+ return kIOReturnSuccess;
+}
+
+static kern_return_t
+internal_io_service_match_property_table(
+ io_service_t _service,
+ const char * matching,
+ mach_msg_type_number_t matching_size,
+ boolean_t *matches)
+{
+ CHECK( IOService, _service, service );
+
+ kern_return_t kr;
+ OSObject * obj;
+ OSDictionary * dict;
+
+ assert(matching_size);
+
+
+ obj = OSUnserializeXML(matching, matching_size);
+
+ if ((dict = OSDynamicCast( OSDictionary, obj))) {
+ IOTaskRegistryCompatibilityMatching(current_task(), dict);
+ *matches = service->passiveMatch( dict );
+ kr = kIOReturnSuccess;
+ } else {
+ kr = kIOReturnBadArgument;
+ }
+
+ if (obj) {
+ obj->release();
+ }
+
+ return kr;
+}
+
+/* Routine io_service_match_property_table */
+kern_return_t
+is_io_service_match_property_table(
+ io_service_t service,
+ io_string_t matching,
+ boolean_t *matches )
+{
+ return kIOReturnUnsupported;
+}
+
+
+/* Routine io_service_match_property_table_ool */
+kern_return_t
+is_io_service_match_property_table_ool(
+ io_object_t service,
+ io_buf_ptr_t matching,
+ mach_msg_type_number_t matchingCnt,
+ kern_return_t *result,
+ boolean_t *matches )
+{
+ kern_return_t kr;
+ vm_offset_t data;
+ vm_map_offset_t map_data;
+
+ kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) matching );
+ data = CAST_DOWN(vm_offset_t, map_data);
+
+ if (KERN_SUCCESS == kr) {
+ // must return success after vm_map_copyout() succeeds
+ *result = internal_io_service_match_property_table(service,
+ (const char *)data, matchingCnt, matches );
+ vm_deallocate( kernel_map, data, matchingCnt );
+ }
+
+ return kr;
+}
+
+/* Routine io_service_match_property_table_bin */
+kern_return_t
+is_io_service_match_property_table_bin(
+ io_object_t service,
+ io_struct_inband_t matching,
+ mach_msg_type_number_t matchingCnt,
+ boolean_t *matches)
+{
+ return internal_io_service_match_property_table(service, matching, matchingCnt, matches);
+}
+
+static kern_return_t
+internal_io_service_get_matching_services(
+ mach_port_t master_port,
+ const char * matching,
+ mach_msg_type_number_t matching_size,
+ io_iterator_t *existing )
+{
+ kern_return_t kr;
+ OSObject * obj;
+ OSDictionary * dict;
+
+ if (master_port != master_device_port) {
+ return kIOReturnNotPrivileged;
+ }
+
+ assert(matching_size);
+ obj = OSUnserializeXML(matching, matching_size);
+
+ if ((dict = OSDynamicCast( OSDictionary, obj))) {
+ IOTaskRegistryCompatibilityMatching(current_task(), dict);
+ *existing = IOUserIterator::withIterator(IOService::getMatchingServices( dict ));
+ kr = kIOReturnSuccess;
+ } else {
+ kr = kIOReturnBadArgument;
+ }
+
+ if (obj) {
+ obj->release();
+ }
+
+ return kr;
+}
+
+/* Routine io_service_get_matching_services */
+kern_return_t
+is_io_service_get_matching_services(
+ mach_port_t master_port,
+ io_string_t matching,
+ io_iterator_t *existing )
+{
+ return kIOReturnUnsupported;
+}
+
+/* Routine io_service_get_matching_services_ool */
+kern_return_t
+is_io_service_get_matching_services_ool(
+ mach_port_t master_port,
+ io_buf_ptr_t matching,
+ mach_msg_type_number_t matchingCnt,
+ kern_return_t *result,
+ io_object_t *existing )
+{
+ kern_return_t kr;
+ vm_offset_t data;
+ vm_map_offset_t map_data;
+
+ kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) matching );
+ data = CAST_DOWN(vm_offset_t, map_data);
+
+ if (KERN_SUCCESS == kr) {
+ // must return success after vm_map_copyout() succeeds
+ // and mig will copy out objects on success
+ *existing = NULL;
+ *result = internal_io_service_get_matching_services(master_port,
+ (const char *) data, matchingCnt, existing);
+ vm_deallocate( kernel_map, data, matchingCnt );
+ }
+
+ return kr;
+}
+
+/* Routine io_service_get_matching_services_bin */
+kern_return_t
+is_io_service_get_matching_services_bin(
+ mach_port_t master_port,
+ io_struct_inband_t matching,
+ mach_msg_type_number_t matchingCnt,
+ io_object_t *existing)
+{
+ return internal_io_service_get_matching_services(master_port, matching, matchingCnt, existing);
+}
+
+
+static kern_return_t
+internal_io_service_get_matching_service(
+ mach_port_t master_port,
+ const char * matching,
+ mach_msg_type_number_t matching_size,
+ io_service_t *service )
+{
+ kern_return_t kr;
+ OSObject * obj;
+ OSDictionary * dict;
+
+ if (master_port != master_device_port) {
+ return kIOReturnNotPrivileged;
+ }
+
+ assert(matching_size);
+ obj = OSUnserializeXML(matching, matching_size);
+
+ if ((dict = OSDynamicCast( OSDictionary, obj))) {
+ IOTaskRegistryCompatibilityMatching(current_task(), dict);
+ *service = IOService::copyMatchingService( dict );
+ kr = *service ? kIOReturnSuccess : kIOReturnNotFound;
+ } else {
+ kr = kIOReturnBadArgument;
+ }
+
+ if (obj) {
+ obj->release();
+ }
+
+ return kr;
+}
+
+/* Routine io_service_get_matching_service */
+kern_return_t
+is_io_service_get_matching_service(
+ mach_port_t master_port,
+ io_string_t matching,
+ io_service_t *service )
+{
+ return kIOReturnUnsupported;
+}
+
+/* Routine io_service_get_matching_services_ool */
+kern_return_t
+is_io_service_get_matching_service_ool(
+ mach_port_t master_port,
+ io_buf_ptr_t matching,
+ mach_msg_type_number_t matchingCnt,
+ kern_return_t *result,
+ io_object_t *service )
+{
+ kern_return_t kr;
+ vm_offset_t data;
+ vm_map_offset_t map_data;
+
+ kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) matching );
+ data = CAST_DOWN(vm_offset_t, map_data);
+
+ if (KERN_SUCCESS == kr) {
+ // must return success after vm_map_copyout() succeeds
+ // and mig will copy out objects on success
+ *service = NULL;
+ *result = internal_io_service_get_matching_service(master_port,
+ (const char *) data, matchingCnt, service );
+ vm_deallocate( kernel_map, data, matchingCnt );
+ }
+
+ return kr;
+}
+
+/* Routine io_service_get_matching_service_bin */
+kern_return_t
+is_io_service_get_matching_service_bin(
+ mach_port_t master_port,
+ io_struct_inband_t matching,
+ mach_msg_type_number_t matchingCnt,
+ io_object_t *service)
+{
+ return internal_io_service_get_matching_service(master_port, matching, matchingCnt, service);
+}
+
+static kern_return_t
+internal_io_service_add_notification(
+ mach_port_t master_port,
+ io_name_t notification_type,
+ const char * matching,
+ size_t matching_size,
+ mach_port_t port,
+ void * reference,
+ vm_size_t referenceSize,
+ bool client64,
+ io_object_t * notification )
+{
+ IOServiceUserNotification * userNotify = NULL;
+ IONotifier * notify = NULL;
+ const OSSymbol * sym;
+ OSObject * obj;
+ OSDictionary * dict;
+ IOReturn err;
+ natural_t userMsgType;
+
+ if (master_port != master_device_port) {
+ return kIOReturnNotPrivileged;
+ }
+
+ do {
+ err = kIOReturnNoResources;
+
+ if (matching_size > (sizeof(io_struct_inband_t) * 1024)) {
+ return kIOReturnMessageTooLarge;
+ }
+
+ if (!(sym = OSSymbol::withCString( notification_type ))) {
+ err = kIOReturnNoResources;
+ }
+
+ assert(matching_size);
+ obj = OSUnserializeXML(matching, matching_size);
+ dict = OSDynamicCast(OSDictionary, obj);
+ if (!dict) {
+ err = kIOReturnBadArgument;
+ continue;
+ }
+ IOTaskRegistryCompatibilityMatching(current_task(), dict);
+
+ if ((sym == gIOPublishNotification)
+ || (sym == gIOFirstPublishNotification)) {
+ userMsgType = kIOServicePublishNotificationType;
+ } else if ((sym == gIOMatchedNotification)
+ || (sym == gIOFirstMatchNotification)) {
+ userMsgType = kIOServiceMatchedNotificationType;
+ } else if ((sym == gIOTerminatedNotification)
+ || (sym == gIOWillTerminateNotification)) {
+ userMsgType = kIOServiceTerminatedNotificationType;
+ } else {
+ userMsgType = kLastIOKitNotificationType;
+ }
+
+ userNotify = new IOServiceUserNotification;
+
+ if (userNotify && !userNotify->init( port, userMsgType,
+ reference, referenceSize, client64)) {
+ userNotify->release();
+ userNotify = NULL;
+ }
+ if (!userNotify) {
+ continue;
+ }
+
+ notify = IOService::addMatchingNotification( sym, dict,
+ &userNotify->_handler, userNotify );
+ if (notify) {
+ *notification = userNotify;
+ userNotify->setNotification( notify );
+ err = kIOReturnSuccess;
+ } else {
+ err = kIOReturnUnsupported;
+ }
+ } while (false);
+
+ if ((kIOReturnSuccess != err) && userNotify) {
+ userNotify->invalidatePort();
+ userNotify->release();
+ userNotify = NULL;
+ }
+
+ if (sym) {
+ sym->release();
+ }
+ if (obj) {
+ obj->release();
+ }
+
+ return err;
+}
+
+
+/* Routine io_service_add_notification */
+kern_return_t
+is_io_service_add_notification(
+ mach_port_t master_port,
+ io_name_t notification_type,
+ io_string_t matching,
+ mach_port_t port,
+ io_async_ref_t reference,
+ mach_msg_type_number_t referenceCnt,
+ io_object_t * notification )
+{
+ return kIOReturnUnsupported;
+}
+
+/* Routine io_service_add_notification_64 */
+kern_return_t
+is_io_service_add_notification_64(
+ mach_port_t master_port,
+ io_name_t notification_type,
+ io_string_t matching,
+ mach_port_t wake_port,
+ io_async_ref64_t reference,
+ mach_msg_type_number_t referenceCnt,
+ io_object_t *notification )
+{
+ return kIOReturnUnsupported;
+}
+
+/* Routine io_service_add_notification_bin */
+kern_return_t
+is_io_service_add_notification_bin
+(
+ mach_port_t master_port,
+ io_name_t notification_type,
+ io_struct_inband_t matching,
+ mach_msg_type_number_t matchingCnt,
+ mach_port_t wake_port,
+ io_async_ref_t reference,
+ mach_msg_type_number_t referenceCnt,
+ io_object_t *notification)
+{
+ io_async_ref_t zreference;
+
+ if (referenceCnt > ASYNC_REF_COUNT) {
+ return kIOReturnBadArgument;
+ }
+ bcopy(&reference[0], &zreference[0], referenceCnt * sizeof(zreference[0]));
+ bzero(&zreference[referenceCnt], (ASYNC_REF_COUNT - referenceCnt) * sizeof(zreference[0]));
+
+ return internal_io_service_add_notification(master_port, notification_type,
+ matching, matchingCnt, wake_port, &zreference[0], sizeof(io_async_ref_t),
+ false, notification);
+}
+
+/* Routine io_service_add_notification_bin_64 */
+kern_return_t
+is_io_service_add_notification_bin_64
+(
+ mach_port_t master_port,
+ io_name_t notification_type,
+ io_struct_inband_t matching,
+ mach_msg_type_number_t matchingCnt,
+ mach_port_t wake_port,
+ io_async_ref64_t reference,
+ mach_msg_type_number_t referenceCnt,
+ io_object_t *notification)
+{
+ io_async_ref64_t zreference;
+
+ if (referenceCnt > ASYNC_REF64_COUNT) {
+ return kIOReturnBadArgument;
+ }
+ bcopy(&reference[0], &zreference[0], referenceCnt * sizeof(zreference[0]));
+ bzero(&zreference[referenceCnt], (ASYNC_REF64_COUNT - referenceCnt) * sizeof(zreference[0]));
+
+ return internal_io_service_add_notification(master_port, notification_type,
+ matching, matchingCnt, wake_port, &zreference[0], sizeof(io_async_ref64_t),
+ true, notification);
+}
+
+static kern_return_t
+internal_io_service_add_notification_ool(
+ mach_port_t master_port,
+ io_name_t notification_type,
+ io_buf_ptr_t matching,
+ mach_msg_type_number_t matchingCnt,
+ mach_port_t wake_port,
+ void * reference,
+ vm_size_t referenceSize,
+ bool client64,
+ kern_return_t *result,
+ io_object_t *notification )
+{
+ kern_return_t kr;
+ vm_offset_t data;
+ vm_map_offset_t map_data;
+
+ kr = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) matching );
+ data = CAST_DOWN(vm_offset_t, map_data);
+
+ if (KERN_SUCCESS == kr) {
+ // must return success after vm_map_copyout() succeeds
+ // and mig will copy out objects on success
+ *notification = NULL;
+ *result = internal_io_service_add_notification( master_port, notification_type,
+ (char *) data, matchingCnt, wake_port, reference, referenceSize, client64, notification );
+ vm_deallocate( kernel_map, data, matchingCnt );
+ }
+
+ return kr;
+}
+
+/* Routine io_service_add_notification_ool */
+kern_return_t
+is_io_service_add_notification_ool(
+ mach_port_t master_port,
+ io_name_t notification_type,
+ io_buf_ptr_t matching,
+ mach_msg_type_number_t matchingCnt,
+ mach_port_t wake_port,
+ io_async_ref_t reference,
+ mach_msg_type_number_t referenceCnt,
+ kern_return_t *result,
+ io_object_t *notification )
+{
+ io_async_ref_t zreference;
+
+ if (referenceCnt > ASYNC_REF_COUNT) {
+ return kIOReturnBadArgument;
+ }
+ bcopy(&reference[0], &zreference[0], referenceCnt * sizeof(zreference[0]));
+ bzero(&zreference[referenceCnt], (ASYNC_REF_COUNT - referenceCnt) * sizeof(zreference[0]));
+
+ return internal_io_service_add_notification_ool(master_port, notification_type,
+ matching, matchingCnt, wake_port, &zreference[0], sizeof(io_async_ref_t),
+ false, result, notification);
+}
+
+/* Routine io_service_add_notification_ool_64 */
+kern_return_t
+is_io_service_add_notification_ool_64(
+ mach_port_t master_port,
+ io_name_t notification_type,
+ io_buf_ptr_t matching,
+ mach_msg_type_number_t matchingCnt,
+ mach_port_t wake_port,
+ io_async_ref64_t reference,
+ mach_msg_type_number_t referenceCnt,
+ kern_return_t *result,
+ io_object_t *notification )
+{
+ io_async_ref64_t zreference;
+
+ if (referenceCnt > ASYNC_REF64_COUNT) {
+ return kIOReturnBadArgument;
+ }
+ bcopy(&reference[0], &zreference[0], referenceCnt * sizeof(zreference[0]));
+ bzero(&zreference[referenceCnt], (ASYNC_REF64_COUNT - referenceCnt) * sizeof(zreference[0]));
+
+ return internal_io_service_add_notification_ool(master_port, notification_type,
+ matching, matchingCnt, wake_port, &zreference[0], sizeof(io_async_ref64_t),
+ true, result, notification);
+}
+
+/* Routine io_service_add_notification_old */
+kern_return_t
+is_io_service_add_notification_old(
+ mach_port_t master_port,
+ io_name_t notification_type,
+ io_string_t matching,
+ mach_port_t port,
+ // for binary compatibility reasons, this must be natural_t for ILP32
+ natural_t ref,
+ io_object_t * notification )
+{
+ return is_io_service_add_notification( master_port, notification_type,
+ matching, port, &ref, 1, notification );
+}
+
+
+static kern_return_t
+internal_io_service_add_interest_notification(
+ io_object_t _service,
+ io_name_t type_of_interest,
+ mach_port_t port,
+ void * reference,
+ vm_size_t referenceSize,
+ bool client64,
+ io_object_t * notification )
+{
+ IOServiceMessageUserNotification * userNotify = NULL;
+ IONotifier * notify = NULL;
+ const OSSymbol * sym;
+ IOReturn err;
+
+ CHECK( IOService, _service, service );
+
+ err = kIOReturnNoResources;
+ if ((sym = OSSymbol::withCString( type_of_interest ))) {
+ do {
+ userNotify = new IOServiceMessageUserNotification;
+
+ if (userNotify && !userNotify->init( port, kIOServiceMessageNotificationType,
+ reference, referenceSize,
+ kIOUserNotifyMaxMessageSize,
+ client64 )) {
+ userNotify->release();
+ userNotify = NULL;
+ }
+ if (!userNotify) {
+ continue;
+ }
+
+ notify = service->registerInterest( sym,
+ &userNotify->_handler, userNotify );
+ if (notify) {
+ *notification = userNotify;
+ userNotify->setNotification( notify );
+ err = kIOReturnSuccess;
+ } else {
+ err = kIOReturnUnsupported;
+ }
+
+ sym->release();
+ } while (false);
+ }
+
+ if ((kIOReturnSuccess != err) && userNotify) {
+ userNotify->invalidatePort();
+ userNotify->release();
+ userNotify = NULL;
+ }
+
+ return err;
+}
+
+/* Routine io_service_add_message_notification */
+kern_return_t
+is_io_service_add_interest_notification(
+ io_object_t service,
+ io_name_t type_of_interest,
+ mach_port_t port,
+ io_async_ref_t reference,
+ mach_msg_type_number_t referenceCnt,
+ io_object_t * notification )
+{
+ io_async_ref_t zreference;
+
+ if (referenceCnt > ASYNC_REF_COUNT) {
+ return kIOReturnBadArgument;
+ }
+ bcopy(&reference[0], &zreference[0], referenceCnt * sizeof(zreference[0]));
+ bzero(&zreference[referenceCnt], (ASYNC_REF_COUNT - referenceCnt) * sizeof(zreference[0]));
+
+ return internal_io_service_add_interest_notification(service, type_of_interest,
+ port, &zreference[0], sizeof(io_async_ref_t), false, notification);
+}
+
+/* Routine io_service_add_interest_notification_64 */
+kern_return_t
+is_io_service_add_interest_notification_64(
+ io_object_t service,
+ io_name_t type_of_interest,
+ mach_port_t wake_port,
+ io_async_ref64_t reference,
+ mach_msg_type_number_t referenceCnt,
+ io_object_t *notification )
+{
+ io_async_ref64_t zreference;
+
+ if (referenceCnt > ASYNC_REF64_COUNT) {
+ return kIOReturnBadArgument;
+ }
+ bcopy(&reference[0], &zreference[0], referenceCnt * sizeof(zreference[0]));
+ bzero(&zreference[referenceCnt], (ASYNC_REF64_COUNT - referenceCnt) * sizeof(zreference[0]));
+
+ return internal_io_service_add_interest_notification(service, type_of_interest,
+ wake_port, &zreference[0], sizeof(io_async_ref64_t), true, notification);
+}
+
+
+/* Routine io_service_acknowledge_notification */
+kern_return_t
+is_io_service_acknowledge_notification(
+ io_object_t _service,
+ natural_t notify_ref,
+ natural_t response )
+{
+ CHECK( IOService, _service, service );
+
+ return service->acknowledgeNotification((IONotificationRef)(uintptr_t) notify_ref,
+ (IOOptionBits) response );
+}
+
+/* Routine io_connect_get_semaphore */
+kern_return_t
+is_io_connect_get_notification_semaphore(
+ io_connect_t connection,
+ natural_t notification_type,
+ semaphore_t *semaphore )
+{
+ IOReturn ret;
+ CHECK( IOUserClient, connection, client );
+
+ IOStatisticsClientCall();
+ IORWLockWrite(client->lock);
+ ret = client->getNotificationSemaphore((UInt32) notification_type,
+ semaphore );
+ IORWLockUnlock(client->lock);
+
+ return ret;
+}
+
+/* Routine io_registry_get_root_entry */
+kern_return_t
+is_io_registry_get_root_entry(
+ mach_port_t master_port,
+ io_object_t *root )
+{
+ IORegistryEntry * entry;
+
+ if (master_port != master_device_port) {
+ return kIOReturnNotPrivileged;
+ }
+
+ entry = IORegistryEntry::getRegistryRoot();
+ if (entry) {
+ entry->retain();
+ }
+ *root = entry;
+
+ return kIOReturnSuccess;
+}
+
+/* Routine io_registry_create_iterator */
+kern_return_t
+is_io_registry_create_iterator(
+ mach_port_t master_port,
+ io_name_t plane,
+ uint32_t options,
+ io_object_t *iterator )
+{
+ if (master_port != master_device_port) {
+ return kIOReturnNotPrivileged;
+ }
+
+ *iterator = IOUserIterator::withIterator(
+ IORegistryIterator::iterateOver(
+ IORegistryEntry::getPlane( plane ), options ));
+
+ return *iterator ? kIOReturnSuccess : kIOReturnBadArgument;
+}
+
+/* Routine io_registry_entry_create_iterator */
+kern_return_t
+is_io_registry_entry_create_iterator(
+ io_object_t registry_entry,
+ io_name_t plane,
+ uint32_t options,
+ io_object_t *iterator )
+{
+ CHECK( IORegistryEntry, registry_entry, entry );
+
+ *iterator = IOUserIterator::withIterator(
+ IORegistryIterator::iterateOver( entry,
+ IORegistryEntry::getPlane( plane ), options ));
+
+ return *iterator ? kIOReturnSuccess : kIOReturnBadArgument;
+}
+
+/* Routine io_registry_iterator_enter */
+kern_return_t
+is_io_registry_iterator_enter_entry(
+ io_object_t iterator )
+{
+ CHECKLOCKED( IORegistryIterator, iterator, iter );
+
+ IOLockLock(oIter->lock);
+ iter->enterEntry();
+ IOLockUnlock(oIter->lock);
+
+ return kIOReturnSuccess;
+}
+
+/* Routine io_registry_iterator_exit */
+kern_return_t
+is_io_registry_iterator_exit_entry(
+ io_object_t iterator )
+{
+ bool didIt;
+
+ CHECKLOCKED( IORegistryIterator, iterator, iter );
+
+ IOLockLock(oIter->lock);
+ didIt = iter->exitEntry();
+ IOLockUnlock(oIter->lock);
+
+ return didIt ? kIOReturnSuccess : kIOReturnNoDevice;
+}
+
+/* Routine io_registry_entry_from_path */
+kern_return_t
+is_io_registry_entry_from_path(
+ mach_port_t master_port,
+ io_string_t path,
+ io_object_t *registry_entry )
+{
+ IORegistryEntry * entry;
+
+ if (master_port != master_device_port) {
+ return kIOReturnNotPrivileged;
+ }
+
+ entry = IORegistryEntry::fromPath( path );
+
+ if (!entry && IOTaskRegistryCompatibility(current_task())) {
+ OSDictionary * matching;
+ const OSObject * objects[2] = { kOSBooleanTrue, NULL };
+ const OSSymbol * keys[2] = { gIOCompatibilityMatchKey, gIOPathMatchKey };
+
+ objects[1] = OSString::withCStringNoCopy(path);
+ matching = OSDictionary::withObjects(objects, keys, 2, 2);
+ if (matching) {
+ entry = IOService::copyMatchingService(matching);
+ }
+ OSSafeReleaseNULL(matching);
+ OSSafeReleaseNULL(objects[1]);
+ }
+
+ *registry_entry = entry;
+
+ return kIOReturnSuccess;
+}
+
+
+/* Routine io_registry_entry_from_path */
+kern_return_t
+is_io_registry_entry_from_path_ool(
+ mach_port_t master_port,
+ io_string_inband_t path,
+ io_buf_ptr_t path_ool,
+ mach_msg_type_number_t path_oolCnt,
+ kern_return_t *result,
+ io_object_t *registry_entry)
+{
+ IORegistryEntry * entry;
+ vm_map_offset_t map_data;
+ const char * cpath;
+ IOReturn res;
+ kern_return_t err;
+
+ if (master_port != master_device_port) {
+ return kIOReturnNotPrivileged;
+ }
+
+ map_data = 0;
+ entry = NULL;
+ res = err = KERN_SUCCESS;
+ if (path[0]) {
+ cpath = path;
+ } else {
+ if (!path_oolCnt) {
+ return kIOReturnBadArgument;
+ }
+ if (path_oolCnt > (sizeof(io_struct_inband_t) * 1024)) {
+ return kIOReturnMessageTooLarge;
+ }
+
+ err = vm_map_copyout(kernel_map, &map_data, (vm_map_copy_t) path_ool);
+ if (KERN_SUCCESS == err) {
+ // must return success to mig after vm_map_copyout() succeeds, so result is actual
+ cpath = CAST_DOWN(const char *, map_data);
+ if (cpath[path_oolCnt - 1]) {
+ res = kIOReturnBadArgument;
+ }
+ }
+ }
+
+ if ((KERN_SUCCESS == err) && (KERN_SUCCESS == res)) {
+ entry = IORegistryEntry::fromPath(cpath);
+ res = entry ? kIOReturnSuccess : kIOReturnNotFound;
+ }
+
+ if (map_data) {
+ vm_deallocate(kernel_map, map_data, path_oolCnt);
+ }
+
+ if (KERN_SUCCESS != err) {
+ res = err;
+ }
+ *registry_entry = entry;
+ *result = res;
+
+ return err;
+}
+
+
+/* Routine io_registry_entry_in_plane */
+kern_return_t
+is_io_registry_entry_in_plane(
+ io_object_t registry_entry,
+ io_name_t plane,
+ boolean_t *inPlane )
+{
+ CHECK( IORegistryEntry, registry_entry, entry );
+
+ *inPlane = entry->inPlane( IORegistryEntry::getPlane( plane ));
+
+ return kIOReturnSuccess;
+}
+
+
+/* Routine io_registry_entry_get_path */
+kern_return_t
+is_io_registry_entry_get_path(
+ io_object_t registry_entry,
+ io_name_t plane,
+ io_string_t path )
+{
+ int length;
+ CHECK( IORegistryEntry, registry_entry, entry );
+
+ length = sizeof(io_string_t);
+ if (entry->getPath( path, &length, IORegistryEntry::getPlane( plane ))) {
+ return kIOReturnSuccess;
+ } else {
+ return kIOReturnBadArgument;
+ }
+}
+
+/* Routine io_registry_entry_get_path */
+kern_return_t
+is_io_registry_entry_get_path_ool(
+ io_object_t registry_entry,
+ io_name_t plane,
+ io_string_inband_t path,
+ io_buf_ptr_t *path_ool,
+ mach_msg_type_number_t *path_oolCnt)
+{
+ enum { kMaxPath = 16384 };
+ IOReturn err;
+ int length;
+ char * buf;
+
+ CHECK( IORegistryEntry, registry_entry, entry );
+
+ *path_ool = NULL;
+ *path_oolCnt = 0;
+ length = sizeof(io_string_inband_t);
+ if (entry->getPath(path, &length, IORegistryEntry::getPlane(plane))) {
+ err = kIOReturnSuccess;
+ } else {
+ length = kMaxPath;
+ buf = IONew(char, length);
+ if (!buf) {
+ err = kIOReturnNoMemory;
+ } else if (!entry->getPath(buf, &length, IORegistryEntry::getPlane(plane))) {
+ err = kIOReturnError;
+ } else {
+ *path_oolCnt = length;
+ err = copyoutkdata(buf, length, path_ool);
+ }
+ if (buf) {
+ IODelete(buf, char, kMaxPath);
+ }
+ }
+
+ return err;
+}
+
+
+/* Routine io_registry_entry_get_name */
+kern_return_t
+is_io_registry_entry_get_name(
+ io_object_t registry_entry,
+ io_name_t name )
+{
+ CHECK( IORegistryEntry, registry_entry, entry );
+
+ strncpy( name, entry->getName(), sizeof(io_name_t));
+
+ return kIOReturnSuccess;
+}
+
+/* Routine io_registry_entry_get_name_in_plane */
+kern_return_t
+is_io_registry_entry_get_name_in_plane(
+ io_object_t registry_entry,
+ io_name_t planeName,
+ io_name_t name )
+{
+ const IORegistryPlane * plane;
+ CHECK( IORegistryEntry, registry_entry, entry );
+
+ if (planeName[0]) {
+ plane = IORegistryEntry::getPlane( planeName );
+ } else {
+ plane = NULL;
+ }
+
+ strncpy( name, entry->getName( plane), sizeof(io_name_t));
+
+ return kIOReturnSuccess;
+}
+
+/* Routine io_registry_entry_get_location_in_plane */
+kern_return_t
+is_io_registry_entry_get_location_in_plane(
+ io_object_t registry_entry,
+ io_name_t planeName,
+ io_name_t location )
+{
+ const IORegistryPlane * plane;
+ CHECK( IORegistryEntry, registry_entry, entry );
+
+ if (planeName[0]) {
+ plane = IORegistryEntry::getPlane( planeName );
+ } else {
+ plane = NULL;
+ }
+
+ const char * cstr = entry->getLocation( plane );
+
+ if (cstr) {
+ strncpy( location, cstr, sizeof(io_name_t));
+ return kIOReturnSuccess;
+ } else {
+ return kIOReturnNotFound;
+ }
+}
+
+/* Routine io_registry_entry_get_registry_entry_id */
+kern_return_t
+is_io_registry_entry_get_registry_entry_id(
+ io_object_t registry_entry,
+ uint64_t *entry_id )
+{
+ CHECK( IORegistryEntry, registry_entry, entry );
+
+ *entry_id = entry->getRegistryEntryID();
+
+ return kIOReturnSuccess;
+}
+
+
+static OSObject *
+IOCopyPropertyCompatible(IORegistryEntry * regEntry, const char * name)
+{
+ OSObject * obj;
+ OSObject * compatProps;
+ OSDictionary * props;
+
+ obj = regEntry->copyProperty(name);
+ if (!obj
+ && IOTaskRegistryCompatibility(current_task())
+ && (compatProps = regEntry->copyProperty(gIOCompatibilityPropertiesKey))) {
+ props = OSDynamicCast(OSDictionary, compatProps);
+ if (props) {
+ obj = props->getObject(name);
+ if (obj) {
+ obj->retain();
+ }
+ }
+ compatProps->release();
+ }
+
+ return obj;
+}
+
+/* Routine io_registry_entry_get_property */
+kern_return_t
+is_io_registry_entry_get_property_bytes(
+ io_object_t registry_entry,
+ io_name_t property_name,
+ io_struct_inband_t buf,
+ mach_msg_type_number_t *dataCnt )
+{
+ OSObject * obj;
+ OSData * data;
+ OSString * str;
+ OSBoolean * boo;
+ OSNumber * off;
+ UInt64 offsetBytes;
+ unsigned int len = 0;
+ const void * bytes = NULL;
+ IOReturn ret = kIOReturnSuccess;
+
+ CHECK( IORegistryEntry, registry_entry, entry );
+
+#if CONFIG_MACF
+ if (0 != mac_iokit_check_get_property(kauth_cred_get(), entry, property_name)) {
+ return kIOReturnNotPermitted;
+ }
+#endif
+
+ obj = IOCopyPropertyCompatible(entry, property_name);
+ if (!obj) {
+ return kIOReturnNoResources;
+ }
+
+ // One day OSData will be a common container base class
+ // until then...
+ if ((data = OSDynamicCast( OSData, obj ))) {
+ len = data->getLength();
+ bytes = data->getBytesNoCopy();
+ if (!data->isSerializable()) {
+ len = 0;
+ }
+ } else if ((str = OSDynamicCast( OSString, obj ))) {
+ len = str->getLength() + 1;
+ bytes = str->getCStringNoCopy();
+ } else if ((boo = OSDynamicCast( OSBoolean, obj ))) {
+ len = boo->isTrue() ? sizeof("Yes") : sizeof("No");
+ bytes = boo->isTrue() ? "Yes" : "No";
+ } else if ((off = OSDynamicCast( OSNumber, obj ))) {
+ offsetBytes = off->unsigned64BitValue();
+ len = off->numberOfBytes();
+ if (len > sizeof(offsetBytes)) {
+ len = sizeof(offsetBytes);
+ }
+ bytes = &offsetBytes;
+#ifdef __BIG_ENDIAN__
+ bytes = (const void *)
+ (((UInt32) bytes) + (sizeof(UInt64) - len));
+#endif
+ } else {
+ ret = kIOReturnBadArgument;
+ }
+
+ if (bytes) {
+ if (*dataCnt < len) {
+ ret = kIOReturnIPCError;
+ } else {
+ *dataCnt = len;
+ bcopy( bytes, buf, len );
+ }
+ }
+ obj->release();
+
+ return ret;
+}
+
+
+/* Routine io_registry_entry_get_property */
+kern_return_t
+is_io_registry_entry_get_property(
+ io_object_t registry_entry,
+ io_name_t property_name,
+ io_buf_ptr_t *properties,
+ mach_msg_type_number_t *propertiesCnt )
+{
+ kern_return_t err;
+ unsigned int len;
+ OSObject * obj;
+
+ CHECK( IORegistryEntry, registry_entry, entry );
+
+#if CONFIG_MACF
+ if (0 != mac_iokit_check_get_property(kauth_cred_get(), entry, property_name)) {
+ return kIOReturnNotPermitted;
+ }
+#endif
+
+ obj = IOCopyPropertyCompatible(entry, property_name);
+ if (!obj) {
+ return kIOReturnNotFound;
+ }
+
+ OSSerialize * s = OSSerialize::withCapacity(4096);
+ if (!s) {
+ obj->release();
+ return kIOReturnNoMemory;
+ }
+
+ if (obj->serialize( s )) {
+ len = s->getLength();
+ *propertiesCnt = len;
+ err = copyoutkdata( s->text(), len, properties );
+ } else {
+ err = kIOReturnUnsupported;
+ }
+
+ s->release();
+ obj->release();
+
+ return err;
+}
+
+/* Routine io_registry_entry_get_property_recursively */
+kern_return_t
+is_io_registry_entry_get_property_recursively(
+ io_object_t registry_entry,
+ io_name_t plane,
+ io_name_t property_name,
+ uint32_t options,
+ io_buf_ptr_t *properties,
+ mach_msg_type_number_t *propertiesCnt )
+{
+ kern_return_t err;
+ unsigned int len;
+ OSObject * obj;
+
+ CHECK( IORegistryEntry, registry_entry, entry );
+
+#if CONFIG_MACF
+ if (0 != mac_iokit_check_get_property(kauth_cred_get(), entry, property_name)) {
+ return kIOReturnNotPermitted;
+ }
+#endif
+
+ obj = entry->copyProperty( property_name,
+ IORegistryEntry::getPlane( plane ), options );
+ if (!obj) {
+ return kIOReturnNotFound;
+ }
+
+ OSSerialize * s = OSSerialize::withCapacity(4096);
+ if (!s) {
+ obj->release();
+ return kIOReturnNoMemory;
+ }
+
+ if (obj->serialize( s )) {
+ len = s->getLength();
+ *propertiesCnt = len;
+ err = copyoutkdata( s->text(), len, properties );
+ } else {
+ err = kIOReturnUnsupported;
+ }
+
+ s->release();
+ obj->release();
+
+ return err;
+}
+
+/* Routine io_registry_entry_get_properties */
+kern_return_t
+is_io_registry_entry_get_properties(
+ io_object_t registry_entry,
+ io_buf_ptr_t *properties,
+ mach_msg_type_number_t *propertiesCnt )
+{
+ return kIOReturnUnsupported;
+}
+
+#if CONFIG_MACF
+
+struct GetPropertiesEditorRef {
+ kauth_cred_t cred;
+ IORegistryEntry * entry;
+ OSCollection * root;
+};
+
+static const OSMetaClassBase *
+GetPropertiesEditor(void * reference,
+ OSSerialize * s,
+ OSCollection * container,
+ const OSSymbol * name,
+ const OSMetaClassBase * value)
+{
+ GetPropertiesEditorRef * ref = (typeof(ref))reference;
+
+ if (!ref->root) {
+ ref->root = container;
+ }
+ if (ref->root == container) {
+ if (0 != mac_iokit_check_get_property(ref->cred, ref->entry, name->getCStringNoCopy())) {
+ value = NULL;
+ }
+ }
+ if (value) {
+ value->retain();
+ }
+ return value;
+}
+
+#endif /* CONFIG_MACF */
+
+/* Routine io_registry_entry_get_properties_bin_buf */
+kern_return_t
+is_io_registry_entry_get_properties_bin_buf(
+ io_object_t registry_entry,
+ mach_vm_address_t buf,
+ mach_vm_size_t *bufsize,
+ io_buf_ptr_t *properties,
+ mach_msg_type_number_t *propertiesCnt)
+{
+ kern_return_t err = kIOReturnSuccess;
+ unsigned int len;
+ OSObject * compatProperties;
+ OSSerialize * s;
+ OSSerialize::Editor editor = NULL;
+ void * editRef = NULL;
+
+ CHECK(IORegistryEntry, registry_entry, entry);
+
+#if CONFIG_MACF
+ GetPropertiesEditorRef ref;
+ if (mac_iokit_check_filter_properties(kauth_cred_get(), entry)) {
+ editor = &GetPropertiesEditor;
+ editRef = &ref;
+ ref.cred = kauth_cred_get();
+ ref.entry = entry;
+ ref.root = NULL;
+ }
+#endif
+
+ s = OSSerialize::binaryWithCapacity(4096, editor, editRef);
+ if (!s) {
+ return kIOReturnNoMemory;
+ }
+
+ if (IOTaskRegistryCompatibility(current_task())
+ && (compatProperties = entry->copyProperty(gIOCompatibilityPropertiesKey))) {
+ OSDictionary * dict;
+
+ dict = entry->dictionaryWithProperties();
+ if (!dict) {
+ err = kIOReturnNoMemory;
+ } else {
+ dict->removeObject(gIOCompatibilityPropertiesKey);
+ dict->merge(OSDynamicCast(OSDictionary, compatProperties));
+ if (!dict->serialize(s)) {
+ err = kIOReturnUnsupported;
+ }
+ dict->release();
+ }
+ compatProperties->release();
+ } else if (!entry->serializeProperties(s)) {
+ err = kIOReturnUnsupported;
+ }
+
+ if (kIOReturnSuccess == err) {
+ len = s->getLength();
+ if (buf && bufsize && len <= *bufsize) {
+ *bufsize = len;
+ *propertiesCnt = 0;
+ *properties = nullptr;
+ if (copyout(s->text(), buf, len)) {
+ err = kIOReturnVMError;
+ } else {
+ err = kIOReturnSuccess;
+ }
+ } else {
+ if (bufsize) {
+ *bufsize = 0;
+ }
+ *propertiesCnt = len;
+ err = copyoutkdata( s->text(), len, properties );
+ }
+ }
+ s->release();
+
+ return err;
+}
+
+/* Routine io_registry_entry_get_properties_bin */
+kern_return_t
+is_io_registry_entry_get_properties_bin(
+ io_object_t registry_entry,
+ io_buf_ptr_t *properties,
+ mach_msg_type_number_t *propertiesCnt)
+{
+ return is_io_registry_entry_get_properties_bin_buf(registry_entry,
+ 0, NULL, properties, propertiesCnt);
+}
+
+/* Routine io_registry_entry_get_property_bin_buf */
+kern_return_t
+is_io_registry_entry_get_property_bin_buf(
+ io_object_t registry_entry,
+ io_name_t plane,
+ io_name_t property_name,
+ uint32_t options,
+ mach_vm_address_t buf,
+ mach_vm_size_t *bufsize,
+ io_buf_ptr_t *properties,
+ mach_msg_type_number_t *propertiesCnt )
+{
+ kern_return_t err;
+ unsigned int len;
+ OSObject * obj;
+ const OSSymbol * sym;
+
+ CHECK( IORegistryEntry, registry_entry, entry );
+
+#if CONFIG_MACF
+ if (0 != mac_iokit_check_get_property(kauth_cred_get(), entry, property_name)) {
+ return kIOReturnNotPermitted;
+ }
+#endif
+
+ sym = OSSymbol::withCString(property_name);
+ if (!sym) {
+ return kIOReturnNoMemory;
+ }
+
+ if (gIORegistryEntryPropertyKeysKey == sym) {
+ obj = entry->copyPropertyKeys();
+ } else {
+ if ((kIORegistryIterateRecursively & options) && plane[0]) {
+ if (!IOTaskRegistryCompatibility(current_task())) {
+ obj = entry->copyProperty(property_name,
+ IORegistryEntry::getPlane(plane), options);
+ } else {
+ obj = IOCopyPropertyCompatible(entry, property_name);
+ if ((NULL == obj) && plane && (options & kIORegistryIterateRecursively)) {
+ IORegistryIterator * iter;
+ iter = IORegistryIterator::iterateOver(entry, IORegistryEntry::getPlane(plane), options);
+ if (iter) {
+ while ((NULL == obj) && (entry = iter->getNextObject())) {
+ obj = IOCopyPropertyCompatible(entry, property_name);
+ }
+ iter->release();
+ }
+ }
+ }
+ } else {
+ obj = IOCopyPropertyCompatible(entry, property_name);
+ }
+ if (obj && gIORemoveOnReadProperties->containsObject(sym)) {
+ entry->removeProperty(sym);
+ }
+ }
+
+ sym->release();
+ if (!obj) {
+ return kIOReturnNotFound;
+ }
+
+ OSSerialize * s = OSSerialize::binaryWithCapacity(4096);
+ if (!s) {
+ obj->release();
+ return kIOReturnNoMemory;
+ }
+
+ if (obj->serialize( s )) {
+ len = s->getLength();
+ if (buf && bufsize && len <= *bufsize) {
+ *bufsize = len;
+ *propertiesCnt = 0;
+ *properties = nullptr;
+ if (copyout(s->text(), buf, len)) {
+ err = kIOReturnVMError;
+ } else {
+ err = kIOReturnSuccess;
+ }
+ } else {
+ if (bufsize) {
+ *bufsize = 0;
+ }
+ *propertiesCnt = len;
+ err = copyoutkdata( s->text(), len, properties );
+ }
+ } else {
+ err = kIOReturnUnsupported;
+ }
+
+ s->release();
+ obj->release();
+
+ return err;
+}
+
+/* Routine io_registry_entry_get_property_bin */
+kern_return_t
+is_io_registry_entry_get_property_bin(
+ io_object_t registry_entry,
+ io_name_t plane,
+ io_name_t property_name,
+ uint32_t options,
+ io_buf_ptr_t *properties,
+ mach_msg_type_number_t *propertiesCnt )
+{
+ return is_io_registry_entry_get_property_bin_buf(registry_entry, plane,
+ property_name, options, 0, NULL, properties, propertiesCnt);
+}
+
+
+/* Routine io_registry_entry_set_properties */
+kern_return_t
+is_io_registry_entry_set_properties
+(
+ io_object_t registry_entry,
+ io_buf_ptr_t properties,
+ mach_msg_type_number_t propertiesCnt,
+ kern_return_t * result)
+{
+ OSObject * obj;
+ kern_return_t err;
+ IOReturn res;
+ vm_offset_t data;
+ vm_map_offset_t map_data;
+
+ CHECK( IORegistryEntry, registry_entry, entry );
+
+ if (propertiesCnt > sizeof(io_struct_inband_t) * 1024) {
+ return kIOReturnMessageTooLarge;
+ }
+
+ err = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) properties );
+ data = CAST_DOWN(vm_offset_t, map_data);
+
+ if (KERN_SUCCESS == err) {
+ FAKE_STACK_FRAME(entry->getMetaClass());
+
+ // must return success after vm_map_copyout() succeeds
+ obj = OSUnserializeXML((const char *) data, propertiesCnt );
+ vm_deallocate( kernel_map, data, propertiesCnt );
+
+ if (!obj) {
+ res = kIOReturnBadArgument;
+ }
+#if CONFIG_MACF
+ else if (0 != mac_iokit_check_set_properties(kauth_cred_get(),
+ registry_entry, obj)) {
+ res = kIOReturnNotPermitted;
+ }
+#endif
+ else {
+ res = entry->setProperties( obj );
+ }
+
+ if (obj) {
+ obj->release();
+ }
+
+ FAKE_STACK_FRAME_END();
+ } else {
+ res = err;
+ }
+
+ *result = res;
+ return err;
+}
+
+/* Routine io_registry_entry_get_child_iterator */
+kern_return_t
+is_io_registry_entry_get_child_iterator(
+ io_object_t registry_entry,
+ io_name_t plane,
+ io_object_t *iterator )
+{
+ CHECK( IORegistryEntry, registry_entry, entry );
+
+ *iterator = IOUserIterator::withIterator(entry->getChildIterator(
+ IORegistryEntry::getPlane( plane )));
+
+ return kIOReturnSuccess;
+}
+
+/* Routine io_registry_entry_get_parent_iterator */
+kern_return_t
+is_io_registry_entry_get_parent_iterator(
+ io_object_t registry_entry,
+ io_name_t plane,
+ io_object_t *iterator)
+{
+ CHECK( IORegistryEntry, registry_entry, entry );
+
+ *iterator = IOUserIterator::withIterator(entry->getParentIterator(
+ IORegistryEntry::getPlane( plane )));
+
+ return kIOReturnSuccess;
+}
+
+/* Routine io_service_get_busy_state */
+kern_return_t
+is_io_service_get_busy_state(
+ io_object_t _service,
+ uint32_t *busyState )
+{
+ CHECK( IOService, _service, service );
+
+ *busyState = service->getBusyState();
+
+ return kIOReturnSuccess;
+}
+
+/* Routine io_service_get_state */
+kern_return_t
+is_io_service_get_state(
+ io_object_t _service,
+ uint64_t *state,
+ uint32_t *busy_state,
+ uint64_t *accumulated_busy_time )
+{
+ CHECK( IOService, _service, service );
+
+ *state = service->getState();
+ *busy_state = service->getBusyState();
+ *accumulated_busy_time = service->getAccumulatedBusyTime();
+
+ return kIOReturnSuccess;
+}
+
+/* Routine io_service_wait_quiet */
+kern_return_t
+is_io_service_wait_quiet(
+ io_object_t _service,
+ mach_timespec_t wait_time )
+{
+ uint64_t timeoutNS;
+
+ CHECK( IOService, _service, service );
+
+ timeoutNS = wait_time.tv_sec;
+ timeoutNS *= kSecondScale;
+ timeoutNS += wait_time.tv_nsec;
+
+ return service->waitQuiet(timeoutNS);
+}
+
+/* Routine io_service_request_probe */
+kern_return_t
+is_io_service_request_probe(
+ io_object_t _service,
+ uint32_t options )
+{
+ CHECK( IOService, _service, service );
+
+ return service->requestProbe( options );
+}
+
+/* Routine io_service_get_authorization_id */
+kern_return_t
+is_io_service_get_authorization_id(
+ io_object_t _service,
+ uint64_t *authorization_id )
+{
+ kern_return_t kr;
+
+ CHECK( IOService, _service, service );
+
+ kr = IOUserClient::clientHasPrivilege((void *) current_task(),
+ kIOClientPrivilegeAdministrator );
+ if (kIOReturnSuccess != kr) {
+ return kr;
+ }
+
+ *authorization_id = service->getAuthorizationID();
+
+ return kr;
+}
+
+/* Routine io_service_set_authorization_id */
+kern_return_t
+is_io_service_set_authorization_id(
+ io_object_t _service,
+ uint64_t authorization_id )
+{
+ CHECK( IOService, _service, service );
+
+ return service->setAuthorizationID( authorization_id );
+}
+
+/* Routine io_service_open_ndr */
+kern_return_t
+is_io_service_open_extended(
+ io_object_t _service,
+ task_t owningTask,
+ uint32_t connect_type,
+ NDR_record_t ndr,
+ io_buf_ptr_t properties,
+ mach_msg_type_number_t propertiesCnt,
+ kern_return_t * result,
+ io_object_t *connection )
+{
+ IOUserClient * client = NULL;
+ kern_return_t err = KERN_SUCCESS;
+ IOReturn res = kIOReturnSuccess;
+ OSDictionary * propertiesDict = NULL;
+ bool crossEndian;
+ bool disallowAccess;
+
+ CHECK( IOService, _service, service );
+
+ if (!owningTask) {
+ return kIOReturnBadArgument;
+ }
+ assert(owningTask == current_task());
+ if (owningTask != current_task()) {
+ return kIOReturnBadArgument;
+ }
+
+#if CONFIG_MACF
+ if (mac_iokit_check_open_service(kauth_cred_get(), service, connect_type) != 0) {
+ return kIOReturnNotPermitted;
+ }
+#endif
+ do{
+ if (properties) {
+ return kIOReturnUnsupported;
+ }
+#if 0
+ {
+ OSObject * obj;
+ vm_offset_t data;
+ vm_map_offset_t map_data;
+
+ if (propertiesCnt > sizeof(io_struct_inband_t)) {
+ return kIOReturnMessageTooLarge;
+ }
+
+ err = vm_map_copyout( kernel_map, &map_data, (vm_map_copy_t) properties );
+ res = err;
+ data = CAST_DOWN(vm_offset_t, map_data);
+ if (KERN_SUCCESS == err) {
+ // must return success after vm_map_copyout() succeeds
+ obj = OSUnserializeXML((const char *) data, propertiesCnt );
+ vm_deallocate( kernel_map, data, propertiesCnt );
+ propertiesDict = OSDynamicCast(OSDictionary, obj);
+ if (!propertiesDict) {
+ res = kIOReturnBadArgument;
+ if (obj) {
+ obj->release();
+ }
+ }
+ }
+ if (kIOReturnSuccess != res) {
+ break;
+ }
+ }
+#endif
+ crossEndian = (ndr.int_rep != NDR_record.int_rep);
+ if (crossEndian) {
+ if (!propertiesDict) {
+ propertiesDict = OSDictionary::withCapacity(4);
+ }
+ OSData * data = OSData::withBytes(&ndr, sizeof(ndr));
+ if (data) {
+ if (propertiesDict) {
+ propertiesDict->setObject(kIOUserClientCrossEndianKey, data);
+ }
+ data->release();
+ }
+ }
+
+ res = service->newUserClient( owningTask, (void *) owningTask,
+ connect_type, propertiesDict, &client );
+
+ if (propertiesDict) {
+ propertiesDict->release();
+ }
+
+ if (res == kIOReturnSuccess) {
+ assert( OSDynamicCast(IOUserClient, client));
+ if (!client->reserved) {
+ if (!client->reserve()) {
+ client->clientClose();
+ OSSafeReleaseNULL(client);
+ res = kIOReturnNoMemory;
+ }
+ }
+ }
+
+ if (res == kIOReturnSuccess) {
+ client->sharedInstance = (NULL != client->getProperty(kIOUserClientSharedInstanceKey));
+ if (client->sharedInstance) {
+ IOLockLock(gIOUserClientOwnersLock);
+ }
+ if (!client->lock) {
+ client->lock = IORWLockAlloc();
+ client->filterLock = IOLockAlloc();
+
+ client->messageAppSuspended = (NULL != client->getProperty(kIOUserClientMessageAppSuspendedKey));
+ {
+ OSObject * obj;
+ extern const OSSymbol * gIOSurfaceIdentifier;
+ obj = client->getProperty(kIOUserClientDefaultLockingKey);
+ if (obj) {
+ client->defaultLocking = (kOSBooleanFalse != client->getProperty(kIOUserClientDefaultLockingKey));
+ } else {
+ const OSMetaClass * meta;
+ OSKext * kext;
+ meta = client->getMetaClass();
+ kext = meta->getKext();
+ if (!kext || !kext->hasDependency(gIOSurfaceIdentifier)) {
+ client->defaultLocking = true;
+ client->setProperty(kIOUserClientDefaultLockingKey, kOSBooleanTrue);
+ }
+ }
+ }
+ }
+ if (client->sharedInstance) {
+ IOLockUnlock(gIOUserClientOwnersLock);
+ }
+
+ disallowAccess = (crossEndian
+ && (kOSBooleanTrue != service->getProperty(kIOUserClientCrossEndianCompatibleKey))
+ && (kOSBooleanTrue != client->getProperty(kIOUserClientCrossEndianCompatibleKey)));
+ if (disallowAccess) {
+ res = kIOReturnUnsupported;
+ }
+#if CONFIG_MACF
+ else if (0 != mac_iokit_check_open(kauth_cred_get(), client, connect_type)) {
+ res = kIOReturnNotPermitted;
+ }
+#endif
+
+ if ((kIOReturnSuccess == res)
+ && gIOUCFilterCallbacks
+ && gIOUCFilterCallbacks->io_filter_resolver) {
+ io_filter_policy_t filterPolicy;
+ filterPolicy = client->filterForTask(owningTask, 0);
+ if (!filterPolicy) {
+ res = gIOUCFilterCallbacks->io_filter_resolver(owningTask, client, connect_type, &filterPolicy);
+ if (kIOReturnUnsupported == res) {
+ res = kIOReturnSuccess;
+ } else if (kIOReturnSuccess == res) {
+ client->filterForTask(owningTask, filterPolicy);
+ }
+ }
+ }
+
+ if (kIOReturnSuccess == res) {
+ res = client->registerOwner(owningTask);
+ }
+
+ if (kIOReturnSuccess != res) {
+ IOStatisticsClientCall();
+ client->clientClose();
+ client->release();
+ client = NULL;
+ break;
+ }
+ OSString * creatorName = IOCopyLogNameForPID(proc_selfpid());
+ if (creatorName) {
+ client->setProperty(kIOUserClientCreatorKey, creatorName);
+ creatorName->release();
+ }
+ client->setTerminateDefer(service, false);
+ }
+ }while (false);
+
+ *connection = client;
+ *result = res;
+
+ return err;
+}
+
+/* Routine io_service_close */
+kern_return_t
+is_io_service_close(
+ io_object_t connection )
+{
+ OSSet * mappings;
+ if ((mappings = OSDynamicCast(OSSet, connection))) {
+ return kIOReturnSuccess;
+ }
+
+ CHECK( IOUserClient, connection, client );
+
+ IOStatisticsClientCall();
+
+ if (client->sharedInstance || OSCompareAndSwap8(0, 1, &client->closed)) {
+ IORWLockWrite(client->lock);
+ client->clientClose();
+ IORWLockUnlock(client->lock);
+ } else {
+ IOLog("ignored is_io_service_close(0x%qx,%s)\n",
+ client->getRegistryEntryID(), client->getName());
+ }
+
+ return kIOReturnSuccess;
+}
+
+/* Routine io_connect_get_service */
+kern_return_t
+is_io_connect_get_service(
+ io_object_t connection,
+ io_object_t *service )
+{
+ IOService * theService;
+
+ CHECK( IOUserClient, connection, client );
+
+ theService = client->getService();
+ if (theService) {
+ theService->retain();
+ }
+
+ *service = theService;
+
+ return theService ? kIOReturnSuccess : kIOReturnUnsupported;
+}
+
+/* Routine io_connect_set_notification_port */
+kern_return_t
+is_io_connect_set_notification_port(
+ io_object_t connection,
+ uint32_t notification_type,
+ mach_port_t port,
+ uint32_t reference)
+{
+ kern_return_t ret;
+ CHECK( IOUserClient, connection, client );
+
+ IOStatisticsClientCall();
+ IORWLockWrite(client->lock);
+ ret = client->registerNotificationPort( port, notification_type,
+ (io_user_reference_t) reference );
+ IORWLockUnlock(client->lock);
+ return ret;
+}
+
+/* Routine io_connect_set_notification_port */
+kern_return_t
+is_io_connect_set_notification_port_64(
+ io_object_t connection,
+ uint32_t notification_type,
+ mach_port_t port,
+ io_user_reference_t reference)
+{
+ kern_return_t ret;
+ CHECK( IOUserClient, connection, client );
+
+ IOStatisticsClientCall();
+ IORWLockWrite(client->lock);
+ ret = client->registerNotificationPort( port, notification_type,
+ reference );
+ IORWLockUnlock(client->lock);
+ return ret;
+}
+
+/* Routine io_connect_map_memory_into_task */
+kern_return_t
+is_io_connect_map_memory_into_task
+(
+ io_connect_t connection,
+ uint32_t memory_type,
+ task_t into_task,
+ mach_vm_address_t *address,
+ mach_vm_size_t *size,
+ uint32_t flags
+)
+{
+ IOReturn err;
+ IOMemoryMap * map;
+
+ CHECK( IOUserClient, connection, client );
+
+ if (!into_task) {
+ return kIOReturnBadArgument;
+ }
+
+ IOStatisticsClientCall();
+ if (client->defaultLocking) {
+ IORWLockWrite(client->lock);
+ }
+ map = client->mapClientMemory64( memory_type, into_task, flags, *address );
+ if (client->defaultLocking) {
+ IORWLockUnlock(client->lock);
+ }
+
+ if (map) {
+ *address = map->getAddress();
+ if (size) {
+ *size = map->getSize();
+ }
+
+ if (client->sharedInstance
+ || (into_task != current_task())) {
+ // push a name out to the task owning the map,
+ // so we can clean up maps
+ mach_port_name_t name __unused =
+ IOMachPort::makeSendRightForTask(
+ into_task, map, IKOT_IOKIT_OBJECT );
+ map->release();
+ } else {
+ // keep it with the user client
+ IOLockLock( gIOObjectPortLock);
+ if (NULL == client->mappings) {
+ client->mappings = OSSet::withCapacity(2);
+ }
+ if (client->mappings) {
+ client->mappings->setObject( map);
+ }
+ IOLockUnlock( gIOObjectPortLock);
+ map->release();
+ }
+ err = kIOReturnSuccess;
+ } else {
+ err = kIOReturnBadArgument;
+ }
+
+ return err;
+}
+
+/* Routine is_io_connect_map_memory */
+kern_return_t
+is_io_connect_map_memory(
+ io_object_t connect,
+ uint32_t type,
+ task_t task,
+ uint32_t * mapAddr,
+ uint32_t * mapSize,
+ uint32_t flags )
+{
+ IOReturn err;
+ mach_vm_address_t address;
+ mach_vm_size_t size;
+
+ address = SCALAR64(*mapAddr);
+ size = SCALAR64(*mapSize);
+
+ err = is_io_connect_map_memory_into_task(connect, type, task, &address, &size, flags);
+
+ *mapAddr = SCALAR32(address);
+ *mapSize = SCALAR32(size);
+
+ return err;
+}
+} /* extern "C" */
+
+IOMemoryMap *
+IOUserClient::removeMappingForDescriptor(IOMemoryDescriptor * mem)
+{
+ OSIterator * iter;
+ IOMemoryMap * map = NULL;
+
+ IOLockLock(gIOObjectPortLock);
+
+ iter = OSCollectionIterator::withCollection(mappings);
+ if (iter) {
+ while ((map = OSDynamicCast(IOMemoryMap, iter->getNextObject()))) {
+ if (mem == map->getMemoryDescriptor()) {
+ map->retain();
+ mappings->removeObject(map);
+ break;
+ }
+ }
+ iter->release();
+ }
+
+ IOLockUnlock(gIOObjectPortLock);
+
+ return map;
+}
+
+extern "C" {
+/* Routine io_connect_unmap_memory_from_task */
+kern_return_t
+is_io_connect_unmap_memory_from_task
+(
+ io_connect_t connection,
+ uint32_t memory_type,
+ task_t from_task,
+ mach_vm_address_t address)
+{
+ IOReturn err;
+ IOOptionBits options = 0;
+ IOMemoryDescriptor * memory = NULL;
+ IOMemoryMap * map;
+
+ CHECK( IOUserClient, connection, client );
+
+ if (!from_task) {
+ return kIOReturnBadArgument;
+ }
+
+ IOStatisticsClientCall();
+ if (client->defaultLocking) {
+ IORWLockWrite(client->lock);
+ }
+ err = client->clientMemoryForType((UInt32) memory_type, &options, &memory );
+ if (client->defaultLocking) {
+ IORWLockUnlock(client->lock);
+ }
+
+ if (memory && (kIOReturnSuccess == err)) {
+ options = (options & ~kIOMapUserOptionsMask)
+ | kIOMapAnywhere | kIOMapReference;
+
+ map = memory->createMappingInTask( from_task, address, options );
+ memory->release();
+ if (map) {
+ IOLockLock( gIOObjectPortLock);
+ if (client->mappings) {
+ client->mappings->removeObject( map);
+ }
+ IOLockUnlock( gIOObjectPortLock);
+
+ mach_port_name_t name = 0;
+ bool is_shared_instance_or_from_current_task = from_task != current_task() || client->sharedInstance;
+ if (is_shared_instance_or_from_current_task) {
+ name = IOMachPort::makeSendRightForTask( from_task, map, IKOT_IOKIT_OBJECT );
+ map->release();
+ }
+
+ if (name) {
+ map->userClientUnmap();
+ err = iokit_mod_send_right( from_task, name, -2 );
+ err = kIOReturnSuccess;
+ } else {
+ IOMachPort::releasePortForObject( map, IKOT_IOKIT_OBJECT );
+ }
+ if (!is_shared_instance_or_from_current_task) {
+ map->release();
+ }
+ } else {
+ err = kIOReturnBadArgument;
+ }
+ }
+
+ return err;
+}
+
+kern_return_t
+is_io_connect_unmap_memory(
+ io_object_t connect,
+ uint32_t type,
+ task_t task,
+ uint32_t mapAddr )
+{
+ IOReturn err;
+ mach_vm_address_t address;
+
+ address = SCALAR64(mapAddr);
+
+ err = is_io_connect_unmap_memory_from_task(connect, type, task, mapAddr);
+
+ return err;
+}
+
+
+/* Routine io_connect_add_client */
+kern_return_t
+is_io_connect_add_client(
+ io_object_t connection,
+ io_object_t connect_to)
+{
+ CHECK( IOUserClient, connection, client );
+ CHECK( IOUserClient, connect_to, to );
+
+ IOReturn ret;
+
+ IOStatisticsClientCall();
+ if (client->defaultLocking) {
+ IORWLockWrite(client->lock);
+ }
+ ret = client->connectClient( to );
+ if (client->defaultLocking) {
+ IORWLockUnlock(client->lock);
+ }
+ return ret;
+}
+
+
+/* Routine io_connect_set_properties */
+kern_return_t
+is_io_connect_set_properties(
+ io_object_t connection,
+ io_buf_ptr_t properties,
+ mach_msg_type_number_t propertiesCnt,
+ kern_return_t * result)
+{
+ return is_io_registry_entry_set_properties( connection, properties, propertiesCnt, result );
+}
+
+/* Routine io_user_client_method */
+kern_return_t
+is_io_connect_method_var_output
+(
+ io_connect_t connection,
+ uint32_t selector,
+ io_scalar_inband64_t scalar_input,
+ mach_msg_type_number_t scalar_inputCnt,
+ io_struct_inband_t inband_input,
+ mach_msg_type_number_t inband_inputCnt,
+ mach_vm_address_t ool_input,
+ mach_vm_size_t ool_input_size,
+ io_struct_inband_t inband_output,
+ mach_msg_type_number_t *inband_outputCnt,
+ io_scalar_inband64_t scalar_output,
+ mach_msg_type_number_t *scalar_outputCnt,
+ io_buf_ptr_t *var_output,
+ mach_msg_type_number_t *var_outputCnt
+)
+{
+ CHECK( IOUserClient, connection, client );
+
+ IOExternalMethodArguments args;
+ IOReturn ret;
+ IOMemoryDescriptor * inputMD = NULL;
+ OSObject * structureVariableOutputData = NULL;
+
+ bzero(&args.__reserved[0], sizeof(args.__reserved));
+ args.__reservedA = 0;
+ args.version = kIOExternalMethodArgumentsCurrentVersion;
+
+ args.selector = selector;
+
+ args.asyncWakePort = MACH_PORT_NULL;
+ args.asyncReference = NULL;
+ args.asyncReferenceCount = 0;
+ args.structureVariableOutputData = &structureVariableOutputData;
+
+ args.scalarInput = scalar_input;
+ args.scalarInputCount = scalar_inputCnt;
+ args.structureInput = inband_input;
+ args.structureInputSize = inband_inputCnt;
+
+ if (ool_input && (ool_input_size <= sizeof(io_struct_inband_t))) {
+ return kIOReturnIPCError;
+ }
+
+ if (ool_input) {
+ inputMD = IOMemoryDescriptor::withAddressRange(ool_input, ool_input_size,
+ kIODirectionOut | kIOMemoryMapCopyOnWrite,
+ current_task());
+ }
+
+ args.structureInputDescriptor = inputMD;
+
+ args.scalarOutput = scalar_output;
+ args.scalarOutputCount = *scalar_outputCnt;
+ bzero(&scalar_output[0], *scalar_outputCnt * sizeof(scalar_output[0]));
+ args.structureOutput = inband_output;
+ args.structureOutputSize = *inband_outputCnt;
+ args.structureOutputDescriptor = NULL;
+ args.structureOutputDescriptorSize = 0;
+
+ IOStatisticsClientCall();
+ ret = kIOReturnSuccess;
+
+ io_filter_policy_t filterPolicy = client->filterForTask(current_task(), 0);
+ if (filterPolicy && gIOUCFilterCallbacks->io_filter_applier) {
+ ret = gIOUCFilterCallbacks->io_filter_applier(filterPolicy, io_filter_type_external_method, selector);
+ }
+ if (kIOReturnSuccess == ret) {
+ if (client->defaultLocking) {
+ IORWLockRead(client->lock);
+ }
+ ret = client->externalMethod( selector, &args );
+ if (client->defaultLocking) {
+ IORWLockUnlock(client->lock);
+ }
+ }
+
+ *scalar_outputCnt = args.scalarOutputCount;
+ *inband_outputCnt = args.structureOutputSize;
+
+ if (var_outputCnt && var_output && (kIOReturnSuccess == ret)) {
+ OSSerialize * serialize;
+ OSData * data;
+ unsigned int len;
+
+ if ((serialize = OSDynamicCast(OSSerialize, structureVariableOutputData))) {
+ len = serialize->getLength();
+ *var_outputCnt = len;
+ ret = copyoutkdata(serialize->text(), len, var_output);
+ } else if ((data = OSDynamicCast(OSData, structureVariableOutputData))) {
+ len = data->getLength();
+ *var_outputCnt = len;
+ ret = copyoutkdata(data->getBytesNoCopy(), len, var_output);
+ } else {
+ ret = kIOReturnUnderrun;
+ }
+ }
+
+ if (inputMD) {
+ inputMD->release();
+ }
+ if (structureVariableOutputData) {
+ structureVariableOutputData->release();
+ }
+
+ return ret;
+}
+
+/* Routine io_user_client_method */
+kern_return_t
+is_io_connect_method
+(
+ io_connect_t connection,
+ uint32_t selector,
+ io_scalar_inband64_t scalar_input,
+ mach_msg_type_number_t scalar_inputCnt,
+ io_struct_inband_t inband_input,
+ mach_msg_type_number_t inband_inputCnt,
+ mach_vm_address_t ool_input,
+ mach_vm_size_t ool_input_size,
+ io_struct_inband_t inband_output,
+ mach_msg_type_number_t *inband_outputCnt,
+ io_scalar_inband64_t scalar_output,
+ mach_msg_type_number_t *scalar_outputCnt,
+ mach_vm_address_t ool_output,
+ mach_vm_size_t *ool_output_size
+)
+{
+ CHECK( IOUserClient, connection, client );
+
+ IOExternalMethodArguments args;
+ IOReturn ret;
+ IOMemoryDescriptor * inputMD = NULL;
+ IOMemoryDescriptor * outputMD = NULL;
+
+ bzero(&args.__reserved[0], sizeof(args.__reserved));
+ args.__reservedA = 0;
+ args.version = kIOExternalMethodArgumentsCurrentVersion;
+
+ args.selector = selector;
+
+ args.asyncWakePort = MACH_PORT_NULL;
+ args.asyncReference = NULL;
+ args.asyncReferenceCount = 0;
+ args.structureVariableOutputData = NULL;
+
+ args.scalarInput = scalar_input;
+ args.scalarInputCount = scalar_inputCnt;
+ args.structureInput = inband_input;
+ args.structureInputSize = inband_inputCnt;
+
+ if (ool_input && (ool_input_size <= sizeof(io_struct_inband_t))) {
+ return kIOReturnIPCError;
+ }
+ if (ool_output) {
+ if (*ool_output_size <= sizeof(io_struct_inband_t)) {
+ return kIOReturnIPCError;
+ }
+ if (*ool_output_size > UINT_MAX) {
+ return kIOReturnIPCError;
+ }
+ }
+
+ if (ool_input) {
+ inputMD = IOMemoryDescriptor::withAddressRange(ool_input, ool_input_size,
+ kIODirectionOut | kIOMemoryMapCopyOnWrite,
+ current_task());
+ }
+
+ args.structureInputDescriptor = inputMD;
+
+ args.scalarOutput = scalar_output;
+ args.scalarOutputCount = *scalar_outputCnt;
+ bzero(&scalar_output[0], *scalar_outputCnt * sizeof(scalar_output[0]));
+ args.structureOutput = inband_output;
+ args.structureOutputSize = *inband_outputCnt;
+
+ if (ool_output && ool_output_size) {
+ outputMD = IOMemoryDescriptor::withAddressRange(ool_output, *ool_output_size,
+ kIODirectionIn, current_task());
+ }
+
+ args.structureOutputDescriptor = outputMD;
+ args.structureOutputDescriptorSize = ool_output_size
+ ? ((typeof(args.structureOutputDescriptorSize)) * ool_output_size)
+ : 0;
+
+ IOStatisticsClientCall();
+ ret = kIOReturnSuccess;
+ io_filter_policy_t filterPolicy = client->filterForTask(current_task(), 0);
+ if (filterPolicy && gIOUCFilterCallbacks->io_filter_applier) {
+ ret = gIOUCFilterCallbacks->io_filter_applier(filterPolicy, io_filter_type_external_method, selector);
+ }
+ if (kIOReturnSuccess == ret) {
+ if (client->defaultLocking) {
+ IORWLockRead(client->lock);
+ }
+ ret = client->externalMethod( selector, &args );
+ if (client->defaultLocking) {
+ IORWLockUnlock(client->lock);
+ }
+ }
+
+ *scalar_outputCnt = args.scalarOutputCount;
+ *inband_outputCnt = args.structureOutputSize;
+ *ool_output_size = args.structureOutputDescriptorSize;
+
+ if (inputMD) {
+ inputMD->release();
+ }
+ if (outputMD) {
+ outputMD->release();
+ }
+
+ return ret;
+}
+
+/* Routine io_async_user_client_method */
+kern_return_t
+is_io_connect_async_method
+(
+ io_connect_t connection,
+ mach_port_t wake_port,
+ io_async_ref64_t reference,
+ mach_msg_type_number_t referenceCnt,
+ uint32_t selector,
+ io_scalar_inband64_t scalar_input,
+ mach_msg_type_number_t scalar_inputCnt,
+ io_struct_inband_t inband_input,
+ mach_msg_type_number_t inband_inputCnt,
+ mach_vm_address_t ool_input,
+ mach_vm_size_t ool_input_size,
+ io_struct_inband_t inband_output,
+ mach_msg_type_number_t *inband_outputCnt,
+ io_scalar_inband64_t scalar_output,
+ mach_msg_type_number_t *scalar_outputCnt,
+ mach_vm_address_t ool_output,
+ mach_vm_size_t * ool_output_size
+)
+{
+ CHECK( IOUserClient, connection, client );
+
+ IOExternalMethodArguments args;
+ IOReturn ret;
+ IOMemoryDescriptor * inputMD = NULL;
+ IOMemoryDescriptor * outputMD = NULL;
+
+ if (referenceCnt < 1) {
+ return kIOReturnBadArgument;
+ }
+
+ bzero(&args.__reserved[0], sizeof(args.__reserved));
+ args.__reservedA = 0;
+ args.version = kIOExternalMethodArgumentsCurrentVersion;
+
+ reference[0] = (io_user_reference_t) wake_port;
+ if (vm_map_is_64bit(get_task_map(current_task()))) {
+ reference[0] |= kIOUCAsync64Flag;
+ }
+
+ args.selector = selector;