1/*
2 * Copyright (c) 1998-2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License").  You may not use this file except in compliance with the
9 * License.  Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23#include <IOKit/assert.h>
24#include <IOKit/network/IONetworkInterface.h>
25#include <IOKit/network/IONetworkData.h>
26#include "IONetworkUserClient.h"
27#include "IONetworkDebug.h"
28
29//------------------------------------------------------------------------
30
31#define super IOUserClient
32OSDefineMetaClassAndStructors( IONetworkUserClient, IOUserClient )
33
34//---------------------------------------------------------------------------
35// Factory method that performs allocation and initialization
36// of an IONetworkUserClient instance.
37
38IONetworkUserClient * IONetworkUserClient::withTask(task_t owningTask)
39{
40    IONetworkUserClient * me;
41
42    me = new IONetworkUserClient;
43    if (me)
44    {
45        if (!me->init())
46        {
47            me->release();
48            return 0;
49        }
50        me->_task = owningTask;
51    }
52    return me;
53}
54
55//---------------------------------------------------------------------------
56// Start the IONetworkUserClient.
57
58bool IONetworkUserClient::start(IOService * provider)
59{
60    _owner = OSDynamicCast(IONetworkInterface, provider);
61    assert(_owner);
62
63    _handleArray = OSArray::withCapacity(4);
64    if (!_handleArray)
65        return false;
66
67    _handleLock = IOLockAlloc();
68    if (!_handleLock)
69        return false;
70
71    if (!super::start(_owner))
72        return false;
73
74    if (!_owner->open(this))
75        return false;
76
77    return true;
78}
79
80//---------------------------------------------------------------------------
81// Free the IONetworkUserClient instance.
82
83void IONetworkUserClient::free(void)
84{
85    if (_handleArray)
86    {
87        _handleArray->release();
88        _handleArray = 0;
89    }
90    if (_handleLock)
91    {
92        IOLockFree(_handleLock);
93        _handleLock = 0;
94    }
95    super::free();
96}
97
98//---------------------------------------------------------------------------
99// Handle a client close. Close and detach from our owner (provider).
100
101IOReturn IONetworkUserClient::clientClose(void)
102{
103    if (_owner) {
104        _owner->close(this);
105        detach(_owner);
106    }
107
108    return kIOReturnSuccess;
109}
110
111//---------------------------------------------------------------------------
112// Handle client death. Close and detach from our owner (provider).
113
114IOReturn IONetworkUserClient::clientDied(void)
115{
116    return clientClose();
117}
118
119//---------------------------------------------------------------------------
120
121IOReturn IONetworkUserClient::externalMethod(
122            uint32_t selector, IOExternalMethodArguments * arguments,
123            IOExternalMethodDispatch * dispatch, OSObject * target,
124            void * reference )
125{
126    IOReturn    ret = kIOReturnBadArgument;
127
128    if (!arguments)
129        return kIOReturnBadArgument;
130
131    switch (selector)
132    {
133        case kIONUCResetNetworkDataIndex:
134            if (arguments->scalarInputCount == 1)
135                ret = resetNetworkData(
136                        (uint32_t) arguments->scalarInput[0]);
137            break;
138
139        case kIONUCWriteNetworkDataIndex:
140            if ((arguments->scalarInputCount == 1) &&
141                (arguments->structureInputSize > 0))
142                ret = writeNetworkData(
143                        (uint32_t) arguments->scalarInput[0],
144                        (void *) arguments->structureInput,
145                        arguments->structureInputSize);
146            break;
147
148        case kIONUCReadNetworkDataIndex:
149            if ((arguments->scalarInputCount == 1) &&
150                (arguments->structureOutputSize > 0))
151                ret = readNetworkData(
152                        (uint32_t) arguments->scalarInput[0],
153                        arguments->structureOutput,
154                        &arguments->structureOutputSize);
155            break;
156
157        case kIONUCGetNetworkDataCapacityIndex:
158            if ((arguments->scalarInputCount  == 1) &&
159                (arguments->scalarOutputCount == 1))
160                ret = getNetworkDataCapacity(
161                        (uint32_t) arguments->scalarInput[0],
162                        &arguments->scalarOutput[0]);
163            break;
164
165        case kIONUCGetNetworkDataHandleIndex:
166            ret = getNetworkDataHandle(
167                    (const char *) arguments->structureInput,
168                    (uint32_t *) arguments->structureOutput,
169                    arguments->structureInputSize,
170                    &arguments->structureOutputSize);
171            break;
172
173    }
174
175    return ret;
176}
177
178//---------------------------------------------------------------------------
179// Fill the data buffer in an IONetworkData object with zeroes.
180
181IOReturn IONetworkUserClient::resetNetworkData(uint32_t  dataHandle)
182{
183    IONetworkData *  data;
184    const OSSymbol * key;
185    IOReturn         ret;
186
187    IOLockLock(_handleLock);
188    key = (const OSSymbol *) _handleArray->getObject(dataHandle);
189    IOLockUnlock(_handleLock);
190
191    if (!key)
192        return kIOReturnBadArgument;
193
194    data = _owner->getNetworkData(key);
195    ret = data ? data->reset() : kIOReturnBadArgument;
196
197    return ret;
198}
199
200//---------------------------------------------------------------------------
201// Write to the data buffer in an IONetworkData object with data from a
202// source buffer provided by the caller.
203
204IOReturn
205IONetworkUserClient::writeNetworkData(uint32_t  dataHandle,
206                                      void *    srcBuffer,
207                                      uint32_t  srcBufferSize)
208{
209    IONetworkData *  data;
210    const OSSymbol * key;
211    IOReturn         ret;
212
213    IOLockLock(_handleLock);
214    key = (const OSSymbol *) _handleArray->getObject(dataHandle);
215    IOLockUnlock(_handleLock);
216
217    if (!key || !srcBuffer || !srcBufferSize)
218        return kIOReturnBadArgument;
219
220    data = _owner->getNetworkData(key);
221    ret = data ? data->write(srcBuffer, srcBufferSize) : kIOReturnBadArgument;
222
223    return ret;
224}
225
226//---------------------------------------------------------------------------
227// Read the data buffer in an IONetworkData object and copy
228// this data to a destination buffer provided by the caller.
229
230IOReturn
231IONetworkUserClient::readNetworkData(uint32_t   dataHandle,
232                                     void *     dstBuffer,
233                                     uint32_t * dstBufferSize)
234{
235    IONetworkData *  data;
236    const OSSymbol * key;
237    IOReturn         ret;
238
239    IOLockLock(_handleLock);
240    key = (const OSSymbol *) _handleArray->getObject(dataHandle);
241    IOLockUnlock(_handleLock);
242
243    if (!key || !dstBuffer || !dstBufferSize)
244        return kIOReturnBadArgument;
245
246    data = _owner->getNetworkData(key);
247    ret = data ? data->read(dstBuffer, (UInt32 *) dstBufferSize) :
248                 kIOReturnBadArgument;
249
250    return ret;
251}
252
253//---------------------------------------------------------------------------
254// Get the capacity of an IONetworkData object.
255
256IOReturn
257IONetworkUserClient::getNetworkDataCapacity(uint32_t   dataHandle,
258                                            uint64_t * capacity)
259{
260    const OSSymbol * key;
261    IONetworkData *  data;
262    IOReturn         ret = kIOReturnBadArgument;
263
264    IOLockLock(_handleLock);
265    key = (const OSSymbol *) _handleArray->getObject(dataHandle);
266    IOLockUnlock(_handleLock);
267
268    if (key)
269    {
270        data = _owner->getNetworkData(key);
271        if (data) {
272            *capacity = (uint64_t) data->getSize();
273            ret = kIOReturnSuccess;
274        }
275    }
276
277    return ret;
278}
279
280//---------------------------------------------------------------------------
281// Called to obtain a handle that maps to an IONetworkData object.
282// This handle can be later passed to other methods in this class
283// to refer to the same object.
284
285IOReturn
286IONetworkUserClient::getNetworkDataHandle(const char * name,
287                                          uint32_t *   handle,
288                                          uint32_t     nameSize,
289                                          uint32_t *   handleSizeP)
290{
291    IOReturn         ret = kIOReturnBadArgument;
292    const OSSymbol * key;
293    int              index;
294
295    if (!name || !nameSize || (name[nameSize - 1] != '\0') ||
296        (*handleSizeP != sizeof(*handle)))
297        return kIOReturnBadArgument;
298
299    key = OSSymbol::withCStringNoCopy(name);
300    if (!key)
301        return kIOReturnNoMemory;
302
303    if (_owner->getNetworkData(key))
304    {
305        IOLockLock(_handleLock);
306        index = _handleArray->getNextIndexOfObject(key, 0);
307        if (index < 0)
308        {
309            _handleArray->setObject(key);
310            index = _handleArray->getNextIndexOfObject(key, 0);
311        }
312        IOLockUnlock(_handleLock);
313
314        if (index >= 0)
315        {
316            *handle = index;
317            ret = kIOReturnSuccess;
318        }
319    }
320
321    if (key)
322        key->release();
323
324    return ret;
325}
326
327//---------------------------------------------------------------------------
328// Route setProperties() to our provider.
329
330IOReturn
331IONetworkUserClient::setProperties(OSObject * properties)
332{
333    return _owner->setProperties(properties);
334}
335
336//---------------------------------------------------------------------------
337// Return our provider. This is called by IOConnectGetService().
338
339IOService * IONetworkUserClient::getService()
340{
341    return _owner;
342}
343