1/*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 * Copyright (c) 1999 Apple Computer, Inc.  All rights reserved.
30 *
31 */
32
33#include <IOKit/assert.h>
34#include <IOKit/IOLib.h>
35#include <IOKit/IOKitKeys.h>
36#include <IOKit/IOBufferMemoryDescriptor.h>
37#include "RootDomainUserClient.h"
38#include <IOKit/pwr_mgt/IOPMLibDefs.h>
39#include <IOKit/pwr_mgt/IOPMPrivate.h>
40
41#define super IOUserClient
42
43/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
44
45OSDefineMetaClassAndStructors(RootDomainUserClient, IOUserClient)
46
47/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
48
49bool RootDomainUserClient::initWithTask(task_t owningTask, void *security_id,
50					UInt32 type, OSDictionary * properties)
51{
52    if (properties)
53	properties->setObject(kIOUserClientCrossEndianCompatibleKey, kOSBooleanTrue);
54
55    if (!super::initWithTask(owningTask, security_id, type, properties))
56	return false;
57
58    fOwningTask = owningTask;
59    task_reference (fOwningTask);
60    return true;
61}
62
63
64bool RootDomainUserClient::start( IOService * provider )
65{
66    assert(OSDynamicCast(IOPMrootDomain, provider));
67    if(!super::start(provider))
68        return false;
69    fOwner = (IOPMrootDomain *)provider;
70
71
72    return true;
73}
74
75IOReturn RootDomainUserClient::secureSleepSystem( uint32_t *return_code )
76{
77    return secureSleepSystemOptions(NULL, 0, return_code);
78}
79
80IOReturn RootDomainUserClient::secureSleepSystemOptions(
81    const void      *inOptions,
82    IOByteCount     inOptionsSize __unused,
83    uint32_t        *returnCode)
84{
85
86    int             local_priv = 0;
87    int             admin_priv = 0;
88    IOReturn        ret = kIOReturnNotPrivileged;
89    OSDictionary    *unserializedOptions =  NULL;
90    OSString        *unserializeErrorString = NULL;
91
92    ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeLocalUser);
93    local_priv = (kIOReturnSuccess == ret);
94
95    ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeAdministrator);
96    admin_priv = (kIOReturnSuccess == ret);
97
98
99    if (inOptions)
100    {
101        unserializedOptions = OSDynamicCast( OSDictionary,
102                                             OSUnserializeXML((const char *)inOptions, &unserializeErrorString));
103
104        if (!unserializedOptions) {
105            IOLog("IOPMRootDomain SleepSystem unserialization failure: %s\n",
106                unserializeErrorString ? unserializeErrorString->getCStringNoCopy() : "Unknown");
107        }
108    }
109
110    if ( (local_priv || admin_priv)
111          && fOwner )
112    {
113        if (unserializedOptions)
114        {
115            // Publish Sleep Options in registry under root_domain
116            fOwner->setProperty( kRootDomainSleepOptionsKey, unserializedOptions);
117
118            *returnCode = fOwner->sleepSystemOptions( unserializedOptions );
119
120            unserializedOptions->release();
121        } else {
122            // No options
123            // Clear any pre-existing options
124            fOwner->removeProperty( kRootDomainSleepOptionsKey );
125
126            *returnCode = fOwner->sleepSystemOptions( NULL );
127        }
128
129    } else {
130        *returnCode = kIOReturnNotPrivileged;
131    }
132
133    return kIOReturnSuccess;
134}
135
136IOReturn RootDomainUserClient::secureSetAggressiveness(
137    unsigned long   type,
138    unsigned long   newLevel,
139    int             *return_code )
140{
141    int             local_priv = 0;
142    int             admin_priv = 0;
143    IOReturn        ret = kIOReturnNotPrivileged;
144
145    ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeLocalUser);
146    local_priv = (kIOReturnSuccess == ret);
147
148    ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeAdministrator);
149    admin_priv = (kIOReturnSuccess == ret);
150
151    if((local_priv || admin_priv) && fOwner) {
152        *return_code = fOwner->setAggressiveness(type, newLevel);
153    } else {
154        *return_code = kIOReturnNotPrivileged;
155    }
156    return kIOReturnSuccess;
157}
158
159IOReturn RootDomainUserClient::secureSetMaintenanceWakeCalendar(
160    IOPMCalendarStruct      *inCalendar,
161    uint32_t                *returnCode)
162{
163    int                     admin_priv = 0;
164    IOReturn                ret = kIOReturnNotPrivileged;
165
166    ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeAdministrator);
167    admin_priv = (kIOReturnSuccess == ret);
168
169    if (admin_priv && fOwner) {
170        *returnCode = fOwner->setMaintenanceWakeCalendar(inCalendar);
171    } else {
172        *returnCode = kIOReturnNotPrivileged;
173    }
174    return kIOReturnSuccess;
175}
176
177IOReturn RootDomainUserClient::secureSetUserAssertionLevels(
178    uint32_t    assertionBitfield)
179{
180    int                     admin_priv = 0;
181    IOReturn                ret = kIOReturnNotPrivileged;
182
183    ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeAdministrator);
184    admin_priv = (kIOReturnSuccess == ret);
185
186    if (admin_priv && fOwner) {
187        ret = fOwner->setPMAssertionUserLevels(assertionBitfield);
188    } else {
189        ret = kIOReturnNotPrivileged;
190    }
191    return kIOReturnSuccess;
192}
193
194IOReturn RootDomainUserClient::secureGetSystemSleepType(
195    uint32_t    *outSleepType)
196{
197    int                     admin_priv = 0;
198    IOReturn                ret;
199
200    ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeAdministrator);
201    admin_priv = (kIOReturnSuccess == ret);
202
203    if (admin_priv && fOwner) {
204        ret = fOwner->getSystemSleepType(outSleepType);
205    } else {
206        ret = kIOReturnNotPrivileged;
207    }
208    return ret;
209}
210
211IOReturn RootDomainUserClient::clientClose( void )
212{
213    detach(fOwner);
214
215    if(fOwningTask) {
216        task_deallocate(fOwningTask);
217        fOwningTask = 0;
218    }
219
220    return kIOReturnSuccess;
221}
222
223IOReturn RootDomainUserClient::clientMemoryForType(
224    UInt32 type,
225    IOOptionBits *options,
226    IOMemoryDescriptor ** memory)
227{
228    if (!fOwner)
229        return kIOReturnNotReady;
230
231    if (kPMRootDomainMapTraceBuffer == type)
232    {
233        *memory = fOwner->getPMTraceMemoryDescriptor();
234        if (*memory) {
235            (*memory)->retain();
236            *options = 0;
237            return kIOReturnSuccess;
238        } else {
239            return kIOReturnNotFound;
240        }
241
242    }
243    return kIOReturnUnsupported;
244}
245
246IOReturn RootDomainUserClient::externalMethod(
247    uint32_t selector,
248    IOExternalMethodArguments * arguments,
249    IOExternalMethodDispatch * dispatch __unused,
250    OSObject * target __unused,
251    void * reference __unused )
252{
253    IOReturn    ret = kIOReturnBadArgument;
254
255    switch (selector)
256    {
257        case kPMSetAggressiveness:
258            if ((2 == arguments->scalarInputCount)
259                && (1 == arguments->scalarOutputCount))
260            {
261                ret = this->secureSetAggressiveness(
262                                (unsigned long)arguments->scalarInput[0],
263                                (unsigned long)arguments->scalarInput[1],
264                                (int *)&arguments->scalarOutput[0]);
265            }
266            break;
267
268        case kPMGetAggressiveness:
269            if ((1 == arguments->scalarInputCount)
270                && (1 == arguments->scalarOutputCount))
271            {
272                ret = fOwner->getAggressiveness(
273                                (unsigned long)arguments->scalarInput[0],
274                                (unsigned long *)&arguments->scalarOutput[0]);
275            }
276            break;
277
278        case kPMSleepSystem:
279            if (1 == arguments->scalarOutputCount)
280            {
281                ret = this->secureSleepSystem(
282                                (uint32_t *)&arguments->scalarOutput[0]);
283            }
284            break;
285
286        case kPMAllowPowerChange:
287            if (1 == arguments->scalarInputCount)
288            {
289                ret = fOwner->allowPowerChange(
290                                arguments->scalarInput[0]);
291            }
292            break;
293
294        case kPMCancelPowerChange:
295            if (1 == arguments->scalarInputCount)
296            {
297                ret = fOwner->cancelPowerChange(
298                                arguments->scalarInput[0]);
299            }
300            break;
301
302        case kPMShutdownSystem:
303            // deperecated interface
304            ret = kIOReturnUnsupported;
305            break;
306
307        case kPMRestartSystem:
308            // deperecated interface
309            ret = kIOReturnUnsupported;
310            break;
311
312        case kPMSleepSystemOptions:
313            ret = this->secureSleepSystemOptions(
314                    arguments->structureInput,
315                    arguments->structureInputSize,
316                    (uint32_t *)&arguments->scalarOutput[0]);
317            break;
318        case kPMSetMaintenanceWakeCalendar:
319            ret = this->secureSetMaintenanceWakeCalendar(
320                    (IOPMCalendarStruct *)arguments->structureInput,
321                    (uint32_t *)&arguments->structureOutput);
322            arguments->structureOutputSize = sizeof(uint32_t);
323            break;
324
325        case kPMSetUserAssertionLevels:
326            ret = this->secureSetUserAssertionLevels(
327                        (uint32_t)arguments->scalarInput[0]);
328            break;
329
330        case kPMActivityTickle:
331            if ( fOwner->checkSystemCanSustainFullWake() )
332            {
333               fOwner->reportUserInput( );
334               fOwner->setProperty(kIOPMRootDomainWakeTypeKey, "UserActivity Assertion");
335            }
336            ret = kIOReturnSuccess;
337            break;
338
339        case kPMSetClamshellSleepState:
340            fOwner->setDisableClamShellSleep(arguments->scalarInput[0] ? true : false);
341            ret = kIOReturnSuccess;
342            break;
343
344        case kPMGetSystemSleepType:
345            if (1 == arguments->scalarOutputCount)
346            {
347                ret = this->secureGetSystemSleepType(
348                        (uint32_t *) &arguments->scalarOutput[0]);
349            }
350            break;
351/*
352        case kPMMethodCopySystemTimeline:
353            // intentional fallthrough
354        case kPMMethodCopyDetailedTimeline:
355
356            if (!arguments->structureOutputDescriptor)
357            {
358                // TODO: Force IOKit.framework to always send this data out
359                // of line; so I don't have to create a MemoryDescriptor here.
360                mem_size = arguments->structureOutputSize;
361                mem = IOMemoryDescriptor::withAddressRange(
362                                    (mach_vm_address_t)arguments->structureOutput,
363                                    (mach_vm_size_t)mem_size,
364                                    kIODirectionIn, current_task());
365            } else {
366                mem_size = arguments->structureOutputDescriptorSize;
367                if (( mem = arguments->structureOutputDescriptor ))
368                    mem->retain();
369            }
370
371            if (mem)
372            {
373                mem->prepare(kIODirectionNone);
374
375                if (kPMMethodCopySystemTimeline == selector) {
376                    arguments->scalarOutput[0] = fOwner->copySystemTimeline(
377                                    mem, &mem_size);
378                }
379                else
380                if (kPMMethodCopyDetailedTimeline == selector) {
381                    arguments->scalarOutput[0] = fOwner->copyDetailedTimeline(
382                                    mem, &mem_size);
383                }
384
385                if (arguments->structureOutputDescriptor) {
386                    arguments->structureOutputDescriptorSize = mem_size;
387                } else {
388                    arguments->structureOutputSize = mem_size;
389                }
390
391                mem->release();
392
393                ret = kIOReturnSuccess;
394            } else {
395                ret = kIOReturnCannotWire;
396            }
397
398            break;
399*/
400        default:
401            // bad selector
402            return kIOReturnBadArgument;
403    }
404
405    return ret;
406}
407
408/* getTargetAndMethodForIndex
409 * Not used. We prefer to use externalMethod() for user client invocations.
410 * We maintain getTargetAndExternalMethod since it's an exported symbol,
411 * and only for that reason.
412 */
413IOExternalMethod * RootDomainUserClient::getTargetAndMethodForIndex(
414    IOService ** targetP, UInt32 index )
415{
416    // DO NOT EDIT
417    return super::getTargetAndMethodForIndex(targetP, index);
418}
419
420/* setPreventative
421 * Does nothing. Exists only for exported symbol compatibility.
422 */
423void
424RootDomainUserClient::setPreventative(UInt32 on_off, UInt32 types_of_sleep)
425{ return; } // DO NOT EDIT
426