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, &notify, 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