1#include "../../KernelHeaders/IOKit/IOFWIPBusInterface.h" 2#include <sys/kpi_mbuf.h> 3 4#define BCOPY(s, d, l) do { bcopy((void *) s, (void *) d, l); } while(0) 5 6struct GASPVAL 7{ 8 UInt8 specifierID[3]; // 24-bit RID 9 UInt8 version[3]; // 24-bit version 10} gaspVal = { {0x00, 0x00, 0x5E}, {0x00, 0x00, 0x01} }; 11 12 13extern "C" 14{ 15/*! 16 @function watchdog 17 @abstract watchdog timer - cleans the Link control block's rcb's. 18 @param timer - IOTimerEventsource. 19 @result void. 20*/ 21void watchdog(OSObject *, IOTimerEventSource *); 22 23extern errno_t mbuf_inet6_cksum(mbuf_t mbuf, int protocol, u_int32_t offset, u_int32_t length, u_int16_t *csum); 24} 25 26#define super IOService 27 28OSDefineMetaClassAndStructors(IOFWIPBusInterface, IOService) 29 30OSDefineMetaClassAndStructors(MARB, OSObject) 31OSDefineMetaClassAndStructors(ARB, OSObject) 32OSDefineMetaClassAndStructors(DRB, OSObject) 33OSDefineMetaClassAndStructors(RCB, IOCommand) 34OSDefineMetaClassAndStructors(MCB, OSObject) 35OSDefineMetaClassAndStructors(IOFWIPMBufCommand, IOCommand) 36 37bool IOFWIPBusInterface::init(IOFireWireIP *primaryInterface) 38{ 39 fIPLocalNode = OSDynamicCast(IOFireWireIP, primaryInterface); 40 41 if( fStarted ) 42 return fStarted; 43 44 if(not fIPLocalNode) 45 { 46 IOLog("IOFWIPBusInterface::init - Coudn't get Localnode\n"); 47 return false; 48 } 49 50 fControl = fIPLocalNode->getController(); 51 52 if( not fControl) 53 { 54 IOLog("IOFWIPBusInterface::init - Coudn't get Controller\n"); 55 return false; 56 } 57 58 if ( not super::init() ) 59 { 60 IOLog("IOFWIPBusInterface::init - Couldn't init super\n"); 61 return false; 62 } 63 64 fIP1394AddressSpace = 0; 65 fAsyncCmdPool = 0; 66 fMbufCmdPool = 0; 67 fRCBCmdPool = 0; 68 fAsyncStreamTxCmdPool = 0; 69 fAsyncTransitSet = 0; 70 fAsyncStreamTransitSet = 0; 71 fCurrentMBufCommands = 0; 72 fCurrentAsyncIPCommands = 0; 73 fCurrentRCBCommands = 0; 74 fUnitCount = 0; 75 fOptimalMTU = 0; 76 fLowWaterMark = kLowWaterMark; 77 fIPLocalNode->fIPoFWDiagnostics.fMaxQueueSize = TRANSMIT_QUEUE_SIZE; 78 79 // set the secondary interface handlers with IOFireWireIP 80 if( not attachIOFireWireIP ( fIPLocalNode ) ) 81 { 82 IOLog("IOFWIPBusInterface::init - Coudn't attachIOFireWireIP\n"); 83 return false; 84 } 85 else 86 { 87 this->release(); 88 89 fControl->retain(); 90 91 fIPLocalNode->retain(); 92 93 fControl->resetBus(); 94 95 fStarted = true; 96 97 registerService(); 98 } 99 100 return fStarted; 101} 102 103bool IOFWIPBusInterface::finalize(IOOptionBits options) 104{ 105 if( fStarted ) 106 { 107 IORecursiveLockLock(fIPLock); 108 109 fIPLocalNode->deRegisterFWIPPrivateHandlers(); 110 111 // Release the Asyncstream receive broadcast client 112 if(fBroadcastReceiveClient != NULL) 113 { 114 fBroadcastReceiveClient->TurnOffNotification(); 115 fControl->removeAsyncStreamListener(fBroadcastReceiveClient); 116 } 117 118 fBroadcastReceiveClient = NULL; 119 120 if (fIP1394AddressSpace != NULL) 121 { 122 fIP1394AddressSpace->deactivate(); 123 fIP1394AddressSpace->release(); 124 } 125 fIP1394AddressSpace = NULL; 126 127 if(timerSource != NULL) 128 { 129 if (workLoop != NULL) 130 workLoop->removeEventSource(timerSource); 131 timerSource->release(); 132 } 133 timerSource = NULL; 134 135 IORecursiveLockUnlock(fIPLock); 136 137 IOFWIPAsyncWriteCommand *cmd1 = NULL; 138 OSCollectionIterator * iterator = OSCollectionIterator::withCollection( fAsyncTransitSet ); 139 if( iterator ) 140 { 141 while( NULL != (cmd1 = OSDynamicCast(IOFWIPAsyncWriteCommand, iterator->getNextObject())) ) 142 { 143 if(cmd1->Busy()) 144 cmd1->wait(); 145 } 146 iterator->release(); 147 } 148 fAsyncTransitSet->flushCollection(); 149 fAsyncTransitSet->free(); 150 fAsyncTransitSet = NULL; 151 152 IOFWIPAsyncStreamTxCommand *cmd2 = NULL; 153 iterator = OSCollectionIterator::withCollection( fAsyncStreamTransitSet ); 154 if( iterator ) 155 { 156 while( NULL != (cmd2 = OSDynamicCast(IOFWIPAsyncStreamTxCommand, iterator->getNextObject())) ) 157 { 158 if(cmd2->Busy()) 159 cmd2->wait(); 160 } 161 iterator->release(); 162 } 163 fAsyncStreamTransitSet->flushCollection(); 164 fAsyncStreamTransitSet->free(); 165 fAsyncStreamTransitSet = NULL; 166 } 167 168 return super::finalize(options); 169} 170 171void IOFWIPBusInterface::stop(IOService *provider) 172{ 173 if( fStarted ) 174 { 175 IORecursiveLockLock(fIPLock); 176 177 freeAsyncCmdPool(); 178 179 freeAsyncStreamCmdPool(); 180 181 if(mcapState != NULL) 182 { 183 for ( int channel = 0; channel < kMaxChannels; channel++ ) 184 { 185 MCB *mcb = OSDynamicCast(MCB, mcapState->getObject(channel)); 186 if(mcb) 187 { 188 IOFWAsyncStreamListener *asyncStreamRxClient = OSDynamicCast(IOFWAsyncStreamListener, mcb->asyncStreamID); 189 if(asyncStreamRxClient != NULL) 190 { 191 fControl->removeAsyncStreamListener( asyncStreamRxClient ); 192 asyncStreamRxClient->release(); 193 } 194 195 mcb->asyncStreamID = NULL; 196 } 197 } 198 199 mcapState->flushCollection(); 200 mcapState->free(); 201 mcapState = NULL; 202 } 203 204 if(fControl) 205 fControl->release(); 206 207 fControl = NULL; 208 209 detachIOFireWireIP(); 210 211 super::stop(provider); 212 213 fStarted = false; 214 215 IORecursiveLockUnlock(fIPLock); 216 } 217} 218 219void IOFWIPBusInterface::free() 220{ 221 super::free(); 222} 223 224IOReturn IOFWIPBusInterface::message(UInt32 type, IOService *provider, void *argument) 225{ 226 IOReturn res = kIOReturnSuccess; 227 228 switch (type) 229 { 230 case kIOMessageServiceIsTerminated: 231 break; 232 233 case kIOMessageServiceIsSuspended: 234 break; 235 236 case kIOMessageServiceIsResumed: 237 if(fStarted == true) 238 { 239 resetRCBCache(); 240 241 resetMcapState(); 242 243 resetMARBCache(); 244 245 updateBroadcastValues(true); 246 } 247 break; 248 249 case kIOMessageServiceIsRequestingClose: 250 break; 251 252 default: 253 res = kIOReturnUnsupported; 254 break; 255 } 256 257 return res; 258} 259 260 261 262bool IOFWIPBusInterface::attachIOFireWireIP(IOFireWireIP *provider) 263{ 264 fIPLocalNode = provider; 265 fLcb = fIPLocalNode->getLcb(); 266 fIPLock = fIPLocalNode->getIPLock(); 267 workLoop = fIPLocalNode->getWorkLoop(); 268 269 if( initAsyncCmdPool() != kIOReturnSuccess) 270 return false; 271 272 unicastArb = OSSet::withCapacity(kUnicastArbs); 273 if(unicastArb == 0) 274 return false; 275 276 multicastArb = OSSet::withCapacity(kMulticastArbs); 277 if(multicastArb == 0) 278 return false; 279 280 activeDrb = OSSet::withCapacity(kActiveDrbs); 281 if(activeDrb == 0) 282 return false; 283 284 activeRcb = OSSet::withCapacity(kActiveRcbs); 285 if(activeRcb == 0) 286 return false; 287 288 mcapState = OSArray::withCapacity(kMaxChannels); 289 if(mcapState == 0) 290 return false; 291 292 for ( int channel = 0; channel < kMaxChannels; channel++ ) 293 { 294 MCB *mcb = new MCB; 295 if(mcb) 296 { 297 mcb->channel = channel; 298 mcapState->setObject(channel, mcb); 299 mcb->release(); 300 } 301 } 302 303 fAsyncStreamTransitSet = OSSet::withCapacity(kMaxAsyncStreamCommands); 304 if(fAsyncStreamTransitSet == 0) 305 return false; 306 307 fAsyncTransitSet = OSSet::withCapacity(kMaxAsyncCommands); 308 if(fAsyncTransitSet == 0) 309 return false; 310 311 // Does calculate the fMaxTxAsyncDoubleBuffer & fAsyncRxIsocPacketSize; 312 calculateMaxTransferUnit(); 313 314 // Allocate Timer event source 315 timerSource = IOTimerEventSource::timerEventSource ( ( OSObject* ) this, 316 ( IOTimerEventSource::Action ) &watchdog); 317 if ( timerSource == NULL ) 318 { 319 IOLog( "IOFWIPBusInterface::attachIOFireWireIP - Couldn't allocate timer event source\n" ); 320 return false; 321 } 322 323 if ( workLoop->addEventSource ( timerSource ) != kIOReturnSuccess ) 324 { 325 IOLog( "IOFWIPBusInterface::attachIOFireWireIP - Couldn't add timer event source\n" ); 326 return false; 327 } 328 329 // Asyncstream hook up to recieve the broadcast packets 330 fBroadcastReceiveClient = fControl->createAsyncStreamListener( 0x1f, rxAsyncStream, this ); 331 if ( not fBroadcastReceiveClient ) 332 { 333 IOLog("IOFWIPBusInterface::attachIOFireWireIP - Couldn't createAsyncStreamListener\n"); 334 return false; 335 } 336 337 // Create pseudo address space 338 if ( createIPFifoAddress (kMaxPseudoAddressSize) != kIOReturnSuccess) 339 { 340 IOLog("IOFWIPBusInterface::attachIOFireWireIP - Couldn't createIPFifoAddress\n"); 341 return false; 342 } 343 344 // might eventually start the timer 345 timerSource->setTimeoutMS ( kWatchDogTimerMS ); 346 347 IOFireWireIPPrivateHandlers privateHandlers; 348 349 privateHandlers.newService = this; 350 privateHandlers.transmitPacket = getOutputHandler(); 351 privateHandlers.updateARPCache = getARPCacheHandler(); 352 privateHandlers.updateMulticastCache = getMulticastCacheHandler(); 353 354 fIPLocalNode->registerFWIPPrivateHandlers(&privateHandlers); 355 356 fBroadcastReceiveClient->TurnOnNotification(); 357 358 OSObject * prop = fIPLocalNode->getProperty(gFireWire_GUID); 359 if( prop ) 360 { 361 setProperty( gFireWire_GUID, prop ); 362 } 363 364 return attach(fIPLocalNode); 365} 366 367void IOFWIPBusInterface::detachIOFireWireIP() 368{ 369 IORecursiveLockLock(fIPLock); 370 371 if(fMbufCmdPool != NULL) 372 { 373 IOFWIPMBufCommand *cmd = NULL; 374 do 375 { 376 cmd = (IOFWIPMBufCommand*)fMbufCmdPool->getCommand(false); 377 if(cmd != NULL) 378 cmd->release(); 379 }while(cmd != NULL); 380 381 fMbufCmdPool->release(); 382 fMbufCmdPool = NULL; 383 fCurrentMBufCommands = 0; 384 } 385 386 if(fRCBCmdPool != NULL) 387 { 388 RCB *cmd = NULL; 389 do 390 { 391 cmd = (RCB*)fRCBCmdPool->getCommand(false); 392 if(cmd != NULL) 393 cmd->release(); 394 }while(cmd != NULL); 395 396 fRCBCmdPool->release(); 397 fRCBCmdPool = NULL; 398 fCurrentRCBCommands = 0; 399 } 400 401 if(unicastArb != NULL) 402 { 403 { 404 ARB *arb = 0; 405 OSCollectionIterator * iterator = OSCollectionIterator::withCollection( unicastArb ); 406 if( iterator ) 407 { 408 while( NULL != (arb = OSDynamicCast(ARB, iterator->getNextObject())) ) 409 { 410 unicastArb->removeObject(arb); 411 arb->release(); 412 } 413 414 iterator->release(); 415 } 416 } 417 unicastArb->flushCollection(); 418 unicastArb->free(); 419 unicastArb = NULL; 420 } 421 422 if(multicastArb != NULL) 423 { 424 { 425 MARB *marb = 0; 426 OSCollectionIterator * iterator = OSCollectionIterator::withCollection( multicastArb ); 427 428 if( iterator ) 429 { 430 while( NULL != (marb = OSDynamicCast(MARB, iterator->getNextObject())) ) 431 { 432 multicastArb->removeObject(marb); 433 marb->release(); 434 } 435 436 iterator->release(); 437 } 438 } 439 440 multicastArb->flushCollection(); 441 multicastArb->free(); 442 multicastArb = NULL; 443 } 444 445 if(activeDrb != NULL) 446 { 447 { 448 DRB *drb = 0; 449 OSCollectionIterator * iterator = OSCollectionIterator::withCollection( activeDrb ); 450 451 if( iterator ) 452 { 453 while( NULL != (drb = OSDynamicCast(DRB, iterator->getNextObject())) ) 454 { 455 activeDrb->removeObject(drb); 456 drb->release(); 457 } 458 459 iterator->release(); 460 } 461 } 462 463 activeDrb->flushCollection(); 464 activeDrb->free(); 465 activeDrb = NULL; 466 } 467 468 if(activeRcb != NULL) 469 { 470 { 471 RCB *rcb = 0; 472 OSCollectionIterator * iterator = OSCollectionIterator::withCollection( activeRcb ); 473 474 if( iterator ) 475 { 476 while( NULL != (rcb = OSDynamicCast(RCB, iterator->getNextObject())) ) 477 { 478 activeRcb->removeObject(rcb); 479 rcb->release(); 480 } 481 482 iterator->release(); 483 } 484 } 485 486 activeRcb->flushCollection(); 487 activeRcb->free(); 488 activeRcb = NULL; 489 } 490 491 if(fIPLocalNode) 492 { 493 detach(fIPLocalNode); 494 fIPLocalNode->release(); 495 } 496 497 fIPLocalNode = NULL; 498 499 IORecursiveLockUnlock(fIPLock); 500} 501 502void IOFWIPBusInterface::decrementUnitCount() 503{ 504 recursiveScopeLock lock(fIPLock); 505 506 if(fUnitCount > 0) 507 fUnitCount--; 508} 509 510void IOFWIPBusInterface::incrementUnitCount() 511{ 512 recursiveScopeLock lock(fIPLock); 513 514 fUnitCount++; 515} 516 517SInt16 IOFWIPBusInterface::getUnitCount() 518{ 519 recursiveScopeLock lock(fIPLock); 520 521 return fUnitCount; 522} 523 524/*! 525 @function fwIPUnitAttach 526 @abstract Callback for a Unit Attach of type IPv4 or IPv6 527 @result void. 528*/ 529void IOFWIPBusInterface::fwIPUnitAttach() 530{ 531 incrementUnitCount(); 532 533 updateBroadcastValues(true); 534 535 fLowWaterMark = kLowWaterMark; // new unit, so lets learn afresh 536} 537 538/*! 539 @function fwIPUnitTerminate 540 @abstract Callback for a Unit detach of type IP1394 541 @result void. 542*/ 543void IOFWIPBusInterface::fwIPUnitTerminate() 544{ 545 decrementUnitCount(); 546 547 updateBroadcastValues(true); 548} 549 550/*! 551 @function updateBroadcastValues 552 @abstract Updates the max broadcast payload and speed 553 @param reset - useful to know whether to start from beginning. 554 @result void. 555*/ 556void IOFWIPBusInterface::updateBroadcastValues(bool reset) 557{ 558 recursiveScopeLock lock(fIPLock); 559 560 if(fStarted) 561 { 562 if(reset and (fIPLocalNode != NULL) ) 563 { 564 IOFireWireNub *localDevice = OSDynamicCast(IOFireWireNub, fIPLocalNode->getDevice()); 565 566 if( localDevice ) 567 { 568 fLcb->maxBroadcastPayload = localDevice->maxPackLog(true); 569 570 fLcb->maxBroadcastSpeed = localDevice->FWSpeed(); 571 // Update our own max payload 572 fLcb->ownMaxPayload = localDevice->maxPackLog(true); 573 // Update the nodeID 574 localDevice->getNodeIDGeneration(fLcb->busGeneration, fLcb->ownNodeID); 575 // Update the speed 576 fLcb->ownMaxSpeed = localDevice->FWSpeed(); 577 } 578 } 579 580 // Display the active DRB 581 DRB *drb = NULL; 582 OSCollectionIterator * iterator = OSCollectionIterator::withCollection( activeDrb ); 583 if( iterator ) 584 { 585 while( NULL != (drb = OSDynamicCast(DRB, iterator->getNextObject())) ) 586 { 587 if(fLcb->maxBroadcastSpeed > drb->maxSpeed) 588 fLcb->maxBroadcastSpeed = drb->maxSpeed; 589 590 if(fLcb->maxBroadcastPayload > drb->maxPayload) 591 fLcb->maxBroadcastPayload = drb->maxPayload; 592 } 593 iterator->release(); 594 } 595 } 596 597 updateLinkStatus(); 598} 599 600/*! 601 @function updateLinkStatus 602 @abstract Updates the link status based on maxbroadcast speed & payload. 603 @param None. 604 @result void. 605*/ 606void IOFWIPBusInterface::updateLinkStatus() 607{ 608 recursiveScopeLock lock(fIPLock); 609 610 if(fStarted and (fIPLocalNode != NULL) ) 611 { 612 // set medium inactive, before setting it to active for radar 3300357 613 fIPLocalNode->setLinkStatus(kIONetworkLinkValid, fIPLocalNode->getCurrentMedium(), 0); 614 615 // lets update the link status as active, if only units are greater than 0 616 if(fUnitCount > 0) 617 fIPLocalNode->setLinkStatus (kIONetworkLinkActive | kIONetworkLinkValid, 618 fIPLocalNode->getCurrentMedium(), 619 (1 << fLcb->maxBroadcastSpeed) * 100 * 1000000); 620 621 fLcb->ownHardwareAddress.spd = fLcb->maxBroadcastSpeed; 622 // fix to enable the arp/dhcp support from network pref pane 623 fIPLocalNode->setProperty(kIOFWHWAddr, (void *)&fLcb->ownHardwareAddress, sizeof(IP1394_HDW_ADDR)); 624 625 fOptimalMTU = 0; 626 } 627} 628 629/*! 630 @function createIPFifoAddress 631 @abstract creates the pseudo address space for IP over Firewire. 632 @param UInt32 fifosize - size of the pseudo address space 633 @result IOReturn - kIOReturnSuccess or error if failure. 634*/ 635IOReturn IOFWIPBusInterface::createIPFifoAddress(UInt32 fifosize) 636{ 637 IOReturn ioStat = kIOReturnSuccess; 638 639 // add csr address space 640 fIP1394AddressSpace = fControl->createPseudoAddressSpace(&fIP1394Address, fifosize, 641 NULL, 642 &rxUnicast, 643 this); 644 if (fIP1394AddressSpace == NULL) 645 ioStat = kIOReturnNoMemory; 646 647 if(ioStat == kIOReturnSuccess ) // change for performance, coalescing incoming writes 648 fIP1394AddressSpace->setARxReqIntCompleteHandler(this, &rxUnicastComplete); 649 650 fLcb->ownHardwareAddress.unicastFifoHi = fIP1394Address.addressHi; 651 fLcb->ownHardwareAddress.unicastFifoLo = fIP1394Address.addressLo; 652 // fix to enable the arp/dhcp support from network pref pane 653 fIPLocalNode->setProperty(kIOFWHWAddr, (void *)&fLcb->ownHardwareAddress, sizeof(IP1394_HDW_ADDR)); 654 655 if(ioStat == kIOReturnSuccess ) 656 ioStat = fIP1394AddressSpace->activate(); 657 658 if(ioStat != kIOReturnSuccess) 659 IOLog("IOFireWireIP PseudoAddressSpace Activate failure status %d\n", ioStat); 660 661 // end of csr address space 662 return ioStat; 663} 664 665/*! 666 @function calculateMaxTransferUnit 667 @abstract checks whether the FWIM is for calculateMaxTransferUnit H/W, if not 668 sets appropriate performance related params 669 @param none. 670 @result Returns void. 671*/ 672void IOFWIPBusInterface::calculateMaxTransferUnit() 673{ 674 IORegistryEntry *parent = fControl->getParentEntry(gIOServicePlane); 675 676 if(strncmp(parent->getName(gIOServicePlane), "AppleLynx", strlen("AppleLynx")) == 0) 677 { 678 //fMaxRxIsocPacketSize = 2048; 679 fMaxTxAsyncDoubleBuffer = 1 << 9; 680 } 681 else 682 { 683 //fMaxRxIsocPacketSize = 4096; 684 fMaxTxAsyncDoubleBuffer = 1 << ((IOFireWireNub*)(fIPLocalNode->getDevice()))->maxPackLog(true); 685 } 686 687 fMaxTxAsyncDoubleBuffer = MAX(512, fMaxTxAsyncDoubleBuffer); 688 689 fIPLocalNode->updateMTU(fMaxTxAsyncDoubleBuffer); 690} 691 692/*! 693 @function initAsyncCmdPool 694 @abstract constructs Asynchronous command objects and queues them in the pool 695 @param none. 696 @result Returns kIOReturnSuccess if it was successful, else kIOReturnNoMemory. 697*/ 698UInt32 IOFWIPBusInterface::initAsyncCmdPool() 699{ 700 IOReturn status = kIOReturnSuccess; 701 702 if( (fAsyncCmdPool == NULL) ) 703 fAsyncCmdPool = IOCommandPool::withWorkLoop(workLoop); 704 705 if( (fMbufCmdPool == NULL) ) 706 fMbufCmdPool = IOCommandPool::withWorkLoop(workLoop); 707 708 if( (fRCBCmdPool == NULL) ) 709 fRCBCmdPool = IOCommandPool::withWorkLoop(workLoop); 710 711 if( (fMbufCmdPool == NULL) or (fAsyncCmdPool == NULL) or (fRCBCmdPool == NULL) ) 712 status = kIOReturnNoMemory; 713 714 return status; 715} 716 717IOFWIPMBufCommand *IOFWIPBusInterface::getMBufCommand() 718{ 719 IOFWIPMBufCommand * mBufCommand = NULL; 720 721 if( fMbufCmdPool ) 722 mBufCommand = (IOFWIPMBufCommand *)fMbufCmdPool->getCommand(false); 723 724 if(mBufCommand == NULL) 725 { 726 if( fCurrentMBufCommands < kMaxAsyncCommands ) 727 { 728 mBufCommand = new IOFWIPMBufCommand; 729 if(not mBufCommand->init()) 730 { 731 mBufCommand->release(); 732 mBufCommand = NULL; 733 } 734 else 735 fCurrentMBufCommands++; 736 } 737 } 738 739 return mBufCommand; 740} 741 742IOFWIPAsyncWriteCommand *IOFWIPBusInterface::getAsyncCommand(bool block, bool *deferNotify) 743{ 744 IOFWIPAsyncWriteCommand * cmd = (IOFWIPAsyncWriteCommand *)fAsyncCmdPool->getCommand(block); 745 746 if(cmd == NULL) 747 { 748 if( fCurrentAsyncIPCommands < kMaxAsyncCommands ) 749 { 750 cmd = new IOFWIPAsyncWriteCommand; 751 752 FWAddress addr; 753 // setup block write 754 addr.addressHi = 0xdead; 755 addr.addressLo = 0xbabeface; 756 757 if(not cmd->initAll(fIPLocalNode, this, fMaxTxAsyncDoubleBuffer, addr, txCompleteBlockWrite, this, false)) 758 { 759 cmd->release(); 760 cmd = NULL; 761 } 762 else 763 { 764 fCurrentAsyncIPCommands++; 765 fAsyncTransitSet->setObject(cmd); 766 } 767 } 768 } 769 770 if( cmd ) 771 { 772 fIPLocalNode->fIPoFWDiagnostics.fActiveCmds++; 773 } 774 else 775 { 776 fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors); 777 fIPLocalNode->fIPoFWDiagnostics.fNoCommands++; 778 } 779 780 if((fIPLocalNode->fIPoFWDiagnostics.fActiveCmds - fIPLocalNode->fIPoFWDiagnostics.fInActiveCmds) >= fLowWaterMark) 781 *deferNotify = false; 782 783 return cmd; 784} 785 786void IOFWIPBusInterface::returnAsyncCommand(IOFWIPAsyncWriteCommand *cmd) 787{ 788 if(cmd->notDoubleComplete()) 789 { 790 if(fAsyncCmdPool != NULL) 791 fAsyncCmdPool->returnCommand(cmd); 792 else 793 cmd->release(); 794 fIPLocalNode->fIPoFWDiagnostics.fInActiveCmds++; 795 } 796 else 797 fIPLocalNode->fIPoFWDiagnostics.fDoubleCompletes++; 798} 799 800/*! 801 @function initAsyncStreamCmdPool 802 @abstract constructs AsyncStreamcommand objects and queues them in the pool 803 @param none. 804 @result Returns kIOReturnSuccess if it was successful, else kIOReturnNoMemory. 805*/ 806 807UInt32 IOFWIPBusInterface::initAsyncStreamCmdPool() 808{ 809 IOReturn status = kIOReturnSuccess; 810 int i = 0; 811 812 if(fAsyncStreamTxCmdPool == NULL) 813 fAsyncStreamTxCmdPool = IOCommandPool::withWorkLoop(workLoop); 814 815 IOFWIPAsyncStreamTxCommand *cmd2 = NULL; 816 817 for(i=0; i<=kMaxAsyncStreamCommands; i++){ 818 819 // Create a IP Async write command 820 cmd2 = new IOFWIPAsyncStreamTxCommand; 821 if(!cmd2) { 822 status = kIOReturnNoMemory; 823 break; 824 } 825 826 // Initialize the write command 827 if(!cmd2->initAll(fIPLocalNode, fControl, this, 0, 0, 0, GASP_TAG, fMaxTxAsyncDoubleBuffer, 828 kFWSpeed100MBit, txCompleteAsyncStream, this)) { 829 status = kIOReturnNoMemory; 830 cmd2->release(); 831 break; 832 } 833 834 // Queue the command in the command pool 835 fAsyncStreamTxCmdPool->returnCommand(cmd2); 836 fAsyncStreamTransitSet->setObject(cmd2); 837 } 838 839 return status; 840} 841 842 843/*! 844 @function freeIPCmdPool 845 @abstract frees both Async and AsyncStream command objects from the pool 846 @param none. 847 @result void. 848*/ 849void IOFWIPBusInterface::freeAsyncCmdPool() 850{ 851 IOFWIPAsyncWriteCommand *cmd1 = NULL; 852 UInt32 freeCount = 0; 853 854 if(fAsyncCmdPool == NULL) 855 return; 856 857 // Should block till all outstanding commands are freed 858 do 859 { 860 cmd1 = (IOFWIPAsyncWriteCommand*)fAsyncCmdPool->getCommand(false); 861 if(cmd1 != NULL) 862 { 863 freeCount++; 864 // release the command 865 cmd1->release(); 866 } 867 }while(cmd1 != NULL); 868 869 fAsyncCmdPool->release(); 870 fAsyncCmdPool = NULL; 871} 872 873/*! 874 @function freeIPCmdPool 875 @abstract frees both Async and AsyncStream command objects from the pool 876 @param none. 877 @result void. 878*/ 879void IOFWIPBusInterface::freeAsyncStreamCmdPool() 880{ 881 if(fAsyncStreamTxCmdPool == NULL) 882 return; 883 884 IOFWIPAsyncStreamTxCommand *cmd2 = NULL; 885 UInt32 freeCount = 0; 886 887 // Should block till all outstanding commands are freed 888 do{ 889 cmd2 = (IOFWIPAsyncStreamTxCommand*)fAsyncStreamTxCmdPool->getCommand(false); 890 if(cmd2 != NULL) 891 { 892 freeCount++; 893 // release the command 894 cmd2->release(); 895 } 896 }while(cmd2 != NULL); 897 898 fAsyncStreamTxCmdPool->release(); 899 fAsyncStreamTxCmdPool = NULL; 900 901 return; 902} 903 904IOUpdateARPCache IOFWIPBusInterface::getARPCacheHandler() const 905{ 906 return (IOUpdateARPCache) &IOFWIPBusInterface::staticUpdateARPCache; 907} 908 909IOUpdateMulticastCache IOFWIPBusInterface::getMulticastCacheHandler() const 910{ 911 return (IOUpdateMulticastCache) &IOFWIPBusInterface::staticUpdateMulticastCache; 912} 913 914IOTransmitPacket IOFWIPBusInterface::getOutputHandler() const 915{ 916 return (IOTransmitPacket) &IOFWIPBusInterface::staticOutputPacket; 917} 918 919/*! 920 @function initDRBwithDevice 921 @abstract create device reference block for a device object. 922 @param lcb - the firewire link control block for this interface. 923 @param eui64 - global unique id of a device on the bus. 924 @param fDevObj - IOFireWireNub that has to be linked with the device reference block. 925 @param itsMac - Indicates whether the destination is Macintosh or not. 926 @result DRB* - pointer to the device reference block. 927*/ 928DRB *IOFWIPBusInterface::initDRBwithDevice(UWIDE eui64, IOFireWireNub *device, bool itsMac) 929{ 930 recursiveScopeLock lock(fIPLock); 931 932 DRB *drb = getDrbFromEui64(eui64); 933 934 if(not drb) 935 { 936 if ((drb = new DRB) == NULL) 937 return NULL; 938 } 939 940 CSRNodeUniqueID fwuid = device->getUniqueID(); 941 if(itsMac) 942 fIPLocalNode->makeEthernetAddress(&fwuid, drb->fwaddr, GUID_TYPE); 943 else 944 fIPLocalNode->getBytesFromGUID((void*)(&fwuid), drb->fwaddr, GUID_TYPE); 945 946 drb->deviceID = (void*)device; 947 drb->eui64 = eui64; 948 drb->itsMac = itsMac; 949 drb->maxSpeed = kFWSpeed100MBit; 950 drb->maxSpeed = device->FWSpeed(); 951 drb->maxPayload = device->maxPackLog(true); 952 953 activeDrb->setObject(drb); 954 955 return drb; 956} 957 958/*! 959 @function getMTU 960 @abstract returns the MTU (Max Transmission Unit) supported by the IOFireWireIP. 961 @param None. 962 @result UInt32 - MTU value. 963*/ 964UInt32 IOFWIPBusInterface::getMTU() 965{ 966 return FIREWIRE_MTU; 967} 968 969UInt32 IOFWIPBusInterface::outputPacket(mbuf_t pkt, void * param) 970{ 971 register struct firewire_header *fwh; 972 int status = kIOReturnError; 973 974 fwh = (struct firewire_header*)mbuf_data(pkt); 975 976 switch(htons(fwh->fw_type)) 977 { 978 case FWTYPE_IPV6: 979 addNDPOptions(pkt); 980 status = txIP(pkt, fLcb->ownNodeID, fLcb->busGeneration, fLcb->ownMaxPayload, fLcb->maxBroadcastPayload, fLcb->maxBroadcastSpeed, FWTYPE_IPV6); 981 break; 982 983 case FWTYPE_IP: 984 status = txIP(pkt, fLcb->ownNodeID, fLcb->busGeneration, fLcb->ownMaxPayload, fLcb->maxBroadcastPayload, fLcb->maxBroadcastSpeed, FWTYPE_IP); 985 break; 986 987 case FWTYPE_ARP: 988 status = txARP(pkt, fLcb->ownNodeID, fLcb->busGeneration, fLcb->maxBroadcastSpeed); 989 break; 990 991 default : 992 fIPLocalNode->freePacket(pkt); 993 break; 994 } 995 996 if(status == kIOFireWireOutOfTLabels) 997 { 998 status = kIOReturnOutputStall; 999 1000 if((fIPLocalNode->fIPoFWDiagnostics.fActiveCmds - fIPLocalNode->fIPoFWDiagnostics.fInActiveCmds) <= 1) 1001 fIPLocalNode->fIPoFWDiagnostics.fServiceInOutput++; 1002 1003 if((fIPLocalNode->transmitQueue->getSize() > fIPLocalNode->fIPoFWDiagnostics.fMaxQueueSize) 1004 || ((fIPLocalNode->fIPoFWDiagnostics.fActiveCmds - fIPLocalNode->fIPoFWDiagnostics.fInActiveCmds) <= 1)) 1005 { 1006 // So far, too many stalls. Sink the packets, till we have manageable queue 1007 fIPLocalNode->freePacket(pkt); 1008 fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors); 1009 status = kIOReturnOutputDropped; 1010 } 1011 } 1012 else 1013 status = kIOReturnOutputSuccess; 1014 1015 return status; 1016} 1017 1018/*! 1019 @function txComplete 1020 @abstract Callback for the Async write complete 1021 @param refcon - callback data. 1022 @param status - status of the command. 1023 @param device - device that the command was send to. 1024 @param fwCmd - command object which generated the transaction. 1025 @result void. 1026*/ 1027void IOFWIPBusInterface::txCompleteBlockWrite(void *refcon, IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd) 1028{ 1029 IOFWIPBusInterface *fwIPPriv = (IOFWIPBusInterface*)refcon; 1030 1031 if(not fwIPPriv) 1032 return; 1033 1034 IOFireWireIP *fwIPObject = OSDynamicCast(IOFireWireIP, fwIPPriv->fIPLocalNode); 1035 1036 if(not fwIPObject) 1037 return; 1038 1039 IOFWIPAsyncWriteCommand *cmd = OSDynamicCast(IOFWIPAsyncWriteCommand, fwCmd); 1040 1041 if(not cmd) 1042 return; 1043 1044 // Only in case of kIOFireWireOutOfTLabels, we ignore freeing of Mbuf 1045 if(status == kIOReturnSuccess) 1046 { 1047 // We get callback 1 packet at a time, so we can increment by 1 1048 fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->outputPackets); 1049 fwIPObject->fIPoFWDiagnostics.fTxUni++; 1050 } 1051 else 1052 { 1053 // Increment error output packets 1054 fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->outputErrors); 1055 fwIPObject->fIPoFWDiagnostics.fCallErrs++; 1056 } 1057 1058 cmd->resetDescriptor(status); 1059 1060 fwIPPriv->returnAsyncCommand(cmd); 1061 1062 if ( (fwIPObject->fIPoFWDiagnostics.fActiveCmds - fwIPObject->fIPoFWDiagnostics.fInActiveCmds) <= fwIPPriv->fLowWaterMark ) 1063 { 1064 fwIPObject->transmitQueue->service( IOBasicOutputQueue::kServiceAsync ); 1065 fwIPObject->fIPoFWDiagnostics.fServiceInCallback++; 1066 } 1067 1068 return; 1069} 1070 1071/*! 1072 @function txAsyncStreamComplete 1073 @abstract Callback for the Async stream transmit complete 1074 @param refcon - callback 1075 @param status - status of the command. 1076 @param bus information. 1077 @param fwCmd - command object which generated the transaction. 1078 @result void. 1079*/ 1080void IOFWIPBusInterface::txCompleteAsyncStream(void *refcon, IOReturn status, 1081 IOFireWireBus *bus, IOFWAsyncStreamCommand *fwCmd) 1082{ 1083 IOFWIPBusInterface *fwIPPriv = (IOFWIPBusInterface*)refcon; 1084 1085 if(not fwIPPriv) 1086 return; 1087 1088 IOFireWireIP *fwIPObject = OSDynamicCast(IOFireWireIP, fwIPPriv->fIPLocalNode); 1089 1090 if(not fwIPObject) 1091 return; 1092 1093 IOFWIPAsyncStreamTxCommand *cmd = OSDynamicCast(IOFWIPAsyncStreamTxCommand, fwCmd); 1094 1095 if(not cmd) 1096 return; 1097 1098 if(status == kIOReturnSuccess) 1099 { 1100 fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->outputPackets); 1101 fwIPObject->fIPoFWDiagnostics.fTxBcast++; 1102 } 1103 else 1104 fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->outputErrors); 1105 1106 if(fwIPPriv->fAsyncStreamTxCmdPool != NULL) // Queue the command back into the command pool 1107 { 1108 fwIPPriv->fAsyncStreamTxCmdPool->returnCommand(cmd); 1109 fwIPObject->fIPoFWDiagnostics.fInActiveBcastCmds++; 1110 } 1111 1112 return; 1113} 1114 1115/*! 1116 @function txARP 1117 @abstract Transmit ARP request or response. 1118 @param m - mbuf containing the ARP packet. 1119 @result void. 1120*/ 1121SInt32 IOFWIPBusInterface::txARP(mbuf_t m, UInt16 nodeID, UInt32 busGeneration, IOFWSpeed speed) 1122{ 1123 IOReturn status = kIOReturnSuccess; 1124 1125 if(fAsyncStreamTxCmdPool == NULL) 1126 status = initAsyncStreamCmdPool(); 1127 1128 // Get an async command from the command pool 1129 IOFWIPAsyncStreamTxCommand *cmd = (IOFWIPAsyncStreamTxCommand*)fAsyncStreamTxCmdPool->getCommand(false); 1130 1131 // Lets not block to get a command, IP may retry soon ..:) 1132 if(cmd == NULL) 1133 { 1134 // Error, so we touch the error output packets 1135 fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors); 1136 fIPLocalNode->fIPoFWDiagnostics.fNoBCastCommands++; 1137 return status; 1138 } 1139 1140 fIPLocalNode->fIPoFWDiagnostics.fActiveBcastCmds++; 1141 1142 IORecursiveLockLock(fIPLock); 1143 1144 mbuf_t n = m; 1145 1146 // Get the buffer pointer from the command pool 1147 UInt8 *buf = (UInt8*)cmd->getBufferFromDesc(); 1148 UInt32 dstBufLen = cmd->getMaxBufLen(); 1149 1150 UInt32 offset = sizeof(struct firewire_header); 1151 UInt32 cmdLen = mbuf_pkthdr_len(m) - offset; 1152 1153 // Construct the GASP_HDR and Unfragment header 1154 struct arp_packet *fwa_pkt = (struct arp_packet*)(buf); 1155 bzero((caddr_t)fwa_pkt, sizeof(*fwa_pkt)); 1156 1157 // Fill the GASP fields 1158 fwa_pkt->gaspHdr.sourceID = htons(nodeID); 1159 memcpy(&fwa_pkt->gaspHdr.gaspID, &gaspVal, sizeof(GASP_ID)); 1160 1161 // Set the unfragmented header information 1162 fwa_pkt->ip1394Hdr.etherType = htons(FWTYPE_ARP); 1163 // Modify the buffer pointer 1164 buf += (sizeof(GASP_HDR) + sizeof(IP1394_UNFRAG_HDR)); 1165 // Copy the arp packet into the buffer 1166 mbufTobuffer(n, &offset, (vm_address_t*)buf, dstBufLen, cmdLen); 1167 // Update the length to have the GASP and IP1394 Header 1168 cmdLen += (sizeof(GASP_HDR) + sizeof(IP1394_UNFRAG_HDR)); 1169 1170 // Initialize the command with new values of device object 1171 status = cmd->reinit( busGeneration, 1172 DEFAULT_BROADCAST_CHANNEL, 1173 cmdLen, 1174 speed, 1175 txCompleteAsyncStream, 1176 this); 1177 1178 if(status == kIOReturnSuccess) 1179 status = cmd->submit(); 1180 else 1181 { 1182 fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors); 1183 fAsyncStreamTxCmdPool->returnCommand(cmd); 1184 fIPLocalNode->fIPoFWDiagnostics.fInActiveBcastCmds++; 1185 } 1186 1187 if(status != kIOReturnSuccess) 1188 fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors); 1189 1190 fIPLocalNode->freePacket(m); 1191 1192 IORecursiveLockUnlock(fIPLock); 1193 1194 return status; 1195} 1196 1197SInt32 IOFWIPBusInterface::txBroadcastIP(const mbuf_t m, UInt16 nodeID, UInt32 busGeneration, 1198 UInt16 ownMaxPayload, UInt16 maxBroadcastPayload, 1199 IOFWSpeed speed, const UInt16 type, UInt32 channel) 1200{ 1201 UInt16 datagramSize = mbuf_pkthdr_len(m) - sizeof(struct firewire_header); 1202 1203 UInt16 maxPayload = MIN((UInt16)1 << maxBroadcastPayload, (UInt16)1 << ownMaxPayload); 1204 1205 if( maxPayload < fOptimalMTU || fOptimalMTU == 0 ) 1206 { 1207 fOptimalMTU = maxPayload; 1208 fIPLocalNode->networkInterface->setIfnetMTU( MAX(fOptimalMTU, 1500) ); 1209 fIPLocalNode->fIPoFWDiagnostics.fMaxPacketSize = fOptimalMTU; 1210 } 1211 1212 IOReturn status = ENOBUFS; 1213 // Asynchronous stream datagrams are never fragmented! 1214 if (datagramSize + sizeof(IP1394_UNFRAG_HDR) > maxPayload) 1215 { 1216 fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors); 1217 fIPLocalNode->freePacket(m); 1218 return status; 1219 } 1220 1221 // create a command pool on demand 1222 if(fAsyncStreamTxCmdPool == NULL) 1223 initAsyncStreamCmdPool(); 1224 1225 // Get an async command from the command pool 1226 IOFWIPAsyncStreamTxCommand *asyncStreamCmd = (IOFWIPAsyncStreamTxCommand*)fAsyncStreamTxCmdPool->getCommand(false); 1227 1228 // Lets not block to get a command, IP may retry soon ..:) 1229 if(asyncStreamCmd == NULL) 1230 { 1231 fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors); 1232 fIPLocalNode->freePacket(m); 1233 fIPLocalNode->fIPoFWDiagnostics.fNoBCastCommands++; 1234 return status; 1235 } 1236 1237 fIPLocalNode->fIPoFWDiagnostics.fActiveBcastCmds++; 1238 1239 IORecursiveLockLock(fIPLock); 1240 1241 // Get the buffer pointer from the command pool 1242 UInt8 *buf = (UInt8*)asyncStreamCmd->getBufferFromDesc(); 1243 UInt32 dstBufLen = asyncStreamCmd->getMaxBufLen(); 1244 1245 // Get it assigned to the header 1246 GASP_HDR *gaspHdr = (GASP_HDR *)buf; 1247 gaspHdr->sourceID = htons(nodeID); 1248 memcpy(&gaspHdr->gaspID, &gaspVal, sizeof(GASP_ID)); 1249 1250 IP1394_ENCAP_HDR *ip1394Hdr = (IP1394_ENCAP_HDR*)((UInt8*)buf + sizeof(GASP_HDR)); 1251 ip1394Hdr->singleFragment.etherType = htons(type); 1252 ip1394Hdr->singleFragment.reserved = htons(UNFRAGMENTED); 1253 1254 UInt32 cmdLen = datagramSize; 1255 UInt32 offset = sizeof(struct firewire_header); 1256 UInt16 headerSize = sizeof(GASP_HDR) + sizeof(IP1394_UNFRAG_HDR); 1257 1258 // Increment the buffer pointer for the unfrag or frag header 1259 buf += headerSize; 1260 1261 mbufTobuffer(m, &offset, (vm_address_t*)buf, dstBufLen, cmdLen); 1262 1263 cmdLen += headerSize; 1264 1265 // Initialize the command with new values of device object 1266 status = asyncStreamCmd->reinit(busGeneration, channel, 1267 cmdLen, speed, txCompleteAsyncStream, this); 1268 1269 if(status == kIOReturnSuccess) 1270 status = asyncStreamCmd->submit(); 1271 else 1272 { 1273 fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors); 1274 fAsyncStreamTxCmdPool->returnCommand(asyncStreamCmd); 1275 fIPLocalNode->fIPoFWDiagnostics.fInActiveBcastCmds++; 1276 } 1277 1278 if(status != kIOReturnSuccess) 1279 fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors); 1280 1281 fIPLocalNode->freePacket(m); 1282 1283 IORecursiveLockUnlock(fIPLock); 1284 1285 return status; 1286} 1287 1288SInt32 IOFWIPBusInterface::txUnicastUnFragmented(IOFireWireNub *device, const FWAddress addr, const mbuf_t m, const UInt16 pktSize, const UInt16 type) 1289{ 1290 SInt32 status = kIOReturnSuccess; 1291 1292 bool deferNotify = true; 1293 1294 IOFWIPMBufCommand * mBufCommand = getMBufCommand(); 1295 1296 if( not mBufCommand ) 1297 { 1298 fIPLocalNode->freePacket(m); 1299 fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors); 1300 return status; 1301 } 1302 1303 mBufCommand->reinit(m, fIPLocalNode, fMbufCmdPool); 1304 1305 IOFWIPAsyncWriteCommand *cmd = getAsyncCommand(false, &deferNotify); // Get an async command from the command pool 1306 1307 mBufCommand->retain(); 1308 1309 // Lets not block to get a command, IP may retry soon ..:) 1310 if(cmd) 1311 { 1312 // All done in one gulp! 1313 IP1394_ENCAP_HDR *ip1394Hdr = (IP1394_ENCAP_HDR*)cmd->initPacketHeader(mBufCommand, kCopyBuffers, UNFRAGMENTED, 1314 sizeof(IP1394_UNFRAG_HDR), 1315 sizeof(struct firewire_header)); 1316 ip1394Hdr->fragment.datagramSize = htons(UNFRAGMENTED); 1317 ip1394Hdr->singleFragment.etherType = htons(type); 1318 ip1394Hdr->singleFragment.reserved = 0; 1319 1320 status = cmd->transmit (device, pktSize, addr, txCompleteBlockWrite, this, true, 1321 deferNotify, kQueueCommands); 1322 1323 } 1324 1325 mBufCommand->releaseWithStatus(status); 1326 1327 if( status != kIOFireWireOutOfTLabels ) 1328 fIPLocalNode->fIPoFWDiagnostics.activeMbufs++; 1329 1330 return status; 1331} 1332 1333SInt32 IOFWIPBusInterface::txUnicastFragmented(IOFireWireNub *device, const FWAddress addr, const mbuf_t m, 1334 const UInt16 pktSize, const UInt16 type, UInt16 maxPayload, UInt16 dgl) 1335{ 1336 UInt32 residual = pktSize; 1337 UInt32 fragmentOffset = 0; 1338 UInt32 offset = sizeof(struct firewire_header); 1339 SInt32 status = kIOReturnSuccess; 1340 bool deferNotify = true; 1341 1342 IOFWIPMBufCommand * mBufCommand = getMBufCommand(); 1343 1344 if( not mBufCommand ) 1345 { 1346 fIPLocalNode->freePacket(m); 1347 fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors); 1348 return status; 1349 } 1350 1351 mBufCommand->reinit(m, fIPLocalNode, fMbufCmdPool); 1352 mBufCommand->retain(); 1353 1354 while (residual) 1355 { 1356 deferNotify = true; 1357 status = kIOReturnSuccess; 1358 1359 IOFWIPAsyncWriteCommand *cmd = getAsyncCommand(false, &deferNotify); // Get an async command from the command pool 1360 1361 // Lets not block to get a command, IP may retry soon ..:) 1362 if(not cmd) 1363 break; 1364 1365 // false - don't copy , if true - copy the packets 1366 fIPLocalNode->fIPoFWDiagnostics.fTxFragmentPkts++; 1367 FragmentType fragmentType = FIRST_FRAGMENT; 1368 1369 IP1394_ENCAP_HDR *ip1394Hdr = (IP1394_ENCAP_HDR*)cmd->initPacketHeader(mBufCommand, kCopyBuffers, fragmentType, 1370 sizeof(IP1394_FRAG_HDR), 1371 offset); 1372 1373 // Distinguish first, interior and last fragments 1374 UInt32 cmdLen = MIN(residual, maxPayload - sizeof(IP1394_FRAG_HDR)); 1375 1376 ip1394Hdr->fragment.datagramSize = htons(pktSize - 1); 1377 1378 if (fragmentOffset == 0) 1379 ip1394Hdr->singleFragment.etherType = htons(type); 1380 else 1381 { 1382 ip1394Hdr->fragment.fragmentOffset = htons(fragmentOffset); 1383 fragmentType = (cmdLen < residual) ? INTERIOR_FRAGMENT : LAST_FRAGMENT; 1384 } 1385 1386 // Get your datagram labels correct 1387 ip1394Hdr->fragment.datagramSize |= htons(fragmentType << 14); 1388 ip1394Hdr->fragment.dgl = htons(dgl); 1389 ip1394Hdr->fragment.reserved = 0; 1390 1391 status = cmd->transmit (device, cmdLen, addr, txCompleteBlockWrite, this, true, 1392 deferNotify, kQueueCommands, fragmentType); 1393 1394 if(status != kIOReturnSuccess) 1395 break; 1396 1397 fragmentOffset += cmdLen; // Account for the position and... 1398 offset += cmdLen; 1399 residual -= cmdLen; // ...size of the fragment just sent 1400 } 1401 1402 mBufCommand->releaseWithStatus(status); 1403 1404 if( status != kIOFireWireOutOfTLabels ) 1405 fIPLocalNode->fIPoFWDiagnostics.activeMbufs++; 1406 1407 return status; 1408} 1409 1410SInt32 IOFWIPBusInterface::txUnicastIP(mbuf_t m, UInt16 nodeID, UInt32 busGeneration, UInt16 ownMaxPayload, IOFWSpeed speed, const UInt16 type) 1411{ 1412 struct firewire_header *fwh = (struct firewire_header *)mbuf_data(m); 1413 1414 IORecursiveLockLock(fIPLock); 1415 1416 ARB *arb = getArbFromFwAddr(fwh->fw_dhost); 1417 1418 SInt32 status = EHOSTUNREACH; 1419 1420 if(arb == NULL) 1421 { 1422 fIPLocalNode->freePacket(m); 1423 fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors); 1424 IORecursiveLockUnlock(fIPLock); 1425 return status; 1426 } 1427 1428 TNF_HANDLE *handle = &arb->handle; 1429 IOFireWireNub *device = OSDynamicCast(IOFireWireNub, (IOFireWireNub*)handle->unicast.deviceID); 1430 1431 // Node had disappeared, but entry exists for specified timer value 1432 if(device == NULL) 1433 { 1434 fIPLocalNode->freePacket(m); 1435 fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors); 1436 IORecursiveLockUnlock(fIPLock); 1437 return status; 1438 } 1439 1440 // Get the actual length of the packet from the mbuf 1441 UInt16 datagramSize = mbuf_pkthdr_len(m) - sizeof(struct firewire_header); 1442 UInt16 residual = datagramSize; 1443 1444 // setup block write 1445 FWAddress addr; 1446 addr.addressHi = handle->unicast.unicastFifoHi; 1447 addr.addressLo = handle->unicast.unicastFifoLo; 1448 1449 // Calculate the payload and further down will decide the fragmentation based on that 1450 UInt32 drbMaxPayload = 1 << device->maxPackLog(true, addr); 1451 1452 UInt32 maxPayload = MIN((UInt32)1 << (handle->unicast.maxRec+1), (UInt32)1 << fLcb->ownMaxPayload); 1453 maxPayload = MIN(drbMaxPayload, maxPayload); 1454 1455 if( maxPayload < fOptimalMTU || fOptimalMTU == 0 ) 1456 { 1457 fOptimalMTU = maxPayload; 1458 fIPLocalNode->networkInterface->setIfnetMTU( MAX(fOptimalMTU, 1500) ); 1459 fIPLocalNode->fIPoFWDiagnostics.fMaxPacketSize = fOptimalMTU; 1460 } 1461 1462 UInt16 dgl = 0; 1463 bool unfragmented = false; 1464 // Only fragments use datagram label 1465 if (!(unfragmented = ((datagramSize + sizeof(IP1394_UNFRAG_HDR)) <= maxPayload))) 1466 dgl = fLcb->datagramLabel++; 1467 1468 if (unfragmented) 1469 status = txUnicastUnFragmented(device, addr, m, residual, type); 1470 else 1471 status = txUnicastFragmented(device, addr, m, residual, type, maxPayload, dgl); 1472 1473 IORecursiveLockUnlock(fIPLock); 1474 1475 return status; 1476} 1477 1478/*! 1479 @function txIP 1480 @abstract Transmit IP packet. 1481 @param m - mbuf containing the IP packet. 1482 @param type - type of the packet (IPv6 or IPv4). 1483 @result void. 1484*/ 1485SInt32 IOFWIPBusInterface::txIP(mbuf_t m, UInt16 nodeID, UInt32 busGeneration, UInt16 ownMaxPayload, UInt16 maxBroadcastPayload, IOFWSpeed speed, UInt16 type) 1486{ 1487 // If its not a packet header 1488 if(not (mbuf_flags(m) & MBUF_PKTHDR)) 1489 { 1490 fIPLocalNode->freePacket(m); 1491 fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors); 1492 return kIOReturnError; 1493 } 1494 1495 SInt32 status = kIOReturnSuccess; 1496 1497 struct firewire_header *fwh = (struct firewire_header *)mbuf_data(m); 1498 1499 if( ( bcmp(fwh->fw_dhost, fwbroadcastaddr, kIOFWAddressSize) == 0 ) 1500 or ( bcmp(fwh->fw_dhost, ipv4multicast, FIREWIREMCAST_V4_LEN) == 0 ) 1501 or ( bcmp(fwh->fw_dhost, ipv6multicast, FIREWIREMCAST_V6_LEN) == 0 ) ) 1502 status = txBroadcastIP(m, nodeID, busGeneration, ownMaxPayload, maxBroadcastPayload, speed, type, DEFAULT_BROADCAST_CHANNEL); 1503 else 1504 status = txUnicastIP(m, nodeID, busGeneration, ownMaxPayload, speed, type); 1505 1506 return status; 1507} 1508 1509/*! 1510 @function txMCAP 1511 @abstract This procedure transmits either an MCAP solicitation or advertisement on the 1512 default broadcast channel, dependent upon whether or not an MCB is supplied. 1513 If more than one multicast address group is associated with a particular channel 1514 that many multiple MCAP group descriptors are created. 1515 @param mcb - multicast control block. 1516 @param groupAddress - group address. 1517 @result void. 1518*/ 1519void IOFWIPBusInterface::txMCAP(MCB *mcb, UInt32 groupAddress) 1520{ 1521 if(fAsyncStreamTxCmdPool == NULL) 1522 initAsyncStreamCmdPool(); 1523 1524 // Get an async command from the command pool 1525 IOFWIPAsyncStreamTxCommand *asyncStreamCmd = (IOFWIPAsyncStreamTxCommand*)fAsyncStreamTxCmdPool->getCommand(false); 1526 1527 // Lets not block to get a command, IP may retry soon ..:) 1528 if(asyncStreamCmd == NULL) 1529 { 1530 fIPLocalNode->fIPoFWDiagnostics.fNoBCastCommands++; 1531 return; 1532 } 1533 1534 fIPLocalNode->fIPoFWDiagnostics.fActiveBcastCmds++; 1535 1536 // Get the buffer pointer from the command pool 1537 struct mcap_packet *packet = (struct mcap_packet*)asyncStreamCmd->getBufferFromDesc(); 1538 1539 memset(packet, 0, sizeof(*packet)); 1540 packet->gaspHdr.sourceID = htons(fLcb->ownNodeID); 1541 1542 memcpy(&packet->gaspHdr.gaspID, &gaspVal, sizeof(GASP_ID)); 1543 packet->ip1394Hdr.etherType = htons(ETHER_TYPE_MCAP); 1544 packet->mcap.length = sizeof(*packet); 1545 MCAST_DESCR *groupDescriptor = packet->mcap.groupDescr; 1546 1547 if (mcb != NULL) 1548 { 1549 MARB *arb = NULL; 1550 1551 packet->mcap.opcode = MCAP_ADVERTISE; 1552 1553 IORecursiveLockLock(fIPLock); 1554 1555 OSCollectionIterator * iterator = OSCollectionIterator::withCollection( multicastArb ); 1556 if( iterator ) 1557 { 1558 while( NULL != (arb = OSDynamicCast(MARB, iterator->getNextObject())) ) 1559 { 1560 if (arb->handle.multicast.channel == mcb->channel) 1561 { 1562 memset(groupDescriptor, 0, sizeof(MCAST_DESCR)); 1563 groupDescriptor->length = sizeof(MCAST_DESCR); 1564 groupDescriptor->type = MCAST_TYPE; 1565 groupDescriptor->expiration = mcb->expiration; 1566 groupDescriptor->channel = mcb->channel; 1567 groupDescriptor->speed = arb->handle.multicast.spd; 1568 groupDescriptor->groupAddress = arb->handle.multicast.groupAddress; 1569 1570 groupDescriptor = (MCAST_DESCR*)((UInt64)groupDescriptor + sizeof(MCAST_DESCR)); 1571 packet->mcap.length += sizeof(MCAST_DESCR); 1572 } 1573 } 1574 iterator->release(); 1575 } 1576 1577 IORecursiveLockUnlock(fIPLock); 1578 } 1579 else 1580 { 1581 memset(groupDescriptor, 0, sizeof(MCAST_DESCR)); 1582 packet->mcap.opcode = MCAP_SOLICIT; 1583 packet->mcap.length += sizeof(MCAST_DESCR); 1584 groupDescriptor->length = sizeof(MCAST_DESCR); 1585 groupDescriptor->type = MCAST_TYPE; 1586 groupDescriptor->groupAddress = groupAddress; 1587 } 1588 1589 UInt32 cmdLen = packet->mcap.length; // In CPU byte order 1590 packet->mcap.length = htons(cmdLen); // Serial Bus order 1591 1592 // Initialize the command with new values of device object 1593 IOReturn status = asyncStreamCmd->reinit ( fLcb->busGeneration, 1594 DEFAULT_BROADCAST_CHANNEL, 1595 cmdLen, 1596 fLcb->maxBroadcastSpeed, 1597 txCompleteAsyncStream, 1598 this); 1599 1600 if(status == kIOReturnSuccess) 1601 status = asyncStreamCmd->submit(); 1602 else 1603 { 1604 fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors); 1605 fAsyncStreamTxCmdPool->returnCommand(asyncStreamCmd); 1606 fIPLocalNode->fIPoFWDiagnostics.fInActiveBcastCmds++; 1607 } 1608 1609 if(status != kIOReturnSuccess) 1610 fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors); 1611} 1612 1613/*! 1614 @function rxUnicastFlush 1615 @abstract Starts the batch processing of the packets, its 1616 already on its own workloop. 1617*/ 1618void IOFWIPBusInterface::rxUnicastFlush() 1619{ 1620 UInt32 count = 0; 1621 1622 IORecursiveLockLock(fIPLock); 1623 1624 if(fIPLocalNode->fPacketsQueued == true) 1625 { 1626 count = fIPLocalNode->networkInterface->flushInputQueue(); 1627 if(count > fIPLocalNode->fIPoFWDiagnostics.fMaxInputCount) 1628 fIPLocalNode->fIPoFWDiagnostics.fMaxInputCount = count; 1629 1630 fIPLocalNode->fPacketsQueued = false; 1631 } 1632 1633 IORecursiveLockUnlock(fIPLock); 1634 1635 return; 1636} 1637 1638/*! 1639 @function rxUnicastComplete 1640 @abstract triggers the indication workloop to do batch processing 1641 of incoming packets. 1642*/ 1643void IOFWIPBusInterface::rxUnicastComplete(void *refcon) 1644{ 1645 IOFWIPBusInterface *fwIPPriv = (IOFWIPBusInterface*)refcon; 1646 1647 fwIPPriv->rxUnicastFlush(); 1648 1649 return; 1650} 1651 1652/*! 1653 @function rxUnicast 1654 @abstract block write handler. Handles both ARP and IP packet. 1655*/ 1656UInt32 IOFWIPBusInterface::rxUnicast( void *refcon, 1657 UInt16 nodeID, 1658 IOFWSpeed &speed, 1659 FWAddress addr, 1660 UInt32 len, 1661 const void *buf, 1662 IOFWRequestRefCon requestRefcon) 1663{ 1664 IOFWIPBusInterface *fwIPPriv = (IOFWIPBusInterface*)refcon; 1665 IOFireWireIP *fwIPObject = OSDynamicCast(IOFireWireIP, fwIPPriv->fIPLocalNode); 1666 IP1394_UNFRAG_HDR *ip1394Hdr = (IP1394_UNFRAG_HDR *)buf; 1667 1668 if(not fwIPPriv->fStarted) 1669 return kIOReturnSuccess; 1670 1671 UInt8 lf = (htons(ip1394Hdr->reserved) >> 14); 1672 // Handle the unfragmented packet 1673 if (lf == UNFRAGMENTED) 1674 { 1675 void *datagram = (void *) ((UInt64) ip1394Hdr + sizeof(IP1394_UNFRAG_HDR)); 1676 UInt16 datagramSize = len - sizeof(IP1394_UNFRAG_HDR); 1677 UInt16 type = ntohs(ip1394Hdr->etherType); 1678 1679 switch (type) 1680 { 1681 case FWTYPE_IPV6: 1682 case FWTYPE_IP: 1683 if (datagramSize >= IPV4_HDR_SIZE && datagramSize <= FIREWIRE_MTU) 1684 fwIPPriv->rxIP(datagram, datagramSize, FW_M_UCAST, type); 1685 break; 1686 1687 case FWTYPE_ARP: 1688 if (datagramSize >= sizeof(IP1394_ARP) && datagramSize <= FIREWIRE_MTU) 1689 fwIPPriv->rxARP((IP1394_ARP*)datagram, FW_M_UCAST); 1690 break; 1691 1692 default : 1693 // Unknown packet type 1694 fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->inputErrors); 1695 break; 1696 } 1697 } 1698 else 1699 { 1700 fwIPObject->fIPoFWDiagnostics.fRxFragmentPkts++; 1701 1702 if(fwIPPriv->rxFragmentedUnicast(nodeID, (IP1394_FRAG_HDR*)ip1394Hdr, len) == kIOReturnError) 1703 fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->inputErrors); 1704 } 1705 1706 fwIPObject->fIPoFWDiagnostics.fRxUni++; 1707 1708 return kIOReturnSuccess; 1709} 1710 1711IOReturn IOFWIPBusInterface::rxFragmentedUnicast(UInt16 nodeID, IP1394_FRAG_HDR *pkt, UInt32 len) 1712{ 1713 IP1394_FRAG_HDR *fragmentHdr = (IP1394_FRAG_HDR*) pkt; // Different header layout 1714 void *fragment = (void *) ((UInt64) fragmentHdr + sizeof(IP1394_FRAG_HDR)); 1715 UInt16 fragmentSize = len - sizeof(IP1394_FRAG_HDR); 1716 1717 UInt8 lf = htons(fragmentHdr->datagramSize) >> 14; 1718 UInt16 datagramSize = (htons(fragmentHdr->datagramSize) & 0x3FFF) + 1; 1719 UInt16 label = htons(fragmentHdr->dgl); 1720 1721 if(datagramSize > FIREWIRE_MTU) 1722 return kIOReturnError; 1723 1724 recursiveScopeLock lock(fIPLock); 1725 1726 IOReturn result = kIOReturnSuccess; 1727 UInt16 fragmentOffset = htons(fragmentHdr->fragmentOffset); 1728 1729 RCB *rcb = getRcb(nodeID, label); 1730 1731 if (rcb == NULL) 1732 { 1733 if (lf == FIRST_FRAGMENT) 1734 { 1735 mbuf_t rxMBuf = (mbuf_t)allocateMbuf(datagramSize + sizeof(firewire_header)); 1736 1737 if (rxMBuf == NULL) 1738 { 1739 fIPLocalNode->fIPoFWDiagnostics.fNoMbufs++; 1740 return kIOReturnError; 1741 } 1742 1743 if ((rcb = getRCBCommand( nodeID, label, fragmentOffset, datagramSize, rxMBuf )) == NULL) 1744 { 1745 fIPLocalNode->fIPoFWDiagnostics.fNoRCBCommands++; 1746 cleanRCBCache(); 1747 fIPLocalNode->freePacket(rxMBuf, 0); 1748 return kIOReturnError; 1749 } 1750 1751 // Make space for the firewire header to be helpfull in firewire_demux 1752 struct firewire_header *fwh = (struct firewire_header *)mbuf_data(rxMBuf); 1753 bzero(fwh, sizeof(struct firewire_header)); 1754 // when indicating to the top layer 1755 // JLIU - fragmentHdr already in network order, do not swap fragmentOffset 1756 fwh->fw_type = fragmentHdr->fragmentOffset; 1757 rcb->residual = rcb->datagramSize; 1758 1759 activeRcb->setObject(rcb); 1760 fragmentOffset = 0; 1761 } 1762 else 1763 result = kIOReturnError; 1764 } 1765 1766 if( result == kIOReturnSuccess ) 1767 { 1768 UInt16 amountToCopy = MIN(fragmentSize, rcb->datagramSize - fragmentOffset); 1769 1770 if(amountToCopy > rcb->residual) 1771 { 1772 fIPLocalNode->fIPoFWDiagnostics.fRxFragmentPktsDropped++; 1773 result = kIOReturnError; 1774 } 1775 else 1776 { 1777 bufferToMbuf(rcb->mBuf, sizeof(struct firewire_header)+fragmentOffset, (vm_address_t*)fragment, amountToCopy); 1778 1779 rcb->residual -= MIN(fragmentSize, rcb->residual); 1780 1781 if ( rcb->residual == 0 ) 1782 { 1783 // Legitimate etherType ? this prevents corrupted etherType 1784 // being presented to the networking layer 1785 if (rcb->etherType == FWTYPE_IP || rcb->etherType == FWTYPE_IPV6) 1786 fIPLocalNode->receivePackets (rcb->mBuf, mbuf_pkthdr_len(rcb->mBuf), false); 1787 else 1788 { 1789 fIPLocalNode->freePacket(rcb->mBuf, 0); 1790 result = kIOReturnError; 1791 } 1792 1793 releaseRCB(rcb, false); 1794 } 1795 } 1796 } 1797 1798 return result; 1799} 1800 1801/*! 1802 @function rxAsyncStream 1803 @abstract callback for an Asyncstream packet, can be both IP or ARP packet. 1804 This procedure receives an indication when an asynchronous stream 1805 packet arrives on the default broadcast channel. The packet "should" be GASP, 1806 but we perform a few checks to make sure. Once we know these are OK, we check 1807 the etherType field in the unfragmented encapsulation header. This is necessary 1808 to dispatch the three types of packet that RFC 2734 permits on the default 1809 broadcast channel: an IPv4 datagram, and ARP request or response or a multi- 1810 channel allocation protocol (MCAP) message. The only remaining check, for each 1811 of these three cases, is to make sure that the packet is large enough to hold 1812 meaningful data. If so, send the packet to another procedure for further 1813 processing. 1814 @param DCLCommandStruct *callProc. 1815 @result void. 1816*/ 1817void IOFWIPBusInterface::rxAsyncStream(void *refCon, const void *buffer) 1818{ 1819 IOFWIPBusInterface *fwIPPriv = (IOFWIPBusInterface*)refCon; 1820 IOFireWireIP *fwIPObject = OSDynamicCast(IOFireWireIP, fwIPPriv->fIPLocalNode); 1821 1822 void *datagram; 1823 UInt16 datagramSize; 1824 GASP *gasp = (GASP*)buffer; 1825 LCB *lcb = fwIPPriv->fLcb; 1826 ISOC_DATA_PKT *pkt = (ISOC_DATA_PKT*)buffer; 1827 UInt16 type = 0; 1828 1829 if(not fwIPPriv->fStarted) 1830 return; 1831 1832 if(pkt->tag != GASP_TAG){ 1833 // Error, so we touch the error output packets 1834 fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->inputErrors); 1835 fwIPObject->fIPoFWDiagnostics.fGaspTagError++; 1836 return; 1837 } 1838 1839 // Minimum size requirement 1840 if (gasp->dataLength < sizeof(GASP_HDR) + sizeof(IP1394_UNFRAG_HDR)) { 1841 fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->inputErrors); 1842 fwIPObject->fIPoFWDiagnostics.fGaspHeaderError++; 1843 return; 1844 } 1845 1846 // Ignore GASP if not specified by RFC 2734 1847 if (memcmp(&gasp->gaspHdr.gaspID, &gaspVal, sizeof(GASP_ID)) != 0) { 1848 fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->inputErrors); 1849 fwIPObject->fIPoFWDiagnostics.fNonRFC2734Gasp++; 1850 return; 1851 } 1852 1853 // Also ignore GASP if not from the local bus 1854 if ((htons(gasp->gaspHdr.sourceID) >> 6) != LOCAL_BUS_ID) { 1855 fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->inputErrors); 1856 fwIPObject->fIPoFWDiagnostics.fRemoteGaspError++; 1857 return; 1858 } 1859 1860 // Broadcast fragmentation not supported 1861 if (gasp->ip1394Hdr.reserved != htons(UNFRAGMENTED)) { 1862 fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->inputErrors); 1863 fwIPObject->fIPoFWDiagnostics.fEncapsulationHeaderError++; 1864 return; 1865 } 1866 1867 datagram = (void *) ((UInt64) buffer + sizeof(GASP)); 1868 datagramSize = gasp->dataLength - (sizeof(GASP_HDR) + sizeof(IP1394_UNFRAG_HDR)); 1869 type = ntohs(gasp->ip1394Hdr.etherType); 1870 1871 //IOLog(" Ether type 0x%04X (data length %d)\n\r",htons(gasp->ip1394Hdr.etherType), datagramSize); 1872 1873 switch (type) { 1874 case FWTYPE_IPV6: 1875 case FWTYPE_IP: 1876 if (datagramSize >= IPV4_HDR_SIZE && datagramSize <= FIREWIRE_MTU) 1877 fwIPPriv->rxIP(datagram, datagramSize, FW_M_BCAST, type); 1878 break; 1879 1880 case FWTYPE_ARP: 1881 if (datagramSize >= sizeof(IP1394_ARP) && datagramSize <= FIREWIRE_MTU) 1882 fwIPPriv->rxARP((IP1394_ARP*)datagram, FW_M_BCAST); 1883 break; 1884 1885 case ETHER_TYPE_MCAP: 1886 if (datagramSize >= sizeof(IP1394_MCAP) && datagramSize <= FIREWIRE_MTU) 1887 fwIPPriv->rxMCAP(lcb, htons(gasp->gaspHdr.sourceID), 1888 (IP1394_MCAP*)datagram, datagramSize - sizeof(IP1394_MCAP)); 1889 break; 1890 } 1891 1892 fwIPObject->fIPoFWDiagnostics.fRxBcast++; 1893 1894 return; 1895} 1896 1897IOReturn IOFWIPBusInterface::createAsyncStreamRxClient(UInt8 speed, UInt32 channel, MCB *mcb) 1898{ 1899 IOReturn status = kIOReturnNoMemory; 1900 1901 if(channel != DEFAULT_BROADCAST_CHANNEL) 1902 { 1903 IOFWAsyncStreamListener *newAsyncStreamRxClient = fControl->createAsyncStreamListener( channel, rxAsyncStream, this ); 1904 if( newAsyncStreamRxClient != NULL) 1905 { 1906 newAsyncStreamRxClient->retain(); 1907 mcb->asyncStreamID = (OSObject*)newAsyncStreamRxClient; 1908 status = kIOReturnSuccess; 1909 } 1910 } 1911 else 1912 { 1913 if(fBroadcastReceiveClient != NULL) 1914 { 1915 fBroadcastReceiveClient->retain(); 1916 mcb->asyncStreamID = (OSObject*)fBroadcastReceiveClient; 1917 status = kIOReturnSuccess; 1918 } 1919 } 1920 1921 return status; 1922} 1923 1924 1925/*! 1926 @function rxMCAP 1927 @abstract called from rxAsyncstream for processing MCAP advertisement. 1928 When an MCAP advertisement is received, parse all of its descriptors 1929 looking for any that match group addreses in our MCAP cache. For those that 1930 match, update the channel number (it may have changed from the default 1931 broadcast channel or since the last advertisement), update the speed 1932 (the MCAP owner may have changed the speed requirements as nodes joined or 1933 left the group) and refresh the expiration timer so that the MCAP 1934 channel is valid for another number of seconds into the future. 1935 @param lcb - the firewire link control block for this interface. 1936 @param mcapSourceID - source nodeid which generated the multicast advertisement packet. 1937 @param mcap - mulitcast advertisment packet without the GASP header. 1938 @param dataSize - size of the packet. 1939 @result void. 1940*/ 1941void IOFWIPBusInterface::rxMCAP(LCB *lcb, UInt16 mcapSourceID, IP1394_MCAP *mcap, UInt32 dataSize) 1942{ 1943 1944 MARB *arb; 1945 UInt32 currentChannel; 1946 MCAST_DESCR *groupDescr = mcap->groupDescr; 1947 MCB *mcb, *priorMcb; 1948 IOFWAsyncStreamListener *asyncStreamRxClient; 1949 1950 if ((mcap->opcode != MCAP_ADVERTISE) && (mcap->opcode != MCAP_SOLICIT)) 1951 return; // Ignore reserved MCAP opcodes 1952 1953 dataSize = MIN(dataSize, htons(mcap->length) - sizeof(IP1394_MCAP)); 1954 1955 while (dataSize >= sizeof(MCAST_DESCR)) 1956 { 1957 recursiveScopeLock lock(fIPLock); 1958 1959 if (groupDescr->length != sizeof(MCAST_DESCR)) 1960 fIPLocalNode->fIPoFWDiagnostics.fInCorrectMCAPDesc++; // Skip over malformed MCAP group address descriptors 1961 else if (groupDescr->type != MCAST_TYPE) 1962 fIPLocalNode->fIPoFWDiagnostics.fUnknownMCAPDesc++; // Skip over unrecognized descriptor types 1963 else if ((arb = getMulticastArb(groupDescr->groupAddress)) == NULL) 1964 fIPLocalNode->fIPoFWDiagnostics.fUnknownGroupAddress++; // Ignore if not in our multicast cache 1965 else if (mcap->opcode == MCAP_SOLICIT) 1966 { 1967 mcb = OSDynamicCast(MCB, mcapState->getObject(arb->handle.multicast.channel)); 1968 if(mcb) 1969 { 1970 if (mcb->ownerNodeID == lcb->ownNodeID) // Do we own the channel? 1971 txMCAP(mcb, 0); // OK, respond to solicitation 1972 } 1973 } 1974 else if ((groupDescr->channel != DEFAULT_BROADCAST_CHANNEL) && (groupDescr->channel < kMaxChannels)) 1975 { 1976 mcb = OSDynamicCast(MCB, mcapState->getObject(groupDescr->channel)); 1977 if(not mcb) 1978 break; 1979 1980 if ( (groupDescr->expiration < 60) and (mcb->ownerNodeID == mcapSourceID) ) 1981 { 1982 currentChannel = groupDescr->channel; 1983 // mcb->ownerNodeID = lcb->ownNodeID; // Take channel ownership 1984 // mcb->nextTransmit = 1; // Transmit advertisement ASAP 1985 } 1986 else if (mcb->ownerNodeID == mcapSourceID) 1987 { 1988 mcb->expiration = groupDescr->expiration; 1989 } 1990 else if ( (mcb->ownerNodeID < mcapSourceID) or (mcb->expiration < 60) ) 1991 { 1992 mcb->ownerNodeID = mcapSourceID; 1993 mcb->expiration = groupDescr->expiration; 1994 } 1995 currentChannel = arb->handle.multicast.channel; 1996 1997 if (currentChannel != groupDescr->channel) 1998 { 1999 priorMcb = OSDynamicCast(MCB, mcapState->getObject(currentChannel)); 2000 if(not priorMcb) 2001 break; 2002 2003 if (priorMcb->groupCount == 1) // Are we the last user? 2004 { 2005 asyncStreamRxClient = OSDynamicCast(IOFWAsyncStreamListener, mcb->asyncStreamID); 2006 if(asyncStreamRxClient != NULL) 2007 { 2008 fControl->removeAsyncStreamListener( asyncStreamRxClient ); 2009 asyncStreamRxClient->release(); 2010 } 2011 2012 priorMcb->asyncStreamID = NULL; 2013 priorMcb->groupCount = 0; 2014 } 2015 else if (priorMcb->groupCount > 0) 2016 priorMcb->groupCount--; 2017 2018 if (mcb->asyncStreamID == NULL) 2019 { 2020 if(createAsyncStreamRxClient(groupDescr->speed, groupDescr->channel, mcb) != kIOReturnSuccess) 2021 break; 2022 } 2023 2024 arb->handle.multicast.channel = groupDescr->channel; 2025 mcb->groupCount++; 2026 } 2027 } 2028 dataSize -= MIN(groupDescr->length, dataSize); 2029 groupDescr = (MCAST_DESCR*)((UInt64)groupDescr + groupDescr->length); 2030 } 2031} 2032 2033 2034/*! 2035 @function rxIP 2036 @abstract Receive IP packet. 2037 @param pkt - points to the IP packet without the header. 2038 @param len - length of the packet. 2039 @params flags - indicates broadcast or unicast 2040 @params type - indicates type of the packet IPv4 or IPv6 2041 @result IOReturn. 2042*/ 2043IOReturn IOFWIPBusInterface::rxIP(void *pkt, UInt32 len, UInt32 flags, UInt16 type) 2044{ 2045 mbuf_t rxMBuf = NULL; 2046 struct firewire_header *fwh = NULL; 2047 bool queuePkt = false; 2048 IOReturn ret = kIOReturnSuccess; 2049 2050 IORecursiveLockLock(fIPLock); 2051 2052 if ((rxMBuf = (mbuf_t)allocateMbuf(len + sizeof(firewire_header))) != NULL) 2053 { 2054 bufferToMbuf(rxMBuf, sizeof(struct firewire_header), (vm_address_t*)pkt, len); 2055 2056 if (rxMBuf != NULL) 2057 { 2058 fwh = (struct firewire_header *)mbuf_data(rxMBuf); 2059 bzero(fwh, sizeof(struct firewire_header)); 2060 fwh->fw_type = htons(type); 2061 2062 queuePkt = (flags == FW_M_UCAST); 2063 2064 if(queuePkt) 2065 bcopy(fIPLocalNode->macAddr, fwh->fw_dhost, kIOFWAddressSize); 2066 else 2067 bcopy(fwbroadcastaddr, fwh->fw_dhost, kIOFWAddressSize); 2068 2069 if(FWTYPE_IPV6 == type) 2070 { 2071 if( updateNDPCache(rxMBuf) == true ) 2072 { 2073 mbuf_prepend(&rxMBuf, sizeof(struct firewire_header), MBUF_DONTWAIT); 2074 } 2075 } 2076 } 2077 else 2078 { 2079 fIPLocalNode->fIPoFWDiagnostics.fNoMbufs++; 2080 ret = kIOReturnNoMemory; 2081 } 2082 2083 if(ret == kIOReturnSuccess) 2084 { 2085 fIPLocalNode->receivePackets(rxMBuf, mbuf_pkthdr_len(rxMBuf), queuePkt); 2086 } 2087 else 2088 { 2089 if(rxMBuf != NULL) 2090 fIPLocalNode->freePacket(rxMBuf, 0); 2091 2092 fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->inputErrors); 2093 } 2094 } 2095 2096 IORecursiveLockUnlock(fIPLock); 2097 2098 return ret; 2099} 2100 2101/*! 2102 @function rxARP 2103 @abstract ARP processing routine called from both Asynstream path and Async path. 2104 @param fwIPObj - IOFireWireIP object. 2105 @param arp - 1394 arp packet without the GASP or Async header. 2106 @params flags - indicates broadcast or unicast 2107 @result IOReturn. 2108*/ 2109IOReturn IOFWIPBusInterface::rxARP(IP1394_ARP *arp, UInt32 flags){ 2110 2111 mbuf_t rxMBuf; 2112 struct firewire_header *fwh = NULL; 2113 void *datagram = NULL; 2114 2115 if (arp->hardwareType != htons(ARP_HDW_TYPE) 2116 || arp->protocolType != htons(FWTYPE_IP) 2117 || arp->hwAddrLen != sizeof(IP1394_HDW_ADDR) 2118 || arp->ipAddrLen != IPV4_ADDR_SIZE) 2119 { 2120 IOLog("IOFireWireIP: rxARP ERROR in packet header\n"); 2121 return kIOReturnError; 2122 } 2123 2124 IORecursiveLockLock(fIPLock); 2125 2126 if ((rxMBuf = (mbuf_t)allocateMbuf(sizeof(*arp) + sizeof(struct firewire_header))) != NULL) 2127 { 2128 fwh = (struct firewire_header *)mbuf_data(rxMBuf); 2129 datagram = ((UInt8*)mbuf_data(rxMBuf)) + sizeof(struct firewire_header); 2130 bzero(fwh, sizeof(struct firewire_header)); 2131 fwh->fw_type = htons(FWTYPE_ARP); 2132 // Copy the data 2133 memcpy(datagram, arp, sizeof(*arp)); 2134 2135 fIPLocalNode->receivePackets(rxMBuf, mbuf_pkthdr_len(rxMBuf), 0); 2136 } 2137 else 2138 fIPLocalNode->fIPoFWDiagnostics.fNoMbufs++; 2139 2140 IORecursiveLockUnlock(fIPLock); 2141 2142 return kIOReturnSuccess; 2143} 2144 2145/*! 2146 @function watchdog 2147 @abstract cleans the Link control block's stale drb's and rcb's. 2148 The cleanCache's job is to age (and eventually discard) device objects 2149 for FireWireIP devices that have come unplugged. If they do reappear after 2150 they have been discarded from the caches, all that is required is a new ARP. 2151 The IP network stack handles that automatically 2152 @param lcb - the firewire link control block for this interface. 2153 @result void. 2154*/ 2155void watchdog(OSObject *obj, IOTimerEventSource *src) 2156{ 2157 IOFWIPBusInterface *FWIPPriv = (IOFWIPBusInterface*)obj; 2158 2159 FWIPPriv->processWatchDogTimeout(); 2160} 2161 2162void IOFWIPBusInterface::processWatchDogTimeout() 2163{ 2164 recursiveScopeLock lock(fIPLock); 2165 2166 updateMcapState(); 2167 2168 cleanRCBCache(); 2169 2170 fIPLocalNode->fIPoFWDiagnostics.fMaxQueueSize = max(fIPLocalNode->fIPoFWDiagnostics.fTxUni - fPrevTransmitCount, TRANSMIT_QUEUE_SIZE); 2171 2172 fPrevTransmitCount = fIPLocalNode->fIPoFWDiagnostics.fTxUni; 2173 2174 fIPLocalNode->fIPoFWDiagnostics.fLastStarted++; 2175 2176 // Tuning segment for optimum performance, if too many Busy Acks 2177 if( not fIPLocalNode->fIPoFWDiagnostics.fDoFastRetry ) 2178 { 2179 fIPLocalNode->fIPoFWDiagnostics.fDoFastRetry = ((fIPLocalNode->fIPoFWDiagnostics.fBusyAcks - fPrevBusyAcks) > kMaxBusyXAcksPerSecond); 2180 fPrevBusyAcks = fIPLocalNode->fIPoFWDiagnostics.fBusyAcks; 2181 fFastRetryUnsetTimer = fPrevFastRetryBusyAcks = fIPLocalNode->fIPoFWDiagnostics.fFastRetryBusyAcks = 0; 2182 } 2183 else 2184 { 2185 fFastRetryUnsetTimer = (fIPLocalNode->fIPoFWDiagnostics.fFastRetryBusyAcks - fPrevFastRetryBusyAcks) ? 0 : fFastRetryUnsetTimer + 1; 2186 2187 // Fast retry BusyX acks absent for last 60 seconds, so turn it off 2188 fIPLocalNode->fIPoFWDiagnostics.fDoFastRetry = not (fFastRetryUnsetTimer > kMaxSecondsToTurnOffFastRetry); 2189 fPrevBusyAcks = fIPLocalNode->fIPoFWDiagnostics.fBusyAcks; 2190 fPrevFastRetryBusyAcks = fIPLocalNode->fIPoFWDiagnostics.fFastRetryBusyAcks; 2191 } 2192 2193 // Restart the watchdog timer 2194 timerSource->setTimeoutMS(kWatchDogTimerMS); 2195} 2196 2197#pragma mark - 2198#pragma mark ��� IPv6 NDP routines ��� 2199 2200const int ipv6fwoffset = 8; 2201 2202bool IOFWIPBusInterface::addNDPOptions(mbuf_t m) 2203{ 2204 bool ret = false; 2205 2206 if(not (mbuf_flags(m) & MBUF_PKTHDR)) 2207 return ret; 2208 2209 vm_address_t src = (vm_offset_t)mbuf_data(m); 2210 if(src == 0) 2211 return ret; 2212 2213 UInt32 fwhdrlen = sizeof(firewire_header); 2214 mbuf_t ipv6Mbuf = m; 2215 int pkthdrlen = 0; 2216 2217 // check whether len equals ether header 2218 if(mbuf_len(m) == sizeof(firewire_header)) 2219 { 2220 ipv6Mbuf = mbuf_next(m); 2221 if(ipv6Mbuf == NULL) 2222 return ret; 2223 2224 src = (vm_offset_t)mbuf_data(ipv6Mbuf); 2225 2226 fwhdrlen = 0; 2227 pkthdrlen = mbuf_pkthdr_len(ipv6Mbuf); 2228 } 2229 2230 if(mbuf_len(ipv6Mbuf) < (fwhdrlen + sizeof(struct ip6_hdr))) 2231 return ret; 2232 2233 // no space in mbuf 2234 if(mbuf_trailingspace(ipv6Mbuf) < (int)sizeof(IP1394_NDP)) 2235 return ret; 2236 2237 UInt8 *bufPtr = (UInt8*)(src + fwhdrlen); 2238 2239 // show type of ICMPV6 packets being sent 2240 struct ip6_hdr *ip6 = (struct ip6_hdr*)bufPtr; 2241 struct icmp6_hdr *icp = (struct icmp6_hdr*)(ip6 + 1); 2242 struct nd_neighbor_advert *nd_na = (struct nd_neighbor_advert*)icp; 2243 struct nd_neighbor_solicit *nd_ns = (struct nd_neighbor_solicit*)icp; 2244 2245 int offset = sizeof(*ip6) + fwhdrlen; 2246 2247 bool modify = false; 2248 IP1394_NDP *fwndp = NULL; 2249 u_int16_t *icmp6_cksum = NULL; 2250 2251 if(nd_ns->nd_ns_type == ND_NEIGHBOR_SOLICIT) 2252 { 2253 // neighbor solicitation 2254 fwndp = (IP1394_NDP*)((UInt8*)nd_ns + sizeof(struct nd_neighbor_solicit)); 2255 if(fwndp->type == 1) 2256 { 2257 modify = true; 2258 icmp6_cksum = &nd_ns->nd_ns_cksum; 2259 } 2260 } 2261 2262 if(nd_na->nd_na_type == ND_NEIGHBOR_ADVERT) 2263 { 2264 // neighbor advertisment 2265 fwndp = (IP1394_NDP*)((UInt8*)nd_na + sizeof(struct nd_neighbor_advert)); 2266 2267 if(fwndp->type == 2) 2268 { 2269 modify = true; 2270 icmp6_cksum = &nd_na->nd_na_cksum; 2271 } 2272 } 2273 2274 if(modify) 2275 { 2276 fwndp->len = 3; // len in units of 8 octets 2277 bzero(fwndp->reserved, 6); // reserved by the RFC 3146 2278 fwndp->senderMaxRec = fLcb->ownHardwareAddress.maxRec; // Maximum payload (2 ** senderMaxRec) 2279 fwndp->sspd = fLcb->ownHardwareAddress.spd; // Maximum speed 2280 fwndp->senderUnicastFifoHi = htons(fLcb->ownHardwareAddress.unicastFifoHi); // Most significant 16 bits of FIFO address 2281 fwndp->senderUnicastFifoLo = htonl(fLcb->ownHardwareAddress.unicastFifoLo); // Least significant 32 bits of FIFO address 2282 2283 // current mbuf length IPv6+ICMP6 2284 mbuf_setlen(ipv6Mbuf, mbuf_len(ipv6Mbuf)+ipv6fwoffset); 2285 2286 // main mbuf header length of FW+IPv6+ICMP6 2287 mbuf_pkthdr_setlen(m, mbuf_pkthdr_len(m)+ipv6fwoffset); 2288 2289 // fix for <rdar://problem/3483512>: Developer: FireWire IPv6 header payload legnth value 0x28 may be incorrect 2290 // mbuf header length of IPv6+ICMP6 2291 if(pkthdrlen != 0) 2292 mbuf_pkthdr_setlen(ipv6Mbuf, pkthdrlen+ipv6fwoffset); 2293 2294 int icmp6len = ntohs(ip6->ip6_plen) + ipv6fwoffset; 2295 2296 ip6->ip6_plen = htons(icmp6len); 2297 2298 mbuf_inet6_cksum(ipv6Mbuf, IPPROTO_ICMPV6, offset, icmp6len, icmp6_cksum); 2299 } 2300 2301 return ret; 2302} 2303 2304bool IOFWIPBusInterface::updateNDPCache(mbuf_t m) 2305{ 2306 bool result = false; 2307 2308 if(not (mbuf_flags(m) & MBUF_PKTHDR)) 2309 { 2310 return result; 2311 } 2312 2313 mbuf_t ipv6Mbuf = m; 2314 int fwhdrlen = sizeof(firewire_header); 2315 int pkthdrlen = 0; 2316 2317 // check whether len equals ether header 2318 if(mbuf_len(m) == sizeof(firewire_header)) 2319 { 2320 ipv6Mbuf = mbuf_next(m); 2321 if(ipv6Mbuf == NULL) 2322 { 2323 return result ; 2324 } 2325 2326 fwhdrlen = 0; 2327 pkthdrlen = mbuf_pkthdr_len(ipv6Mbuf); 2328 } 2329 2330 vm_address_t src = (vm_offset_t)mbuf_data(ipv6Mbuf); 2331 if(src == 0) 2332 { 2333 return result; 2334 } 2335 2336 if(mbuf_len(ipv6Mbuf) < (sizeof(struct ip6_hdr) + fwhdrlen)) 2337 { 2338 return result; 2339 } 2340 2341 // no space in mbuf 2342 if(mbuf_trailingspace(ipv6Mbuf) < (int)sizeof(IP1394_NDP)) 2343 { 2344 return result; 2345 } 2346 2347 // show type of ICMPV6 packets being sent 2348 struct ip6_hdr *ip6 = (struct ip6_hdr*)((UInt8*)src + fwhdrlen); 2349 struct icmp6_hdr *icp = (struct icmp6_hdr*)(ip6 + 1); 2350 struct nd_neighbor_advert *nd_na = (struct nd_neighbor_advert*)icp; 2351 struct nd_neighbor_solicit *nd_ns = (struct nd_neighbor_solicit*)icp; 2352 2353 int offset = sizeof(*ip6); 2354 2355 IP1394_NDP *fwndp = NULL; 2356 bool modify = false; 2357 2358 u_int16_t *icmp6_cksum = NULL; 2359 2360 if(nd_ns->nd_ns_type == ND_NEIGHBOR_SOLICIT) 2361 { 2362 // neighbor solicitation 2363 fwndp = (IP1394_NDP*)((UInt8*)nd_ns + sizeof(struct nd_neighbor_solicit)); 2364 if(fwndp->type == 1) 2365 { 2366 modify = true; 2367 icmp6_cksum = &nd_ns->nd_ns_cksum; 2368 } 2369 } 2370 2371 if(nd_na->nd_na_type == ND_NEIGHBOR_ADVERT) 2372 { 2373 // neighbor advertisment 2374 fwndp = (IP1394_NDP*)((UInt8*)nd_na + sizeof(struct nd_neighbor_advert)); 2375 2376 if(fwndp->type == 2) 2377 { 2378 modify = true; 2379 icmp6_cksum = &nd_na->nd_na_cksum; 2380 } 2381 } 2382 2383 ARB *arb = NULL; 2384 2385 if(modify && fwndp != NULL && fwndp->len > 2) 2386 { 2387 arb = getArbFromFwAddr(fwndp->lladdr); 2388 2389 if(arb != NULL) 2390 { 2391 bcopy(fwndp->lladdr, &arb->eui64, kIOFWAddressSize); 2392 arb->eui64.hi = OSSwapHostToBigInt32(arb->eui64.hi); 2393 arb->eui64.lo = OSSwapHostToBigInt32(arb->eui64.lo); 2394 bcopy(fwndp->lladdr, arb->fwaddr, kIOFWAddressSize); 2395 arb->handle.unicast.maxRec = fwndp->senderMaxRec; 2396 arb->handle.unicast.spd = fwndp->sspd; 2397 arb->handle.unicast.unicastFifoHi = htons(fwndp->senderUnicastFifoHi); 2398 arb->handle.unicast.unicastFifoLo = htonl(fwndp->senderUnicastFifoLo); 2399 arb->handle.unicast.deviceID = getDeviceID(arb->eui64, &arb->itsMac); 2400 2401 // Reset the packet 2402 fwndp->len = 2; // len in units of 8 octets 2403 fwndp->senderMaxRec = 0; 2404 fwndp->sspd = 0; 2405 fwndp->senderUnicastFifoHi = 0; 2406 fwndp->senderUnicastFifoLo = 0; 2407 2408 // Adjust header, so the checksum becomes right. 2409 mbuf_adj(ipv6Mbuf, fwhdrlen); 2410 2411 // current mbuf length IPv6+ICMP6 2412 mbuf_setlen(ipv6Mbuf, mbuf_len(ipv6Mbuf)-8); 2413 2414 // main mbuf header length of FW+IPv6+ICMP6 2415 mbuf_pkthdr_setlen(m, mbuf_pkthdr_len(m)-8); 2416 2417 // fix for <rdar://problem/3483512>: Developer: FireWire IPv6 header payload legnth value 0x28 may be incorrect 2418 // mbuf header length of IPv6+ICMP6 2419 if(pkthdrlen != 0) 2420 mbuf_pkthdr_setlen(ipv6Mbuf, mbuf_pkthdr_len(ipv6Mbuf)-8); 2421 2422 int icmp6len = ntohs(ip6->ip6_plen) - 8; 2423 2424 ip6->ip6_plen = htons(icmp6len); 2425 2426 *icmp6_cksum = 0xFFFF; 2427 mbuf_inet6_cksum(ipv6Mbuf, IPPROTO_ICMPV6, offset, icmp6len, icmp6_cksum); 2428 result = true; 2429 } 2430 } 2431 2432 return result; 2433} 2434 2435void IOFWIPBusInterface::updateNDPCache(void *buf, UInt16 *len) 2436{ 2437 struct icmp6_hdr *icp = NULL; 2438 struct ip6_hdr *ip6; 2439 struct nd_neighbor_advert *nd_na = NULL; 2440 struct nd_neighbor_solicit *nd_ns = NULL; 2441 2442 ARB *arb = NULL; 2443 IP1394_NDP *fwndp = NULL; 2444 bool update = false; 2445 2446 ip6 = (struct ip6_hdr*)buf; 2447 icp = (struct icmp6_hdr*)(ip6 + 1); 2448 nd_na = (struct nd_neighbor_advert*)icp; 2449 nd_ns = (struct nd_neighbor_solicit*)icp; 2450 2451 if(nd_ns->nd_ns_type == ND_NEIGHBOR_SOLICIT) 2452 { 2453 // neighbor solicitation 2454 fwndp = (IP1394_NDP*)((UInt8*)nd_ns + sizeof(struct nd_neighbor_solicit)); 2455 if(fwndp->type == 1) 2456 { 2457 update = true; 2458 } 2459 } 2460 2461 if(nd_na->nd_na_type == ND_NEIGHBOR_ADVERT) 2462 { 2463 // neighbor advertisment 2464 fwndp = (IP1394_NDP*)((UInt8*)nd_na + sizeof(struct nd_neighbor_advert)); 2465 if(fwndp->type == 2) 2466 { 2467 update = true; 2468 } 2469 } 2470 2471 if(update && fwndp != NULL && fwndp->len > 2) 2472 { 2473 arb = getArbFromFwAddr(fwndp->lladdr); 2474 2475 if(arb != NULL) 2476 { 2477 bcopy(fwndp->lladdr, &arb->eui64, kIOFWAddressSize); 2478 arb->eui64.hi = OSSwapHostToBigInt32(arb->eui64.hi); 2479 arb->eui64.lo = OSSwapHostToBigInt32(arb->eui64.lo); 2480 bcopy(fwndp->lladdr, arb->fwaddr, kIOFWAddressSize); 2481 arb->handle.unicast.maxRec = fwndp->senderMaxRec; 2482 arb->handle.unicast.spd = fwndp->sspd; 2483 arb->handle.unicast.unicastFifoHi = htons(fwndp->senderUnicastFifoHi); 2484 arb->handle.unicast.unicastFifoLo = htonl(fwndp->senderUnicastFifoLo); 2485 arb->handle.unicast.deviceID = getDeviceID(arb->eui64, &arb->itsMac); 2486 2487 // Reset the packet 2488 *len -= 8; 2489 fwndp->len = 2; // len in units of 8 octets 2490 fwndp->senderMaxRec = 0; 2491 fwndp->sspd = 0; 2492 fwndp->senderUnicastFifoHi = 0; 2493 fwndp->senderUnicastFifoLo = 0; 2494 } 2495 } 2496 2497 return; 2498} 2499 2500#pragma mark - 2501#pragma mark ��� IOFWIPBusInterface utility routines ��� 2502 2503bool IOFWIPBusInterface::staticUpdateARPCache(void *refcon, IP1394_ARP *fwa) 2504{ 2505 return ((IOFWIPBusInterface*)refcon)->updateARPCache(fwa); 2506} 2507 2508bool IOFWIPBusInterface::staticUpdateMulticastCache(void *refcon, IOFWAddress *addrs, UInt32 count) 2509{ 2510 return ((IOFWIPBusInterface*)refcon)->updateMulticastCache(addrs, count); 2511} 2512 2513UInt32 IOFWIPBusInterface::staticOutputPacket(mbuf_t pkt, void * param) 2514{ 2515 return ((IOFWIPBusInterface*)param)->outputPacket(pkt,param); 2516} 2517 2518bool IOFWIPBusInterface::wellKnownMulticastAddress(IOFWAddress *addr) 2519{ 2520 // if well know IPv4 multicast address then return true 2521 bool found = (memcmp(addr->bytes, IPv4KnownMcastAddresses, sizeof(IPv4KnownMcastAddresses)) == 0) ? true : false; 2522 2523 if(not found) 2524 { 2525 if(addr->bytes[0] == 0xff) // check if its a IPv6 multicast address 2526 { 2527 found = true; 2528 2529 if(addr->bytes[1] & BIT_SET(4)) 2530 found = false; 2531 else // if Transient Flag not set then well known IPv6 multicast address 2532 found = true; 2533 } 2534 } 2535 2536 return found; 2537} 2538 2539bool IOFWIPBusInterface::updateMulticastCache(IOFWAddress *addrs, UInt32 count) 2540{ 2541 OSSet *newMulticastAddresses = OSSet::withCapacity(kMulticastArbs); 2542 2543 if(newMulticastAddresses == 0) 2544 return false; 2545 2546 // Find if the addresses are in mulicast ARB cache 2547 IORecursiveLockLock(fIPLock); 2548 2549 IOFWAddress *tempAddresses = addrs; 2550 UInt32 tempCount = count; 2551 2552 MARB *arb = NULL; 2553 OSCollectionIterator * iterator = OSCollectionIterator::withCollection( multicastArb ); 2554 bool found = false; 2555 2556 if ( iterator ) 2557 { 2558 while(tempCount) 2559 { 2560 found = false; 2561 2562 while( NULL != (arb = OSDynamicCast(MARB, iterator->getNextObject())) ) 2563 { 2564 UInt32 newGroupAddress = 0; 2565 2566 memcpy(&newGroupAddress, &tempAddresses->bytes[4], sizeof(newGroupAddress)); 2567 2568 found = ( arb->handle.multicast.groupAddress == newGroupAddress ) ? true : false; 2569 2570 if(found) break; 2571 } 2572 2573 iterator->reset(); 2574 2575 // if not found, its a new address and not a well known multicast group address 2576 if( (not found) and (not wellKnownMulticastAddress(tempAddresses)) ) 2577 { 2578 MARB *tempArb = new MARB; 2579 2580 if(tempArb) 2581 { 2582 tempArb->handle.multicast.deviceID = 0; // Always zero 2583 tempArb->handle.multicast.maxRec = fLcb->ownHardwareAddress.maxRec; // Maximum asynchronous payload 2584 tempArb->handle.multicast.spd = fLcb->ownHardwareAddress.spd; // Maximum speed 2585 tempArb->handle.multicast.reserved = 0; 2586 tempArb->handle.multicast.channel = DEFAULT_BROADCAST_CHANNEL; // Channel number for GASP transmit / receive 2587 memcpy(&tempArb->handle.multicast.groupAddress, &tempAddresses->bytes[4], 2588 sizeof(tempArb->handle.multicast.groupAddress)); 2589 2590 newMulticastAddresses->setObject(tempArb); 2591 } 2592 } 2593 2594 tempAddresses++; 2595 tempCount--; 2596 } 2597 2598 iterator->release(); 2599 } 2600 2601 2602 // Add from newMulticastAddresses to original cache 2603 iterator = OSCollectionIterator::withCollection( newMulticastAddresses ); 2604 2605 if ( iterator ) 2606 { 2607 while( NULL != (arb = OSDynamicCast(MARB, iterator->getNextObject())) ) 2608 { 2609 newMulticastAddresses->removeObject(arb); 2610 multicastArb->setObject(arb); 2611 2612 // If its a new multicast address, then send a solicitation request. 2613 txMCAP(0, arb->handle.multicast.groupAddress); 2614 } 2615 iterator->release(); 2616 } 2617 2618 newMulticastAddresses->flushCollection(); 2619 newMulticastAddresses->free(); 2620 2621 IORecursiveLockUnlock(fIPLock); 2622 2623 return true; 2624} 2625 2626/*! 2627 @function updateARPCache 2628 @abstract updates IPv4 ARP cache from the incoming ARP packet 2629 @param fwa - firewire ARP packet. 2630 @result void. 2631*/ 2632bool IOFWIPBusInterface::updateARPCache(IP1394_ARP *fwa) 2633{ 2634 ARB *fwarb = NULL; 2635 UWIDE eui64; 2636 2637 IORecursiveLockLock(fIPLock); 2638 2639 eui64.hi = htonl(fwa->senderUniqueID.hi); 2640 eui64.lo = htonl(fwa->senderUniqueID.lo); 2641 2642 // Get the arb pointer from sdl->data 2643 fwarb = getARBFromEui64(eui64); 2644 2645 if(fwarb) 2646 { 2647 fwarb->handle.unicast.maxRec = fwa->senderMaxRec; // Volatile fields 2648 fwarb->handle.unicast.spd = fwa->sspd; 2649 fwarb->handle.unicast.unicastFifoHi = htons(fwa->senderUnicastFifoHi); 2650 fwarb->handle.unicast.unicastFifoLo = htonl(fwa->senderUnicastFifoLo); 2651 fwarb->eui64.hi = eui64.hi; 2652 fwarb->eui64.lo = eui64.lo; 2653 fwarb->handle.unicast.deviceID = getDeviceID(fwarb->eui64, &fwarb->itsMac); 2654 2655 fIPLocalNode->getBytesFromGUID(&fwarb->eui64, fwarb->fwaddr, 0); 2656 } 2657 2658 IORecursiveLockUnlock(fIPLock); 2659 2660 return true; 2661} 2662 2663ARB *IOFWIPBusInterface::updateARBwithDevice(IOFireWireNub *device, UWIDE eui64) 2664{ 2665 IORecursiveLockLock(fIPLock); 2666 2667 // Create the arb if we recognise a IP unit. 2668 ARB *arb = getARBFromEui64(eui64); 2669 2670 // Update the device object in the address resolution block used in the ARP resolve routine 2671 if(arb != NULL) 2672 { 2673 arb->handle.unicast.deviceID = device; 2674 arb->handle.unicast.maxRec = device->maxPackLog(true); 2675 arb->handle.unicast.spd = device->FWSpeed(); 2676 arb->itsMac = false; 2677 arb->eui64.hi = eui64.hi; 2678 arb->eui64.lo = eui64.lo; 2679 fIPLocalNode->getBytesFromGUID(&eui64, arb->fwaddr, 0); 2680 } 2681 2682 IORecursiveLockUnlock(fIPLock); 2683 2684 return arb; 2685} 2686 2687/*! 2688 @function cleanFWRcbCache 2689 @abstract cleans the Link control block's stale rcb's. UnAssembled RCB's 2690 are returned to the free CBLKs 2691 @param none. 2692 @result void. 2693*/ 2694void IOFWIPBusInterface::cleanRCBCache() 2695{ 2696 IORecursiveLockLock(fIPLock); 2697 2698 RCB *rcb = 0; 2699 OSCollectionIterator * iterator = OSCollectionIterator::withCollection( activeRcb ); 2700 if( iterator ) 2701 { 2702 while( NULL != (rcb = OSDynamicCast(RCB, iterator->getNextObject())) ) 2703 { 2704 if(rcb->timer > 1) 2705 rcb->timer--; // still reassembling packets 2706 else if (rcb->timer == 1) 2707 releaseRCB(rcb); 2708 } 2709 iterator->release(); 2710 } 2711 2712 IORecursiveLockUnlock(fIPLock); 2713} 2714 2715/*! 2716 @function getDeviceID 2717 @abstract returns a fireWire device object for the GUID 2718 @param lcb - the firewire link control block for this interface. 2719 @param eui64 - global unique id of a device on the bus. 2720 @param itsMac - destination is Mac or not. 2721 @result Returns IOFireWireNub if successfull else 0. 2722*/ 2723void* IOFWIPBusInterface::getDeviceID(UWIDE eui64, bool *itsMac) { 2724 2725 // Returns DRB if EUI-64 matches 2726 DRB *drb = getDrbFromEui64(eui64); 2727 2728 // Device reference ID already created 2729 if (drb != NULL) 2730 { 2731 *itsMac = drb->itsMac; 2732 // Just return it to caller 2733 return(drb->deviceID); 2734 } 2735 else 2736 { 2737 *itsMac = false; 2738 // Get an empty DRB 2739 return(NULL); 2740 } 2741} 2742 2743void IOFWIPBusInterface::releaseDRB(UInt8 *fwaddr) 2744{ 2745 IORecursiveLockLock(fIPLock); 2746 2747 DRB *drb = NULL; 2748 OSCollectionIterator * iterator = OSCollectionIterator::withCollection( activeDrb ); 2749 if( iterator ) 2750 { 2751 while( NULL != (drb = OSDynamicCast(DRB, iterator->getNextObject())) ) 2752 { 2753 if (bcmp(fwaddr, drb->fwaddr, kIOFWAddressSize) == 0) 2754 { 2755 drb->deviceID = NULL; // Don't notify in future 2756 activeDrb->removeObject(drb); // time to clean up 2757 drb->release(); 2758 } 2759 } 2760 iterator->release(); 2761 } 2762 2763 IORecursiveLockUnlock(fIPLock); 2764} 2765 2766void IOFWIPBusInterface::releaseARB(UInt8 *fwaddr) 2767{ 2768 IORecursiveLockLock(fIPLock); 2769 2770 ARB *arb = NULL; 2771 OSCollectionIterator * iterator = OSCollectionIterator::withCollection( unicastArb ); 2772 2773 if( iterator ) 2774 { 2775 while( NULL != (arb = OSDynamicCast(ARB, iterator->getNextObject())) ) 2776 { 2777 if (bcmp(fwaddr, arb->fwaddr, kIOFWAddressSize) == 0) 2778 { 2779 arb->handle.unicast.deviceID = NULL; 2780 unicastArb->removeObject(arb); 2781 arb->release(); 2782 } 2783 } 2784 2785 iterator->release(); 2786 } 2787 2788 IORecursiveLockUnlock(fIPLock); 2789} 2790 2791void IOFWIPBusInterface::releaseRCB(RCB *rcb, bool freeMbuf) 2792{ 2793 IORecursiveLockLock(fIPLock); 2794 2795 if(freeMbuf && rcb->mBuf != NULL) 2796 { 2797 fIPLocalNode->freePacket(rcb->mBuf, 0); 2798 rcb->mBuf = NULL; 2799 } 2800 activeRcb->removeObject(rcb); 2801 fRCBCmdPool->returnCommand(rcb); 2802 2803 IORecursiveLockUnlock(fIPLock); 2804} 2805 2806void IOFWIPBusInterface::updateMcapState() 2807{ 2808 IORecursiveLockLock(fIPLock); 2809 2810 MCB *mcb = NULL; 2811 OSCollectionIterator *iterator = OSCollectionIterator::withCollection( mcapState ); 2812 2813 if( iterator ) 2814 { 2815 while( NULL != (mcb = OSDynamicCast(MCB, iterator->getNextObject())) ) 2816 { 2817 // for all mcb's check and relinquich resources 2818 if (mcb->expiration > 1) // Life in this channel allocation yet? 2819 mcb->expiration--; // Yes, but the clock is ticking... 2820 else if (mcb->expiration == 1) // Dead in the water? 2821 { 2822 mcb->expiration = 0; // Yes, mark it expired 2823 if (mcb->groupCount > 0) 2824 mcb->groupCount--; 2825 2826 IOFWAsyncStreamListener *asyncStreamRxClient = OSDynamicCast(IOFWAsyncStreamListener, mcb->asyncStreamID); 2827 if(asyncStreamRxClient != NULL) 2828 { 2829 fControl->removeAsyncStreamListener( asyncStreamRxClient ); 2830 asyncStreamRxClient->release(); 2831 } 2832 2833 mcb->asyncStreamID = NULL; 2834 releaseMulticastARB(mcb); 2835 2836 if (mcb->ownerNodeID == fLcb->ownNodeID) // We own the channel? 2837 { 2838 mcb->finalWarning = 4; // Yes, four final advertisements 2839 mcb->nextTransmit = 1; // Starting right now... 2840 } 2841 } 2842 2843 // If we own this channel, then proceed below 2844 if (mcb->ownerNodeID != fLcb->ownNodeID) 2845 continue; // Cycle to next array entry 2846 else if (mcb->nextTransmit > 1) // Time left before next transmit? 2847 mcb->nextTransmit--; // Keep on ticking... 2848 else if (mcb->nextTransmit == 1) 2849 { // Due to expire now? 2850 if (mcb->groupCount > 0) // Still in use at this machine? 2851 mcb->expiration = 60; // Renew this channel's lease 2852 2853 txMCAP(mcb, 0); // Broadcast the MCAP advertisement 2854 2855 if (mcb->expiration > 0) 2856 mcb->nextTransmit = 10; // Send MCAP again in ten seconds 2857 else if (--mcb->finalWarning > 0) 2858 mcb->nextTransmit = 10; // Channel deallocation warning 2859 else 2860 { 2861 mcb->ownerNodeID = MCAP_UNOWNED; // Reliquish our ownership 2862 mcb->nextTransmit = 0; // We're really, really done! 2863 releaseMulticastARB(mcb); 2864 } 2865 } 2866 } 2867 iterator->release(); 2868 } 2869 2870 IORecursiveLockUnlock(fIPLock); 2871} 2872 2873void IOFWIPBusInterface::releaseMulticastARB(MCB *mcb) 2874{ 2875 IORecursiveLockLock(fIPLock); 2876 2877 MARB *arb = NULL; 2878 OSCollectionIterator * iterator = OSCollectionIterator::withCollection( multicastArb ); 2879 2880 if( iterator ) 2881 { 2882 while( NULL != (arb = OSDynamicCast(MARB, iterator->getNextObject())) ) 2883 { 2884 if (arb->handle.multicast.channel == mcb->channel) 2885 { 2886 multicastArb->removeObject(arb); 2887 arb->release(); 2888 continue; 2889 } 2890 } 2891 iterator->release(); 2892 } 2893 2894 IORecursiveLockUnlock(fIPLock); 2895} 2896 2897void IOFWIPBusInterface::resetRCBCache() 2898{ 2899 IORecursiveLockLock(fIPLock); 2900 2901 RCB *rcb = NULL; 2902 OSCollectionIterator * iterator = OSCollectionIterator::withCollection( activeRcb ); 2903 2904 if( iterator ) 2905 { 2906 while( NULL != (rcb = OSDynamicCast(RCB, iterator->getNextObject())) ) 2907 releaseRCB(rcb); 2908 2909 iterator->release(); 2910 } 2911 2912 IORecursiveLockUnlock(fIPLock); 2913} 2914 2915void IOFWIPBusInterface::resetMARBCache() 2916{ 2917 IORecursiveLockLock(fIPLock); 2918 2919 MARB *arb = NULL; 2920 OSCollectionIterator * iterator = OSCollectionIterator::withCollection( multicastArb ); 2921 if( iterator ) 2922 { 2923 while( NULL != (arb = OSDynamicCast(MARB, iterator->getNextObject())) ) 2924 { 2925 arb->handle.multicast.channel = DEFAULT_BROADCAST_CHANNEL; 2926 } 2927 iterator->release(); 2928 } 2929 2930 IORecursiveLockUnlock(fIPLock); 2931} 2932 2933void IOFWIPBusInterface::resetMcapState() 2934{ 2935 IORecursiveLockLock(fIPLock); 2936 2937 MCB *mcb = NULL; 2938 OSCollectionIterator * iterator = OSCollectionIterator::withCollection( mcapState ); 2939 2940 if( iterator ) 2941 { 2942 while( NULL != (mcb = OSDynamicCast(MCB, iterator->getNextObject())) ) 2943 { 2944 // Since Mac just does MCAP receive switch to channel 31 2945 if( mcb->ownerNodeID != fLcb->ownNodeID ) // we don't own the channel 2946 { 2947 // leave channel & groupcount untouched. 2948 IOFWAsyncStreamListener *asyncStreamRxClient = OSDynamicCast(IOFWAsyncStreamListener, mcb->asyncStreamID); 2949 if(asyncStreamRxClient != NULL) 2950 { 2951 fControl->removeAsyncStreamListener( asyncStreamRxClient ); 2952 asyncStreamRxClient->release(); 2953 } 2954 2955 mcb->asyncStreamID = NULL; 2956 mcb->expiration = 0; 2957 mcb->nextTransmit = 0; 2958 mcb->finalWarning = 0; 2959 } 2960 } 2961 iterator->release(); 2962 } 2963 2964 IORecursiveLockUnlock(fIPLock); 2965} 2966 2967/*! 2968 @function getARBFromEui64 2969 @abstract Locates the corresponding Unicast ARB (Address resolution block) for GUID 2970 @param lcb - the firewire link control block for this interface. 2971 @param eui64 - global unique id of a device on the bus. 2972 @result Returns ARB if successfull else NULL. 2973*/ 2974ARB *IOFWIPBusInterface::getARBFromEui64(UWIDE eui64) 2975{ 2976 IORecursiveLockLock(fIPLock); 2977 2978 ARB *arb = 0; 2979 OSCollectionIterator *iterator = OSCollectionIterator::withCollection( unicastArb ); 2980 2981 if( iterator ) 2982 { 2983 while( NULL != (arb = OSDynamicCast(ARB, iterator->getNextObject())) ) 2984 { 2985 if (arb->eui64.hi == eui64.hi && arb->eui64.lo == eui64.lo) 2986 break; 2987 } 2988 2989 iterator->release(); 2990 2991 if(arb == NULL) 2992 { 2993 // Create a new entry if it does not exist 2994 if((arb = new ARB) == NULL) 2995 { 2996 IORecursiveLockUnlock(fIPLock); 2997 return arb; 2998 } 2999 3000 unicastArb->setObject(arb); 3001 } 3002 } 3003 3004 IORecursiveLockUnlock(fIPLock); 3005 3006 return(arb); 3007} 3008 3009/*! 3010 @function getArbFromFwAddr 3011 @abstract Locates the corresponding Unicast ARB (Address resolution block) for GUID 3012 @param lcb - the firewire link control block for this interface. 3013 @param FwAddr - global unique id of a device on the bus. 3014 @result Returns ARB if successfull else NULL. 3015*/ 3016ARB *IOFWIPBusInterface::getArbFromFwAddr(UInt8 *fwaddr) 3017{ 3018 IORecursiveLockLock(fIPLock); 3019 3020 ARB *arb = 0; 3021 OSCollectionIterator * iterator = OSCollectionIterator::withCollection( unicastArb ); 3022 3023 if( iterator ) 3024 { 3025 while( NULL != (arb = OSDynamicCast(ARB, iterator->getNextObject())) ) 3026 if (bcmp(fwaddr, arb->fwaddr, kIOFWAddressSize) == 0) 3027 break; 3028 3029 iterator->release(); 3030 } 3031 3032 IORecursiveLockUnlock(fIPLock); 3033 3034 return(arb); 3035} 3036 3037/*! 3038 @function getDrbFromEui64 3039 @abstract Locates the corresponding DRB (device reference block) for GUID 3040 @param lcb - the firewire link control block for this interface. 3041 @param eui64 - global unique id of a device on the bus. 3042 @result Returns DRB if successfull else NULL. 3043*/ 3044DRB *IOFWIPBusInterface::getDrbFromEui64(UWIDE eui64) 3045{ 3046 IORecursiveLockLock(fIPLock); 3047 3048 DRB *drb = 0; 3049 OSCollectionIterator * iterator = OSCollectionIterator::withCollection( activeDrb ); 3050 3051 if( iterator ) 3052 { 3053 while( NULL != (drb = OSDynamicCast(DRB, iterator->getNextObject())) ) 3054 if (drb->eui64.hi == eui64.hi && drb->eui64.lo == eui64.lo) 3055 break; 3056 3057 iterator->release(); 3058 } 3059 3060 IORecursiveLockUnlock(fIPLock); 3061 3062 return(drb); 3063} 3064 3065/*! 3066 @function getDrbFromFwAddr 3067 @abstract Locates the corresponding DRB (device reference block) for GUID 3068 @param lcb - the firewire link control block for this interface. 3069 @param fwaddr - global unique id of a device on the bus. 3070 @result Returns DRB if successfull else NULL. 3071*/ 3072DRB *IOFWIPBusInterface::getDrbFromFwAddr(UInt8 *fwaddr) 3073{ 3074 IORecursiveLockLock(fIPLock); 3075 3076 DRB *drb = 0; 3077 OSCollectionIterator *iterator = OSCollectionIterator::withCollection( activeDrb ); 3078 3079 if( iterator ) 3080 { 3081 while( NULL != (drb = OSDynamicCast(DRB, iterator->getNextObject())) ) 3082 if (bcmp(fwaddr, drb->fwaddr, kIOFWAddressSize) == 0) 3083 break; 3084 3085 iterator->release(); 3086 } 3087 3088 IORecursiveLockUnlock(fIPLock); 3089 3090 return(drb); 3091} 3092 3093 3094 3095/*! 3096 @function getDrbFromDeviceID 3097 @abstract Locates the corresponding DRB (Address resolution block) for IOFireWireNub 3098 @param deviceID - IOFireWireNub to look for. 3099 @result Returns DRB if successfull else NULL. 3100*/ 3101DRB *IOFWIPBusInterface::getDrbFromDeviceID(void *deviceID) 3102{ 3103 IORecursiveLockLock(fIPLock); 3104 3105 DRB *drb = 0; 3106 OSCollectionIterator *iterator = OSCollectionIterator::withCollection( activeDrb ); 3107 3108 if( iterator ) 3109 { 3110 while( NULL != (drb = OSDynamicCast(DRB, iterator->getNextObject())) ) 3111 if (drb->deviceID == deviceID) 3112 break; 3113 3114 iterator->release(); 3115 } 3116 3117 IORecursiveLockUnlock(fIPLock); 3118 3119 return drb; 3120} 3121 3122/*! 3123 @function getMulticastArb 3124 @abstract Locates the corresponding multicast MARB (Address resolution block) for ipaddress 3125 @param lcb - the firewire link control block for this interface. 3126 @param ipAddress - destination ipaddress to send the multicast packet. 3127 @result Returns MARB if successfull else NULL. 3128*/ 3129MARB *IOFWIPBusInterface::getMulticastArb(UInt32 groupAddress) 3130{ 3131 IORecursiveLockLock(fIPLock); 3132 3133 MARB *arb = 0; 3134 OSCollectionIterator *iterator = OSCollectionIterator::withCollection( multicastArb ); 3135 3136 if( iterator ) 3137 { 3138 while( NULL != (arb = OSDynamicCast(MARB, iterator->getNextObject())) ) 3139 if (arb->handle.multicast.groupAddress == groupAddress) 3140 break; 3141 3142 iterator->release(); 3143 } 3144 3145 IORecursiveLockUnlock(fIPLock); 3146 3147 return arb; 3148} 3149 3150/*! 3151 @function getRcb 3152 @abstract Locates a reassembly control block. 3153 @param lcb - the firewire link control block for this interface. 3154 @param sourceID - source nodeid which generated the fragmented packet. 3155 @param dgl - datagram label for the fragmented packet. 3156 @result Returns RCB if successfull else NULL. 3157*/ 3158RCB *IOFWIPBusInterface::getRcb(UInt16 sourceID, UInt16 dgl) 3159{ 3160 IORecursiveLockLock(fIPLock); 3161 3162 RCB *rcb = 0; 3163 OSCollectionIterator *iterator = OSCollectionIterator::withCollection( activeRcb ); 3164 3165 if( iterator ) 3166 { 3167 while( NULL != (rcb = OSDynamicCast(RCB, iterator->getNextObject())) ) 3168 if (rcb->sourceID == sourceID && rcb->dgl == dgl) 3169 break; 3170 3171 iterator->release(); 3172 } 3173 3174 IORecursiveLockUnlock(fIPLock); 3175 3176 return(rcb); 3177} 3178 3179RCB *IOFWIPBusInterface::getRCBCommand( UInt16 sourceID, UInt16 dgl, UInt16 etherType, UInt16 datagramSize, mbuf_t m ) 3180{ 3181 RCB * cmd = (RCB *)fRCBCmdPool->getCommand(false); 3182 3183 if( ( cmd == NULL ) and ( fCurrentRCBCommands < kMaxAsyncCommands ) ) 3184 { 3185 if( ( cmd = new RCB ) != NULL ) 3186 fCurrentRCBCommands++; 3187 } 3188 3189 if( cmd ) 3190 cmd->reinit( sourceID, dgl, etherType, datagramSize, m ); 3191 3192 return cmd; 3193} 3194 3195#pragma mark - 3196#pragma mark ��� Control Block Routines ��� 3197 3198void RCB::reinit(UInt16 id, UInt16 label, UInt16 type, UInt16 size, mbuf_t m) 3199{ 3200 sourceID = id; 3201 dgl = label; 3202 mBuf = m; 3203 timer = kRCBExpirationtime; 3204 datagramSize = size; 3205 etherType = type; 3206 residual = 0; 3207} 3208 3209void RCB::free() 3210{ 3211 OSObject::free(); 3212} 3213 3214#pragma mark - 3215#pragma mark ��� Mbuf Utility Routines ��� 3216 3217bool IOFWIPMBufCommand::init() 3218{ 3219 if ( not OSObject::init() ) 3220 return false; 3221 3222 fMbuf = NULL; 3223 fIPLocalNode = NULL; 3224 fStatus = kIOReturnSuccess; 3225 3226 return true; 3227} 3228 3229void IOFWIPMBufCommand::reinit(mbuf_t pkt, IOFireWireIP *ipNode, IOCommandPool *pool) 3230{ 3231 fIPLocalNode = ipNode; 3232 fMbuf = pkt; 3233 fStatus = kIOReturnSuccess; 3234 fPool = pool; 3235 fInited = true; 3236} 3237 3238mbuf_t IOFWIPMBufCommand::getMBuf() 3239{ 3240 return fMbuf; 3241} 3242 3243void IOFWIPMBufCommand::releaseWithStatus(IOReturn status) 3244{ 3245 if (status == kIOFireWireOutOfTLabels) 3246 fStatus = status; 3247 3248 if(this->getRetainCount() == 2) 3249 { 3250 if ( fInited ) 3251 { 3252 if( fMbuf && (fStatus != kIOFireWireOutOfTLabels) ) 3253 { 3254 fIPLocalNode->fIPoFWDiagnostics.inActiveMbufs++; 3255 fIPLocalNode->freePacket(fMbuf); 3256 fMbuf = NULL; 3257 } 3258 fIPLocalNode = NULL; 3259 } 3260 3261 fInited = false; 3262 3263 this->release(); 3264 3265 fPool->returnCommand(this); 3266 } 3267 else 3268 this->release(); 3269} 3270 3271void IOFWIPMBufCommand::free() 3272{ 3273 fMbuf = NULL; 3274 fIPLocalNode = NULL; 3275 fStatus = kIOReturnSuccess; 3276 3277 OSObject::free(); 3278} 3279 3280static mbuf_t getPacket( UInt32 size, 3281 UInt32 how, 3282 UInt32 smask, 3283 UInt32 lmask ) 3284{ 3285 mbuf_t packet; 3286 UInt32 reqSize = size + smask + lmask; // we over-request so we can fulfill alignment needs. 3287 uint32_t mhlen = mbuf_get_mhlen(); 3288 uint32_t minclsize = mbuf_get_minclsize(); 3289 3290 if(reqSize > mhlen && reqSize <= minclsize) //as protection from drivers that incorrectly assume they always get a single-mbuf packet 3291 reqSize = minclsize + 1; //we force kernel to give us a cluster instead of chained small mbufs. 3292 3293 if( 0 == mbuf_allocpacket(how, reqSize, NULL, &packet)) 3294 { 3295 mbuf_t m = packet; 3296 mbuf_pkthdr_setlen(packet, size); 3297 //run the chain and apply alignment 3298 3299 while(size && m) 3300 { 3301 uintptr_t alignedStart, originalStart; 3302 3303 originalStart = (uintptr_t)mbuf_data(m); 3304 alignedStart = (originalStart + smask) & ~((uintptr_t)smask); 3305 mbuf_setdata(m, (caddr_t)alignedStart, (mbuf_maxlen(m) - (alignedStart - originalStart)) & ~lmask); 3306 3307 if(mbuf_len(m) > size) 3308 mbuf_setlen(m, size); //truncate to remaining portion of packet 3309 3310 size -= mbuf_len(m); 3311 m = mbuf_next(m); 3312 } 3313 return packet; 3314 } 3315 else 3316 return NULL; 3317} 3318 3319mbuf_t IOFWIPBusInterface::allocateMbuf( UInt32 size ) 3320{ 3321 return getPacket( size, MBUF_DONTWAIT, kIOPacketBufferAlign1, kIOPacketBufferAlign16 ); 3322} 3323 3324void IOFWIPBusInterface::moveMbufWithOffset(SInt32 tempOffset, mbuf_t *srcm, vm_address_t *src, SInt32 *srcLen) 3325{ 3326 mbuf_t temp = NULL; 3327 3328 for(;;) 3329 { 3330 3331 if(tempOffset == 0) 3332 break; 3333 3334 if(*srcm == NULL) 3335 break; 3336 3337 if(*srcLen < tempOffset) 3338 { 3339 tempOffset = tempOffset - *srcLen; 3340 temp = mbuf_next(*srcm); 3341 *srcm = temp; 3342 if(*srcm != NULL) 3343 *srcLen = mbuf_len(*srcm); 3344 continue; 3345 } 3346 else if (*srcLen > tempOffset) 3347 { 3348 *srcLen = mbuf_len(*srcm); 3349 *src = (vm_offset_t)mbuf_data(*srcm); 3350 *src += tempOffset; 3351 *srcLen -= tempOffset; 3352 break; 3353 } 3354 else if (*srcLen == tempOffset) 3355 { 3356 temp = mbuf_next(*srcm); 3357 *srcm = temp; 3358 if(*srcm != NULL) 3359 { 3360 *srcLen = mbuf_len(*srcm); 3361 *src = (vm_offset_t)mbuf_data(*srcm); 3362 } 3363 break; 3364 } 3365 } 3366} 3367 3368/*! 3369 @function bufferToMbuf 3370 @abstract Copies buffer to Mbuf. 3371 @param m - destination mbuf. 3372 @param offset - offset into the mbuf data pointer. 3373 @param srcbuf - source buf. 3374 @param srcbufLen - source buffer length. 3375 @result bool - true if success else false. 3376*/ 3377bool IOFWIPBusInterface::bufferToMbuf(mbuf_t m, 3378 UInt32 offset, 3379 vm_address_t *srcbuf, 3380 UInt32 srcbufLen) 3381{ 3382 IORecursiveLockLock(fIPLock); 3383 3384 // Get the source 3385 mbuf_t srcm = m; 3386 SInt32 srcLen = mbuf_len(srcm); 3387 3388 vm_address_t src = (vm_offset_t)mbuf_data(srcm); 3389 3390 // Mbuf manipulated to point at the correct offset 3391 SInt32 tempOffset = offset; 3392 3393 moveMbufWithOffset(tempOffset, &srcm, &src, &srcLen); 3394 3395 // Modify according to our fragmentation 3396 SInt32 dstLen = srcbufLen; 3397 SInt32 copylen = dstLen; 3398 vm_address_t dst = (vm_address_t)srcbuf; 3399 3400 mbuf_t temp = NULL; 3401 3402 for (;;) { 3403 3404 if (srcLen < dstLen) { 3405 // Copy remainder of buffer to current mbuf upto m_len. 3406 BCOPY(dst, src, srcLen); 3407 dst += srcLen; 3408 dstLen -= srcLen; 3409 copylen -= srcLen; 3410 // set the offset 3411 3412 if(copylen == 0){ 3413 // set the new mbuf to point to the new chain 3414 if ( srcm ) 3415 { 3416 temp = mbuf_next(srcm); 3417 srcm = temp; 3418 } 3419 break; 3420 } 3421 3422 if (srcm) 3423 { 3424 // Move on to the next source mbuf. 3425 temp = mbuf_next(srcm); 3426 srcm = temp; 3427 } 3428 3429 if (srcm) 3430 { 3431 srcLen = mbuf_len(srcm); 3432 src = (vm_offset_t)mbuf_data(srcm); 3433 } 3434 3435 if(srcLen == 0) 3436 break; 3437 } 3438 else if (srcLen > dstLen) { 3439 // 3440 // Copy some of buffer to src mbuf, since mbuf 3441 // has more space. 3442 // 3443 BCOPY(dst, src, dstLen); 3444 src += dstLen; 3445 srcLen -= dstLen; 3446 copylen -= dstLen; 3447 3448 if(copylen == 0) 3449 break; 3450 } 3451 else { /* (srcLen == dstLen) */ 3452 // copy remainder of src into remaining space of current mbuffer 3453 BCOPY(dst, src, srcLen); 3454 copylen -= srcLen; 3455 3456 if(copylen == 0){ 3457 if ( srcm ) 3458 { 3459 // set the new mbuf to point to the new chain 3460 temp = mbuf_next(srcm); 3461 srcm = temp; 3462 } 3463 break; 3464 } 3465 // Free current mbuf and move the current onto the next 3466 if ( srcm ) 3467 { 3468 srcm = mbuf_next(srcm); 3469 } 3470 3471 // Do we have any data left to copy? 3472 if (dstLen == 0) 3473 break; 3474 3475 if (srcm) 3476 { 3477 srcLen = mbuf_len(srcm); 3478 src = (vm_offset_t)mbuf_data(srcm); 3479 } 3480 3481 if(srcLen == 0) 3482 break; 3483 } 3484 } 3485 IORecursiveLockUnlock(fIPLock); 3486 3487 return true; 3488} 3489 3490/*! 3491 @function mbufTobuffer 3492 @abstract Copies mbuf data into the buffer pointed by IOMemoryDescriptor. 3493 @param src - source mbuf. 3494 @param offset - offset into the mbuf data pointer. 3495 @param dstbuf - destination buf. 3496 @param dstbufLen - destination buffer length. 3497 @param length - length to copy. 3498 @result NULL if copied else should be invoked again till 3499 the residual is copied into the buffer. 3500*/ 3501mbuf_t IOFWIPBusInterface::mbufTobuffer(const mbuf_t m, 3502 UInt32 *offset, 3503 vm_address_t *dstbuf, 3504 UInt32 dstbufLen, 3505 UInt32 length) 3506{ 3507 // Get the source 3508 mbuf_t srcm = m; 3509 SInt32 srcLen = mbuf_len(srcm); 3510 vm_address_t src = (vm_offset_t)mbuf_data(srcm); 3511 3512 // Mbuf manipulated to point at the correct offset 3513 SInt32 tempOffset = *offset; 3514 3515 moveMbufWithOffset(tempOffset, &srcm, &src, &srcLen); 3516 3517 // Modify according to our fragmentation 3518 SInt32 dstLen = length; 3519 SInt32 copylen = dstLen; 3520 vm_address_t dst = (vm_address_t)dstbuf; 3521 3522 mbuf_t temp = NULL; 3523 3524 for (;;) { 3525 3526 if (srcLen < dstLen) { 3527 3528 // Copy remainder of src mbuf to current dst. 3529 BCOPY(src, dst, srcLen); 3530 dst += srcLen; 3531 dstLen -= srcLen; 3532 copylen -= srcLen; 3533 // set the offset 3534 *offset = *offset + srcLen; 3535 3536 if(copylen == 0){ 3537 // set the new mbuf to point to the new chain 3538 if ( srcm ) 3539 { 3540 temp = mbuf_next(srcm); 3541 srcm = temp; 3542 } 3543 break; 3544 } 3545 // Move on to the next source mbuf. 3546 if ( srcm ) 3547 { 3548 temp = mbuf_next(srcm); 3549 srcm = temp; 3550 } 3551 3552 if ( srcm ) 3553 { 3554 srcLen = mbuf_len(srcm); 3555 src = (vm_offset_t)mbuf_data(srcm); 3556 } 3557 3558 if(srcLen == 0) 3559 break; 3560 } 3561 else if (srcLen > dstLen) { 3562 // Copy some of src mbuf to remaining space in dst mbuf. 3563 BCOPY(src, dst, dstLen); 3564 src += dstLen; 3565 srcLen -= dstLen; 3566 copylen -= dstLen; 3567 // set the offset 3568 *offset = *offset + dstLen; 3569 3570 // Move on to the next destination mbuf. 3571 if(copylen == 0) 3572 break; 3573 } 3574 else { /* (srcLen == dstLen) */ 3575 // copy remainder of src into remaining space of current dst 3576 BCOPY(src, dst, srcLen); 3577 copylen -= srcLen; 3578 3579 if(copylen == 0){ 3580 // set the offset 3581 *offset = 0; 3582 // set the new mbuf to point to the new chain 3583 if ( srcm ) 3584 { 3585 temp = mbuf_next(srcm); 3586 srcm = temp; 3587 } 3588 break; 3589 } 3590 // Free current mbuf and move the current onto the next 3591 if ( srcm ) 3592 { 3593 srcm = mbuf_next(srcm); 3594 } 3595 3596 // Do we have any data left to copy? 3597 if (dstLen == 0) 3598 break; 3599 3600 if ( srcm ) 3601 { 3602 srcLen = mbuf_len(srcm); 3603 src = (vm_offset_t)mbuf_data(srcm); 3604 } 3605 3606 if(srcLen == 0) 3607 break; 3608 } 3609 } 3610 3611 return temp; 3612} 3613 3614#ifdef DEBUG 3615 3616#pragma mark - 3617#pragma mark ��� Debug Routines ��� 3618 3619void IOFWIPBusInterface::showMinRcb(RCB *rcb) { 3620 if (rcb != NULL) { 3621 if(rcb->timer == 1) 3622 IOLog("RCB %p dgl %u mBuf %p datagramSize %u residual %u timer %u \n", rcb, rcb->dgl, rcb->mBuf, rcb->datagramSize, rcb->residual, rcb->timer); 3623 } 3624} 3625 3626// Display the reassembly control block 3627void IOFWIPBusInterface::showRcb(RCB *rcb) { 3628 if (rcb != NULL) { 3629 IOLog("RCB %p\n\r", rcb); 3630 IOLog(" sourceID %04X dgl %u etherType %04X mBlk %p\n\r", rcb->sourceID, rcb->dgl, rcb->etherType, rcb->mBuf); 3631 IOLog(" datagramSize %u residual %u timer %u \n\r", rcb->datagramSize, rcb->residual, rcb->timer); 3632 } 3633} 3634 3635void IOFWIPBusInterface::showArb(ARB *arb) 3636{ 3637 IOLog("ARB %p\n\r", arb); 3638 IOLog(" EUI-64 %08lX %08lX\n\r", arb->eui64.hi, arb->eui64.lo); 3639 3640 IOLog(" fwAddr %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n\r", arb->fwaddr[0], 3641 arb->fwaddr[1], arb->fwaddr[2], arb->fwaddr[3], arb->fwaddr[4], 3642 arb->fwaddr[5], arb->fwaddr[6], arb->fwaddr[7]); 3643 IOLog(" Handle: %08lX %02X %02X %04X%08lX\n\r", arb->handle.unicast.deviceID, 3644 arb->handle.unicast.maxRec, arb->handle.unicast.spd, 3645 arb->handle.unicast.unicastFifoHi, arb->handle.unicast.unicastFifoLo); 3646} 3647 3648 3649void IOFWIPBusInterface::showHandle(TNF_HANDLE *handle) 3650{ 3651 if (handle->unicast.deviceID != NULL) 3652 IOLog(" Unicast handle: %08lX %02X %02X %04X%08lX\n\r", 3653 handle->unicast.deviceID, handle->unicast.maxRec, 3654 handle->unicast.spd, handle->unicast.unicastFifoHi, 3655 handle->unicast.unicastFifoLo); 3656 else 3657 IOLog(" Multicast handle: 00000000 %02X %02X %02X %08lX\n\r", 3658 handle->multicast.maxRec, handle->multicast.spd, 3659 handle->multicast.channel, htonl(handle->multicast.groupAddress)); 3660 3661} 3662 3663void IOFWIPBusInterface::showDrb(DRB *drb) 3664{ 3665 if (drb != NULL) 3666 { 3667 IOLog("DRB 0x%p \n\r", drb); 3668 IOLog(" Device ID %08lX EUI-64 %08lX %08lX\n\r", drb->deviceID, drb->eui64.hi, drb->eui64.lo); 3669 IOLog(" maxPayload %d maxSpeed %d\n\r", drb->maxPayload, drb->maxSpeed); 3670 } 3671} 3672 3673void IOFWIPBusInterface::showLcb() 3674{ 3675 IOLog(" Node ID %04X maxPayload %u maxSpeed %u busGeneration 0x%08lX\n", 3676 fLcb->ownNodeID, fLcb->ownMaxPayload, 3677 fLcb->ownMaxSpeed, fLcb->busGeneration); 3678 3679 // Display the arb's 3680 IORecursiveLockLock(fIPLock); 3681 3682 OSCollectionIterator * iterator = 0; 3683 3684 ARB *arb = 0; 3685 3686 iterator = OSCollectionIterator::withCollection( unicastArb ); 3687 3688 IOLog(" Unicast ARBs\n\r"); 3689 while( NULL != (arb = OSDynamicCast(ARB, iterator->getNextObject())) ) 3690 { 3691 IOLog(" %p\n\r", arb); 3692 showArb(arb); 3693 } 3694 3695 iterator->release(); 3696 3697 IOLog(" Active DRBs\n\r"); 3698 DRB *drb = 0; 3699 iterator = OSCollectionIterator::withCollection( activeDrb ); 3700 3701 while( NULL != (drb = OSDynamicCast(DRB, iterator->getNextObject())) ) 3702 { 3703 IOLog(" %p\n\r", drb); 3704 showDrb(drb); 3705 } 3706 3707 iterator->release(); 3708 3709 RCB *rcb = 0; 3710 iterator = OSCollectionIterator::withCollection( activeRcb ); 3711 UInt32 rcbCount = 0; 3712 3713 while( NULL != (rcb = OSDynamicCast(RCB, iterator->getNextObject())) ) 3714 { 3715 showMinRcb(rcb); 3716 rcbCount++; 3717 } 3718 IOLog(" Active RCBs %u \n", rcbCount); 3719 3720 3721 iterator->release(); 3722 3723 IORecursiveLockUnlock(fIPLock); 3724} 3725 3726#endif 3727