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