#include "iodevices.h"
#include <security_utilities/cfutilities.h>
#include <IOKit/IOMessage.h>
#include <IOKit/usb/IOUSBLib.h>
using namespace MachPlusPlus;
namespace Security {
namespace IOKit {
MasterPort::MasterPort()
{
Error::check(::IOMasterPort(MACH_PORT_NULL, &port()));
}
Device::~Device()
{
::IOObjectRelease(mService);
}
string Device::name() const
{
io_name_t tName;
Error::check(::IORegistryEntryGetName(mService, tName));
return tName;
}
string Device::name(const char *plane) const
{
io_name_t tName;
Error::check(::IORegistryEntryGetNameInPlane(mService, plane, tName));
return tName;
}
string Device::path(const char *plane) const
{
io_string_t tPath;
Error::check(::IORegistryEntryGetPath(mService, plane, tPath));
return tPath;
}
CFDictionaryRef Device::properties() const
{
CFMutableDictionaryRef dict;
Error::check(::IORegistryEntryCreateCFProperties(mService, &dict, NULL, 0));
return dict;
}
CFTypeRef Device::property(const char *name) const
{
return ::IORegistryEntryCreateCFProperty(mService, CFTempString(name), NULL, 0);
}
DeviceIterator::~DeviceIterator()
{
while (Device dev = (*this)())
;
}
io_service_t DeviceIterator::operator () ()
{
io_service_t dev = ::IOIteratorNext(mIterator);
mAtEnd = !dev;
return dev;
}
DeviceMatch::DeviceMatch()
: CFRef<CFMutableDictionaryRef>(makeCFMutableDictionary())
{
CFError::check(*this);
}
DeviceMatch::DeviceMatch(const char *cls)
: CFRef<CFMutableDictionaryRef>(::IOServiceMatching(cls))
{
CFError::check(*this);
}
DeviceMatch::DeviceMatch(const char *cls, const char *name, uint32_t value, ...)
: CFRef<CFMutableDictionaryRef>(::IOServiceMatching(cls))
{
CFError::check(*this);
va_list args;
va_start(args, value);
while (name) {
add(name, value);
name = va_arg(args, const char *);
if (!name)
break;
value = va_arg(args, uint32_t);
}
}
void DeviceMatch::add(const char *name, uint32_t value)
{
CFRef<CFNumberRef> number = CFNumberCreate(NULL, kCFNumberSInt32Type, &value);
CFDictionarySetValue(*this, CFTempString(name), number);
}
NotificationPort::NotificationPort()
{
CFError::check(mPortRef = ::IONotificationPortCreate(MasterPort()));
}
NotificationPort::NotificationPort(const MasterPort &master)
{
CFError::check(mPortRef = ::IONotificationPortCreate(master));
}
NotificationPort::~NotificationPort()
{
::IONotificationPortDestroy(mPortRef);
}
mach_port_t NotificationPort::port() const
{
mach_port_t p = ::IONotificationPortGetMachPort(mPortRef);
CFError::check(p);
return p;
}
CFRunLoopSourceRef NotificationPort::source() const
{
CFRunLoopSourceRef rls = ::IONotificationPortGetRunLoopSource(mPortRef);
CFError::check(rls);
return rls;
}
void NotificationPort::add(const DeviceMatch &match, Receiver &receiver, const char *type)
{
io_iterator_t iterator;
CFRetain(match); Error::check(::IOServiceAddMatchingNotification(mPortRef, type,
match,
ioNotify, &receiver,
&iterator));
secinfo("iokit", "dispatching initial device match iterator %d", iterator);
DeviceIterator it(iterator);
receiver.ioChange(it);
}
void NotificationPort::addInterestNotification(Receiver &receiver, io_service_t service,
const io_name_t interestType)
{
io_iterator_t iterator;
secinfo("iokit", "NotificationPort::addInterest - type: %s [port: %p (0x%08X), service: 0x%08X]",
interestType, mPortRef, NotificationPort::port(), service);
kern_return_t kr = ::IOServiceAddInterestNotification(mPortRef,
service, interestType, ioDeviceNotification, &receiver, &iterator);
const char *msgstr = mach_error_string(kr);
const char *msgtyp = mach_error_type(kr);
if (msgstr && msgtyp)
secinfo("iokit", " msg: %s, typ: %s", msgstr, msgtyp);
}
void NotificationPort::ioNotify(void *refCon, io_iterator_t iterator)
{
secinfo("iokit", "dispatching new device match iterator %d", iterator);
DeviceIterator it(iterator);
try {
reinterpret_cast<Receiver *>(refCon)->ioChange(it);
} catch (...) {
secinfo("iokit", "ioChange callback threw an exception (ignored)");
}
}
void NotificationPort::ioDeviceNotification(void *refCon, io_service_t service,
natural_t messageType, void *messageArgument)
{
secinfo("iokit", "dispatching NEW device notification iterator, service 0x%08X, msg: 0x%04X, arg: %p",
service, messageType, messageArgument);
const char *msgstr = mach_error_string(messageType);
const char *msgtyp = mach_error_type(messageType);
if (msgstr && msgtyp)
secinfo("iokit", " msg: %s, typ: %s", msgstr, msgtyp);
if (service!=io_service_t(-1))
reinterpret_cast<Receiver *>(refCon)->ioServiceChange(refCon, service, messageType, messageArgument);
}
NotificationPort::Receiver::~Receiver()
{ }
MachPortNotificationPort::MachPortNotificationPort()
{
NoReplyHandler::port(NotificationPort::port());
}
MachPortNotificationPort::~MachPortNotificationPort()
{
}
boolean_t MachPortNotificationPort::handle(mach_msg_header_t *in)
{
::IODispatchCalloutFromMessage(NULL, in, mPortRef);
return TRUE;
}
} }