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/IOLib.h>
25#include <libkern/c++/OSDictionary.h>
26#include <libkern/c++/OSNumber.h>
27#include <libkern/c++/OSData.h>
28#include <IOKit/network/IONetworkData.h>
29
30#define super OSObject
31OSDefineMetaClassAndStructors( IONetworkData, OSObject )
32OSMetaClassDefineReservedUnused( IONetworkData,  0);
33OSMetaClassDefineReservedUnused( IONetworkData,  1);
34OSMetaClassDefineReservedUnused( IONetworkData,  2);
35OSMetaClassDefineReservedUnused( IONetworkData,  3);
36
37#define TAP_IS_VALID    (_tapAction)
38#define RELEASE(x) do { if (x) { (x)->release(); (x) = 0; } } while (0)
39
40// All access method are serialized by a single global lock,
41// shared among all IONetworkData instances.
42//
43static  IOLock * gIONDLock = 0;
44#define LOCK     IOTakeLock(gIONDLock)
45#define UNLOCK   IOUnlock(gIONDLock)
46
47static const OSSymbol * gIONDDataKey;
48static const OSSymbol * gIONDAccessKey;
49static const OSSymbol * gIONDSizeKey;
50
51class IONetworkDataGlobals
52{
53public:
54    IONetworkDataGlobals();
55    ~IONetworkDataGlobals();
56
57    inline bool isValid() const;
58};
59
60static IONetworkDataGlobals gIONetworkDataGlobals;
61
62IONetworkDataGlobals::IONetworkDataGlobals()
63{
64    // Allocates the global data lock.
65    //
66    gIONDLock = IOLockAlloc();
67    if ( gIONDLock )
68        IOLockInitWithState( gIONDLock, kIOLockStateUnlocked );
69
70    gIONDDataKey   = OSSymbol::withCStringNoCopy( kIONetworkDataBytes );
71    gIONDAccessKey = OSSymbol::withCStringNoCopy( kIONetworkDataAccessTypes );
72    gIONDSizeKey   = OSSymbol::withCStringNoCopy( kIONetworkDataSize );
73}
74
75IONetworkDataGlobals::~IONetworkDataGlobals()
76{
77    RELEASE( gIONDDataKey );
78    RELEASE( gIONDAccessKey );
79    RELEASE( gIONDSizeKey );
80
81    if ( gIONDLock )
82    {
83        IOLockFree( gIONDLock );
84        gIONDLock = 0;
85    }
86}
87
88bool IONetworkDataGlobals::isValid() const
89{
90    return ( gIONDLock && gIONDDataKey && gIONDAccessKey && gIONDSizeKey );
91}
92
93//---------------------------------------------------------------------------
94// Initialize an IONetworkData instance.
95
96bool
97IONetworkData::init(const char * name,
98                    UInt32       bufferType,
99                    UInt32       bufferSize,
100                    void *       extBuffer,
101                    UInt32       accessTypes,
102                    void *       target,
103                    Action       action,
104                    void *       param)
105{
106    if ( super::init() == false )
107        return false;
108
109    if ( gIONetworkDataGlobals.isValid() == false )
110        return false;
111
112    if ((bufferType == kIONetworkDataBufferTypeInternal) ||
113        (bufferType == kIONetworkDataBufferTypeExternal))
114    {
115        _buffer = (bufferType == kIONetworkDataBufferTypeInternal) ?
116                  (void *) IOMalloc(bufferSize) : extBuffer;
117
118        if (_buffer == 0)
119            return false;
120
121        if (bufferType == kIONetworkDataBufferTypeInternal)
122            bzero(_buffer, bufferSize);
123    }
124
125    _bufType   = bufferType;
126    _access    = accessTypes;
127    _tapTarget = target;
128    _tapAction = action;
129    _tapParam  = param;
130    _size      = bufferSize;
131
132    // Generate a key for this object based on its assigned name.
133    //
134    if ((_key = OSSymbol::withCString(name)) == 0)
135        return false;
136
137    return true;
138}
139
140//---------------------------------------------------------------------------
141// Factory method that will construct and initialize an IONetworkData
142// instance with an internal buffer.
143
144IONetworkData *
145IONetworkData::withInternalBuffer(
146                   const char * name,
147                   UInt32       bufferSize,
148                   UInt32       accessTypes,
149                   void *       target,
150                   Action       action,
151                   void *       param)
152{
153    IONetworkData * aData = new IONetworkData;
154
155    if (aData && !aData->init(name,
156                              kIONetworkDataBufferTypeInternal,
157                              bufferSize,
158                              0,
159                              accessTypes,
160                              target,
161                              action,
162                              param))
163    {
164        aData->release();
165        aData = 0;
166    }
167    return aData;
168}
169
170//---------------------------------------------------------------------------
171// Factory method that will construct and initialize an IONetworkData
172// instance with an external buffer.
173
174IONetworkData *
175IONetworkData::withExternalBuffer(
176                   const char * name,
177                   UInt32       bufferSize,
178                   void *       buffer,
179                   UInt32       accessTypes,
180                   void *       target,
181                   Action       action,
182                   void *       param)
183{
184    IONetworkData * aData = new IONetworkData;
185
186    if (aData && !aData->init(name,
187                              kIONetworkDataBufferTypeExternal,
188                              bufferSize,
189                              buffer,
190                              accessTypes,
191                              target,
192                              action,
193                              param))
194    {
195        aData->release();
196        aData = 0;
197    }
198    return aData;
199}
200
201//---------------------------------------------------------------------------
202// Factory method that will construct and initialize an IONetworkData
203// instance with no data buffer. The notification handler must intervene
204// when the IONetworkData is accessed.
205
206IONetworkData *
207IONetworkData::withNoBuffer(const char * name,
208                            UInt32       bufferSize,
209                            UInt32       accessTypes,
210                            void *       target,
211                            Action       action,
212                            void *       param)
213{
214    IONetworkData * aData = new IONetworkData;
215
216    if (aData && !aData->init(name,
217                              kIONetworkDataBufferTypeNone,
218                              bufferSize,
219                              0,
220                              accessTypes,
221                              target,
222                              action,
223                              param))
224    {
225        aData->release();
226        aData = 0;
227    }
228    return aData;
229}
230
231//---------------------------------------------------------------------------
232// Free the IONetworkData instance.
233
234void IONetworkData::free()
235{
236    if (_key)
237        _key->release();
238
239    if (_buffer && (_bufType == kIONetworkDataBufferTypeInternal))
240        IOFree( _buffer, _size);
241
242    super::free();
243}
244
245//---------------------------------------------------------------------------
246// Return the type of buffer managed by this instance.
247// See IONetworkDataBufferType enum definition
248
249UInt32 IONetworkData::getBufferType() const
250{
251    return _bufType;
252}
253
254//---------------------------------------------------------------------------
255// Change the supported access types.
256
257#define kIONetworkDataImmutableAccessTypes   0
258
259void IONetworkData::setAccessTypes(UInt32 types)
260{
261    LOCK;
262    _access = (_access & kIONetworkDataImmutableAccessTypes) |
263              (types & ~kIONetworkDataImmutableAccessTypes);
264    UNLOCK;
265}
266
267//---------------------------------------------------------------------------
268// Register a target/action to handle access notification.
269
270void IONetworkData::setNotificationTarget(void *  target,
271                                          Action  action,
272                                          void *  param)
273{
274    LOCK;
275    _tapTarget = target;
276    _tapAction = action;
277    _tapParam  = param;
278    UNLOCK;
279}
280
281//---------------------------------------------------------------------------
282// Return the supported access types.
283
284UInt32 IONetworkData::getAccessTypes() const
285{
286    return _access;
287}
288
289//---------------------------------------------------------------------------
290// Return the notification target.
291
292void * IONetworkData::getNotificationTarget() const
293{
294    return _tapTarget;
295}
296
297//---------------------------------------------------------------------------
298// Return the notification action.
299
300IONetworkData::Action IONetworkData::getNotificationAction() const
301{
302    return _tapAction;
303}
304
305//---------------------------------------------------------------------------
306// Return the notification parameter.
307
308void * IONetworkData::getNotificationParameter() const
309{
310    return _tapParam;
311}
312
313//---------------------------------------------------------------------------
314// Get an OSSymbol key associated with this instance.
315// During initialization, IONetworkData will create an OSSymbol
316// key based on its assigned name.
317//
318// Return an OSSymbol key generated from the assigned name.
319
320const OSSymbol * IONetworkData::getKey() const
321{
322    return _key;
323}
324
325//---------------------------------------------------------------------------
326// Return the size of the data managed by this instance in bytes.
327
328UInt32 IONetworkData::getSize() const
329{
330    return _size;
331}
332
333//---------------------------------------------------------------------------
334// Write to the data buffer with data from a source buffer provided
335// by the caller.
336
337bool IONetworkData::writeBytes(const void * srcBuffer,
338                               UInt32       srcBufferSize,
339                               UInt32       writeOffset)
340{
341    if ( _buffer == 0 ) return false;
342
343    if ( srcBufferSize          &&
344         (writeOffset < _size)  &&
345         ((writeOffset + srcBufferSize) <= _size) )
346    {
347        bcopy(srcBuffer, (char *) _buffer + writeOffset, srcBufferSize);
348        return true;
349    }
350
351    return false;
352}
353
354//---------------------------------------------------------------------------
355// Return a pointer to the data buffer.
356
357const void * IONetworkData::getBuffer() const
358{
359    return (_buffer) ? _buffer : 0;
360}
361
362//---------------------------------------------------------------------------
363// Copy the data buffer to a destination buffer provided by the caller.
364
365bool IONetworkData::readBytes(void *   dstBuffer,
366                              UInt32 * dstBufferSize,
367                              UInt32   readOffset) const
368{
369    if ( _buffer == 0 ) return false;
370
371    if ( *dstBufferSize && (readOffset < _size) )
372    {
373        UInt32 bytesCopied = min((_size - readOffset), *dstBufferSize);
374
375        bcopy((char *) _buffer + readOffset, dstBuffer, bytesCopied);
376
377        *dstBufferSize = bytesCopied;
378
379        return true;
380    }
381
382    return false;
383}
384
385//---------------------------------------------------------------------------
386// Clear the entire data buffer by filling it with zeroes.
387
388bool IONetworkData::clearBuffer()
389{
390    if ( _buffer )
391    {
392        bzero((void *) _buffer, _size);
393        return true;
394    }
395    return false;
396}
397
398//---------------------------------------------------------------------------
399// Handle a user space request to reset the data buffer.
400
401IOReturn IONetworkData::reset()
402{
403    IOReturn ret = kIOReturnUnsupported;
404
405    LOCK;
406
407    do {
408        // Check access.
409
410        if ( (_access & kIONetworkDataAccessTypeReset) == 0 )
411        {
412            ret = kIOReturnNotWritable;
413            break;
414        }
415
416        // Default action is to bzero the entire buffer.
417
418        if ( clearBuffer() )
419        {
420            ret = kIOReturnSuccess;
421        }
422
423        // Notify our target.
424
425        if ( TAP_IS_VALID )
426        {
427            ret = (*_tapAction)(_tapTarget, _tapParam,
428                                this,
429                                (UInt32) kIONetworkDataAccessTypeReset,
430                                0, 0, 0);
431        }
432    }
433    while (0);
434
435    UNLOCK;
436
437    return ret;
438}
439
440//---------------------------------------------------------------------------
441// Handle an external request to read from the data buffer
442// and copy it to the destination buffer provided by the accessor.
443
444IOReturn IONetworkData::read(void *   dstBuffer,
445                             UInt32 * dstBufferSize,
446                             UInt32   readOffset)
447{
448    IOReturn ret = kIOReturnUnsupported;
449
450    LOCK;
451
452    do {
453        // Check the arguments.
454
455        if ( !dstBuffer || !dstBufferSize )
456        {
457            ret = kIOReturnBadArgument;
458            break;
459        }
460
461        // Check access.
462
463        if ( (_access & kIONetworkDataAccessTypeRead) == 0 )
464        {
465            ret = kIOReturnNotReadable;
466            break;
467        }
468
469        // Notify the target before the read operation.
470        // The target can take this opportunity to update the
471        // data buffer. If the target returns an error,
472        // abort and return the error.
473
474        if ( TAP_IS_VALID )
475        {
476            ret = (*_tapAction)(_tapTarget, _tapParam,
477                                this,
478                                (UInt32) kIONetworkDataAccessTypeRead,
479                                dstBuffer,
480                                dstBufferSize,
481                                readOffset);
482            if (ret != kIOReturnSuccess)
483                break;
484        }
485
486        if ( _buffer )
487        {
488            ret = readBytes(dstBuffer, dstBufferSize, readOffset) ?
489                  kIOReturnSuccess : kIOReturnBadArgument;
490        }
491    }
492    while (0);
493
494    UNLOCK;
495
496    return ret;
497}
498
499//---------------------------------------------------------------------------
500// Handle an external request to write to the data buffer
501// from a source buffer provided by the accessor.
502
503IOReturn IONetworkData::write(void *  srcBuffer,
504                              UInt32  srcBufferSize,
505                              UInt32  writeOffset)
506{
507    IOReturn ret = kIOReturnUnsupported;
508
509    LOCK;
510
511    do {
512        // Check the arguments.
513
514        if ( srcBuffer == 0 )
515        {
516            ret = kIOReturnBadArgument;
517            break;
518        }
519
520        // Check access.
521
522        if ( (_access & kIONetworkDataAccessTypeWrite) == 0 )
523        {
524            ret = kIOReturnNotWritable;
525            break;
526        }
527
528        // Update the data buffer.
529
530        if ( _buffer &&
531             (writeBytes(srcBuffer, srcBufferSize, writeOffset) == false) )
532        {
533            ret = kIOReturnBadArgument;
534            break;
535        }
536
537        // Notify the target after a successful write operation.
538
539        if ( TAP_IS_VALID )
540        {
541            ret = (*_tapAction)(_tapTarget, _tapParam,
542                                this,
543                                (UInt32) kIONetworkDataAccessTypeWrite,
544                                srcBuffer,
545                                &srcBufferSize,
546                                writeOffset);
547        }
548        else
549            ret = kIOReturnSuccess;
550    }
551    while (0);
552
553    UNLOCK;
554
555    return ret;
556}
557
558//---------------------------------------------------------------------------
559// Serialize the IONetworkData object. If notification is enabled,
560// then the notification handler is called before the data buffer is
561// serialized.
562
563bool IONetworkData::serialize(OSSerialize * s) const
564{
565    bool           ok;
566    OSDictionary * dictToSerialize;
567    OSData *       dataEntry;
568    OSNumber *     numberEntry;
569
570    dictToSerialize = OSDictionary::withCapacity(3);
571    if (!dictToSerialize)
572        return false;
573
574    numberEntry = OSNumber::withNumber(_access, sizeof(_access) * 8);
575    if (numberEntry) {
576        dictToSerialize->setObject(gIONDAccessKey, numberEntry);
577        numberEntry->release();
578    }
579
580    numberEntry = OSNumber::withNumber(_size, sizeof(_size) * 8);
581    if (numberEntry) {
582        dictToSerialize->setObject(gIONDSizeKey, numberEntry);
583        numberEntry->release();
584    }
585
586    LOCK;
587
588    do {
589        // Check access.
590
591        if ((_access & kIONetworkDataAccessTypeSerialize) == 0)
592            break;
593
594        if (_buffer == 0)
595            break;
596
597        // Notify the target before the read operation.
598        // The target can take this opportunity to update the
599        // data buffer. If the target returns an error,
600        // then the data buffer is not serialized.
601
602        if (TAP_IS_VALID &&
603            ((*_tapAction)(_tapTarget, _tapParam,
604                           (IONetworkData *) this,
605                           kIONetworkDataAccessTypeSerialize,
606                           0, 0, 0) != kIOReturnSuccess))
607        {
608            break;
609        }
610
611        dataEntry = OSData::withBytesNoCopy(_buffer, _size);
612        if (dataEntry) {
613            dictToSerialize->setObject(gIONDDataKey, dataEntry);
614            dataEntry->release();
615        }
616    }
617    while (0);
618
619    ok = dictToSerialize->serialize(s);
620    dictToSerialize->release();
621
622    UNLOCK;
623
624    return ok;
625}
626