+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* 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))) {
+ *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))) {
+ *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))) {
+ *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;
+ OSDictionary * dict;
+ IOReturn err;
+ unsigned long int 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);
+ dict = OSDynamicCast(OSDictionary, OSUnserializeXML(matching, matching_size));
+ if (!dict) {
+ err = kIOReturnBadArgument;
+ continue;
+ }
+
+ 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 (dict) {
+ dict->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 )
+{
+ CHECK( IOUserClient, connection, client );
+
+ IOStatisticsClientCall();
+ return client->getNotificationSemaphore((UInt32) notification_type,
+ semaphore );
+}
+
+/* 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 );
+
+ *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;
+}
+
+/* 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 = entry->copyProperty(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;
+ vm_size_t 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);
+ 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;
+ vm_size_t 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;
+ vm_size_t len;
+ 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 (!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;
+ vm_size_t 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]) {
+ obj = entry->copyProperty(property_name,
+ IORegistryEntry::getPlane(plane), options );
+ } else {
+ obj = entry->copyProperty(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(