#include <sys/types.h>
#include <mach/mach.h>
#include <pthread.h>
#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CFRuntime.h>
#include <SystemConfiguration/SystemConfiguration.h>
#include <SystemConfiguration/SCValidation.h>
#include <SystemConfiguration/SCPrivate.h>
#include <IOKit/IOKitLib.h>
#include "dy_framework.h"
#include "moh_msg.h"
#include "moh.h"
#include "DeviceOnHold.h"
#define kIODeviceSupportsHoldKey "V92Modem"
typedef struct {
CFRuntimeBase cfBase;
CFStringRef name;
int sock;
} DeviceOnHoldPrivate, *DeviceOnHoldPrivateRef;
static CFStringRef
__DeviceOnHoldCopyDescription(CFTypeRef cf)
{
CFAllocatorRef allocator = CFGetAllocator(cf);
CFMutableStringRef result;
result = CFStringCreateMutable(allocator, 0);
CFStringAppendFormat(result, NULL, CFSTR("<DeviceOnHold %p [%p]> {\n"), cf, allocator);
CFStringAppendFormat(result, NULL, CFSTR("}"));
return result;
}
static void
__DeviceOnHoldDeallocate(CFTypeRef cf)
{
DeviceOnHoldPrivateRef DeviceOnHoldPrivate = (DeviceOnHoldPrivateRef)cf;
SCLog(_sc_verbose, LOG_DEBUG, CFSTR("__DeviceOnHoldDeallocate:"));
if (DeviceOnHoldPrivate->name) CFRelease(DeviceOnHoldPrivate->name);
if (DeviceOnHoldPrivate->sock != -1) {
}
return;
}
static CFTypeID __kDeviceOnHoldTypeID = _kCFRuntimeNotATypeID;
static const CFRuntimeClass __DeviceOnHoldClass = {
0, "DeviceOnHold", NULL, NULL, __DeviceOnHoldDeallocate, NULL, NULL, NULL, __DeviceOnHoldCopyDescription };
static pthread_once_t initialized = PTHREAD_ONCE_INIT;
static void
__DeviceOnHoldInitialize(void)
{
__kDeviceOnHoldTypeID = _CFRuntimeRegisterClass(&__DeviceOnHoldClass);
return;
}
static DeviceOnHoldPrivateRef
__DeviceOnHoldCreatePrivate(CFAllocatorRef allocator)
{
DeviceOnHoldPrivateRef devicePrivate;
uint32_t size;
pthread_once(&initialized, __DeviceOnHoldInitialize);
size = sizeof(DeviceOnHoldPrivate) - sizeof(CFRuntimeBase);
devicePrivate = (DeviceOnHoldPrivateRef)_CFRuntimeCreateInstance(allocator,
__kDeviceOnHoldTypeID,
size,
NULL);
if (!devicePrivate) {
return NULL;
}
devicePrivate->name = NULL;
devicePrivate->sock = -1;
return devicePrivate;
}
CFTypeID
DeviceOnHoldGetTypeID(void) {
pthread_once(&initialized, __DeviceOnHoldInitialize);
return __kDeviceOnHoldTypeID;
}
Boolean
IsDeviceOnHoldSupported(CFStringRef deviceName, CFDictionaryRef options)
{
CFMutableDictionaryRef deviceToMatch;
uint32_t deviceSupportsHoldValue;
kern_return_t kr;
mach_port_t masterPort;
io_iterator_t matchingServices;
CFNumberRef num;
CFMutableDictionaryRef properties;
Boolean result = FALSE;
io_service_t service;
if (CFStringCompare(deviceName, CFSTR("modem"), NULL) == kCFCompareEqualTo) {
kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
if (kr != KERN_SUCCESS) {
goto errorExit;
}
deviceToMatch = IOServiceMatching("InternalModemSupport");
if (!deviceToMatch) {
goto errorExit;
}
kr = IOServiceGetMatchingServices(masterPort, deviceToMatch, &matchingServices);
if (kr != KERN_SUCCESS) {
goto errorExit;
}
for ( ; (service = IOIteratorNext(matchingServices)) ; IOObjectRelease(service)) {
io_string_t path;
kr = IORegistryEntryGetPath(service, kIOServicePlane, path);
assert( kr == KERN_SUCCESS );
kr = IORegistryEntryCreateCFProperties(service, &properties, kCFAllocatorDefault, kNilOptions);
assert( kr == KERN_SUCCESS );
num = CFDictionaryGetValue(properties, CFSTR(kIODeviceSupportsHoldKey));
if (isA_CFNumber(num)) {
CFNumberGetValue(num, kCFNumberSInt32Type, &deviceSupportsHoldValue);
if (deviceSupportsHoldValue == 1) {
result = TRUE;
}
}
CFRelease(properties);
}
IOObjectRelease(matchingServices);
}
return result;
errorExit:
return FALSE;
}
DeviceOnHoldRef
DeviceOnHoldCreate(CFAllocatorRef allocator,
CFStringRef deviceName, CFDictionaryRef options)
{
DeviceOnHoldPrivateRef devicePrivate;
int status;
if (CFStringCompare(deviceName, CFSTR("modem"), NULL) != kCFCompareEqualTo) {
return NULL;
}
devicePrivate = __DeviceOnHoldCreatePrivate(allocator);
if (!devicePrivate) {
return NULL;
}
status = MOHInit(&devicePrivate->sock, deviceName);
if (status != 0) {
CFRelease(devicePrivate);
return NULL;
}
devicePrivate->name = CFStringCreateCopy(NULL, deviceName);
return (DeviceOnHoldRef)devicePrivate;
}
int32_t
DeviceOnHoldGetStatus(DeviceOnHoldRef device)
{
DeviceOnHoldPrivateRef devicePrivate = (DeviceOnHoldPrivateRef)device;
int err;
u_long link = 1;
void *replyBuf;
u_long replyBufLen;
int32_t result = -1;
if (!device) {
return -1;
}
if (devicePrivate->sock == -1) {
return -1;
}
err = MOHExec(devicePrivate->sock,
link,
MOH_SESSION_GET_STATUS,
NULL,
0,
&replyBuf,
&replyBufLen);
if (err != 0) {
return -1;
}
if (replyBufLen == sizeof(result)) {
result = *(int32_t *)replyBuf;
}
if (replyBuf) CFAllocatorDeallocate(NULL, replyBuf);
return result;
}
Boolean
DeviceOnHoldSuspend(DeviceOnHoldRef device)
{
DeviceOnHoldPrivateRef devicePrivate = (DeviceOnHoldPrivateRef)device;
int err;
u_long link = 1;
void *replyBuf;
u_long replyBufLen;
Boolean result = FALSE;
if (!device) {
return FALSE;
}
if (devicePrivate->sock == -1) {
return FALSE;
}
err = MOHExec(devicePrivate->sock,
link,
MOH_PUT_SESSION_ON_HOLD,
NULL,
0,
&replyBuf,
&replyBufLen);
if (err != 0) {
return -1;
}
if (replyBufLen == sizeof(result)) {
result = (*(int32_t *)replyBuf) ? TRUE : FALSE;
}
if (replyBuf) CFAllocatorDeallocate(NULL, replyBuf);
return result;
}
Boolean
DeviceOnHoldResume(DeviceOnHoldRef device)
{
DeviceOnHoldPrivateRef devicePrivate = (DeviceOnHoldPrivateRef)device;
int err;
u_long link = 1;
void *replyBuf;
u_long replyBufLen;
Boolean result = FALSE;
if (!device) {
return FALSE;
}
if (devicePrivate->sock == -1) {
return FALSE;
}
err = MOHExec(devicePrivate->sock,
link,
MOH_RESUME_SESSION_ON_HOLD,NULL,
0,
&replyBuf,
&replyBufLen);
if (err != 0) {
return -1;
}
if (replyBufLen == sizeof(result)) {
result = (*(int32_t *)replyBuf) ? TRUE : FALSE;
}
if (replyBuf) CFAllocatorDeallocate(NULL, replyBuf);
return result;
}