IOFWIPBusInterface.cpp [plain text]
#include "../../KernelHeaders/IOKit/IOFWIPBusInterface.h"
#include <sys/kpi_mbuf.h>
#define BCOPY(s, d, l) do { bcopy((void *) s, (void *) d, l); } while(0)
struct GASPVAL
{
UInt8 specifierID[3]; UInt8 version[3]; } gaspVal = { {0x00, 0x00, 0x5E}, {0x00, 0x00, 0x01} };
extern "C"
{
void watchdog(OSObject *, IOTimerEventSource *);
extern errno_t mbuf_inet6_cksum(mbuf_t mbuf, int protocol, u_int32_t offset, u_int32_t length, u_int16_t *csum);
}
#define super IOService
OSDefineMetaClassAndStructors(IOFWIPBusInterface, IOService)
OSDefineMetaClassAndStructors(MARB, OSObject)
OSDefineMetaClassAndStructors(ARB, OSObject)
OSDefineMetaClassAndStructors(DRB, OSObject)
OSDefineMetaClassAndStructors(RCB, IOCommand)
OSDefineMetaClassAndStructors(MCB, OSObject)
OSDefineMetaClassAndStructors(IOFWIPMBufCommand, IOCommand)
bool IOFWIPBusInterface::init(IOFireWireIP *primaryInterface)
{
fIPLocalNode = OSDynamicCast(IOFireWireIP, primaryInterface);
if( fStarted )
return fStarted;
if(not fIPLocalNode)
{
IOLog("IOFWIPBusInterface::init - Coudn't get Localnode\n");
return false;
}
fControl = fIPLocalNode->getController();
if( not fControl)
{
IOLog("IOFWIPBusInterface::init - Coudn't get Controller\n");
return false;
}
if ( not super::init() )
{
IOLog("IOFWIPBusInterface::init - Couldn't init super\n");
return false;
}
fIP1394AddressSpace = 0;
fAsyncCmdPool = 0;
fMbufCmdPool = 0;
fRCBCmdPool = 0;
fAsyncStreamTxCmdPool = 0;
fAsyncTransitSet = 0;
fAsyncStreamTransitSet = 0;
fCurrentMBufCommands = 0;
fCurrentAsyncIPCommands = 0;
fCurrentRCBCommands = 0;
fUnitCount = 0;
fOptimalMTU = 0;
fLowWaterMark = kLowWaterMark;
fIPLocalNode->fIPoFWDiagnostics.fMaxQueueSize = TRANSMIT_QUEUE_SIZE;
if( not attachIOFireWireIP ( fIPLocalNode ) )
{
IOLog("IOFWIPBusInterface::init - Coudn't attachIOFireWireIP\n");
return false;
}
else
{
this->release();
fControl->retain();
fIPLocalNode->retain();
fControl->resetBus();
fStarted = true;
registerService();
}
return fStarted;
}
bool IOFWIPBusInterface::finalize(IOOptionBits options)
{
if( fStarted )
{
IORecursiveLockLock(fIPLock);
fIPLocalNode->deRegisterFWIPPrivateHandlers();
if(fBroadcastReceiveClient != NULL)
{
fBroadcastReceiveClient->TurnOffNotification();
fControl->removeAsyncStreamListener(fBroadcastReceiveClient);
}
fBroadcastReceiveClient = NULL;
if (fIP1394AddressSpace != NULL)
{
fIP1394AddressSpace->deactivate();
fIP1394AddressSpace->release();
}
fIP1394AddressSpace = NULL;
if(timerSource != NULL)
{
if (workLoop != NULL)
workLoop->removeEventSource(timerSource);
timerSource->release();
}
timerSource = NULL;
IORecursiveLockUnlock(fIPLock);
IOFWIPAsyncWriteCommand *cmd1 = NULL;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( fAsyncTransitSet );
if( iterator )
{
while( NULL != (cmd1 = OSDynamicCast(IOFWIPAsyncWriteCommand, iterator->getNextObject())) )
{
if(cmd1->Busy())
cmd1->wait();
}
iterator->release();
}
fAsyncTransitSet->flushCollection();
fAsyncTransitSet->free();
fAsyncTransitSet = NULL;
IOFWIPAsyncStreamTxCommand *cmd2 = NULL;
iterator = OSCollectionIterator::withCollection( fAsyncStreamTransitSet );
if( iterator )
{
while( NULL != (cmd2 = OSDynamicCast(IOFWIPAsyncStreamTxCommand, iterator->getNextObject())) )
{
if(cmd2->Busy())
cmd2->wait();
}
iterator->release();
}
fAsyncStreamTransitSet->flushCollection();
fAsyncStreamTransitSet->free();
fAsyncStreamTransitSet = NULL;
}
return super::finalize(options);
}
void IOFWIPBusInterface::stop(IOService *provider)
{
if( fStarted )
{
IORecursiveLockLock(fIPLock);
freeAsyncCmdPool();
freeAsyncStreamCmdPool();
if(mcapState != NULL)
{
for ( int channel = 0; channel < kMaxChannels; channel++ )
{
MCB *mcb = OSDynamicCast(MCB, mcapState->getObject(channel));
if(mcb)
{
IOFWAsyncStreamListener *asyncStreamRxClient = OSDynamicCast(IOFWAsyncStreamListener, mcb->asyncStreamID);
if(asyncStreamRxClient != NULL)
{
fControl->removeAsyncStreamListener( asyncStreamRxClient );
asyncStreamRxClient->release();
}
mcb->asyncStreamID = NULL;
}
}
mcapState->flushCollection();
mcapState->free();
mcapState = NULL;
}
if(fControl)
fControl->release();
fControl = NULL;
detachIOFireWireIP();
super::stop(provider);
fStarted = false;
IORecursiveLockUnlock(fIPLock);
}
}
void IOFWIPBusInterface::free()
{
super::free();
}
IOReturn IOFWIPBusInterface::message(UInt32 type, IOService *provider, void *argument)
{
IOReturn res = kIOReturnSuccess;
switch (type)
{
case kIOMessageServiceIsTerminated:
break;
case kIOMessageServiceIsSuspended:
break;
case kIOMessageServiceIsResumed:
if(fStarted == true)
{
resetRCBCache();
resetMcapState();
resetMARBCache();
updateBroadcastValues(true);
}
break;
case kIOMessageServiceIsRequestingClose:
break;
default:
res = kIOReturnUnsupported;
break;
}
return res;
}
bool IOFWIPBusInterface::attachIOFireWireIP(IOFireWireIP *provider)
{
fIPLocalNode = provider;
fLcb = fIPLocalNode->getLcb();
fIPLock = fIPLocalNode->getIPLock();
workLoop = fIPLocalNode->getWorkLoop();
if( initAsyncCmdPool() != kIOReturnSuccess)
return false;
unicastArb = OSSet::withCapacity(kUnicastArbs);
if(unicastArb == 0)
return false;
multicastArb = OSSet::withCapacity(kMulticastArbs);
if(multicastArb == 0)
return false;
activeDrb = OSSet::withCapacity(kActiveDrbs);
if(activeDrb == 0)
return false;
activeRcb = OSSet::withCapacity(kActiveRcbs);
if(activeRcb == 0)
return false;
mcapState = OSArray::withCapacity(kMaxChannels);
if(mcapState == 0)
return false;
for ( int channel = 0; channel < kMaxChannels; channel++ )
{
MCB *mcb = new MCB;
if(mcb)
{
mcb->channel = channel;
mcapState->setObject(channel, mcb);
mcb->release();
}
}
fAsyncStreamTransitSet = OSSet::withCapacity(kMaxAsyncStreamCommands);
if(fAsyncStreamTransitSet == 0)
return false;
fAsyncTransitSet = OSSet::withCapacity(kMaxAsyncCommands);
if(fAsyncTransitSet == 0)
return false;
calculateMaxTransferUnit();
timerSource = IOTimerEventSource::timerEventSource ( ( OSObject* ) this,
( IOTimerEventSource::Action ) &watchdog);
if ( timerSource == NULL )
{
IOLog( "IOFWIPBusInterface::attachIOFireWireIP - Couldn't allocate timer event source\n" );
return false;
}
if ( workLoop->addEventSource ( timerSource ) != kIOReturnSuccess )
{
IOLog( "IOFWIPBusInterface::attachIOFireWireIP - Couldn't add timer event source\n" );
return false;
}
fBroadcastReceiveClient = fControl->createAsyncStreamListener( 0x1f, rxAsyncStream, this );
if ( not fBroadcastReceiveClient )
{
IOLog("IOFWIPBusInterface::attachIOFireWireIP - Couldn't createAsyncStreamListener\n");
return false;
}
if ( createIPFifoAddress (kMaxPseudoAddressSize) != kIOReturnSuccess)
{
IOLog("IOFWIPBusInterface::attachIOFireWireIP - Couldn't createIPFifoAddress\n");
return false;
}
timerSource->setTimeoutMS ( kWatchDogTimerMS );
IOFireWireIPPrivateHandlers privateHandlers;
privateHandlers.newService = this;
privateHandlers.transmitPacket = getOutputHandler();
privateHandlers.updateARPCache = getARPCacheHandler();
privateHandlers.updateMulticastCache = getMulticastCacheHandler();
fIPLocalNode->registerFWIPPrivateHandlers(&privateHandlers);
fBroadcastReceiveClient->TurnOnNotification();
OSObject * prop = fIPLocalNode->getProperty(gFireWire_GUID);
if( prop )
{
setProperty( gFireWire_GUID, prop );
}
return attach(fIPLocalNode);
}
void IOFWIPBusInterface::detachIOFireWireIP()
{
IORecursiveLockLock(fIPLock);
if(fMbufCmdPool != NULL)
{
IOFWIPMBufCommand *cmd = NULL;
do
{
cmd = (IOFWIPMBufCommand*)fMbufCmdPool->getCommand(false);
if(cmd != NULL)
cmd->release();
}while(cmd != NULL);
fMbufCmdPool->release();
fMbufCmdPool = NULL;
fCurrentMBufCommands = 0;
}
if(fRCBCmdPool != NULL)
{
RCB *cmd = NULL;
do
{
cmd = (RCB*)fRCBCmdPool->getCommand(false);
if(cmd != NULL)
cmd->release();
}while(cmd != NULL);
fRCBCmdPool->release();
fRCBCmdPool = NULL;
fCurrentRCBCommands = 0;
}
if(unicastArb != NULL)
{
{
ARB *arb = 0;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( unicastArb );
if( iterator )
{
while( NULL != (arb = OSDynamicCast(ARB, iterator->getNextObject())) )
{
unicastArb->removeObject(arb);
arb->release();
}
iterator->release();
}
}
unicastArb->flushCollection();
unicastArb->free();
unicastArb = NULL;
}
if(multicastArb != NULL)
{
{
MARB *marb = 0;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( multicastArb );
if( iterator )
{
while( NULL != (marb = OSDynamicCast(MARB, iterator->getNextObject())) )
{
multicastArb->removeObject(marb);
marb->release();
}
iterator->release();
}
}
multicastArb->flushCollection();
multicastArb->free();
multicastArb = NULL;
}
if(activeDrb != NULL)
{
{
DRB *drb = 0;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( activeDrb );
if( iterator )
{
while( NULL != (drb = OSDynamicCast(DRB, iterator->getNextObject())) )
{
activeDrb->removeObject(drb);
drb->release();
}
iterator->release();
}
}
activeDrb->flushCollection();
activeDrb->free();
activeDrb = NULL;
}
if(activeRcb != NULL)
{
{
RCB *rcb = 0;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( activeRcb );
if( iterator )
{
while( NULL != (rcb = OSDynamicCast(RCB, iterator->getNextObject())) )
{
activeRcb->removeObject(rcb);
rcb->release();
}
iterator->release();
}
}
activeRcb->flushCollection();
activeRcb->free();
activeRcb = NULL;
}
if(fIPLocalNode)
{
detach(fIPLocalNode);
fIPLocalNode->release();
}
fIPLocalNode = NULL;
IORecursiveLockUnlock(fIPLock);
}
void IOFWIPBusInterface::decrementUnitCount()
{
recursiveScopeLock lock(fIPLock);
if(fUnitCount > 0)
fUnitCount--;
}
void IOFWIPBusInterface::incrementUnitCount()
{
recursiveScopeLock lock(fIPLock);
fUnitCount++;
}
SInt16 IOFWIPBusInterface::getUnitCount()
{
recursiveScopeLock lock(fIPLock);
return fUnitCount;
}
void IOFWIPBusInterface::fwIPUnitAttach()
{
incrementUnitCount();
updateBroadcastValues(true);
fLowWaterMark = kLowWaterMark; }
void IOFWIPBusInterface::fwIPUnitTerminate()
{
decrementUnitCount();
updateBroadcastValues(true);
}
void IOFWIPBusInterface::updateBroadcastValues(bool reset)
{
recursiveScopeLock lock(fIPLock);
if(fStarted)
{
if(reset and (fIPLocalNode != NULL) )
{
IOFireWireNub *localDevice = OSDynamicCast(IOFireWireNub, fIPLocalNode->getDevice());
if( localDevice )
{
fLcb->maxBroadcastPayload = localDevice->maxPackLog(true);
fLcb->maxBroadcastSpeed = localDevice->FWSpeed();
fLcb->ownMaxPayload = localDevice->maxPackLog(true);
localDevice->getNodeIDGeneration(fLcb->busGeneration, fLcb->ownNodeID);
fLcb->ownMaxSpeed = localDevice->FWSpeed();
}
}
DRB *drb = NULL;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( activeDrb );
if( iterator )
{
while( NULL != (drb = OSDynamicCast(DRB, iterator->getNextObject())) )
{
if(fLcb->maxBroadcastSpeed > drb->maxSpeed)
fLcb->maxBroadcastSpeed = drb->maxSpeed;
if(fLcb->maxBroadcastPayload > drb->maxPayload)
fLcb->maxBroadcastPayload = drb->maxPayload;
}
iterator->release();
}
}
updateLinkStatus();
}
void IOFWIPBusInterface::updateLinkStatus()
{
recursiveScopeLock lock(fIPLock);
if(fStarted and (fIPLocalNode != NULL) )
{
fIPLocalNode->setLinkStatus(kIONetworkLinkValid, fIPLocalNode->getCurrentMedium(), 0);
if(fUnitCount > 0)
fIPLocalNode->setLinkStatus (kIONetworkLinkActive | kIONetworkLinkValid,
fIPLocalNode->getCurrentMedium(),
(1 << fLcb->maxBroadcastSpeed) * 100 * 1000000);
fLcb->ownHardwareAddress.spd = fLcb->maxBroadcastSpeed;
fIPLocalNode->setProperty(kIOFWHWAddr, (void *)&fLcb->ownHardwareAddress, sizeof(IP1394_HDW_ADDR));
fOptimalMTU = 0;
}
}
IOReturn IOFWIPBusInterface::createIPFifoAddress(UInt32 fifosize)
{
IOReturn ioStat = kIOReturnSuccess;
fIP1394AddressSpace = fControl->createPseudoAddressSpace(&fIP1394Address, fifosize,
NULL,
&rxUnicast,
this);
if (fIP1394AddressSpace == NULL)
ioStat = kIOReturnNoMemory;
if(ioStat == kIOReturnSuccess ) fIP1394AddressSpace->setARxReqIntCompleteHandler(this, &rxUnicastComplete);
fLcb->ownHardwareAddress.unicastFifoHi = fIP1394Address.addressHi;
fLcb->ownHardwareAddress.unicastFifoLo = fIP1394Address.addressLo;
fIPLocalNode->setProperty(kIOFWHWAddr, (void *)&fLcb->ownHardwareAddress, sizeof(IP1394_HDW_ADDR));
if(ioStat == kIOReturnSuccess )
ioStat = fIP1394AddressSpace->activate();
if(ioStat != kIOReturnSuccess)
IOLog("IOFireWireIP PseudoAddressSpace Activate failure status %d\n", ioStat);
return ioStat;
}
void IOFWIPBusInterface::calculateMaxTransferUnit()
{
IORegistryEntry *parent = fControl->getParentEntry(gIOServicePlane);
if(strncmp(parent->getName(gIOServicePlane), "AppleLynx", strlen("AppleLynx")) == 0)
{
fMaxTxAsyncDoubleBuffer = 1 << 9;
}
else
{
fMaxTxAsyncDoubleBuffer = 1 << ((IOFireWireNub*)(fIPLocalNode->getDevice()))->maxPackLog(true);
}
fMaxTxAsyncDoubleBuffer = MAX(512, fMaxTxAsyncDoubleBuffer);
fIPLocalNode->updateMTU(fMaxTxAsyncDoubleBuffer);
}
UInt32 IOFWIPBusInterface::initAsyncCmdPool()
{
IOReturn status = kIOReturnSuccess;
if( (fAsyncCmdPool == NULL) )
fAsyncCmdPool = IOCommandPool::withWorkLoop(workLoop);
if( (fMbufCmdPool == NULL) )
fMbufCmdPool = IOCommandPool::withWorkLoop(workLoop);
if( (fRCBCmdPool == NULL) )
fRCBCmdPool = IOCommandPool::withWorkLoop(workLoop);
if( (fMbufCmdPool == NULL) or (fAsyncCmdPool == NULL) or (fRCBCmdPool == NULL) )
status = kIOReturnNoMemory;
return status;
}
IOFWIPMBufCommand *IOFWIPBusInterface::getMBufCommand()
{
IOFWIPMBufCommand * mBufCommand = NULL;
if( fMbufCmdPool )
mBufCommand = (IOFWIPMBufCommand *)fMbufCmdPool->getCommand(false);
if(mBufCommand == NULL)
{
if( fCurrentMBufCommands < kMaxAsyncCommands )
{
mBufCommand = new IOFWIPMBufCommand;
if(not mBufCommand->init())
{
mBufCommand->release();
mBufCommand = NULL;
}
else
fCurrentMBufCommands++;
}
}
return mBufCommand;
}
IOFWIPAsyncWriteCommand *IOFWIPBusInterface::getAsyncCommand(bool block, bool *deferNotify)
{
IOFWIPAsyncWriteCommand * cmd = (IOFWIPAsyncWriteCommand *)fAsyncCmdPool->getCommand(block);
if(cmd == NULL)
{
if( fCurrentAsyncIPCommands < kMaxAsyncCommands )
{
cmd = new IOFWIPAsyncWriteCommand;
FWAddress addr;
addr.addressHi = 0xdead;
addr.addressLo = 0xbabeface;
if(not cmd->initAll(fIPLocalNode, this, fMaxTxAsyncDoubleBuffer, addr, txCompleteBlockWrite, this, false))
{
cmd->release();
cmd = NULL;
}
else
{
fCurrentAsyncIPCommands++;
fAsyncTransitSet->setObject(cmd);
}
}
}
if( cmd )
{
fIPLocalNode->fIPoFWDiagnostics.fActiveCmds++;
}
else
{
fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors);
fIPLocalNode->fIPoFWDiagnostics.fNoCommands++;
}
if((fIPLocalNode->fIPoFWDiagnostics.fActiveCmds - fIPLocalNode->fIPoFWDiagnostics.fInActiveCmds) >= fLowWaterMark)
*deferNotify = false;
return cmd;
}
void IOFWIPBusInterface::returnAsyncCommand(IOFWIPAsyncWriteCommand *cmd)
{
if(cmd->notDoubleComplete())
{
if(fAsyncCmdPool != NULL)
fAsyncCmdPool->returnCommand(cmd);
else
cmd->release();
fIPLocalNode->fIPoFWDiagnostics.fInActiveCmds++;
}
else
fIPLocalNode->fIPoFWDiagnostics.fDoubleCompletes++;
}
UInt32 IOFWIPBusInterface::initAsyncStreamCmdPool()
{
IOReturn status = kIOReturnSuccess;
int i = 0;
if(fAsyncStreamTxCmdPool == NULL)
fAsyncStreamTxCmdPool = IOCommandPool::withWorkLoop(workLoop);
IOFWIPAsyncStreamTxCommand *cmd2 = NULL;
for(i=0; i<=kMaxAsyncStreamCommands; i++){
cmd2 = new IOFWIPAsyncStreamTxCommand;
if(!cmd2) {
status = kIOReturnNoMemory;
break;
}
if(!cmd2->initAll(fIPLocalNode, fControl, this, 0, 0, 0, GASP_TAG, fMaxTxAsyncDoubleBuffer,
kFWSpeed100MBit, txCompleteAsyncStream, this)) {
status = kIOReturnNoMemory;
cmd2->release();
break;
}
fAsyncStreamTxCmdPool->returnCommand(cmd2);
fAsyncStreamTransitSet->setObject(cmd2);
}
return status;
}
void IOFWIPBusInterface::freeAsyncCmdPool()
{
IOFWIPAsyncWriteCommand *cmd1 = NULL;
UInt32 freeCount = 0;
if(fAsyncCmdPool == NULL)
return;
do
{
cmd1 = (IOFWIPAsyncWriteCommand*)fAsyncCmdPool->getCommand(false);
if(cmd1 != NULL)
{
freeCount++;
cmd1->release();
}
}while(cmd1 != NULL);
fAsyncCmdPool->release();
fAsyncCmdPool = NULL;
}
void IOFWIPBusInterface::freeAsyncStreamCmdPool()
{
if(fAsyncStreamTxCmdPool == NULL)
return;
IOFWIPAsyncStreamTxCommand *cmd2 = NULL;
UInt32 freeCount = 0;
do{
cmd2 = (IOFWIPAsyncStreamTxCommand*)fAsyncStreamTxCmdPool->getCommand(false);
if(cmd2 != NULL)
{
freeCount++;
cmd2->release();
}
}while(cmd2 != NULL);
fAsyncStreamTxCmdPool->release();
fAsyncStreamTxCmdPool = NULL;
return;
}
IOUpdateARPCache IOFWIPBusInterface::getARPCacheHandler() const
{
return (IOUpdateARPCache) &IOFWIPBusInterface::staticUpdateARPCache;
}
IOUpdateMulticastCache IOFWIPBusInterface::getMulticastCacheHandler() const
{
return (IOUpdateMulticastCache) &IOFWIPBusInterface::staticUpdateMulticastCache;
}
IOTransmitPacket IOFWIPBusInterface::getOutputHandler() const
{
return (IOTransmitPacket) &IOFWIPBusInterface::staticOutputPacket;
}
DRB *IOFWIPBusInterface::initDRBwithDevice(UWIDE eui64, IOFireWireNub *device, bool itsMac)
{
recursiveScopeLock lock(fIPLock);
DRB *drb = getDrbFromEui64(eui64);
if(not drb)
{
if ((drb = new DRB) == NULL)
return NULL;
}
CSRNodeUniqueID fwuid = device->getUniqueID();
if(itsMac)
fIPLocalNode->makeEthernetAddress(&fwuid, drb->fwaddr, GUID_TYPE);
else
fIPLocalNode->getBytesFromGUID((void*)(&fwuid), drb->fwaddr, GUID_TYPE);
drb->deviceID = (void*)device;
drb->eui64 = eui64;
drb->itsMac = itsMac;
drb->maxSpeed = kFWSpeed100MBit;
drb->maxSpeed = device->FWSpeed();
drb->maxPayload = device->maxPackLog(true);
activeDrb->setObject(drb);
return drb;
}
UInt32 IOFWIPBusInterface::getMTU()
{
return FIREWIRE_MTU;
}
UInt32 IOFWIPBusInterface::outputPacket(mbuf_t pkt, void * param)
{
register struct firewire_header *fwh;
int status = kIOReturnError;
fwh = (struct firewire_header*)mbuf_data(pkt);
switch(htons(fwh->fw_type))
{
case FWTYPE_IPV6:
addNDPOptions(pkt);
status = txIP(pkt, fLcb->ownNodeID, fLcb->busGeneration, fLcb->ownMaxPayload, fLcb->maxBroadcastPayload, fLcb->maxBroadcastSpeed, FWTYPE_IPV6);
break;
case FWTYPE_IP:
status = txIP(pkt, fLcb->ownNodeID, fLcb->busGeneration, fLcb->ownMaxPayload, fLcb->maxBroadcastPayload, fLcb->maxBroadcastSpeed, FWTYPE_IP);
break;
case FWTYPE_ARP:
status = txARP(pkt, fLcb->ownNodeID, fLcb->busGeneration, fLcb->maxBroadcastSpeed);
break;
default :
fIPLocalNode->freePacket(pkt);
break;
}
if(status == kIOFireWireOutOfTLabels)
{
status = kIOReturnOutputStall;
if((fIPLocalNode->fIPoFWDiagnostics.fActiveCmds - fIPLocalNode->fIPoFWDiagnostics.fInActiveCmds) <= 1)
fIPLocalNode->fIPoFWDiagnostics.fServiceInOutput++;
if((fIPLocalNode->transmitQueue->getSize() > fIPLocalNode->fIPoFWDiagnostics.fMaxQueueSize)
|| ((fIPLocalNode->fIPoFWDiagnostics.fActiveCmds - fIPLocalNode->fIPoFWDiagnostics.fInActiveCmds) <= 1))
{
fIPLocalNode->freePacket(pkt);
fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors);
status = kIOReturnOutputDropped;
}
}
else
status = kIOReturnOutputSuccess;
return status;
}
void IOFWIPBusInterface::txCompleteBlockWrite(void *refcon, IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd)
{
IOFWIPBusInterface *fwIPPriv = (IOFWIPBusInterface*)refcon;
if(not fwIPPriv)
return;
IOFireWireIP *fwIPObject = OSDynamicCast(IOFireWireIP, fwIPPriv->fIPLocalNode);
if(not fwIPObject)
return;
IOFWIPAsyncWriteCommand *cmd = OSDynamicCast(IOFWIPAsyncWriteCommand, fwCmd);
if(not cmd)
return;
if(status == kIOReturnSuccess)
{
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->outputPackets);
fwIPObject->fIPoFWDiagnostics.fTxUni++;
}
else
{
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->outputErrors);
fwIPObject->fIPoFWDiagnostics.fCallErrs++;
}
cmd->resetDescriptor(status);
fwIPPriv->returnAsyncCommand(cmd);
if ( (fwIPObject->fIPoFWDiagnostics.fActiveCmds - fwIPObject->fIPoFWDiagnostics.fInActiveCmds) <= fwIPPriv->fLowWaterMark )
{
fwIPObject->transmitQueue->service( IOBasicOutputQueue::kServiceAsync );
fwIPObject->fIPoFWDiagnostics.fServiceInCallback++;
}
return;
}
void IOFWIPBusInterface::txCompleteAsyncStream(void *refcon, IOReturn status,
IOFireWireBus *bus, IOFWAsyncStreamCommand *fwCmd)
{
IOFWIPBusInterface *fwIPPriv = (IOFWIPBusInterface*)refcon;
if(not fwIPPriv)
return;
IOFireWireIP *fwIPObject = OSDynamicCast(IOFireWireIP, fwIPPriv->fIPLocalNode);
if(not fwIPObject)
return;
IOFWIPAsyncStreamTxCommand *cmd = OSDynamicCast(IOFWIPAsyncStreamTxCommand, fwCmd);
if(not cmd)
return;
if(status == kIOReturnSuccess)
{
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->outputPackets);
fwIPObject->fIPoFWDiagnostics.fTxBcast++;
}
else
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->outputErrors);
if(fwIPPriv->fAsyncStreamTxCmdPool != NULL) {
fwIPPriv->fAsyncStreamTxCmdPool->returnCommand(cmd);
fwIPObject->fIPoFWDiagnostics.fInActiveBcastCmds++;
}
return;
}
SInt32 IOFWIPBusInterface::txARP(mbuf_t m, UInt16 nodeID, UInt32 busGeneration, IOFWSpeed speed)
{
IOReturn status = kIOReturnSuccess;
if(fAsyncStreamTxCmdPool == NULL)
status = initAsyncStreamCmdPool();
IOFWIPAsyncStreamTxCommand *cmd = (IOFWIPAsyncStreamTxCommand*)fAsyncStreamTxCmdPool->getCommand(false);
if(cmd == NULL)
{
fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors);
fIPLocalNode->fIPoFWDiagnostics.fNoBCastCommands++;
return status;
}
fIPLocalNode->fIPoFWDiagnostics.fActiveBcastCmds++;
IORecursiveLockLock(fIPLock);
mbuf_t n = m;
UInt8 *buf = (UInt8*)cmd->getBufferFromDesc();
UInt32 dstBufLen = cmd->getMaxBufLen();
UInt32 offset = sizeof(struct firewire_header);
UInt32 cmdLen = mbuf_pkthdr_len(m) - offset;
struct arp_packet *fwa_pkt = (struct arp_packet*)(buf);
bzero((caddr_t)fwa_pkt, sizeof(*fwa_pkt));
fwa_pkt->gaspHdr.sourceID = htons(nodeID);
memcpy(&fwa_pkt->gaspHdr.gaspID, &gaspVal, sizeof(GASP_ID));
fwa_pkt->ip1394Hdr.etherType = htons(FWTYPE_ARP);
buf += (sizeof(GASP_HDR) + sizeof(IP1394_UNFRAG_HDR));
mbufTobuffer(n, &offset, (vm_address_t*)buf, dstBufLen, cmdLen);
cmdLen += (sizeof(GASP_HDR) + sizeof(IP1394_UNFRAG_HDR));
status = cmd->reinit( busGeneration,
DEFAULT_BROADCAST_CHANNEL,
cmdLen,
speed,
txCompleteAsyncStream,
this);
if(status == kIOReturnSuccess)
status = cmd->submit();
else
{
fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors);
fAsyncStreamTxCmdPool->returnCommand(cmd);
fIPLocalNode->fIPoFWDiagnostics.fInActiveBcastCmds++;
}
if(status != kIOReturnSuccess)
fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors);
fIPLocalNode->freePacket(m);
IORecursiveLockUnlock(fIPLock);
return status;
}
SInt32 IOFWIPBusInterface::txBroadcastIP(const mbuf_t m, UInt16 nodeID, UInt32 busGeneration,
UInt16 ownMaxPayload, UInt16 maxBroadcastPayload,
IOFWSpeed speed, const UInt16 type, UInt32 channel)
{
UInt16 datagramSize = mbuf_pkthdr_len(m) - sizeof(struct firewire_header);
UInt16 maxPayload = MIN((UInt16)1 << maxBroadcastPayload, (UInt16)1 << ownMaxPayload);
if( maxPayload < fOptimalMTU || fOptimalMTU == 0 )
{
fOptimalMTU = maxPayload;
fIPLocalNode->networkInterface->setIfnetMTU( MAX(fOptimalMTU, 1500) );
fIPLocalNode->fIPoFWDiagnostics.fMaxPacketSize = fOptimalMTU;
}
IOReturn status = ENOBUFS;
if (datagramSize + sizeof(IP1394_UNFRAG_HDR) > maxPayload)
{
fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors);
fIPLocalNode->freePacket(m);
return status;
}
if(fAsyncStreamTxCmdPool == NULL)
initAsyncStreamCmdPool();
IOFWIPAsyncStreamTxCommand *asyncStreamCmd = (IOFWIPAsyncStreamTxCommand*)fAsyncStreamTxCmdPool->getCommand(false);
if(asyncStreamCmd == NULL)
{
fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors);
fIPLocalNode->freePacket(m);
fIPLocalNode->fIPoFWDiagnostics.fNoBCastCommands++;
return status;
}
fIPLocalNode->fIPoFWDiagnostics.fActiveBcastCmds++;
IORecursiveLockLock(fIPLock);
UInt8 *buf = (UInt8*)asyncStreamCmd->getBufferFromDesc();
UInt32 dstBufLen = asyncStreamCmd->getMaxBufLen();
GASP_HDR *gaspHdr = (GASP_HDR *)buf;
gaspHdr->sourceID = htons(nodeID);
memcpy(&gaspHdr->gaspID, &gaspVal, sizeof(GASP_ID));
IP1394_ENCAP_HDR *ip1394Hdr = (IP1394_ENCAP_HDR*)((UInt8*)buf + sizeof(GASP_HDR));
ip1394Hdr->singleFragment.etherType = htons(type);
ip1394Hdr->singleFragment.reserved = htons(UNFRAGMENTED);
UInt32 cmdLen = datagramSize;
UInt32 offset = sizeof(struct firewire_header);
UInt16 headerSize = sizeof(GASP_HDR) + sizeof(IP1394_UNFRAG_HDR);
buf += headerSize;
mbufTobuffer(m, &offset, (vm_address_t*)buf, dstBufLen, cmdLen);
cmdLen += headerSize;
status = asyncStreamCmd->reinit(busGeneration, channel,
cmdLen, speed, txCompleteAsyncStream, this);
if(status == kIOReturnSuccess)
status = asyncStreamCmd->submit();
else
{
fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors);
fAsyncStreamTxCmdPool->returnCommand(asyncStreamCmd);
fIPLocalNode->fIPoFWDiagnostics.fInActiveBcastCmds++;
}
if(status != kIOReturnSuccess)
fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors);
fIPLocalNode->freePacket(m);
IORecursiveLockUnlock(fIPLock);
return status;
}
SInt32 IOFWIPBusInterface::txUnicastUnFragmented(IOFireWireNub *device, const FWAddress addr, const mbuf_t m, const UInt16 pktSize, const UInt16 type)
{
SInt32 status = kIOReturnSuccess;
bool deferNotify = true;
IOFWIPMBufCommand * mBufCommand = getMBufCommand();
if( not mBufCommand )
{
fIPLocalNode->freePacket(m);
fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors);
return status;
}
mBufCommand->reinit(m, fIPLocalNode, fMbufCmdPool);
IOFWIPAsyncWriteCommand *cmd = getAsyncCommand(false, &deferNotify);
mBufCommand->retain();
if(cmd)
{
IP1394_ENCAP_HDR *ip1394Hdr = (IP1394_ENCAP_HDR*)cmd->initPacketHeader(mBufCommand, kCopyBuffers, UNFRAGMENTED,
sizeof(IP1394_UNFRAG_HDR),
sizeof(struct firewire_header));
ip1394Hdr->fragment.datagramSize = htons(UNFRAGMENTED);
ip1394Hdr->singleFragment.etherType = htons(type);
ip1394Hdr->singleFragment.reserved = 0;
status = cmd->transmit (device, pktSize, addr, txCompleteBlockWrite, this, true,
deferNotify, kQueueCommands);
}
mBufCommand->releaseWithStatus(status);
if( status != kIOFireWireOutOfTLabels )
fIPLocalNode->fIPoFWDiagnostics.activeMbufs++;
return status;
}
SInt32 IOFWIPBusInterface::txUnicastFragmented(IOFireWireNub *device, const FWAddress addr, const mbuf_t m,
const UInt16 pktSize, const UInt16 type, UInt16 maxPayload, UInt16 dgl)
{
UInt32 residual = pktSize;
UInt32 fragmentOffset = 0;
UInt32 offset = sizeof(struct firewire_header);
SInt32 status = kIOReturnSuccess;
bool deferNotify = true;
IOFWIPMBufCommand * mBufCommand = getMBufCommand();
if( not mBufCommand )
{
fIPLocalNode->freePacket(m);
fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors);
return status;
}
mBufCommand->reinit(m, fIPLocalNode, fMbufCmdPool);
mBufCommand->retain();
while (residual)
{
deferNotify = true;
status = kIOReturnSuccess;
IOFWIPAsyncWriteCommand *cmd = getAsyncCommand(false, &deferNotify);
if(not cmd)
break;
fIPLocalNode->fIPoFWDiagnostics.fTxFragmentPkts++;
FragmentType fragmentType = FIRST_FRAGMENT;
IP1394_ENCAP_HDR *ip1394Hdr = (IP1394_ENCAP_HDR*)cmd->initPacketHeader(mBufCommand, kCopyBuffers, fragmentType,
sizeof(IP1394_FRAG_HDR),
offset);
UInt32 cmdLen = MIN(residual, maxPayload - sizeof(IP1394_FRAG_HDR));
ip1394Hdr->fragment.datagramSize = htons(pktSize - 1);
if (fragmentOffset == 0)
ip1394Hdr->singleFragment.etherType = htons(type);
else
{
ip1394Hdr->fragment.fragmentOffset = htons(fragmentOffset);
fragmentType = (cmdLen < residual) ? INTERIOR_FRAGMENT : LAST_FRAGMENT;
}
ip1394Hdr->fragment.datagramSize |= htons(fragmentType << 14);
ip1394Hdr->fragment.dgl = htons(dgl);
ip1394Hdr->fragment.reserved = 0;
status = cmd->transmit (device, cmdLen, addr, txCompleteBlockWrite, this, true,
deferNotify, kQueueCommands, fragmentType);
if(status != kIOReturnSuccess)
break;
fragmentOffset += cmdLen; offset += cmdLen;
residual -= cmdLen; }
mBufCommand->releaseWithStatus(status);
if( status != kIOFireWireOutOfTLabels )
fIPLocalNode->fIPoFWDiagnostics.activeMbufs++;
return status;
}
SInt32 IOFWIPBusInterface::txUnicastIP(mbuf_t m, UInt16 nodeID, UInt32 busGeneration, UInt16 ownMaxPayload, IOFWSpeed speed, const UInt16 type)
{
struct firewire_header *fwh = (struct firewire_header *)mbuf_data(m);
IORecursiveLockLock(fIPLock);
ARB *arb = getArbFromFwAddr(fwh->fw_dhost);
SInt32 status = EHOSTUNREACH;
if(arb == NULL)
{
fIPLocalNode->freePacket(m);
fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors);
IORecursiveLockUnlock(fIPLock);
return status;
}
TNF_HANDLE *handle = &arb->handle;
IOFireWireNub *device = OSDynamicCast(IOFireWireNub, (IOFireWireNub*)handle->unicast.deviceID);
if(device == NULL)
{
fIPLocalNode->freePacket(m);
fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors);
IORecursiveLockUnlock(fIPLock);
return status;
}
UInt16 datagramSize = mbuf_pkthdr_len(m) - sizeof(struct firewire_header);
UInt16 residual = datagramSize;
FWAddress addr;
addr.addressHi = handle->unicast.unicastFifoHi;
addr.addressLo = handle->unicast.unicastFifoLo;
UInt32 drbMaxPayload = 1 << device->maxPackLog(true, addr);
UInt32 maxPayload = MIN((UInt32)1 << (handle->unicast.maxRec+1), (UInt32)1 << fLcb->ownMaxPayload);
maxPayload = MIN(drbMaxPayload, maxPayload);
if( maxPayload < fOptimalMTU || fOptimalMTU == 0 )
{
fOptimalMTU = maxPayload;
fIPLocalNode->networkInterface->setIfnetMTU( MAX(fOptimalMTU, 1500) );
fIPLocalNode->fIPoFWDiagnostics.fMaxPacketSize = fOptimalMTU;
}
UInt16 dgl = 0;
bool unfragmented = false;
if (!(unfragmented = ((datagramSize + sizeof(IP1394_UNFRAG_HDR)) <= maxPayload)))
dgl = fLcb->datagramLabel++;
if (unfragmented)
status = txUnicastUnFragmented(device, addr, m, residual, type);
else
status = txUnicastFragmented(device, addr, m, residual, type, maxPayload, dgl);
IORecursiveLockUnlock(fIPLock);
return status;
}
SInt32 IOFWIPBusInterface::txIP(mbuf_t m, UInt16 nodeID, UInt32 busGeneration, UInt16 ownMaxPayload, UInt16 maxBroadcastPayload, IOFWSpeed speed, UInt16 type)
{
if(not (mbuf_flags(m) & MBUF_PKTHDR))
{
fIPLocalNode->freePacket(m);
fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors);
return kIOReturnError;
}
SInt32 status = kIOReturnSuccess;
struct firewire_header *fwh = (struct firewire_header *)mbuf_data(m);
if( ( bcmp(fwh->fw_dhost, fwbroadcastaddr, kIOFWAddressSize) == 0 )
or ( bcmp(fwh->fw_dhost, ipv4multicast, FIREWIREMCAST_V4_LEN) == 0 )
or ( bcmp(fwh->fw_dhost, ipv6multicast, FIREWIREMCAST_V6_LEN) == 0 ) )
status = txBroadcastIP(m, nodeID, busGeneration, ownMaxPayload, maxBroadcastPayload, speed, type, DEFAULT_BROADCAST_CHANNEL);
else
status = txUnicastIP(m, nodeID, busGeneration, ownMaxPayload, speed, type);
return status;
}
void IOFWIPBusInterface::txMCAP(MCB *mcb, UInt32 groupAddress)
{
if(fAsyncStreamTxCmdPool == NULL)
initAsyncStreamCmdPool();
IOFWIPAsyncStreamTxCommand *asyncStreamCmd = (IOFWIPAsyncStreamTxCommand*)fAsyncStreamTxCmdPool->getCommand(false);
if(asyncStreamCmd == NULL)
{
fIPLocalNode->fIPoFWDiagnostics.fNoBCastCommands++;
return;
}
fIPLocalNode->fIPoFWDiagnostics.fActiveBcastCmds++;
struct mcap_packet *packet = (struct mcap_packet*)asyncStreamCmd->getBufferFromDesc();
memset(packet, 0, sizeof(*packet));
packet->gaspHdr.sourceID = htons(fLcb->ownNodeID);
memcpy(&packet->gaspHdr.gaspID, &gaspVal, sizeof(GASP_ID));
packet->ip1394Hdr.etherType = htons(ETHER_TYPE_MCAP);
packet->mcap.length = sizeof(*packet);
MCAST_DESCR *groupDescriptor = packet->mcap.groupDescr;
if (mcb != NULL)
{
MARB *arb = NULL;
packet->mcap.opcode = MCAP_ADVERTISE;
IORecursiveLockLock(fIPLock);
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( multicastArb );
if( iterator )
{
while( NULL != (arb = OSDynamicCast(MARB, iterator->getNextObject())) )
{
if (arb->handle.multicast.channel == mcb->channel)
{
memset(groupDescriptor, 0, sizeof(MCAST_DESCR));
groupDescriptor->length = sizeof(MCAST_DESCR);
groupDescriptor->type = MCAST_TYPE;
groupDescriptor->expiration = mcb->expiration;
groupDescriptor->channel = mcb->channel;
groupDescriptor->speed = arb->handle.multicast.spd;
groupDescriptor->groupAddress = arb->handle.multicast.groupAddress;
groupDescriptor = (MCAST_DESCR*)((UInt64)groupDescriptor + sizeof(MCAST_DESCR));
packet->mcap.length += sizeof(MCAST_DESCR);
}
}
iterator->release();
}
IORecursiveLockUnlock(fIPLock);
}
else
{
memset(groupDescriptor, 0, sizeof(MCAST_DESCR));
packet->mcap.opcode = MCAP_SOLICIT;
packet->mcap.length += sizeof(MCAST_DESCR);
groupDescriptor->length = sizeof(MCAST_DESCR);
groupDescriptor->type = MCAST_TYPE;
groupDescriptor->groupAddress = groupAddress;
}
UInt32 cmdLen = packet->mcap.length; packet->mcap.length = htons(cmdLen);
IOReturn status = asyncStreamCmd->reinit ( fLcb->busGeneration,
DEFAULT_BROADCAST_CHANNEL,
cmdLen,
fLcb->maxBroadcastSpeed,
txCompleteAsyncStream,
this);
if(status == kIOReturnSuccess)
status = asyncStreamCmd->submit();
else
{
fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors);
fAsyncStreamTxCmdPool->returnCommand(asyncStreamCmd);
fIPLocalNode->fIPoFWDiagnostics.fInActiveBcastCmds++;
}
if(status != kIOReturnSuccess)
fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors);
}
void IOFWIPBusInterface::rxUnicastFlush()
{
UInt32 count = 0;
IORecursiveLockLock(fIPLock);
if(fIPLocalNode->fPacketsQueued == true)
{
count = fIPLocalNode->networkInterface->flushInputQueue();
if(count > fIPLocalNode->fIPoFWDiagnostics.fMaxInputCount)
fIPLocalNode->fIPoFWDiagnostics.fMaxInputCount = count;
fIPLocalNode->fPacketsQueued = false;
}
IORecursiveLockUnlock(fIPLock);
return;
}
void IOFWIPBusInterface::rxUnicastComplete(void *refcon)
{
IOFWIPBusInterface *fwIPPriv = (IOFWIPBusInterface*)refcon;
fwIPPriv->rxUnicastFlush();
return;
}
UInt32 IOFWIPBusInterface::rxUnicast( void *refcon,
UInt16 nodeID,
IOFWSpeed &speed,
FWAddress addr,
UInt32 len,
const void *buf,
IOFWRequestRefCon requestRefcon)
{
IOFWIPBusInterface *fwIPPriv = (IOFWIPBusInterface*)refcon;
IOFireWireIP *fwIPObject = OSDynamicCast(IOFireWireIP, fwIPPriv->fIPLocalNode);
IP1394_UNFRAG_HDR *ip1394Hdr = (IP1394_UNFRAG_HDR *)buf;
if(not fwIPPriv->fStarted)
return kIOReturnSuccess;
UInt8 lf = (htons(ip1394Hdr->reserved) >> 14);
if (lf == UNFRAGMENTED)
{
void *datagram = (void *) ((UInt64) ip1394Hdr + sizeof(IP1394_UNFRAG_HDR));
UInt16 datagramSize = len - sizeof(IP1394_UNFRAG_HDR);
UInt16 type = ntohs(ip1394Hdr->etherType);
switch (type)
{
case FWTYPE_IPV6:
case FWTYPE_IP:
if (datagramSize >= IPV4_HDR_SIZE && datagramSize <= FIREWIRE_MTU)
fwIPPriv->rxIP(datagram, datagramSize, FW_M_UCAST, type);
break;
case FWTYPE_ARP:
if (datagramSize >= sizeof(IP1394_ARP) && datagramSize <= FIREWIRE_MTU)
fwIPPriv->rxARP((IP1394_ARP*)datagram, FW_M_UCAST);
break;
default :
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->inputErrors);
break;
}
}
else
{
fwIPObject->fIPoFWDiagnostics.fRxFragmentPkts++;
if(fwIPPriv->rxFragmentedUnicast(nodeID, (IP1394_FRAG_HDR*)ip1394Hdr, len) == kIOReturnError)
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->inputErrors);
}
fwIPObject->fIPoFWDiagnostics.fRxUni++;
return kIOReturnSuccess;
}
IOReturn IOFWIPBusInterface::rxFragmentedUnicast(UInt16 nodeID, IP1394_FRAG_HDR *pkt, UInt32 len)
{
IP1394_FRAG_HDR *fragmentHdr = (IP1394_FRAG_HDR*) pkt; void *fragment = (void *) ((UInt64) fragmentHdr + sizeof(IP1394_FRAG_HDR));
UInt16 fragmentSize = len - sizeof(IP1394_FRAG_HDR);
UInt8 lf = htons(fragmentHdr->datagramSize) >> 14;
UInt16 datagramSize = (htons(fragmentHdr->datagramSize) & 0x3FFF) + 1;
UInt16 label = htons(fragmentHdr->dgl);
if(datagramSize > FIREWIRE_MTU)
return kIOReturnError;
recursiveScopeLock lock(fIPLock);
IOReturn result = kIOReturnSuccess;
UInt16 fragmentOffset = htons(fragmentHdr->fragmentOffset);
RCB *rcb = getRcb(nodeID, label);
if (rcb == NULL)
{
if (lf == FIRST_FRAGMENT)
{
mbuf_t rxMBuf = (mbuf_t)allocateMbuf(datagramSize + sizeof(firewire_header));
if (rxMBuf == NULL)
{
fIPLocalNode->fIPoFWDiagnostics.fNoMbufs++;
return kIOReturnError;
}
if ((rcb = getRCBCommand( nodeID, label, fragmentOffset, datagramSize, rxMBuf )) == NULL)
{
fIPLocalNode->fIPoFWDiagnostics.fNoRCBCommands++;
cleanRCBCache();
fIPLocalNode->freePacket(rxMBuf, 0);
return kIOReturnError;
}
struct firewire_header *fwh = (struct firewire_header *)mbuf_data(rxMBuf);
bzero(fwh, sizeof(struct firewire_header));
fwh->fw_type = fragmentHdr->fragmentOffset;
rcb->residual = rcb->datagramSize;
activeRcb->setObject(rcb);
fragmentOffset = 0;
}
else
result = kIOReturnError;
}
if( result == kIOReturnSuccess )
{
UInt16 amountToCopy = MIN(fragmentSize, rcb->datagramSize - fragmentOffset);
if(amountToCopy > rcb->residual)
{
fIPLocalNode->fIPoFWDiagnostics.fRxFragmentPktsDropped++;
result = kIOReturnError;
}
else
{
bufferToMbuf(rcb->mBuf, sizeof(struct firewire_header)+fragmentOffset, (vm_address_t*)fragment, amountToCopy);
rcb->residual -= MIN(fragmentSize, rcb->residual);
if ( rcb->residual == 0 )
{
if (rcb->etherType == FWTYPE_IP || rcb->etherType == FWTYPE_IPV6)
fIPLocalNode->receivePackets (rcb->mBuf, mbuf_pkthdr_len(rcb->mBuf), false);
else
{
fIPLocalNode->freePacket(rcb->mBuf, 0);
result = kIOReturnError;
}
releaseRCB(rcb, false);
}
}
}
return result;
}
void IOFWIPBusInterface::rxAsyncStream(void *refCon, const void *buffer)
{
IOFWIPBusInterface *fwIPPriv = (IOFWIPBusInterface*)refCon;
IOFireWireIP *fwIPObject = OSDynamicCast(IOFireWireIP, fwIPPriv->fIPLocalNode);
void *datagram;
UInt16 datagramSize;
GASP *gasp = (GASP*)buffer;
LCB *lcb = fwIPPriv->fLcb;
ISOC_DATA_PKT *pkt = (ISOC_DATA_PKT*)buffer;
UInt16 type = 0;
if(not fwIPPriv->fStarted)
return;
if(pkt->tag != GASP_TAG){
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->inputErrors);
fwIPObject->fIPoFWDiagnostics.fGaspTagError++;
return;
}
if (gasp->dataLength < sizeof(GASP_HDR) + sizeof(IP1394_UNFRAG_HDR)) {
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->inputErrors);
fwIPObject->fIPoFWDiagnostics.fGaspHeaderError++;
return;
}
if (memcmp(&gasp->gaspHdr.gaspID, &gaspVal, sizeof(GASP_ID)) != 0) {
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->inputErrors);
fwIPObject->fIPoFWDiagnostics.fNonRFC2734Gasp++;
return;
}
if ((htons(gasp->gaspHdr.sourceID) >> 6) != LOCAL_BUS_ID) {
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->inputErrors);
fwIPObject->fIPoFWDiagnostics.fRemoteGaspError++;
return;
}
if (gasp->ip1394Hdr.reserved != htons(UNFRAGMENTED)) {
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->inputErrors);
fwIPObject->fIPoFWDiagnostics.fEncapsulationHeaderError++;
return;
}
datagram = (void *) ((UInt64) buffer + sizeof(GASP));
datagramSize = gasp->dataLength - (sizeof(GASP_HDR) + sizeof(IP1394_UNFRAG_HDR));
type = ntohs(gasp->ip1394Hdr.etherType);
switch (type) {
case FWTYPE_IPV6:
case FWTYPE_IP:
if (datagramSize >= IPV4_HDR_SIZE && datagramSize <= FIREWIRE_MTU)
fwIPPriv->rxIP(datagram, datagramSize, FW_M_BCAST, type);
break;
case FWTYPE_ARP:
if (datagramSize >= sizeof(IP1394_ARP) && datagramSize <= FIREWIRE_MTU)
fwIPPriv->rxARP((IP1394_ARP*)datagram, FW_M_BCAST);
break;
case ETHER_TYPE_MCAP:
if (datagramSize >= sizeof(IP1394_MCAP) && datagramSize <= FIREWIRE_MTU)
fwIPPriv->rxMCAP(lcb, htons(gasp->gaspHdr.sourceID),
(IP1394_MCAP*)datagram, datagramSize - sizeof(IP1394_MCAP));
break;
}
fwIPObject->fIPoFWDiagnostics.fRxBcast++;
return;
}
IOReturn IOFWIPBusInterface::createAsyncStreamRxClient(UInt8 speed, UInt32 channel, MCB *mcb)
{
IOReturn status = kIOReturnNoMemory;
if(channel != DEFAULT_BROADCAST_CHANNEL)
{
IOFWAsyncStreamListener *newAsyncStreamRxClient = fControl->createAsyncStreamListener( channel, rxAsyncStream, this );
if( newAsyncStreamRxClient != NULL)
{
newAsyncStreamRxClient->retain();
mcb->asyncStreamID = (OSObject*)newAsyncStreamRxClient;
status = kIOReturnSuccess;
}
}
else
{
if(fBroadcastReceiveClient != NULL)
{
fBroadcastReceiveClient->retain();
mcb->asyncStreamID = (OSObject*)fBroadcastReceiveClient;
status = kIOReturnSuccess;
}
}
return status;
}
void IOFWIPBusInterface::rxMCAP(LCB *lcb, UInt16 mcapSourceID, IP1394_MCAP *mcap, UInt32 dataSize)
{
MARB *arb;
UInt32 currentChannel;
MCAST_DESCR *groupDescr = mcap->groupDescr;
MCB *mcb, *priorMcb;
IOFWAsyncStreamListener *asyncStreamRxClient;
if ((mcap->opcode != MCAP_ADVERTISE) && (mcap->opcode != MCAP_SOLICIT))
return;
dataSize = MIN(dataSize, htons(mcap->length) - sizeof(IP1394_MCAP));
while (dataSize >= sizeof(MCAST_DESCR))
{
recursiveScopeLock lock(fIPLock);
if (groupDescr->length != sizeof(MCAST_DESCR))
fIPLocalNode->fIPoFWDiagnostics.fInCorrectMCAPDesc++; else if (groupDescr->type != MCAST_TYPE)
fIPLocalNode->fIPoFWDiagnostics.fUnknownMCAPDesc++; else if ((arb = getMulticastArb(groupDescr->groupAddress)) == NULL)
fIPLocalNode->fIPoFWDiagnostics.fUnknownGroupAddress++; else if (mcap->opcode == MCAP_SOLICIT)
{
mcb = OSDynamicCast(MCB, mcapState->getObject(arb->handle.multicast.channel));
if(mcb)
{
if (mcb->ownerNodeID == lcb->ownNodeID) txMCAP(mcb, 0); }
}
else if ((groupDescr->channel != DEFAULT_BROADCAST_CHANNEL) && (groupDescr->channel < kMaxChannels))
{
mcb = OSDynamicCast(MCB, mcapState->getObject(groupDescr->channel));
if(not mcb)
break;
if ( (groupDescr->expiration < 60) and (mcb->ownerNodeID == mcapSourceID) )
{
currentChannel = groupDescr->channel;
}
else if (mcb->ownerNodeID == mcapSourceID)
{
mcb->expiration = groupDescr->expiration;
}
else if ( (mcb->ownerNodeID < mcapSourceID) or (mcb->expiration < 60) )
{
mcb->ownerNodeID = mcapSourceID;
mcb->expiration = groupDescr->expiration;
}
currentChannel = arb->handle.multicast.channel;
if (currentChannel != groupDescr->channel)
{
priorMcb = OSDynamicCast(MCB, mcapState->getObject(currentChannel));
if(not priorMcb)
break;
if (priorMcb->groupCount == 1) {
asyncStreamRxClient = OSDynamicCast(IOFWAsyncStreamListener, mcb->asyncStreamID);
if(asyncStreamRxClient != NULL)
{
fControl->removeAsyncStreamListener( asyncStreamRxClient );
asyncStreamRxClient->release();
}
priorMcb->asyncStreamID = NULL;
priorMcb->groupCount = 0;
}
else if (priorMcb->groupCount > 0)
priorMcb->groupCount--;
if (mcb->asyncStreamID == NULL)
{
if(createAsyncStreamRxClient(groupDescr->speed, groupDescr->channel, mcb) != kIOReturnSuccess)
break;
}
arb->handle.multicast.channel = groupDescr->channel;
mcb->groupCount++;
}
}
dataSize -= MIN(groupDescr->length, dataSize);
groupDescr = (MCAST_DESCR*)((UInt64)groupDescr + groupDescr->length);
}
}
IOReturn IOFWIPBusInterface::rxIP(void *pkt, UInt32 len, UInt32 flags, UInt16 type)
{
mbuf_t rxMBuf = NULL;
struct firewire_header *fwh = NULL;
bool queuePkt = false;
IOReturn ret = kIOReturnSuccess;
IORecursiveLockLock(fIPLock);
if ((rxMBuf = (mbuf_t)allocateMbuf(len + sizeof(firewire_header))) != NULL)
{
bufferToMbuf(rxMBuf, sizeof(struct firewire_header), (vm_address_t*)pkt, len);
if (rxMBuf != NULL)
{
fwh = (struct firewire_header *)mbuf_data(rxMBuf);
bzero(fwh, sizeof(struct firewire_header));
fwh->fw_type = htons(type);
queuePkt = (flags == FW_M_UCAST);
if(queuePkt)
bcopy(fIPLocalNode->macAddr, fwh->fw_dhost, kIOFWAddressSize);
else
bcopy(fwbroadcastaddr, fwh->fw_dhost, kIOFWAddressSize);
if(FWTYPE_IPV6 == type)
{
if( updateNDPCache(rxMBuf) == true )
{
mbuf_prepend(&rxMBuf, sizeof(struct firewire_header), MBUF_DONTWAIT);
}
}
}
else
{
fIPLocalNode->fIPoFWDiagnostics.fNoMbufs++;
ret = kIOReturnNoMemory;
}
if(ret == kIOReturnSuccess)
{
fIPLocalNode->receivePackets(rxMBuf, mbuf_pkthdr_len(rxMBuf), queuePkt);
}
else
{
if(rxMBuf != NULL)
fIPLocalNode->freePacket(rxMBuf, 0);
fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->inputErrors);
}
}
IORecursiveLockUnlock(fIPLock);
return ret;
}
IOReturn IOFWIPBusInterface::rxARP(IP1394_ARP *arp, UInt32 flags){
mbuf_t rxMBuf;
struct firewire_header *fwh = NULL;
void *datagram = NULL;
if (arp->hardwareType != htons(ARP_HDW_TYPE)
|| arp->protocolType != htons(FWTYPE_IP)
|| arp->hwAddrLen != sizeof(IP1394_HDW_ADDR)
|| arp->ipAddrLen != IPV4_ADDR_SIZE)
{
IOLog("IOFireWireIP: rxARP ERROR in packet header\n");
return kIOReturnError;
}
IORecursiveLockLock(fIPLock);
if ((rxMBuf = (mbuf_t)allocateMbuf(sizeof(*arp) + sizeof(struct firewire_header))) != NULL)
{
fwh = (struct firewire_header *)mbuf_data(rxMBuf);
datagram = ((UInt8*)mbuf_data(rxMBuf)) + sizeof(struct firewire_header);
bzero(fwh, sizeof(struct firewire_header));
fwh->fw_type = htons(FWTYPE_ARP);
memcpy(datagram, arp, sizeof(*arp));
fIPLocalNode->receivePackets(rxMBuf, mbuf_pkthdr_len(rxMBuf), 0);
}
else
fIPLocalNode->fIPoFWDiagnostics.fNoMbufs++;
IORecursiveLockUnlock(fIPLock);
return kIOReturnSuccess;
}
void watchdog(OSObject *obj, IOTimerEventSource *src)
{
IOFWIPBusInterface *FWIPPriv = (IOFWIPBusInterface*)obj;
FWIPPriv->processWatchDogTimeout();
}
void IOFWIPBusInterface::processWatchDogTimeout()
{
recursiveScopeLock lock(fIPLock);
updateMcapState();
cleanRCBCache();
fIPLocalNode->fIPoFWDiagnostics.fMaxQueueSize = max(fIPLocalNode->fIPoFWDiagnostics.fTxUni - fPrevTransmitCount, TRANSMIT_QUEUE_SIZE);
fPrevTransmitCount = fIPLocalNode->fIPoFWDiagnostics.fTxUni;
fIPLocalNode->fIPoFWDiagnostics.fLastStarted++;
if( not fIPLocalNode->fIPoFWDiagnostics.fDoFastRetry )
{
fIPLocalNode->fIPoFWDiagnostics.fDoFastRetry = ((fIPLocalNode->fIPoFWDiagnostics.fBusyAcks - fPrevBusyAcks) > kMaxBusyXAcksPerSecond);
fPrevBusyAcks = fIPLocalNode->fIPoFWDiagnostics.fBusyAcks;
fFastRetryUnsetTimer = fPrevFastRetryBusyAcks = fIPLocalNode->fIPoFWDiagnostics.fFastRetryBusyAcks = 0;
}
else
{
fFastRetryUnsetTimer = (fIPLocalNode->fIPoFWDiagnostics.fFastRetryBusyAcks - fPrevFastRetryBusyAcks) ? 0 : fFastRetryUnsetTimer + 1;
fIPLocalNode->fIPoFWDiagnostics.fDoFastRetry = not (fFastRetryUnsetTimer > kMaxSecondsToTurnOffFastRetry);
fPrevBusyAcks = fIPLocalNode->fIPoFWDiagnostics.fBusyAcks;
fPrevFastRetryBusyAcks = fIPLocalNode->fIPoFWDiagnostics.fFastRetryBusyAcks;
}
timerSource->setTimeoutMS(kWatchDogTimerMS);
}
#pragma mark -
#pragma mark еее IPv6 NDP routines еее
const int ipv6fwoffset = 8;
bool IOFWIPBusInterface::addNDPOptions(mbuf_t m)
{
bool ret = false;
if(not (mbuf_flags(m) & MBUF_PKTHDR))
return ret;
vm_address_t src = (vm_offset_t)mbuf_data(m);
if(src == 0)
return ret;
UInt32 fwhdrlen = sizeof(firewire_header);
mbuf_t ipv6Mbuf = m;
int pkthdrlen = 0;
if(mbuf_len(m) == sizeof(firewire_header))
{
ipv6Mbuf = mbuf_next(m);
if(ipv6Mbuf == NULL)
return ret;
src = (vm_offset_t)mbuf_data(ipv6Mbuf);
fwhdrlen = 0;
pkthdrlen = mbuf_pkthdr_len(ipv6Mbuf);
}
if(mbuf_len(ipv6Mbuf) < (fwhdrlen + sizeof(struct ip6_hdr)))
return ret;
if(mbuf_trailingspace(ipv6Mbuf) < (int)sizeof(IP1394_NDP))
return ret;
UInt8 *bufPtr = (UInt8*)(src + fwhdrlen);
struct ip6_hdr *ip6 = (struct ip6_hdr*)bufPtr;
struct icmp6_hdr *icp = (struct icmp6_hdr*)(ip6 + 1);
struct nd_neighbor_advert *nd_na = (struct nd_neighbor_advert*)icp;
struct nd_neighbor_solicit *nd_ns = (struct nd_neighbor_solicit*)icp;
int offset = sizeof(*ip6) + fwhdrlen;
bool modify = false;
IP1394_NDP *fwndp = NULL;
u_int16_t *icmp6_cksum = NULL;
if(nd_ns->nd_ns_type == ND_NEIGHBOR_SOLICIT)
{
fwndp = (IP1394_NDP*)((UInt8*)nd_ns + sizeof(struct nd_neighbor_solicit));
if(fwndp->type == 1)
{
modify = true;
icmp6_cksum = &nd_ns->nd_ns_cksum;
}
}
if(nd_na->nd_na_type == ND_NEIGHBOR_ADVERT)
{
fwndp = (IP1394_NDP*)((UInt8*)nd_na + sizeof(struct nd_neighbor_advert));
if(fwndp->type == 2)
{
modify = true;
icmp6_cksum = &nd_na->nd_na_cksum;
}
}
if(modify)
{
fwndp->len = 3; bzero(fwndp->reserved, 6); fwndp->senderMaxRec = fLcb->ownHardwareAddress.maxRec; fwndp->sspd = fLcb->ownHardwareAddress.spd; fwndp->senderUnicastFifoHi = htons(fLcb->ownHardwareAddress.unicastFifoHi); fwndp->senderUnicastFifoLo = htonl(fLcb->ownHardwareAddress.unicastFifoLo);
mbuf_setlen(ipv6Mbuf, mbuf_len(ipv6Mbuf)+ipv6fwoffset);
mbuf_pkthdr_setlen(m, mbuf_pkthdr_len(m)+ipv6fwoffset);
if(pkthdrlen != 0)
mbuf_pkthdr_setlen(ipv6Mbuf, pkthdrlen+ipv6fwoffset);
int icmp6len = ntohs(ip6->ip6_plen) + ipv6fwoffset;
ip6->ip6_plen = htons(icmp6len);
mbuf_inet6_cksum(ipv6Mbuf, IPPROTO_ICMPV6, offset, icmp6len, icmp6_cksum);
}
return ret;
}
bool IOFWIPBusInterface::updateNDPCache(mbuf_t m)
{
bool result = false;
if(not (mbuf_flags(m) & MBUF_PKTHDR))
{
return result;
}
mbuf_t ipv6Mbuf = m;
int fwhdrlen = sizeof(firewire_header);
int pkthdrlen = 0;
if(mbuf_len(m) == sizeof(firewire_header))
{
ipv6Mbuf = mbuf_next(m);
if(ipv6Mbuf == NULL)
{
return result ;
}
fwhdrlen = 0;
pkthdrlen = mbuf_pkthdr_len(ipv6Mbuf);
}
vm_address_t src = (vm_offset_t)mbuf_data(ipv6Mbuf);
if(src == 0)
{
return result;
}
if(mbuf_len(ipv6Mbuf) < (sizeof(struct ip6_hdr) + fwhdrlen))
{
return result;
}
if(mbuf_trailingspace(ipv6Mbuf) < (int)sizeof(IP1394_NDP))
{
return result;
}
struct ip6_hdr *ip6 = (struct ip6_hdr*)((UInt8*)src + fwhdrlen);
struct icmp6_hdr *icp = (struct icmp6_hdr*)(ip6 + 1);
struct nd_neighbor_advert *nd_na = (struct nd_neighbor_advert*)icp;
struct nd_neighbor_solicit *nd_ns = (struct nd_neighbor_solicit*)icp;
int offset = sizeof(*ip6);
IP1394_NDP *fwndp = NULL;
bool modify = false;
u_int16_t *icmp6_cksum = NULL;
if(nd_ns->nd_ns_type == ND_NEIGHBOR_SOLICIT)
{
fwndp = (IP1394_NDP*)((UInt8*)nd_ns + sizeof(struct nd_neighbor_solicit));
if(fwndp->type == 1)
{
modify = true;
icmp6_cksum = &nd_ns->nd_ns_cksum;
}
}
if(nd_na->nd_na_type == ND_NEIGHBOR_ADVERT)
{
fwndp = (IP1394_NDP*)((UInt8*)nd_na + sizeof(struct nd_neighbor_advert));
if(fwndp->type == 2)
{
modify = true;
icmp6_cksum = &nd_na->nd_na_cksum;
}
}
ARB *arb = NULL;
if(modify && fwndp != NULL && fwndp->len > 2)
{
arb = getArbFromFwAddr(fwndp->lladdr);
if(arb != NULL)
{
bcopy(fwndp->lladdr, &arb->eui64, kIOFWAddressSize);
arb->eui64.hi = OSSwapHostToBigInt32(arb->eui64.hi);
arb->eui64.lo = OSSwapHostToBigInt32(arb->eui64.lo);
bcopy(fwndp->lladdr, arb->fwaddr, kIOFWAddressSize);
arb->handle.unicast.maxRec = fwndp->senderMaxRec;
arb->handle.unicast.spd = fwndp->sspd;
arb->handle.unicast.unicastFifoHi = htons(fwndp->senderUnicastFifoHi);
arb->handle.unicast.unicastFifoLo = htonl(fwndp->senderUnicastFifoLo);
arb->handle.unicast.deviceID = getDeviceID(arb->eui64, &arb->itsMac);
fwndp->len = 2; fwndp->senderMaxRec = 0;
fwndp->sspd = 0;
fwndp->senderUnicastFifoHi = 0;
fwndp->senderUnicastFifoLo = 0;
mbuf_adj(ipv6Mbuf, fwhdrlen);
mbuf_setlen(ipv6Mbuf, mbuf_len(ipv6Mbuf)-8);
mbuf_pkthdr_setlen(m, mbuf_pkthdr_len(m)-8);
if(pkthdrlen != 0)
mbuf_pkthdr_setlen(ipv6Mbuf, mbuf_pkthdr_len(ipv6Mbuf)-8);
int icmp6len = ntohs(ip6->ip6_plen) - 8;
ip6->ip6_plen = htons(icmp6len);
*icmp6_cksum = 0xFFFF;
mbuf_inet6_cksum(ipv6Mbuf, IPPROTO_ICMPV6, offset, icmp6len, icmp6_cksum);
result = true;
}
}
return result;
}
void IOFWIPBusInterface::updateNDPCache(void *buf, UInt16 *len)
{
struct icmp6_hdr *icp = NULL;
struct ip6_hdr *ip6;
struct nd_neighbor_advert *nd_na = NULL;
struct nd_neighbor_solicit *nd_ns = NULL;
ARB *arb = NULL;
IP1394_NDP *fwndp = NULL;
bool update = false;
ip6 = (struct ip6_hdr*)buf;
icp = (struct icmp6_hdr*)(ip6 + 1);
nd_na = (struct nd_neighbor_advert*)icp;
nd_ns = (struct nd_neighbor_solicit*)icp;
if(nd_ns->nd_ns_type == ND_NEIGHBOR_SOLICIT)
{
fwndp = (IP1394_NDP*)((UInt8*)nd_ns + sizeof(struct nd_neighbor_solicit));
if(fwndp->type == 1)
{
update = true;
}
}
if(nd_na->nd_na_type == ND_NEIGHBOR_ADVERT)
{
fwndp = (IP1394_NDP*)((UInt8*)nd_na + sizeof(struct nd_neighbor_advert));
if(fwndp->type == 2)
{
update = true;
}
}
if(update && fwndp != NULL && fwndp->len > 2)
{
arb = getArbFromFwAddr(fwndp->lladdr);
if(arb != NULL)
{
bcopy(fwndp->lladdr, &arb->eui64, kIOFWAddressSize);
arb->eui64.hi = OSSwapHostToBigInt32(arb->eui64.hi);
arb->eui64.lo = OSSwapHostToBigInt32(arb->eui64.lo);
bcopy(fwndp->lladdr, arb->fwaddr, kIOFWAddressSize);
arb->handle.unicast.maxRec = fwndp->senderMaxRec;
arb->handle.unicast.spd = fwndp->sspd;
arb->handle.unicast.unicastFifoHi = htons(fwndp->senderUnicastFifoHi);
arb->handle.unicast.unicastFifoLo = htonl(fwndp->senderUnicastFifoLo);
arb->handle.unicast.deviceID = getDeviceID(arb->eui64, &arb->itsMac);
*len -= 8;
fwndp->len = 2; fwndp->senderMaxRec = 0;
fwndp->sspd = 0;
fwndp->senderUnicastFifoHi = 0;
fwndp->senderUnicastFifoLo = 0;
}
}
return;
}
#pragma mark -
#pragma mark еее IOFWIPBusInterface utility routines еее
bool IOFWIPBusInterface::staticUpdateARPCache(void *refcon, IP1394_ARP *fwa)
{
return ((IOFWIPBusInterface*)refcon)->updateARPCache(fwa);
}
bool IOFWIPBusInterface::staticUpdateMulticastCache(void *refcon, IOFWAddress *addrs, UInt32 count)
{
return ((IOFWIPBusInterface*)refcon)->updateMulticastCache(addrs, count);
}
UInt32 IOFWIPBusInterface::staticOutputPacket(mbuf_t pkt, void * param)
{
return ((IOFWIPBusInterface*)param)->outputPacket(pkt,param);
}
bool IOFWIPBusInterface::wellKnownMulticastAddress(IOFWAddress *addr)
{
bool found = (memcmp(addr->bytes, IPv4KnownMcastAddresses, sizeof(IPv4KnownMcastAddresses)) == 0) ? true : false;
if(not found)
{
if(addr->bytes[0] == 0xff) {
found = true;
if(addr->bytes[1] & BIT_SET(4))
found = false;
else found = true;
}
}
return found;
}
bool IOFWIPBusInterface::updateMulticastCache(IOFWAddress *addrs, UInt32 count)
{
OSSet *newMulticastAddresses = OSSet::withCapacity(kMulticastArbs);
if(newMulticastAddresses == 0)
return false;
IORecursiveLockLock(fIPLock);
IOFWAddress *tempAddresses = addrs;
UInt32 tempCount = count;
MARB *arb = NULL;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( multicastArb );
bool found = false;
if ( iterator )
{
while(tempCount)
{
found = false;
while( NULL != (arb = OSDynamicCast(MARB, iterator->getNextObject())) )
{
UInt32 newGroupAddress = 0;
memcpy(&newGroupAddress, &tempAddresses->bytes[4], sizeof(newGroupAddress));
found = ( arb->handle.multicast.groupAddress == newGroupAddress ) ? true : false;
if(found) break;
}
iterator->reset();
if( (not found) and (not wellKnownMulticastAddress(tempAddresses)) )
{
MARB *tempArb = new MARB;
if(tempArb)
{
tempArb->handle.multicast.deviceID = 0; tempArb->handle.multicast.maxRec = fLcb->ownHardwareAddress.maxRec; tempArb->handle.multicast.spd = fLcb->ownHardwareAddress.spd; tempArb->handle.multicast.reserved = 0;
tempArb->handle.multicast.channel = DEFAULT_BROADCAST_CHANNEL; memcpy(&tempArb->handle.multicast.groupAddress, &tempAddresses->bytes[4],
sizeof(tempArb->handle.multicast.groupAddress));
newMulticastAddresses->setObject(tempArb);
}
}
tempAddresses++;
tempCount--;
}
iterator->release();
}
iterator = OSCollectionIterator::withCollection( newMulticastAddresses );
if ( iterator )
{
while( NULL != (arb = OSDynamicCast(MARB, iterator->getNextObject())) )
{
newMulticastAddresses->removeObject(arb);
multicastArb->setObject(arb);
txMCAP(0, arb->handle.multicast.groupAddress);
}
iterator->release();
}
newMulticastAddresses->flushCollection();
newMulticastAddresses->free();
IORecursiveLockUnlock(fIPLock);
return true;
}
bool IOFWIPBusInterface::updateARPCache(IP1394_ARP *fwa)
{
ARB *fwarb = NULL;
UWIDE eui64;
IORecursiveLockLock(fIPLock);
eui64.hi = htonl(fwa->senderUniqueID.hi);
eui64.lo = htonl(fwa->senderUniqueID.lo);
fwarb = getARBFromEui64(eui64);
if(fwarb)
{
fwarb->handle.unicast.maxRec = fwa->senderMaxRec; fwarb->handle.unicast.spd = fwa->sspd;
fwarb->handle.unicast.unicastFifoHi = htons(fwa->senderUnicastFifoHi);
fwarb->handle.unicast.unicastFifoLo = htonl(fwa->senderUnicastFifoLo);
fwarb->eui64.hi = eui64.hi;
fwarb->eui64.lo = eui64.lo;
fwarb->handle.unicast.deviceID = getDeviceID(fwarb->eui64, &fwarb->itsMac);
fIPLocalNode->getBytesFromGUID(&fwarb->eui64, fwarb->fwaddr, 0);
}
IORecursiveLockUnlock(fIPLock);
return true;
}
ARB *IOFWIPBusInterface::updateARBwithDevice(IOFireWireNub *device, UWIDE eui64)
{
IORecursiveLockLock(fIPLock);
ARB *arb = getARBFromEui64(eui64);
if(arb != NULL)
{
arb->handle.unicast.deviceID = device;
arb->handle.unicast.maxRec = device->maxPackLog(true);
arb->handle.unicast.spd = device->FWSpeed();
arb->itsMac = false;
arb->eui64.hi = eui64.hi;
arb->eui64.lo = eui64.lo;
fIPLocalNode->getBytesFromGUID(&eui64, arb->fwaddr, 0);
}
IORecursiveLockUnlock(fIPLock);
return arb;
}
void IOFWIPBusInterface::cleanRCBCache()
{
IORecursiveLockLock(fIPLock);
RCB *rcb = 0;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( activeRcb );
if( iterator )
{
while( NULL != (rcb = OSDynamicCast(RCB, iterator->getNextObject())) )
{
if(rcb->timer > 1)
rcb->timer--; else if (rcb->timer == 1)
releaseRCB(rcb);
}
iterator->release();
}
IORecursiveLockUnlock(fIPLock);
}
void* IOFWIPBusInterface::getDeviceID(UWIDE eui64, bool *itsMac) {
DRB *drb = getDrbFromEui64(eui64);
if (drb != NULL)
{
*itsMac = drb->itsMac;
return(drb->deviceID);
}
else
{
*itsMac = false;
return(NULL);
}
}
void IOFWIPBusInterface::releaseDRB(UInt8 *fwaddr)
{
IORecursiveLockLock(fIPLock);
DRB *drb = NULL;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( activeDrb );
if( iterator )
{
while( NULL != (drb = OSDynamicCast(DRB, iterator->getNextObject())) )
{
if (bcmp(fwaddr, drb->fwaddr, kIOFWAddressSize) == 0)
{
drb->deviceID = NULL; activeDrb->removeObject(drb); drb->release();
}
}
iterator->release();
}
IORecursiveLockUnlock(fIPLock);
}
void IOFWIPBusInterface::releaseARB(UInt8 *fwaddr)
{
IORecursiveLockLock(fIPLock);
ARB *arb = NULL;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( unicastArb );
if( iterator )
{
while( NULL != (arb = OSDynamicCast(ARB, iterator->getNextObject())) )
{
if (bcmp(fwaddr, arb->fwaddr, kIOFWAddressSize) == 0)
{
arb->handle.unicast.deviceID = NULL;
unicastArb->removeObject(arb);
arb->release();
}
}
iterator->release();
}
IORecursiveLockUnlock(fIPLock);
}
void IOFWIPBusInterface::releaseRCB(RCB *rcb, bool freeMbuf)
{
IORecursiveLockLock(fIPLock);
if(freeMbuf && rcb->mBuf != NULL)
{
fIPLocalNode->freePacket(rcb->mBuf, 0);
rcb->mBuf = NULL;
}
activeRcb->removeObject(rcb);
fRCBCmdPool->returnCommand(rcb);
IORecursiveLockUnlock(fIPLock);
}
void IOFWIPBusInterface::updateMcapState()
{
IORecursiveLockLock(fIPLock);
MCB *mcb = NULL;
OSCollectionIterator *iterator = OSCollectionIterator::withCollection( mcapState );
if( iterator )
{
while( NULL != (mcb = OSDynamicCast(MCB, iterator->getNextObject())) )
{
if (mcb->expiration > 1) mcb->expiration--; else if (mcb->expiration == 1) {
mcb->expiration = 0; if (mcb->groupCount > 0)
mcb->groupCount--;
IOFWAsyncStreamListener *asyncStreamRxClient = OSDynamicCast(IOFWAsyncStreamListener, mcb->asyncStreamID);
if(asyncStreamRxClient != NULL)
{
fControl->removeAsyncStreamListener( asyncStreamRxClient );
asyncStreamRxClient->release();
}
mcb->asyncStreamID = NULL;
releaseMulticastARB(mcb);
if (mcb->ownerNodeID == fLcb->ownNodeID) {
mcb->finalWarning = 4; mcb->nextTransmit = 1; }
}
if (mcb->ownerNodeID != fLcb->ownNodeID)
continue; else if (mcb->nextTransmit > 1) mcb->nextTransmit--; else if (mcb->nextTransmit == 1)
{ if (mcb->groupCount > 0) mcb->expiration = 60;
txMCAP(mcb, 0);
if (mcb->expiration > 0)
mcb->nextTransmit = 10; else if (--mcb->finalWarning > 0)
mcb->nextTransmit = 10; else
{
mcb->ownerNodeID = MCAP_UNOWNED; mcb->nextTransmit = 0; releaseMulticastARB(mcb);
}
}
}
iterator->release();
}
IORecursiveLockUnlock(fIPLock);
}
void IOFWIPBusInterface::releaseMulticastARB(MCB *mcb)
{
IORecursiveLockLock(fIPLock);
MARB *arb = NULL;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( multicastArb );
if( iterator )
{
while( NULL != (arb = OSDynamicCast(MARB, iterator->getNextObject())) )
{
if (arb->handle.multicast.channel == mcb->channel)
{
multicastArb->removeObject(arb);
arb->release();
continue;
}
}
iterator->release();
}
IORecursiveLockUnlock(fIPLock);
}
void IOFWIPBusInterface::resetRCBCache()
{
IORecursiveLockLock(fIPLock);
RCB *rcb = NULL;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( activeRcb );
if( iterator )
{
while( NULL != (rcb = OSDynamicCast(RCB, iterator->getNextObject())) )
releaseRCB(rcb);
iterator->release();
}
IORecursiveLockUnlock(fIPLock);
}
void IOFWIPBusInterface::resetMARBCache()
{
IORecursiveLockLock(fIPLock);
MARB *arb = NULL;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( multicastArb );
if( iterator )
{
while( NULL != (arb = OSDynamicCast(MARB, iterator->getNextObject())) )
{
arb->handle.multicast.channel = DEFAULT_BROADCAST_CHANNEL;
}
iterator->release();
}
IORecursiveLockUnlock(fIPLock);
}
void IOFWIPBusInterface::resetMcapState()
{
IORecursiveLockLock(fIPLock);
MCB *mcb = NULL;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( mcapState );
if( iterator )
{
while( NULL != (mcb = OSDynamicCast(MCB, iterator->getNextObject())) )
{
if( mcb->ownerNodeID != fLcb->ownNodeID ) {
IOFWAsyncStreamListener *asyncStreamRxClient = OSDynamicCast(IOFWAsyncStreamListener, mcb->asyncStreamID);
if(asyncStreamRxClient != NULL)
{
fControl->removeAsyncStreamListener( asyncStreamRxClient );
asyncStreamRxClient->release();
}
mcb->asyncStreamID = NULL;
mcb->expiration = 0;
mcb->nextTransmit = 0;
mcb->finalWarning = 0;
}
}
iterator->release();
}
IORecursiveLockUnlock(fIPLock);
}
ARB *IOFWIPBusInterface::getARBFromEui64(UWIDE eui64)
{
IORecursiveLockLock(fIPLock);
ARB *arb = 0;
OSCollectionIterator *iterator = OSCollectionIterator::withCollection( unicastArb );
if( iterator )
{
while( NULL != (arb = OSDynamicCast(ARB, iterator->getNextObject())) )
{
if (arb->eui64.hi == eui64.hi && arb->eui64.lo == eui64.lo)
break;
}
iterator->release();
if(arb == NULL)
{
if((arb = new ARB) == NULL)
{
IORecursiveLockUnlock(fIPLock);
return arb;
}
unicastArb->setObject(arb);
}
}
IORecursiveLockUnlock(fIPLock);
return(arb);
}
ARB *IOFWIPBusInterface::getArbFromFwAddr(UInt8 *fwaddr)
{
IORecursiveLockLock(fIPLock);
ARB *arb = 0;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( unicastArb );
if( iterator )
{
while( NULL != (arb = OSDynamicCast(ARB, iterator->getNextObject())) )
if (bcmp(fwaddr, arb->fwaddr, kIOFWAddressSize) == 0)
break;
iterator->release();
}
IORecursiveLockUnlock(fIPLock);
return(arb);
}
DRB *IOFWIPBusInterface::getDrbFromEui64(UWIDE eui64)
{
IORecursiveLockLock(fIPLock);
DRB *drb = 0;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( activeDrb );
if( iterator )
{
while( NULL != (drb = OSDynamicCast(DRB, iterator->getNextObject())) )
if (drb->eui64.hi == eui64.hi && drb->eui64.lo == eui64.lo)
break;
iterator->release();
}
IORecursiveLockUnlock(fIPLock);
return(drb);
}
DRB *IOFWIPBusInterface::getDrbFromFwAddr(UInt8 *fwaddr)
{
IORecursiveLockLock(fIPLock);
DRB *drb = 0;
OSCollectionIterator *iterator = OSCollectionIterator::withCollection( activeDrb );
if( iterator )
{
while( NULL != (drb = OSDynamicCast(DRB, iterator->getNextObject())) )
if (bcmp(fwaddr, drb->fwaddr, kIOFWAddressSize) == 0)
break;
iterator->release();
}
IORecursiveLockUnlock(fIPLock);
return(drb);
}
DRB *IOFWIPBusInterface::getDrbFromDeviceID(void *deviceID)
{
IORecursiveLockLock(fIPLock);
DRB *drb = 0;
OSCollectionIterator *iterator = OSCollectionIterator::withCollection( activeDrb );
if( iterator )
{
while( NULL != (drb = OSDynamicCast(DRB, iterator->getNextObject())) )
if (drb->deviceID == deviceID)
break;
iterator->release();
}
IORecursiveLockUnlock(fIPLock);
return drb;
}
MARB *IOFWIPBusInterface::getMulticastArb(UInt32 groupAddress)
{
IORecursiveLockLock(fIPLock);
MARB *arb = 0;
OSCollectionIterator *iterator = OSCollectionIterator::withCollection( multicastArb );
if( iterator )
{
while( NULL != (arb = OSDynamicCast(MARB, iterator->getNextObject())) )
if (arb->handle.multicast.groupAddress == groupAddress)
break;
iterator->release();
}
IORecursiveLockUnlock(fIPLock);
return arb;
}
RCB *IOFWIPBusInterface::getRcb(UInt16 sourceID, UInt16 dgl)
{
IORecursiveLockLock(fIPLock);
RCB *rcb = 0;
OSCollectionIterator *iterator = OSCollectionIterator::withCollection( activeRcb );
if( iterator )
{
while( NULL != (rcb = OSDynamicCast(RCB, iterator->getNextObject())) )
if (rcb->sourceID == sourceID && rcb->dgl == dgl)
break;
iterator->release();
}
IORecursiveLockUnlock(fIPLock);
return(rcb);
}
RCB *IOFWIPBusInterface::getRCBCommand( UInt16 sourceID, UInt16 dgl, UInt16 etherType, UInt16 datagramSize, mbuf_t m )
{
RCB * cmd = (RCB *)fRCBCmdPool->getCommand(false);
if( ( cmd == NULL ) and ( fCurrentRCBCommands < kMaxAsyncCommands ) )
{
if( ( cmd = new RCB ) != NULL )
fCurrentRCBCommands++;
}
if( cmd )
cmd->reinit( sourceID, dgl, etherType, datagramSize, m );
return cmd;
}
#pragma mark -
#pragma mark еее Control Block Routines еее
void RCB::reinit(UInt16 id, UInt16 label, UInt16 type, UInt16 size, mbuf_t m)
{
sourceID = id;
dgl = label;
mBuf = m;
timer = kRCBExpirationtime;
datagramSize = size;
etherType = type;
residual = 0;
}
void RCB::free()
{
OSObject::free();
}
#pragma mark -
#pragma mark еее Mbuf Utility Routines еее
bool IOFWIPMBufCommand::init()
{
if ( not OSObject::init() )
return false;
fMbuf = NULL;
fIPLocalNode = NULL;
fStatus = kIOReturnSuccess;
return true;
}
void IOFWIPMBufCommand::reinit(mbuf_t pkt, IOFireWireIP *ipNode, IOCommandPool *pool)
{
fIPLocalNode = ipNode;
fMbuf = pkt;
fStatus = kIOReturnSuccess;
fPool = pool;
fInited = true;
}
mbuf_t IOFWIPMBufCommand::getMBuf()
{
return fMbuf;
}
void IOFWIPMBufCommand::releaseWithStatus(IOReturn status)
{
if (status == kIOFireWireOutOfTLabels)
fStatus = status;
if(this->getRetainCount() == 2)
{
if ( fInited )
{
if( fMbuf && (fStatus != kIOFireWireOutOfTLabels) )
{
fIPLocalNode->fIPoFWDiagnostics.inActiveMbufs++;
fIPLocalNode->freePacket(fMbuf);
fMbuf = NULL;
}
fIPLocalNode = NULL;
}
fInited = false;
this->release();
fPool->returnCommand(this);
}
else
this->release();
}
void IOFWIPMBufCommand::free()
{
fMbuf = NULL;
fIPLocalNode = NULL;
fStatus = kIOReturnSuccess;
OSObject::free();
}
static mbuf_t getPacket( UInt32 size,
UInt32 how,
UInt32 smask,
UInt32 lmask )
{
mbuf_t packet;
UInt32 reqSize = size + smask + lmask; uint32_t mhlen = mbuf_get_mhlen();
uint32_t minclsize = mbuf_get_minclsize();
if(reqSize > mhlen && reqSize <= minclsize) reqSize = minclsize + 1;
if( 0 == mbuf_allocpacket(how, reqSize, NULL, &packet))
{
mbuf_t m = packet;
mbuf_pkthdr_setlen(packet, size);
while(size && m)
{
uintptr_t alignedStart, originalStart;
originalStart = (uintptr_t)mbuf_data(m);
alignedStart = (originalStart + smask) & ~((uintptr_t)smask);
mbuf_setdata(m, (caddr_t)alignedStart, (mbuf_maxlen(m) - (alignedStart - originalStart)) & ~lmask);
if(mbuf_len(m) > size)
mbuf_setlen(m, size);
size -= mbuf_len(m);
m = mbuf_next(m);
}
return packet;
}
else
return NULL;
}
mbuf_t IOFWIPBusInterface::allocateMbuf( UInt32 size )
{
return getPacket( size, MBUF_DONTWAIT, kIOPacketBufferAlign1, kIOPacketBufferAlign16 );
}
void IOFWIPBusInterface::moveMbufWithOffset(SInt32 tempOffset, mbuf_t *srcm, vm_address_t *src, SInt32 *srcLen)
{
mbuf_t temp = NULL;
for(;;)
{
if(tempOffset == 0)
break;
if(*srcm == NULL)
break;
if(*srcLen < tempOffset)
{
tempOffset = tempOffset - *srcLen;
temp = mbuf_next(*srcm);
*srcm = temp;
if(*srcm != NULL)
*srcLen = mbuf_len(*srcm);
continue;
}
else if (*srcLen > tempOffset)
{
*srcLen = mbuf_len(*srcm);
*src = (vm_offset_t)mbuf_data(*srcm);
*src += tempOffset;
*srcLen -= tempOffset;
break;
}
else if (*srcLen == tempOffset)
{
temp = mbuf_next(*srcm);
*srcm = temp;
if(*srcm != NULL)
{
*srcLen = mbuf_len(*srcm);
*src = (vm_offset_t)mbuf_data(*srcm);
}
break;
}
}
}
bool IOFWIPBusInterface::bufferToMbuf(mbuf_t m,
UInt32 offset,
vm_address_t *srcbuf,
UInt32 srcbufLen)
{
IORecursiveLockLock(fIPLock);
mbuf_t srcm = m;
SInt32 srcLen = mbuf_len(srcm);
vm_address_t src = (vm_offset_t)mbuf_data(srcm);
SInt32 tempOffset = offset;
moveMbufWithOffset(tempOffset, &srcm, &src, &srcLen);
SInt32 dstLen = srcbufLen;
SInt32 copylen = dstLen;
vm_address_t dst = (vm_address_t)srcbuf;
mbuf_t temp = NULL;
for (;;) {
if (srcLen < dstLen) {
BCOPY(dst, src, srcLen);
dst += srcLen;
dstLen -= srcLen;
copylen -= srcLen;
if(copylen == 0){
if ( srcm )
{
temp = mbuf_next(srcm);
srcm = temp;
}
break;
}
if (srcm)
{
temp = mbuf_next(srcm);
srcm = temp;
}
if (srcm)
{
srcLen = mbuf_len(srcm);
src = (vm_offset_t)mbuf_data(srcm);
}
if(srcLen == 0)
break;
}
else if (srcLen > dstLen) {
BCOPY(dst, src, dstLen);
src += dstLen;
srcLen -= dstLen;
copylen -= dstLen;
if(copylen == 0)
break;
}
else {
BCOPY(dst, src, srcLen);
copylen -= srcLen;
if(copylen == 0){
if ( srcm )
{
temp = mbuf_next(srcm);
srcm = temp;
}
break;
}
if ( srcm )
{
srcm = mbuf_next(srcm);
}
if (dstLen == 0)
break;
if (srcm)
{
srcLen = mbuf_len(srcm);
src = (vm_offset_t)mbuf_data(srcm);
}
if(srcLen == 0)
break;
}
}
IORecursiveLockUnlock(fIPLock);
return true;
}
mbuf_t IOFWIPBusInterface::mbufTobuffer(const mbuf_t m,
UInt32 *offset,
vm_address_t *dstbuf,
UInt32 dstbufLen,
UInt32 length)
{
mbuf_t srcm = m;
SInt32 srcLen = mbuf_len(srcm);
vm_address_t src = (vm_offset_t)mbuf_data(srcm);
SInt32 tempOffset = *offset;
moveMbufWithOffset(tempOffset, &srcm, &src, &srcLen);
SInt32 dstLen = length;
SInt32 copylen = dstLen;
vm_address_t dst = (vm_address_t)dstbuf;
mbuf_t temp = NULL;
for (;;) {
if (srcLen < dstLen) {
BCOPY(src, dst, srcLen);
dst += srcLen;
dstLen -= srcLen;
copylen -= srcLen;
*offset = *offset + srcLen;
if(copylen == 0){
if ( srcm )
{
temp = mbuf_next(srcm);
srcm = temp;
}
break;
}
if ( srcm )
{
temp = mbuf_next(srcm);
srcm = temp;
}
if ( srcm )
{
srcLen = mbuf_len(srcm);
src = (vm_offset_t)mbuf_data(srcm);
}
if(srcLen == 0)
break;
}
else if (srcLen > dstLen) {
BCOPY(src, dst, dstLen);
src += dstLen;
srcLen -= dstLen;
copylen -= dstLen;
*offset = *offset + dstLen;
if(copylen == 0)
break;
}
else {
BCOPY(src, dst, srcLen);
copylen -= srcLen;
if(copylen == 0){
*offset = 0;
if ( srcm )
{
temp = mbuf_next(srcm);
srcm = temp;
}
break;
}
if ( srcm )
{
srcm = mbuf_next(srcm);
}
if (dstLen == 0)
break;
if ( srcm )
{
srcLen = mbuf_len(srcm);
src = (vm_offset_t)mbuf_data(srcm);
}
if(srcLen == 0)
break;
}
}
return temp;
}
#ifdef DEBUG
#pragma mark -
#pragma mark еее Debug Routines еее
void IOFWIPBusInterface::showMinRcb(RCB *rcb) {
if (rcb != NULL) {
if(rcb->timer == 1)
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);
}
}
void IOFWIPBusInterface::showRcb(RCB *rcb) {
if (rcb != NULL) {
IOLog("RCB %p\n\r", rcb);
IOLog(" sourceID %04X dgl %u etherType %04X mBlk %p\n\r", rcb->sourceID, rcb->dgl, rcb->etherType, rcb->mBuf);
IOLog(" datagramSize %u residual %u timer %u \n\r", rcb->datagramSize, rcb->residual, rcb->timer);
}
}
void IOFWIPBusInterface::showArb(ARB *arb)
{
IOLog("ARB %p\n\r", arb);
IOLog(" EUI-64 %08lX %08lX\n\r", arb->eui64.hi, arb->eui64.lo);
IOLog(" fwAddr %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n\r", arb->fwaddr[0],
arb->fwaddr[1], arb->fwaddr[2], arb->fwaddr[3], arb->fwaddr[4],
arb->fwaddr[5], arb->fwaddr[6], arb->fwaddr[7]);
IOLog(" Handle: %08lX %02X %02X %04X%08lX\n\r", arb->handle.unicast.deviceID,
arb->handle.unicast.maxRec, arb->handle.unicast.spd,
arb->handle.unicast.unicastFifoHi, arb->handle.unicast.unicastFifoLo);
}
void IOFWIPBusInterface::showHandle(TNF_HANDLE *handle)
{
if (handle->unicast.deviceID != NULL)
IOLog(" Unicast handle: %08lX %02X %02X %04X%08lX\n\r",
handle->unicast.deviceID, handle->unicast.maxRec,
handle->unicast.spd, handle->unicast.unicastFifoHi,
handle->unicast.unicastFifoLo);
else
IOLog(" Multicast handle: 00000000 %02X %02X %02X %08lX\n\r",
handle->multicast.maxRec, handle->multicast.spd,
handle->multicast.channel, htonl(handle->multicast.groupAddress));
}
void IOFWIPBusInterface::showDrb(DRB *drb)
{
if (drb != NULL)
{
IOLog("DRB 0x%p \n\r", drb);
IOLog(" Device ID %08lX EUI-64 %08lX %08lX\n\r", drb->deviceID, drb->eui64.hi, drb->eui64.lo);
IOLog(" maxPayload %d maxSpeed %d\n\r", drb->maxPayload, drb->maxSpeed);
}
}
void IOFWIPBusInterface::showLcb()
{
IOLog(" Node ID %04X maxPayload %u maxSpeed %u busGeneration 0x%08lX\n",
fLcb->ownNodeID, fLcb->ownMaxPayload,
fLcb->ownMaxSpeed, fLcb->busGeneration);
IORecursiveLockLock(fIPLock);
OSCollectionIterator * iterator = 0;
ARB *arb = 0;
iterator = OSCollectionIterator::withCollection( unicastArb );
IOLog(" Unicast ARBs\n\r");
while( NULL != (arb = OSDynamicCast(ARB, iterator->getNextObject())) )
{
IOLog(" %p\n\r", arb);
showArb(arb);
}
iterator->release();
IOLog(" Active DRBs\n\r");
DRB *drb = 0;
iterator = OSCollectionIterator::withCollection( activeDrb );
while( NULL != (drb = OSDynamicCast(DRB, iterator->getNextObject())) )
{
IOLog(" %p\n\r", drb);
showDrb(drb);
}
iterator->release();
RCB *rcb = 0;
iterator = OSCollectionIterator::withCollection( activeRcb );
UInt32 rcbCount = 0;
while( NULL != (rcb = OSDynamicCast(RCB, iterator->getNextObject())) )
{
showMinRcb(rcb);
rcbCount++;
}
IOLog(" Active RCBs %u \n", rcbCount);
iterator->release();
IORecursiveLockUnlock(fIPLock);
}
#endif