|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1998-2000 Apple Computer, 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: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 24: * ! 25: * IONetworkData.cpp ! 26: */ ! 27: ! 28: #include <libkern/c++/OSDictionary.h> ! 29: #include <libkern/c++/OSNumber.h> ! 30: #include <IOKit/assert.h> ! 31: #include <IOKit/IOLib.h> ! 32: #include <IOKit/network/IONetworkData.h> ! 33: ! 34: #define super OSData ! 35: OSDefineMetaClassAndStructors( IONetworkData, OSData ) ! 36: ! 37: #define TAP_IS_VALID (_tapTarget && _tapAction) ! 38: ! 39: // All access method are serialized by a single global lock, ! 40: // shared among all IONetworkData instances. ! 41: // ! 42: static IOLock * gIONDLock = 0; ! 43: #define LOCK IOTakeLock(gIONDLock) ! 44: #define UNLOCK IOUnlock(gIONDLock) ! 45: ! 46: static const OSSymbol * gIONDDataKey; ! 47: static const OSSymbol * gIONDAccessKey; ! 48: static const OSSymbol * gIONDCapacityKey; ! 49: ! 50: //--------------------------------------------------------------------------- ! 51: // IONetworkData class initializer. ! 52: ! 53: void IONetworkData::initialize() ! 54: { ! 55: // Allocates the global data lock. ! 56: // ! 57: gIONDLock = IOLockAlloc(); ! 58: assert(gIONDLock); ! 59: IOLockInitWithState(gIONDLock, kIOLockStateUnlocked); ! 60: ! 61: gIONDDataKey = OSSymbol::withCStringNoCopy("Data"); ! 62: gIONDAccessKey = OSSymbol::withCStringNoCopy("Access Flags"); ! 63: gIONDCapacityKey = OSSymbol::withCStringNoCopy("Capacity"); ! 64: ! 65: assert(gIONDDataKey && gIONDAccessKey && gIONDCapacityKey); ! 66: } ! 67: ! 68: //--------------------------------------------------------------------------- ! 69: // Initialize an IONetworkData instance. A target/action may be ! 70: // registered to receive a notification when the read(), write(), ! 71: // reset(), or serialize() methods are called. ! 72: // ! 73: // name: A name assigned to this object. ! 74: // ! 75: // buffer: Pointer to an external data buffer. If 0, ! 76: // then an internal buffer shall be allocated. ! 77: // ! 78: // capacity: Capacity of the data buffer. ! 79: // ! 80: // accessFlags: Access flags. ! 81: // Can be later modified by calling setAccessFlags(). ! 82: // ! 83: // target: Notification target. The target will be notified ! 84: // when IONetworkData receives a call to one of its ! 85: // access methods. If 0, then notification is disabled. ! 86: // ! 87: // action: Notification action. If 0, then notification is ! 88: // disabled. ! 89: // ! 90: // arg: An argument to passed to the notification action. ! 91: // ! 92: // Returns true if initialized successfully, false otherwise. ! 93: ! 94: bool ! 95: IONetworkData::initWithName(const char * name, ! 96: UInt32 inCapacity, ! 97: void * buffer = 0, ! 98: UInt32 accessFlags = kIONDBasicAccessTypes, ! 99: OSObject * target = 0, ! 100: Action action = 0, ! 101: void * arg = 0) ! 102: { ! 103: if ( ((buffer == 0) ? ! 104: super::initWithCapacity(inCapacity) : ! 105: super::initWithBytesNoCopy(buffer, inCapacity)) == false ) ! 106: { ! 107: return false; ! 108: } ! 109: ! 110: _access = accessFlags; ! 111: _tapTarget = target; ! 112: _tapAction = action; ! 113: _tapArg = arg; ! 114: _capacity = inCapacity; ! 115: length = inCapacity; // (ivar in OSData) force length to maximum ! 116: ! 117: // Generate a key for this object based on its assigned name. ! 118: // ! 119: if ((_key = OSSymbol::withCString(name)) == 0) ! 120: return false; ! 121: ! 122: // Clear the data buffer. ! 123: // ! 124: clearBytes(); ! 125: ! 126: return true; ! 127: } ! 128: ! 129: //--------------------------------------------------------------------------- ! 130: // Factory method that will construct and initialize an IONetworkData ! 131: // instance. ! 132: // ! 133: // Returns an IONetworkData instance on success, or 0 otherwise. ! 134: ! 135: IONetworkData * ! 136: IONetworkData::withName(const char * name, ! 137: UInt32 inCapacity, ! 138: void * buffer = 0, ! 139: UInt32 accessFlags = kIONDBasicAccessTypes, ! 140: OSObject * target = 0, ! 141: Action action = 0, ! 142: void * arg = 0) ! 143: { ! 144: IONetworkData * aData = new IONetworkData; ! 145: ! 146: if (aData && !aData->initWithName(name, inCapacity, buffer, accessFlags, ! 147: target, action, arg)) ! 148: { ! 149: aData->release(); ! 150: aData = 0; ! 151: } ! 152: return aData; ! 153: } ! 154: ! 155: //--------------------------------------------------------------------------- ! 156: // Free the IONetworkData instance. ! 157: ! 158: void IONetworkData::free() ! 159: { ! 160: if (_key) ! 161: _key->release(); ! 162: ! 163: // Superclass will free the internal data buffer. ! 164: ! 165: super::free(); ! 166: } ! 167: ! 168: //--------------------------------------------------------------------------- ! 169: // Change the access flags. ! 170: // ! 171: // accessFlags: A bitfield of access flag bits. ! 172: // See IONDAccessFlags enum. ! 173: ! 174: void IONetworkData::setAccessFlags(UInt32 accessFlags) ! 175: { ! 176: LOCK; ! 177: _access = (_access & kIONDImmutableAccessFlags) | ! 178: (accessFlags & ~kIONDImmutableAccessFlags); ! 179: UNLOCK; ! 180: } ! 181: ! 182: //--------------------------------------------------------------------------- ! 183: // Register a target/action to handle access notification. ! 184: // A notification is sent by an IONetworkData to the registered ! 185: // notification handler when an access method is called. ! 186: // ! 187: // target: The target object that implements the notification action. ! 188: // If 0, then notification will be disabled. ! 189: // ! 190: // action: The notification action. If 0, then notification will be disabled. ! 191: // ! 192: // arg: An optional argument passed to the notification handler. ! 193: ! 194: void IONetworkData::setNotificationTarget(OSObject * target, ! 195: Action action, ! 196: void * arg = 0) ! 197: { ! 198: LOCK; ! 199: _tapTarget = target; ! 200: _tapAction = action; ! 201: _tapArg = arg; ! 202: UNLOCK; ! 203: } ! 204: ! 205: //--------------------------------------------------------------------------- ! 206: // Return a pointer to the data buffer. ! 207: ! 208: const void * IONetworkData::getBuffer() const ! 209: { ! 210: return getBytesNoCopy(); ! 211: } ! 212: ! 213: //--------------------------------------------------------------------------- ! 214: // Return the access flags. ! 215: ! 216: UInt32 IONetworkData::getAccessFlags() const ! 217: { ! 218: return _access; ! 219: } ! 220: ! 221: //--------------------------------------------------------------------------- ! 222: // Return the notification target. ! 223: ! 224: OSObject * IONetworkData::getTarget() const ! 225: { ! 226: return _tapTarget; ! 227: } ! 228: ! 229: //--------------------------------------------------------------------------- ! 230: // Return the notification action. ! 231: ! 232: IONetworkData::Action IONetworkData::getAction() const ! 233: { ! 234: return _tapAction; ! 235: } ! 236: ! 237: //--------------------------------------------------------------------------- ! 238: // Return the notification argument. ! 239: ! 240: void * IONetworkData::getArgument() const ! 241: { ! 242: return _tapArg; ! 243: } ! 244: ! 245: //--------------------------------------------------------------------------- ! 246: // Get an OSSymbol key associated with this IONetworkData instance. ! 247: // During initialization, IONetworkData will create an OSSymbol ! 248: // key based on its assigned name. ! 249: // ! 250: // Return an OSSymbol key generated from the assigned name. ! 251: ! 252: const OSSymbol * IONetworkData::getKey() const ! 253: { ! 254: return _key; ! 255: } ! 256: ! 257: //--------------------------------------------------------------------------- ! 258: // Override the getCapacity() method inherited from OSData. ! 259: // This method overrides the implementation in OSData in ! 260: // order to report the capacity for both internal or external ! 261: // data buffers. ! 262: // ! 263: // Return the capacity of the data buffer in bytes. ! 264: ! 265: UInt IONetworkData::getCapacity() const ! 266: { ! 267: return _capacity; ! 268: } ! 269: ! 270: //--------------------------------------------------------------------------- ! 271: // Update the data buffer from a source buffer provided by the ! 272: // caller. ! 273: // ! 274: // bytes: Pointer to a source buffer provided by the caller. ! 275: // ! 276: // inLength: Length of the source buffer, or the amount of data ! 277: // to copy to the data buffer. The length provided must ! 278: // be smaller than or equal to the capacity of the object. ! 279: // ! 280: // Returns true if the length of the source buffer is within limits, and ! 281: // the source buffer was copied, false otherwise. ! 282: ! 283: bool IONetworkData::setBytes(const void * bytes, UInt inLength) ! 284: { ! 285: if (inLength > _capacity) ! 286: return false; // specified buffer is too large. ! 287: ! 288: if (inLength == 0) ! 289: return true; ! 290: ! 291: bcopy(bytes, data, inLength); ! 292: ! 293: length = inLength; // set the new data length. ! 294: ! 295: return true; ! 296: } ! 297: ! 298: //--------------------------------------------------------------------------- ! 299: // Set a new data buffer length to indicate the amount of ! 300: // valid data in the data buffer. ! 301: // ! 302: // inLength: Length of the data buffer in bytes. The length provided must ! 303: // be smaller than or equal to the capacity of the data object. ! 304: // ! 305: // Returns true if the length provided was accepted. ! 306: ! 307: bool IONetworkData::setLength(UInt inLength) ! 308: { ! 309: if (inLength > _capacity) ! 310: return false; // Length cannot exceed capacity. ! 311: ! 312: length = inLength; ! 313: ! 314: return true; ! 315: } ! 316: ! 317: //--------------------------------------------------------------------------- ! 318: // Copy the data buffer (with length bytes) to a destination buffer ! 319: // provided by the caller. ! 320: // ! 321: // bytes: Pointer to a destination buffer. ! 322: // ! 323: // inOutLength: The caller must initialize the integer value pointed ! 324: // by inOutLength with the size of the destination buffer ! 325: // before the call. This method will overwrite it with the ! 326: // number of bytes copied. ! 327: // ! 328: // Returns true if the destination buffer is larger than or equal to the ! 329: // length of the data buffer, false otherwise. ! 330: ! 331: bool IONetworkData::copyBytes(void * bytes, UInt * inOutLength) const ! 332: { ! 333: if (length > *inOutLength) ! 334: return false; // specified buffer is too small. ! 335: ! 336: *inOutLength = length; // return the number of bytes copied. ! 337: ! 338: if (length) ! 339: bcopy(data, bytes, length); ! 340: ! 341: return true; ! 342: } ! 343: ! 344: //--------------------------------------------------------------------------- ! 345: // Clear the entire data buffer and fill it with zeroes. ! 346: // ! 347: // Return true if the buffer was cleared, false otherwise. ! 348: ! 349: bool IONetworkData::clearBytes() ! 350: { ! 351: if (_capacity) ! 352: bzero(data, _capacity); ! 353: ! 354: return true; ! 355: } ! 356: ! 357: //--------------------------------------------------------------------------- ! 358: // Handle a user space request to reset the data buffer. If notication ! 359: // is enabled, then the notification handler is called after the data ! 360: // buffer has been cleared ! 361: // ! 362: // Returns kIOReturnNotWritable if reset access is not allowed, ! 363: // kIOReturnSuccess otherwise. If a notification handler is called, ! 364: // and it returns an error code, then that error is returned. ! 365: ! 366: IOReturn IONetworkData::reset() ! 367: { ! 368: IOReturn ret = kIOReturnUnsupported; ! 369: ! 370: LOCK; ! 371: ! 372: do { ! 373: // Check access. ! 374: // ! 375: if ((_access & kIONDAccessTypeReset) == 0) ! 376: { ! 377: ret = kIOReturnNotWritable; ! 378: break; ! 379: } ! 380: ! 381: // Default action is to bzero the entire buffer. ! 382: // ! 383: if ((_access & kIONDAccessNoBufferAccess) == 0) ! 384: { ! 385: clearBytes(); ! 386: ret = kIOReturnSuccess; ! 387: } ! 388: ! 389: // Notify our target. ! 390: // ! 391: if (TAP_IS_VALID) ! 392: { ! 393: ret = (_tapTarget->*_tapAction)(this, ! 394: (UInt32) kIONDAccessTypeReset, ! 395: _tapArg, 0, 0); ! 396: } ! 397: } ! 398: while (0); ! 399: ! 400: UNLOCK; ! 401: ! 402: return ret; ! 403: } ! 404: ! 405: //--------------------------------------------------------------------------- ! 406: // Handle a user space request to read from the data buffer and copy it ! 407: // to the destination buffer provided. If notification is enabled, ! 408: // then the notification handler is called before the data buffer ! 409: // is copied to the destination buffer. The notification handler may ! 410: // use this opportunity to update the contents of the data buffer. ! 411: // ! 412: // inBuffer: Pointer to the destination buffer. ! 413: // ! 414: // inOutSize: Pointer to an integer containing the size of the destination ! 415: // buffer before the call. Overwritten by this method to the ! 416: // actual number of bytes copied to the destination buffer. ! 417: // ! 418: // Returns kIOReturnSuccess if success, ! 419: // kIOReturnBadArgument if an argument provided is invalid, ! 420: // kIOReturnNoSpace if the destination buffer is too small, ! 421: // kIOReturnNotReadable if read access is not permitted, ! 422: // or an error from the notification handler. ! 423: ! 424: IOReturn IONetworkData::read(void * inBuffer, UInt * inOutSize) ! 425: { ! 426: IOReturn ret = kIOReturnUnsupported; ! 427: ! 428: LOCK; ! 429: ! 430: do { ! 431: // Check the arguments. ! 432: // ! 433: if (!inBuffer || !inOutSize) ! 434: { ! 435: ret = kIOReturnBadArgument; ! 436: break; ! 437: } ! 438: ! 439: // Check access. ! 440: // ! 441: if ((_access & kIONDAccessTypeRead) == 0) ! 442: { ! 443: ret = kIOReturnNotReadable; ! 444: break; ! 445: } ! 446: ! 447: // Notify the target before the read operation. ! 448: // The target can take this opportunity to update the ! 449: // data buffer. If the target returns an error, ! 450: // abort and return the error. ! 451: // ! 452: if (TAP_IS_VALID) ! 453: { ! 454: ret = (_tapTarget->*_tapAction)(this, ! 455: (UInt32) kIONDAccessTypeRead, ! 456: _tapArg, ! 457: inBuffer, ! 458: (UInt32 *) inOutSize); ! 459: if (ret != kIOReturnSuccess) ! 460: break; ! 461: } ! 462: ! 463: if ((_access & kIONDAccessNoBufferAccess) == 0) ! 464: { ! 465: ret = (copyBytes(inBuffer, inOutSize) ? ! 466: kIOReturnSuccess : kIOReturnNoSpace); ! 467: } ! 468: } ! 469: while (0); ! 470: ! 471: UNLOCK; ! 472: ! 473: return ret; ! 474: } ! 475: ! 476: //--------------------------------------------------------------------------- ! 477: // Handle a request to write to the data buffer from a source buffer provided. ! 478: // If notification is enabled, then the notification handler is called after ! 479: // the source buffer has been copied to the data buffer. ! 480: // ! 481: // inBuffer: Pointer to the source buffer. ! 482: // ! 483: // size: Size of the source buffer in bytes. ! 484: // ! 485: // Returns kIOReturnSuccess on success, ! 486: // kIOReturnBadArgument if an argument provided is invalid, ! 487: // kIOReturnNoSpace if the source buffer is too big, ! 488: // kIOReturnNotWritable if write access is not permitted, ! 489: // or an error from the notification handler. ! 490: ! 491: IOReturn IONetworkData::write(void * inBuffer, UInt size) ! 492: { ! 493: IOReturn ret = kIOReturnUnsupported; ! 494: ! 495: LOCK; ! 496: ! 497: do { ! 498: // Check the arguments. ! 499: // ! 500: if (!inBuffer) ! 501: { ! 502: ret = kIOReturnBadArgument; ! 503: break; ! 504: } ! 505: ! 506: // Check access. ! 507: // ! 508: if ((_access & kIONDAccessTypeWrite) == 0) ! 509: { ! 510: ret = kIOReturnNotWritable; ! 511: break; ! 512: } ! 513: ! 514: // Update the data buffer. ! 515: // ! 516: if ((_access & kIONDAccessNoBufferAccess) == 0) ! 517: { ! 518: ret = (setBytes(inBuffer, size)) ? ! 519: kIOReturnSuccess : kIOReturnNoSpace; ! 520: ! 521: if (ret != kIOReturnSuccess) ! 522: break; ! 523: } ! 524: ! 525: // Notify the target after a successful write operation. ! 526: // ! 527: if (TAP_IS_VALID) ! 528: { ! 529: ret = (_tapTarget->*_tapAction)(this, ! 530: (UInt32) kIONDAccessTypeWrite, ! 531: _tapArg, ! 532: inBuffer, ! 533: (UInt32 *) &size); ! 534: } ! 535: } ! 536: while (0); ! 537: ! 538: UNLOCK; ! 539: ! 540: return ret; ! 541: } ! 542: ! 543: //--------------------------------------------------------------------------- ! 544: // Serialize the IONetworkData object. If notification is enabled, ! 545: // then the notification handler is called before the data buffer is ! 546: // serialized. ! 547: // ! 548: // s: An OSSerialize object. ! 549: ! 550: bool IONetworkData::serialize(OSSerialize * s) const ! 551: { ! 552: bool ok; ! 553: OSDictionary * dictToSerialize; ! 554: OSData * dataEntry; ! 555: OSNumber * numberEntry; ! 556: ! 557: dictToSerialize = OSDictionary::withCapacity(3); ! 558: if (!dictToSerialize) ! 559: return false; ! 560: ! 561: dataEntry = OSData::withBytesNoCopy((void *) &_access, sizeof(_access)); ! 562: if (dataEntry) { ! 563: dictToSerialize->setObject(gIONDAccessKey, dataEntry); ! 564: dataEntry->release(); ! 565: } ! 566: ! 567: numberEntry = OSNumber::withNumber(_capacity, sizeof(_capacity) * 8); ! 568: if (numberEntry) { ! 569: dictToSerialize->setObject(gIONDCapacityKey, numberEntry); ! 570: numberEntry->release(); ! 571: } ! 572: ! 573: LOCK; ! 574: ! 575: do { ! 576: // Check access. ! 577: // ! 578: if ((_access & kIONDAccessTypeSerialize) == 0) ! 579: break; ! 580: ! 581: if (_access & kIONDAccessNoBufferAccess) ! 582: break; ! 583: ! 584: // Notify the target before the read operation. ! 585: // The target can take this opportunity to update the ! 586: // data buffer. If the target returns an error, ! 587: // then the data buffer is not serialized. ! 588: // ! 589: if (TAP_IS_VALID && ! 590: ((_tapTarget->*_tapAction)((IONetworkData *) this, ! 591: kIONDAccessTypeSerialize, ! 592: _tapArg, 0, 0) != kIOReturnSuccess)) ! 593: { ! 594: break; ! 595: } ! 596: ! 597: dataEntry = OSData::withBytesNoCopy(data, length); ! 598: if (dataEntry) { ! 599: dictToSerialize->setObject(gIONDDataKey, dataEntry); ! 600: dataEntry->release(); ! 601: } ! 602: } ! 603: while (0); ! 604: ! 605: ok = dictToSerialize->serialize(s); ! 606: dictToSerialize->release(); ! 607: ! 608: UNLOCK; ! 609: ! 610: return ok; ! 611: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.