IOFWIPBusInterface.cpp [plain text]
#include "../../KernelHeaders/IOKit/IOFWIPBusInterface.h"
#include <IOKit/firewire/IOFireWireController.h>
#define BCOPY(s, d, l) do { bcopy((void *) s, (void *) d, l); } while(0)
struct
{
UCHAR specifierID[3]; UCHAR version[3]; } gaspVal = { {0x00, 0x00, 0x5E}, {0x00, 0x00, 0x01} };
extern "C"
{
void watchdog(OSObject *, IOTimerEventSource *);
}
#define super IOService
OSDefineMetaClassAndStructors(IOFWIPBusInterface, IOService)
OSDefineMetaClassAndStructors(ARB, OSObject)
OSDefineMetaClassAndStructors(DRB, OSObject)
OSDefineMetaClassAndStructors(RCB, OSObject)
bool IOFWIPBusInterface::init(IOFireWireIP *primaryInterface)
{
fIPLocalNode = OSDynamicCast(IOFireWireIP, primaryInterface);
if(not fIPLocalNode)
return false;
fControl = fIPLocalNode->getController();
if( not fControl)
return false;
if ( not super::init() )
return false;
fMemoryPool = 0;
fIP1394AddressSpace = 0;
fAsyncCmdPool = 0;
fAsyncStreamTxCmdPool = 0;
fAsyncTransitSet = 0;
fAsyncStreamTransitSet = 0;
if( not attachIOFireWireIP ( fIPLocalNode ) )
return false;
fControl->retain();
fIPLocalNode->retain();
fControl->resetBus();
fStarted = true;
return true;
}
bool IOFWIPBusInterface::finalize(IOOptionBits options)
{
IORecursiveLockLock(fIPLock);
fStarted = false;
fIPLocalNode->deRegisterFWIPPrivateHandlers();
IORecursiveLockUnlock(fIPLock);
IOFWIPAsyncWriteCommand *cmd1 = NULL;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( fAsyncTransitSet );
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 );
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::free()
{
detachIOFireWireIP();
super::free();
}
IOReturn IOFWIPBusInterface::message(UInt32 type, IOService *provider, void *argument)
{
IOReturn res = kIOReturnSuccess;
switch (type)
{
case kIOMessageServiceIsTerminated:
break;
case kIOMessageServiceIsSuspended:
res = kIOReturnSuccess;
if(fStarted == true)
stopReceivingBroadcast();
break;
case kIOMessageServiceIsResumed:
res = kIOReturnSuccess;
if(fStarted == true)
{
resetARBCache();
resetRCBCache();
resetMcapState();
updateBroadcastValues(true);
startReceivingBroadcast(fLcb->maxBroadcastSpeed);
}
break;
case kIOMessageServiceIsRequestingClose:
res = kIOReturnSuccess;
break;
default:
res = kIOReturnUnsupported;
break;
}
return res;
}
bool IOFWIPBusInterface::attachIOFireWireIP(IOFireWireIP *provider)
{
fIPLocalNode = provider;
fLcb = fIPLocalNode->getLcb();
fIPLock = fIPLocalNode->getIPLock();
workLoop = fIPLocalNode->getWorkLoop();
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 = OSDictionary::withCapacity(kMaxChannels);
if(mcapState == 0)
return false;
fAsyncStreamTransitSet = OSSet::withCapacity(kMaxAsyncStreamCommands);
if(fAsyncStreamTransitSet == 0)
return false;
fAsyncTransitSet = OSSet::withCapacity(kMaxAsyncCommands);
if(fAsyncTransitSet == 0)
return false;
isAppleLynx();
timerSource = IOTimerEventSource::timerEventSource ( ( OSObject* ) this,
( IOTimerEventSource::Action ) &watchdog);
if ( timerSource == NULL )
{
IOLog( "IOFireWireIP::start - Couldn't allocate timer event source\n" );
return false;
}
if ( workLoop->addEventSource ( timerSource ) != kIOReturnSuccess )
{
IOLog( "IOFireWireIP::start - Couldn't add timer event source\n" );
return false;
}
fBroadcastReceiveClient = new IOFWAsyncStreamRxCommand;
if ( not fBroadcastReceiveClient )
return false;
if ( not fBroadcastReceiveClient->initAll(0x1f, rxAsyncStream, fControl, fMaxRxIsocPacketSize, this ) )
return false;
fIPLocalNode->updateMTU(bOnLynx);
if ( createIPFifoAddress (MAX_FIFO_SIZE) != kIOReturnSuccess)
return false;
timerSource->setTimeoutMS ( WATCHDOG_TIMER_MS );
IOFireWireIPPrivateHandlers privateHandlers;
privateHandlers.newService = this;
privateHandlers.transmitPacket = getOutputHandler();
privateHandlers.updateARPCache = getARPCacheHandler();
fIPLocalNode->registerFWIPPrivateHandlers(&privateHandlers);
attach(fIPLocalNode);
return true;
}
void IOFWIPBusInterface::detachIOFireWireIP()
{
IORecursiveLockLock(fIPLock);
if(fBroadcastReceiveClient != NULL)
fBroadcastReceiveClient->release();
fBroadcastReceiveClient = NULL;
if (fIP1394AddressSpace != NULL){
fIP1394AddressSpace->deactivate();
fIP1394AddressSpace->release();
fIP1394AddressSpace = NULL;
}
if(timerSource != NULL)
{
if (workLoop != NULL)
workLoop->removeEventSource(timerSource);
timerSource->release();
}
freeAsyncCmdPool();
freeAsyncStreamCmdPool();
if(unicastArb != NULL)
{
unicastArb->flushCollection();
unicastArb->free();
}
if(multicastArb != NULL)
{
multicastArb->flushCollection();
multicastArb->free();
}
if(activeDrb != NULL)
{
activeDrb->flushCollection();
activeDrb->free();
}
if(activeRcb != NULL)
{
activeRcb->flushCollection();
activeRcb->free();
}
if(mcapState != NULL)
{
mcapState->flushCollection();
mcapState->free();
}
if(fControl)
fControl->release();
fControl = NULL;
if(fIPLocalNode)
fIPLocalNode->release();
fIPLocalNode = NULL;
IORecursiveLockUnlock(fIPLock);
}
void IOFWIPBusInterface::decrementUnitCount()
{
recursiveScopeLock lock(fIPLock);
if(fUnitCount > 0)
fUnitCount--;
}
void IOFWIPBusInterface::incrementUnitCount()
{
recursiveScopeLock lock(fIPLock);
fUnitCount++;
}
UInt16 IOFWIPBusInterface::getUnitCount()
{
recursiveScopeLock lock(fIPLock);
return fUnitCount;
}
void IOFWIPBusInterface::fwIPUnitAttach()
{
incrementUnitCount();
updateBroadcastValues(true);
}
void IOFWIPBusInterface::fwIPUnitTerminate()
{
decrementUnitCount();
updateBroadcastValues(true);
}
void IOFWIPBusInterface::updateBroadcastValues(bool reset)
{
IOFireWireDevice *remoteDevice = NULL;
IORecursiveLockLock(fIPLock);
if(reset)
{
IOFireWireDevice *localDevice = (IOFireWireDevice*)(fIPLocalNode->getDevice());
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 );
while( NULL != (drb = OSDynamicCast(DRB, iterator->getNextObject())) )
{
if(drb->timer > 0)
continue;
remoteDevice = (IOFireWireDevice*)drb->deviceID;
if(fLcb->maxBroadcastSpeed > drb->maxSpeed)
fLcb->maxBroadcastSpeed = drb->maxSpeed;
if(fLcb->maxBroadcastPayload > drb->maxPayload)
fLcb->maxBroadcastPayload = drb->maxPayload;
}
iterator->release();
updateLinkStatus();
IORecursiveLockUnlock(fIPLock);
}
void IOFWIPBusInterface::updateLinkStatus()
{
IORecursiveLockLock(fIPLock);
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));
IORecursiveLockUnlock(fIPLock);
}
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::isAppleLynx()
{
IORegistryEntry *parent = fControl->getParentEntry(gIOServicePlane);
if(strcmp(parent->getName(gIOServicePlane), "AppleLynx") == 0)
{
bOnLynx = true;
fMaxRxIsocPacketSize = 2048;
fMaxTxAsyncDoubleBuffer = 1 << 9;
}
else
{
bOnLynx = false;
fMaxRxIsocPacketSize = 4096;
fMaxTxAsyncDoubleBuffer = 1 << ((IOFireWireNub*)(fIPLocalNode->getDevice()))->maxPackLog(true);
}
parent = parent->getParentEntry(gIOServicePlane);
}
UInt32 IOFWIPBusInterface::initAsyncCmdPool()
{
IOFWIPAsyncWriteCommand *cmd1 = NULL;
IOReturn status = kIOReturnSuccess;
int i = 0;
if(fAsyncCmdPool == NULL)
fAsyncCmdPool = IOCommandPool::withWorkLoop(workLoop);
for(i=0; i<=kMaxAsyncCommands; i++){
FWAddress addr;
addr.addressHi = 0xdead;
addr.addressLo = 0xbabeface;
cmd1 = new IOFWIPAsyncWriteCommand;
if(!cmd1) {
status = kIOReturnNoMemory;
break;
}
if(!cmd1->initAll(fIPLocalNode, fMaxTxAsyncDoubleBuffer, addr, txCompleteBlockWrite, this, false)) {
status = kIOReturnNoMemory;
cmd1->release();
break;
}
fAsyncCmdPool->returnCommand(cmd1);
fAsyncTransitSet->setObject(cmd1);
}
return status;
}
IOFWIPAsyncWriteCommand *IOFWIPBusInterface::getAsyncCommand(const mbuf_t m, bool block, bool *deferNotify)
{
IOFWIPAsyncWriteCommand * cmd = (IOFWIPAsyncWriteCommand *)fAsyncCmdPool->getCommand(block);
if(cmd == NULL)
{
fIPLocalNode->freePacket((struct mbuf*)m);
fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors);
fIPLocalNode->fNoCommands++;
return NULL;
}
fIPLocalNode->fActiveCmds++;
if((fIPLocalNode->fActiveCmds % fIPLocalNode->fInActiveCmds) >= kLowWaterMark)
*deferNotify = false;
return cmd;
}
void IOFWIPBusInterface::returnAsyncCommand(IOFWIPAsyncWriteCommand *cmd)
{
if(cmd->notDoubleComplete())
{
if(fAsyncCmdPool != NULL)
fAsyncCmdPool->returnCommand(cmd);
else
cmd->release();
fIPLocalNode->fInActiveCmds++;
}
else
fIPLocalNode->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, 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;
}
IOReturn IOFWIPBusInterface::stopReceivingBroadcast()
{
return fBroadcastReceiveClient->stop();
}
IOReturn IOFWIPBusInterface::startReceivingBroadcast(IOFWSpeed speed)
{
return fBroadcastReceiveClient->start(speed);
}
IOUpdateARPCache IOFWIPBusInterface::getARPCacheHandler() const
{
return (IOUpdateARPCache) &IOFWIPBusInterface::staticUpdateARPCache;
}
IOTransmitPacket IOFWIPBusInterface::getOutputHandler() const
{
return (IOTransmitPacket) &IOFWIPBusInterface::staticOutputPacket;
}
DRB *IOFWIPBusInterface::initDRBwithDevice(UWIDE eui64, IOFireWireNub *device, bool itsMac)
{
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 = (UInt32)device;
drb->timer = 0;
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()
{
UInt32 mtu = 0;
mtu = FIREWIRE_MTU;
return 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((struct mbuf*)pkt);
break;
}
if(status == kIOFireWireOutOfTLabels || status == kIOReturnNoResources)
{
fTxStatus = kIOReturnOutputStall;
status = kIOReturnOutputStall;
}
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;
fwIPObject->closeIPGate();
if(fwIPPriv->fTxStatus == kIOReturnOutputStall)
{
fwIPObject->fStalls++;
fwIPPriv->fTxStatus = kIOReturnOutputSuccess;
}
if(status == kIOReturnSuccess)
{
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->outputPackets);
fwIPObject->fTxUni++;
}
else
{
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->outputErrors);
fwIPObject->fCallErrs++;
}
cmd->resetDescriptor(status);
fwIPPriv->returnAsyncCommand(cmd);
if ((status != kIOFireWireOutOfTLabels) && (status != kIOReturnNoResources)
&& ((fwIPObject->fActiveCmds % fwIPObject->fInActiveCmds) <= (kLowWaterMark+10)))
fwIPObject->transmitQueue->service(kTransmitQueueRestart);
else
fwIPObject->fMissedQRestarts++;
fwIPObject->openIPGate();
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;
fwIPObject->closeIPGate();
if(status == kIOReturnSuccess)
{
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->outputPackets);
fwIPObject->fTxBcast++;
}
else
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->outputErrors);
if(fwIPPriv->fAsyncStreamTxCmdPool != NULL) fwIPPriv->fAsyncStreamTxCmdPool->returnCommand(cmd);
fwIPObject->openIPGate();
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->fNoBCastCommands++;
return status;
}
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, 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
fAsyncStreamTxCmdPool->returnCommand(cmd);
fIPLocalNode->freePacket((struct mbuf*)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)
{
UInt16 datagramSize = mbuf_pkthdr_len(m) - sizeof(struct firewire_header);
fIPLocalNode->fMaxPktSize = max(datagramSize,fIPLocalNode->fMaxPktSize);
UInt16 maxPayload = MIN((UInt16)1 << maxBroadcastPayload, (UInt16)1 << ownMaxPayload);
SInt32 status = ENOBUFS;
if (datagramSize + sizeof(IP1394_UNFRAG_HDR) > maxPayload)
{
fIPLocalNode->freePacket((struct mbuf*)m);
return status;
}
if(fAsyncStreamTxCmdPool == NULL)
initAsyncStreamCmdPool();
IOFWIPAsyncStreamTxCommand *asyncStreamCmd = (IOFWIPAsyncStreamTxCommand*)fAsyncStreamTxCmdPool->getCommand(false);
if(asyncStreamCmd == NULL)
{
fIPLocalNode->freePacket((struct mbuf*)m);
fIPLocalNode->fNoBCastCommands++;
return status;
}
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, buf, dstBufLen, cmdLen);
cmdLen += headerSize;
status = asyncStreamCmd->reinit(busGeneration, DEFAULT_BROADCAST_CHANNEL,
cmdLen, speed, txCompleteAsyncStream, this);
if(status == kIOReturnSuccess)
status = asyncStreamCmd->submit();
else
fAsyncStreamTxCmdPool->returnCommand(asyncStreamCmd);
fIPLocalNode->freePacket((struct mbuf*)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 = EHOSTUNREACH;
bool deferNotify = true;
IOFWIPAsyncWriteCommand *cmd = getAsyncCommand(m, false, &deferNotify);
if(not cmd)
return status;
IP1394_ENCAP_HDR *ip1394Hdr = (IP1394_ENCAP_HDR*)cmd->getDescriptorHeader(m, 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);
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 = EHOSTUNREACH;
bool deferNotify = true;
while (residual)
{
deferNotify = true;
status = EHOSTUNREACH;
IOFWIPAsyncWriteCommand *cmd = getAsyncCommand(m, false, &deferNotify);
if(not cmd)
break;
fIPLocalNode->fTxFragmentPkts++;
FragmentType fragmentType = FIRST_FRAGMENT;
IP1394_ENCAP_HDR *ip1394Hdr = (IP1394_ENCAP_HDR*)cmd->getDescriptorHeader(m, 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; }
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((struct mbuf*)m);
fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors);
IORecursiveLockUnlock(fIPLock);
return status;
}
TNF_HANDLE *handle = &arb->handle;
if(arb->timer > 1 or (handle->unicast.deviceID == kInvalidIPDeviceRefID))
{
fIPLocalNode->freePacket((struct mbuf*)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;
IOFireWireNub *device = (IOFireWireNub*)handle->unicast.deviceID;
UInt32 drbMaxPayload = 1 << device->maxPackLog(true, addr);
UInt32 maxPayload = MIN((UInt32)1 << (handle->unicast.maxRec+1), (UInt32)1 << fLcb->ownMaxPayload);
maxPayload = MIN(drbMaxPayload, maxPayload);
UInt16 dgl = 0;
bool unfragmented = false;
if (!(unfragmented = ((datagramSize + sizeof(IP1394_UNFRAG_HDR)) <= maxPayload)))
dgl = fLcb->datagramLabel++;
if(fAsyncCmdPool == NULL)
initAsyncCmdPool();
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) & M_PKTHDR))
{
fIPLocalNode->freePacket((struct mbuf*)m);
fIPLocalNode->networkStatAdd(&(fIPLocalNode->getNetStats())->outputErrors);
return kIOReturnError;
}
struct firewire_header *fwh = (struct firewire_header *)mbuf_data(m);
SInt32 status = kIOReturnSuccess;
if(bcmp(fwh->fw_dhost, fwbroadcastaddr, FIREWIRE_ADDR_LEN) == 0 ||
bcmp(fwh->fw_dhost, ipv4multicast, FIREWIREMCAST_V4_LEN) == 0 ||
bcmp(fwh->fw_dhost, ipv6multicast, FIREWIREMCAST_V6_LEN) == 0)
status = txBroadcastIP(m, nodeID, busGeneration, ownMaxPayload, maxBroadcastPayload, speed, type);
else
status = txUnicastIP(m, nodeID, busGeneration, ownMaxPayload, speed, type);
return status;
}
void IOFWIPBusInterface::txMCAP(LCB *lcb, MCB *mcb, UInt32 ipAddress){
ARB *arb;
MCAST_DESCR *groupDescriptor;
IOFWIPAsyncStreamTxCommand *asyncStreamCmd = NULL;
struct mcap_packet *packet;
SInt32 status;
UInt32 cmdLen = 0;
UInt8 *buf;
if(fAsyncStreamTxCmdPool == NULL)
initAsyncStreamCmdPool();
asyncStreamCmd = (IOFWIPAsyncStreamTxCommand*)fAsyncStreamTxCmdPool->getCommand(false);
if(asyncStreamCmd == NULL)
return;
buf = (UInt8*)asyncStreamCmd->getBufferFromDesc();
packet = (struct mcap_packet*)buf;
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);
groupDescriptor = packet->mcap.groupDescr;
if (mcb != NULL)
{
packet->mcap.opcode = MCAP_ADVERTISE;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( multicastArb );
while( NULL != (arb = OSDynamicCast(ARB, iterator->getNextObject())) )
{
if (arb->handle.multicast.channel == mcb->channel)
{
memcpy(&ipAddress, &arb->ipAddress, sizeof(ipAddress));
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->ipAddress;
groupDescriptor = (MCAST_DESCR*)((UInt32) groupDescriptor + sizeof(MCAST_DESCR));
packet->mcap.length += sizeof(MCAST_DESCR);
}
}
iterator->release();
}
else
{
packet->mcap.opcode = MCAP_SOLICIT;
memset(groupDescriptor, 0, sizeof(MCAST_DESCR));
groupDescriptor->length = sizeof(MCAST_DESCR);
groupDescriptor->type = MCAST_TYPE;
groupDescriptor->groupAddress = ipAddress;
packet->mcap.length += sizeof(MCAST_DESCR);
}
cmdLen = packet->mcap.length; packet->mcap.length = htons(packet->mcap.length);
status = asyncStreamCmd->reinit(fLcb->busGeneration,
DEFAULT_BROADCAST_CHANNEL,
cmdLen,
fLcb->maxBroadcastSpeed,
txCompleteAsyncStream,
this);
if(status == kIOReturnSuccess)
status = asyncStreamCmd->submit();
else
fAsyncStreamTxCmdPool->returnCommand(asyncStreamCmd);
}
void IOFWIPBusInterface::rxUnicastFlush()
{
UInt32 count = 0;
IORecursiveLockLock(fIPLock);
if(fIPLocalNode->fPacketsQueued = true)
{
count = fIPLocalNode->networkInterface->flushInputQueue();
if(count > fIPLocalNode->fMaxInputCount)
fIPLocalNode->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 fwIPObject->netifEnabled)
return kIOReturnSuccess;
if (ip1394Hdr->reserved == htons(UNFRAGMENTED))
{
void *datagram = (void *) ((ULONG) 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->fRxFragmentPkts++;
if(fwIPPriv->rxFragmentedUnicast(nodeID, (IP1394_FRAG_HDR*)ip1394Hdr, len) == kIOReturnError)
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->inputErrors);
}
fwIPObject->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 *) ((UInt32) 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;
if(datagramSize > FIREWIRE_MTU)
return kIOReturnError;
IORecursiveLockLock(fIPLock);
RCB *rcb = getRcb(nodeID, htons(fragmentHdr->dgl));
if (rcb == NULL)
{
mbuf_t rxMBuf = (mbuf_t)fIPLocalNode->allocatePacket(datagramSize + sizeof(firewire_header));
if (rxMBuf == NULL)
{
IORecursiveLockUnlock(fIPLock);
return kIOReturnError;
}
if ((rcb = new RCB) == NULL)
{
cleanRCBCache();
fIPLocalNode->freePacket((struct mbuf*)rxMBuf, 0);
IORecursiveLockUnlock(fIPLock);
return kIOReturnError;
}
rcb->sourceID = nodeID;
rcb->dgl = htons(fragmentHdr->dgl);
rcb->mBuf = rxMBuf;
rcb->timer = rcbexpirationtime;
struct firewire_header *fwh = (struct firewire_header *)mbuf_data(rxMBuf);
bzero(fwh, sizeof(struct firewire_header));
rcb->datagram = ((UInt8*)mbuf_data(rxMBuf)) + sizeof(struct firewire_header);
fwh->fw_type = (lf == FIRST_FRAGMENT) ? htons(fragmentHdr->fragmentOffset): FWTYPE_IP;
rcb->datagramSize = datagramSize;
rcb->residual = rcb->datagramSize;
activeRcb->setObject(rcb);
}
if (rcb->mBuf == NULL || rcb->datagram == NULL)
{
IORecursiveLockUnlock(fIPLock);
return kIOReturnError;
}
if (lf == FIRST_FRAGMENT)
{
rcb->etherType = htons(fragmentHdr->fragmentOffset);
bufferToMbuf(rcb->mBuf, sizeof(struct firewire_header),
(UInt8*)fragment, MIN(fragmentSize, rcb->datagramSize));
}
else
{
bufferToMbuf(rcb->mBuf, sizeof(struct firewire_header)+htons(fragmentHdr->fragmentOffset),
(UInt8*)fragment, MIN(fragmentSize, rcb->datagramSize - htons(fragmentHdr->fragmentOffset)));
}
IOReturn result = kIOReturnError;
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);
result = kIOReturnSuccess;
}
else
fIPLocalNode->freePacket((struct mbuf*)rcb->mBuf, 0);
releaseRCB(rcb, false);
}
IORecursiveLockUnlock(fIPLock);
return result;
}
void IOFWIPBusInterface::rxAsyncStream(DCLCommandStruct *callProc){
DCLCallProc *ptr = (DCLCallProc*)callProc;
RXProcData *proc = (RXProcData*)ptr->procData;
IOFWIPBusInterface *fwIPPriv = (IOFWIPBusInterface*)proc->obj;
IOFireWireIP *fwIPObject = OSDynamicCast(IOFireWireIP, fwIPPriv->fIPLocalNode);
IOFWAsyncStreamRxCommand *fwRxAsyncStream;
UInt8 *buffer = proc->buffer;
void *datagram;
UInt16 datagramSize;
GASP *gasp = (GASP*)buffer;
LCB *lcb = fwIPPriv->fLcb;
ISOC_DATA_PKT *pkt = (ISOC_DATA_PKT*)buffer;
UInt16 type = 0;
fwRxAsyncStream = (IOFWAsyncStreamRxCommand*)proc->thisObj;
fwRxAsyncStream->modifyDCLJumps(callProc);
if(not fwIPObject->netifEnabled)
return;
if(pkt->tag != GASP_TAG){
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->inputErrors);
IOLog(" GASP tag error\n\r");
return;
}
if (gasp->dataLength < sizeof(GASP_HDR) + sizeof(IP1394_UNFRAG_HDR)) {
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->inputErrors);
IOLog(" GASP header error\n\r");
return;
}
if (memcmp(&gasp->gaspHdr.gaspID, &gaspVal, sizeof(GASP_ID)) != 0) {
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->inputErrors);
IOLog(" Non-RFC 2734 GASP\n\r");
return;
}
if ((htons(gasp->gaspHdr.sourceID) >> 6) != LOCAL_BUS_ID) {
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->inputErrors);
IOLog(" Remote GASP error\n\r");
return;
}
if (gasp->ip1394Hdr.reserved != htons(UNFRAGMENTED)) {
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->inputErrors);
IOLog(" Encapsulation header error\n\r");
return;
}
datagram = (void *) ((UInt32) 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->fRxBcast++;
return;
}
void IOFWIPBusInterface::rxMCAP(LCB *lcb, UInt16 mcapSourceID, IP1394_MCAP *mcap, UInt32 dataSize){
ARB *arb;
UInt32 currentChannel;
MCAST_DESCR *groupDescr = mcap->groupDescr;
MCB *mcb, *priorMcb;
IOFWAsyncStreamRxCommand *asyncStreamRxClient;
IOReturn ioStat = kIOReturnSuccess;
if ((mcap->opcode != MCAP_ADVERTISE) && (mcap->opcode != MCAP_SOLICIT))
return;
dataSize = MIN(dataSize, htons(mcap->length) - sizeof(IP1394_MCAP));
while (dataSize >= sizeof(MCAST_DESCR))
{
if (groupDescr->length != sizeof(MCAST_DESCR))
; else if (groupDescr->type != MCAST_TYPE)
; else if ((arb = getMulticastArb(groupDescr->groupAddress)) == NULL)
; else if (mcap->opcode == MCAP_SOLICIT)
{
mcb = 0;
OSString *channel = OSString::withCString((const char*)&arb->handle.multicast.channel);
mcb = OSDynamicCast(MCB, mcapState->getObject(channel));
channel->free();
if(mcb)
{
if (mcb->ownerNodeID == lcb->ownNodeID) txMCAP(lcb, mcb, 0); }
}
else if ((groupDescr->channel != DEFAULT_BROADCAST_CHANNEL)
&& (groupDescr->channel <= kMaxChannels))
{
mcb = 0;
OSString *channel = OSString::withCString((const char*)&groupDescr->channel);
mcb = OSDynamicCast(MCB, mcapState->getObject(channel));
channel->free();
if(not mcb)
break;
if (groupDescr->expiration < 60)
{
if (mcb->ownerNodeID == mcapSourceID)
{
currentChannel = groupDescr->channel;
mcb->ownerNodeID = lcb->ownNodeID; mcb->nextTransmit = 1;
}
}
else if (mcb->ownerNodeID == mcapSourceID)
{
mcb->expiration = groupDescr->expiration;
}
else if (mcb->ownerNodeID < mcapSourceID || mcb->expiration < 60)
{
if (mcb->ownerNodeID == lcb->ownNodeID) {
}
mcb->ownerNodeID = mcapSourceID;
mcb->expiration = groupDescr->expiration;
}
currentChannel = arb->handle.multicast.channel;
if (currentChannel == DEFAULT_BROADCAST_CHANNEL)
{
if (mcb->asyncStreamID == kInvalidAsyncStreamRefID)
{
if(groupDescr->channel != DEFAULT_BROADCAST_CHANNEL)
{
asyncStreamRxClient = new IOFWAsyncStreamRxCommand;
if(asyncStreamRxClient == NULL)
{
ioStat = kIOReturnNoMemory;
}
if(asyncStreamRxClient->initAll(groupDescr->channel, rxAsyncStream, fControl,
fMaxRxIsocPacketSize, this) == false) {
ioStat = kIOReturnNoMemory;
}
if(ioStat == kIOReturnSuccess)
mcb->asyncStreamID = (UInt32)asyncStreamRxClient;
}
else
{
if(fBroadcastReceiveClient != NULL)
{
fBroadcastReceiveClient->retain();
mcb->asyncStreamID = (UInt32)fBroadcastReceiveClient;
}
}
}
arb->handle.multicast.channel = groupDescr->channel;
mcb->groupCount++;
} else if (currentChannel != groupDescr->channel) {
priorMcb = 0;
OSString *channel = OSString::withCString((const char*)¤tChannel);
priorMcb = OSDynamicCast(MCB, mcapState->getObject(channel));
channel->free();
if(not priorMcb)
break;
if (priorMcb->groupCount == 1)
{
asyncStreamRxClient = (IOFWAsyncStreamRxCommand *)mcb->asyncStreamID;
if(asyncStreamRxClient != NULL)
asyncStreamRxClient->release();
priorMcb->asyncStreamID = kInvalidAsyncStreamRefID;
priorMcb->groupCount = 0;
} else if (priorMcb->groupCount > 0)
priorMcb->groupCount--;
if (mcb->asyncStreamID == kInvalidAsyncStreamRefID)
{
if(groupDescr->channel != DEFAULT_BROADCAST_CHANNEL)
{
asyncStreamRxClient = new IOFWAsyncStreamRxCommand;
if(asyncStreamRxClient == NULL)
ioStat = kIOReturnNoMemory;
if(asyncStreamRxClient->initAll(groupDescr->channel, rxAsyncStream, fControl,
fMaxRxIsocPacketSize, this) == false)
ioStat = kIOReturnNoMemory;
if(ioStat == kIOReturnSuccess)
mcb->asyncStreamID = (UInt32)asyncStreamRxClient;
}
else
{
if(fBroadcastReceiveClient != NULL)
{
fBroadcastReceiveClient->retain();
mcb->asyncStreamID = (UInt32)fBroadcastReceiveClient;
}
}
}
arb->handle.multicast.channel = groupDescr->channel;
mcb->groupCount++;
}
if (mcb->ownerNodeID != lcb->ownNodeID)
{
multicastArb->removeObject(arb);
arb->release();
}
}
dataSize -= MIN(groupDescr->length, dataSize);
groupDescr = (MCAST_DESCR*)((ULONG) 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)fIPLocalNode->allocatePacket(len)) != NULL)
{
bufferToMbuf(rxMBuf, 0, (UInt8*)pkt, len);
mbuf_prepend(&rxMBuf, sizeof(struct firewire_header), M_DONTWAIT);
if (rxMBuf != NULL)
{
fwh = (struct firewire_header *)mbuf_data(rxMBuf);
bzero(fwh, sizeof(struct firewire_header));
fwh->fw_type = type;
queuePkt = (flags == FW_M_UCAST);
if(queuePkt)
bcopy(fIPLocalNode->macAddr, fwh->fw_dhost, FIREWIRE_ADDR_LEN);
else
bcopy(fwbroadcastaddr, fwh->fw_dhost, FIREWIRE_ADDR_LEN);
if(FWTYPE_IPV6 == type)
updateNDPCache(rxMBuf);
}
else
ret = kIOReturnNoMemory;
if(ret == kIOReturnSuccess)
{
fIPLocalNode->receivePackets(rxMBuf, mbuf_pkthdr_len(rxMBuf), queuePkt);
}
else
{
if(rxMBuf != NULL)
fIPLocalNode->freePacket((struct mbuf*)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;
}
if ((rxMBuf = (mbuf_t)fIPLocalNode->allocatePacket(sizeof(*arp) + sizeof(struct firewire_header))) != NULL)
{
IORecursiveLockLock(fIPLock);
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 = FWTYPE_ARP;
memcpy(datagram, arp, sizeof(*arp));
IORecursiveLockUnlock(fIPLock);
fIPLocalNode->receivePackets(rxMBuf, mbuf_pkthdr_len(rxMBuf), 0);
}
return kIOReturnSuccess;
}
void watchdog(OSObject *obj, IOTimerEventSource *src)
{
IOFWIPBusInterface *FWIPPriv = (IOFWIPBusInterface*)obj;
FWIPPriv->processWatchDogTimeout();
}
void IOFWIPBusInterface::processWatchDogTimeout()
{
recursiveScopeLock lock(fIPLock);
cleanDRBCache();
updateMcapState();
cleanARBCache();
cleanRCBCache();
timerSource->setTimeoutMS(WATCHDOG_TIMER_MS);
}
#pragma mark -
#pragma mark еее IPv6 NDP routines еее
const int ipv6fwoffset = 8;
bool IOFWIPBusInterface::addNDPOptions(mbuf_t m)
{
if(not (mbuf_flags(m) & M_PKTHDR))
return false;
vm_address_t src = (vm_offset_t)mbuf_data(m);
if(src == 0)
return false;
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 false;
src = (vm_offset_t)mbuf_data(ipv6Mbuf);
fwhdrlen = 0;
pkthdrlen = mbuf_pkthdr_len(ipv6Mbuf);
}
if(mbuf_len(ipv6Mbuf) < (fwhdrlen + sizeof(struct ip6_hdr)))
return false;
if(mbuf_trailingspace(ipv6Mbuf) < (int)sizeof(IP1394_NDP))
return false;
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);
*icmp6_cksum = in6_cksum((struct mbuf*)ipv6Mbuf, IPPROTO_ICMPV6, offset, icmp6len);
return true;
}
return false;
}
void IOFWIPBusInterface::updateNDPCache(mbuf_t m)
{
if(not (mbuf_flags(m) & M_PKTHDR))
return ;
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;
fwhdrlen = 0;
pkthdrlen = mbuf_pkthdr_len(ipv6Mbuf);
}
vm_address_t src = (vm_offset_t)mbuf_data(ipv6Mbuf);
if(src == 0)
return;
if(mbuf_len(ipv6Mbuf) < (sizeof(struct ip6_hdr) + fwhdrlen))
return;
if(mbuf_trailingspace(ipv6Mbuf) < (int)sizeof(IP1394_NDP))
return;
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) + fwhdrlen;
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)
{
if((arb = new ARB) == NULL)
return;
unicastArb->setObject(arb);
}
if(arb != NULL)
{
bcopy(fwndp->lladdr, &arb->eui64, FIREWIRE_ADDR_LEN);
bcopy(fwndp->lladdr, arb->fwaddr, FIREWIRE_ADDR_LEN);
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->timer = 0;
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_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 = 0;
*icmp6_cksum = in6_cksum((struct mbuf*)ipv6Mbuf, IPPROTO_ICMPV6, offset, icmp6len);
}
}
}
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;
BOOLEAN 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)
{
if((arb = new ARB) == NULL)
return;
unicastArb->setObject(arb);
}
if(arb != NULL)
{
bcopy(fwndp->lladdr, &arb->eui64, FIREWIRE_ADDR_LEN);
bcopy(fwndp->lladdr, arb->fwaddr, FIREWIRE_ADDR_LEN);
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->timer = 0;
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);
}
ARB *IOFWIPBusInterface::staticGetArbFromFwAddr(void *refcon, u_char *fwaddr)
{
return ((IOFWIPBusInterface*)refcon)->getArbFromFwAddr(fwaddr);
}
ARB *IOFWIPBusInterface::staticGetARBFromEui64(void *refcon, UWIDE eui64)
{
return ((IOFWIPBusInterface*)refcon)->getARBFromEui64(eui64);
}
DRB *IOFWIPBusInterface::staticInitDRBwithDevice(void *refcon, UWIDE eui64, IOFireWireNub *fDevObj, bool itsMac)
{
return ((IOFWIPBusInterface*)refcon)->initDRBwithDevice(eui64,fDevObj,itsMac);
}
UInt32 IOFWIPBusInterface::staticOutputPacket(mbuf_t pkt, void * param)
{
return ((IOFWIPBusInterface*)param)->outputPacket(pkt,param);
}
bool IOFWIPBusInterface::updateARPCache(IP1394_ARP *fwa)
{
ARB *fwarb = NULL;
IORecursiveLockLock(fIPLock);
fwarb = getUnicastArb(fwa->senderIpAddress);
if(fwarb == NULL)
{
if((fwarb = new ARB) == NULL)
{
IOLog("arp: arb allocation failed !\n");
IORecursiveLockUnlock(fIPLock);
return false;
}
fwarb->ipAddress = fwa->senderIpAddress; unicastArb->setObject(fwarb);
}
if (ntohs(fwa->opcode) != ARPOP_REQUEST)
fwarb->timer = 0;
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 = htonl(fwa->senderUniqueID.hi);
fwarb->eui64.lo = htonl(fwa->senderUniqueID.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)
{
ARB *arb = getARBFromEui64(eui64);
if(arb != NULL)
{
arb->handle.unicast.deviceID = (UInt32)device;
arb->handle.unicast.maxRec = device->maxPackLog(true);
arb->handle.unicast.spd = device->FWSpeed();
arb->timer = 0;
arb->itsMac = false;
}
return arb;
}
void IOFWIPBusInterface::cleanARBCache()
{
IORecursiveLockLock(fIPLock);
ARB *arb = NULL;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( unicastArb );
while( NULL != (arb = OSDynamicCast(ARB, iterator->getNextObject())) )
{
if(arb->timer > 1)
arb->timer--;
else if (arb->timer == 1)
{
arb->handle.unicast.deviceID = kInvalidIPDeviceRefID;
unicastArb->removeObject(arb);
arb->release();
}
}
iterator->release();
IORecursiveLockUnlock(fIPLock);
}
void IOFWIPBusInterface::cleanDRBCache()
{
IORecursiveLockLock(fIPLock);
DRB *drb = NULL;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( activeDrb );
while( NULL != (drb = OSDynamicCast(DRB, iterator->getNextObject())) )
{
if (drb->timer > 1) drb->timer--; else if (drb->timer == 1) {
releaseARB(drb->deviceID);
drb->deviceID = kInvalidIPDeviceRefID; activeDrb->removeObject(drb); drb->release();
}
}
iterator->release();
IORecursiveLockUnlock(fIPLock);
}
void IOFWIPBusInterface::cleanRCBCache()
{
IORecursiveLockLock(fIPLock);
RCB *rcb = 0;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( activeRcb );
while( NULL != (rcb = OSDynamicCast(RCB, iterator->getNextObject())) )
{
if(rcb->timer > 1)
rcb->timer--; else if (rcb->timer == 1)
releaseRCB(rcb);
}
iterator->release();
IORecursiveLockUnlock(fIPLock);
}
UInt32 IOFWIPBusInterface::getDeviceID(UWIDE eui64, BOOLEAN *itsMac) {
DRB *drb = getDrbFromEui64(eui64);
if (drb != NULL)
{
*itsMac = drb->itsMac;
return(drb->deviceID);
}
else
{
*itsMac = false;
return(kInvalidIPDeviceRefID);
}
}
void IOFWIPBusInterface::releaseARB(ULONG deviceID)
{
IORecursiveLockLock(fIPLock);
ARB *arb = NULL;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( unicastArb );
while( NULL != (arb = OSDynamicCast(ARB, iterator->getNextObject())) )
{
if (arb->handle.unicast.deviceID == deviceID)
{
arb->handle.unicast.deviceID = kInvalidIPDeviceRefID;
unicastArb->removeObject(arb);
arb->release();
break; }
}
iterator->release();
IORecursiveLockUnlock(fIPLock);
}
void IOFWIPBusInterface::releaseRCB(RCB *rcb, bool freeMbuf)
{
IORecursiveLockLock(fIPLock);
if(freeMbuf && rcb->mBuf != NULL)
{
fIPLocalNode->freePacket((struct mbuf*)rcb->mBuf, 0);
rcb->mBuf = NULL;
}
activeRcb->removeObject(rcb);
rcb->release();
IORecursiveLockUnlock(fIPLock);
}
void IOFWIPBusInterface::updateMcapState()
{
IOFWAsyncStreamRxCommand *asyncStreamRxClient;
IORecursiveLockLock(fIPLock);
MCB *mcb = NULL;
OSCollectionIterator *iterator = OSCollectionIterator::withCollection( mcapState );
while( NULL != (mcb = OSDynamicCast(MCB, iterator->getNextObject())) )
{
if (mcb->expiration > 1) mcb->expiration--; else if (mcb->expiration == 1) {
mcb->expiration = 0; asyncStreamRxClient = (IOFWAsyncStreamRxCommand *)mcb->asyncStreamID;
if(asyncStreamRxClient != NULL)
asyncStreamRxClient->release();
mcb->asyncStreamID = kInvalidAsyncStreamRefID;
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(fLcb, 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);
ARB *arb = NULL;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( multicastArb );
while( NULL != (arb = OSDynamicCast(ARB, 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 );
while( NULL != (rcb = OSDynamicCast(RCB, iterator->getNextObject())) )
releaseRCB(rcb);
iterator->release();
IORecursiveLockUnlock(fIPLock);
}
void IOFWIPBusInterface::resetARBCache()
{
IORecursiveLockLock(fIPLock);
ARB *arb = NULL;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( unicastArb );
while( NULL != (arb = OSDynamicCast(ARB, iterator->getNextObject())) )
arb->handle.unicast.deviceID = kInvalidIPDeviceRefID;
iterator->release();
IORecursiveLockUnlock(fIPLock);
}
void IOFWIPBusInterface::resetMcapState()
{
IORecursiveLockLock(fIPLock);
MCB *mcb = NULL;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( mcapState );
while( NULL != (mcb = OSDynamicCast(MCB, iterator->getNextObject())) )
mcb->nextTransmit = 0;
iterator->release();
IORecursiveLockUnlock(fIPLock);
}
ARB *IOFWIPBusInterface::getArbFromFwAddr(u_char *fwaddr)
{
IORecursiveLockLock(fIPLock);
ARB *arb = 0;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( unicastArb );
while( NULL != (arb = OSDynamicCast(ARB, iterator->getNextObject())) )
if (bcmp(fwaddr, arb->fwaddr, FIREWIRE_ADDR_LEN) == 0)
break;
iterator->release();
IORecursiveLockUnlock(fIPLock);
return(arb);
}
DRB *IOFWIPBusInterface::getDrbFromEui64(UWIDE eui64)
{
IORecursiveLockLock(fIPLock);
DRB *drb = 0;
OSCollectionIterator * iterator = OSCollectionIterator::withCollection( activeDrb );
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(u_char *fwaddr)
{
IORecursiveLockLock(fIPLock);
DRB *drb = 0;
OSCollectionIterator *iterator = OSCollectionIterator::withCollection( activeDrb );
while( NULL != (drb = OSDynamicCast(DRB, iterator->getNextObject())) )
if (bcmp(fwaddr, drb->fwaddr, FIREWIRE_ADDR_LEN) == 0)
break;
iterator->release();
IORecursiveLockUnlock(fIPLock);
return(drb);
}
ARB *IOFWIPBusInterface::getARBFromEui64(UWIDE eui64)
{
IORecursiveLockLock(fIPLock);
ARB *arb = 0;
OSCollectionIterator *iterator = OSCollectionIterator::withCollection( unicastArb );
while( NULL != (arb = OSDynamicCast(ARB, iterator->getNextObject())) )
if (arb->eui64.hi == eui64.hi && arb->eui64.lo == eui64.lo)
break;
iterator->release();
IORecursiveLockUnlock(fIPLock);
return(arb);
}
DRB *IOFWIPBusInterface::getDrbFromDeviceID(void *deviceID)
{
IORecursiveLockLock(fIPLock);
DRB *drb = 0;
OSCollectionIterator *iterator = OSCollectionIterator::withCollection( activeDrb );
while( NULL != (drb = OSDynamicCast(DRB, iterator->getNextObject())) )
if (drb->deviceID == (UInt32)deviceID)
break;
iterator->release();
IORecursiveLockUnlock(fIPLock);
return drb;
}
ARB *IOFWIPBusInterface::getMulticastArb(UInt32 ipAddress)
{
IORecursiveLockLock(fIPLock);
ARB *arb = 0;
OSCollectionIterator *iterator = OSCollectionIterator::withCollection( multicastArb );
while( NULL != (arb = OSDynamicCast(ARB, iterator->getNextObject())) )
if (arb->ipAddress == ipAddress)
break;
iterator->release();
IORecursiveLockUnlock(fIPLock);
return arb;
}
ARB *IOFWIPBusInterface::getUnicastArb(UInt32 ipAddress)
{
IORecursiveLockLock(fIPLock);
ARB *arb = 0;
OSCollectionIterator *iterator = OSCollectionIterator::withCollection( unicastArb );
while( NULL != (arb = OSDynamicCast(ARB, iterator->getNextObject())) )
if (arb->ipAddress == ipAddress)
break;
iterator->release();
IORecursiveLockUnlock(fIPLock);
return(arb);
}
RCB *IOFWIPBusInterface::getRcb(UInt16 sourceID, UInt16 dgl)
{
IORecursiveLockLock(fIPLock);
RCB *rcb = 0;
OSCollectionIterator *iterator = OSCollectionIterator::withCollection( activeRcb );
while( NULL != (rcb = OSDynamicCast(RCB, iterator->getNextObject())) )
if (rcb->sourceID == sourceID && rcb->dgl == dgl)
break;
iterator->release();
IORecursiveLockUnlock(fIPLock);
return(rcb);
}
#pragma mark -
#pragma mark еее mbuf utility routines еее
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,
UInt8 *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){
temp = mbuf_next(srcm);
srcm = temp;
break;
}
temp = mbuf_next(srcm); assert(temp);
srcm = temp;
srcLen = mbuf_len(srcm);
src = (vm_offset_t)mbuf_data(srcm);
}
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){
temp = mbuf_next(srcm);
srcm = temp;
break;
}
srcm = mbuf_next(srcm);
if (dstLen == 0)
break;
srcLen = mbuf_len(srcm);
src = (vm_offset_t)mbuf_data(srcm);
}
}
IORecursiveLockUnlock(fIPLock);
return true;
}
mbuf_t IOFWIPBusInterface::mbufTobuffer(const mbuf_t m,
UInt32 *offset,
UInt8 *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){
temp = mbuf_next(srcm);
srcm = temp;
break;
}
temp = mbuf_next(srcm); assert(temp);
srcm = temp;
srcLen = mbuf_len(srcm);
src = (vm_offset_t)mbuf_data(srcm);
}
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;
temp = mbuf_next(srcm);
srcm = temp;
break;
}
srcm = mbuf_next(srcm);
if (dstLen == 0)
break;
srcLen = mbuf_len(srcm);
src = (vm_offset_t)mbuf_data(srcm);
}
}
return temp;
}