1#include <stdio.h> 2#include <string.h> 3#include <stdlib.h> 4#include <sys/types.h> 5#include <sys/time.h> 6#include <unistd.h> 7#include <errno.h> 8#include <notify.h> 9#include <dispatch/dispatch.h> 10 11#include <CoreFoundation/CoreFoundation.h> 12#include <CoreFoundation/CFUserNotification.h> 13#include <mach/mach_port.h> 14#include <mach/mach_interface.h> 15#include <mach/mach_init.h> 16#include <IOKit/IOKitLib.h> 17#include <IOKit/pwr_mgt/IOPM.h> 18#include <IOKit/pwr_mgt/IOPMLib.h> 19#if !TARGET_OS_EMBEDDED 20#include <IOKit/pwr_mgt/IOPMLibPrivate.h> 21#endif /* !TARGET_OS_EMBEDDED */ 22#include <IOKit/IOMessage.h> 23 24#include "var.h" 25#include "misc.h" 26#include "vmbuf.h" 27#include "plog.h" 28#include "sockmisc.h" 29#include "schedule.h" 30#include "debug.h" 31 32#include "isakmp_var.h" 33#include "isakmp.h" 34#include "handler.h" 35 36#ifndef kIOPMAcknowledgmentOptionSystemCapabilityRequirements 37IONotificationPortRef notify; 38io_object_t iterator; 39io_connect_t gIOPort; 40CFUserNotificationRef gSleepNotification = NULL; 41#endif // !kIOPMAcknowledgmentOptionSystemCapabilityRequirements 42 43time_t slept_at = 0; 44time_t woke_at = 0; 45time_t swept_at = 0; 46 47static int sleeping = 0; 48 49int check_power_context; // dummy field for dispatch call 50extern void check_power_mgmt (void*); 51 52#ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements 53#define WAKE_CAPS (kIOPMSystemPowerStateCapabilityCPU | kIOPMSystemPowerStateCapabilityNetwork) 54 55IOPMConnection gPMConnection = NULL; 56 57static void 58iosleep_capabilities_notifier(void *param, IOPMConnection connection, IOPMConnectionMessageToken token, IOPMSystemPowerStateCapabilities capabilities) 59{ 60 plog(ASL_LEVEL_DEBUG, "received power-mgmt event: capabilities %X%s%s%s%s%s", 61 capabilities, 62 capabilities & kIOPMSystemPowerStateCapabilityCPU ? " CPU" : "", 63 capabilities & kIOPMSystemPowerStateCapabilityVideo ? " Video" : "", 64 capabilities & kIOPMSystemPowerStateCapabilityAudio ? " Audio" : "", 65 capabilities & kIOPMSystemPowerStateCapabilityNetwork ? " Network" : "", 66 capabilities & kIOPMSystemPowerStateCapabilityDisk ? " Disk" : ""); 67 68 if ((capabilities & WAKE_CAPS) != WAKE_CAPS) { 69 if (!sleeping) { 70 plog(ASL_LEVEL_DEBUG, 71 "received power-mgmt event: will sleep\n"); 72 sleeping = 1; 73 slept_at = current_time(); 74 } else { 75 plog(ASL_LEVEL_DEBUG, 76 "ignored power-mgmt event: sleep(%x) while asleep\n", capabilities); 77 } 78 IOPMConnectionAcknowledgeEvent(connection, token ); 79 } else if ((capabilities & WAKE_CAPS) == WAKE_CAPS) { 80 // allow processing of packets 81 if (sleeping) { 82 plog(ASL_LEVEL_DEBUG, 83 "received power-mgmt event: will wake(%x)\n", capabilities); 84 sleeping = 0; 85 woke_at = current_time(); 86 } else { 87 plog(ASL_LEVEL_DEBUG, 88 "ignored power-mgmt event: wake(%x) while not asleep\n", capabilities); 89 } 90 IOPMConnectionAcknowledgeEvent(connection, token); 91 } else { 92 plog(ASL_LEVEL_DEBUG, 93 "ignored power-mgmt event: capabilities(%x)\n", capabilities); 94 IOPMConnectionAcknowledgeEvent(connection, token); 95 } 96 dispatch_async_f(dispatch_get_main_queue(), &check_power_context, &check_power_mgmt); 97} 98 99#else 100 101static 102void iosleep_notifier(void * x, io_service_t y, natural_t messageType, void *messageArgument) 103{ 104 switch ( messageType ) { 105 case kIOMessageSystemWillSleep: 106 sleeping = 1; 107 slept_at = current_time(); 108 plog(ASL_LEVEL_DEBUG, 109 "received power-mgmt event: will sleep\n"); 110 IOAllowPowerChange(gIOPort, (long)messageArgument); 111 break; 112 case kIOMessageCanSystemSleep: 113 IOAllowPowerChange(gIOPort, (long)messageArgument); 114 break; 115 case kIOMessageSystemWillNotSleep: 116 /* someone refused an idle sleep */ 117 plog(ASL_LEVEL_DEBUG, 118 "received power-mgmt event: will not sleep\n"); 119 sleeping = 0; 120 slept_at = 0; 121 break; 122 case kIOMessageSystemWillPowerOn: 123 if (sleeping) { 124 plog(ASL_LEVEL_DEBUG, 125 "received power-mgmt event: will wake\n"); 126 sleeping = 0; 127 } else { 128 plog(ASL_LEVEL_DEBUG, 129 "received power-mgmt event: will power-on\n"); 130 } 131 break; 132 case kIOMessageSystemHasPoweredOn: 133 woke_at = current_time(); 134 if (slept_at) { 135 plog(ASL_LEVEL_DEBUG, 136 "received power-mgmt event: has woken\n"); 137 } else { 138 plog(ASL_LEVEL_DEBUG, 139 "received power-mgmt event: has powered-on\n"); 140 } 141 break; 142 default: 143 plog(ASL_LEVEL_DEBUG, 144 "received power-mgmt event: %x\n", messageType); 145 break; 146 } 147 dispatch_async_f(dispatch_get_main_queue(), &check_power_context, &check_power_mgmt); 148} 149#endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements 150 151int 152init_power_mgmt (void) 153{ 154#ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements 155 IOReturn ret; 156 157 ret = IOPMConnectionCreate(CFSTR("racoon power-mgmt"), 158 WAKE_CAPS, 159 &gPMConnection); 160 if (ret != kIOReturnSuccess) { 161 plog(ASL_LEVEL_ERR, "IOPMConnectionCreate failed (%d) power-mgmt thread\n", ret); 162 return -1; 163 } 164 165 ret = IOPMConnectionSetNotification(gPMConnection, NULL, iosleep_capabilities_notifier); 166 if (ret != kIOReturnSuccess) { 167 plog(ASL_LEVEL_ERR, "IOPMConnectionCreate failed (%d) power-mgmt thread\n", ret); 168 return -1; 169 } 170 171 IOPMConnectionSetDispatchQueue(gPMConnection, dispatch_get_main_queue()); 172 173#else 174 if ((gIOPort = IORegisterForSystemPower(0, ¬ify, iosleep_notifier, &iterator)) == MACH_PORT_NULL) { 175 plog(ASL_LEVEL_ERR, 176 "IORegisterForSystemPower failed for power-mgmt thread\n"); 177 return -1; 178 } 179 180 IONotificationPortSetDispatchQueue(notify, dispatch_get_main_queue()); 181 182#endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements 183 184 return 0; 185} 186 187void 188cleanup_power_mgmt (void) 189{ 190#ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements 191 192 IOPMConnectionSetDispatchQueue(gPMConnection, NULL); 193 IOPMConnectionRelease(gPMConnection); 194 195#else 196 197 IODeregisterForSystemPower(&iterator); 198 IONotificationPortDestroy(notify); 199 200#endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements 201 202} 203 204void 205check_power_mgmt (void *context) 206{ 207 if (slept_at && woke_at) { 208 plog(ASL_LEVEL_DEBUG, 209 "handling power-mgmt event: sleep-wake\n"); 210 swept_at = current_time(); 211 sweep_sleepwake(); 212 slept_at = 0; 213 woke_at = 0; 214 } else if (woke_at) { 215 plog(ASL_LEVEL_DEBUG, 216 "handling power-mgmt event: power-on\n"); 217 woke_at = 0; 218 } 219} 220