#include "IOFireWireIP.h"
#include "IOFireWireIPUnit.h"
#include "IOFireWireIPCommand.h"
#include "IOFWAsyncStreamRxCommand.h"
extern "C"
{
struct mbuf * m_getpackets(int num_needed, int num_with_pkthdrs, int how);
void _logMbuf(struct mbuf * m);
void _logPkt(void *pkt, UInt16 len);
void moveMbufWithOffset(SInt32 tempOffset, struct mbuf **srcm, vm_address_t *src, SInt32 *srcLen);
}
#define super IOFWController
struct {
UCHAR specifierID[3]; UCHAR version[3]; } gaspVal = { {0x00, 0x00, 0x5E}, {0x00, 0x00, 0x01} };
static u_char multicast[3] = {0x01, 0x00, 0x5e};
static u_char fwbroadcastaddr[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
#define kNumOfPowerStates 2
#define BCOPY(s, d, l) do { bcopy((void *) s, (void *) d, l); } while(0)
static IOPMPowerState ourPowerStates[kNumOfPowerStates] = {
{1,0,0,0,0,0,0,0,0,0,0,0},
{1,IOPMDeviceUsable,IOPMPowerOn,IOPMPowerOn,0,0,0,0,0,0,0,0}
};
extern funnel_t * network_flock;
#pragma mark -
#pragma mark еее copy & queue flags еее
bool gDoCopy = false;
bool gDoQueue = false;
UInt16 gLowWaterMark = 48;
OSDefineMetaClassAndStructors(IOFireWireIP, IOFWController);
#pragma mark -
#pragma mark еее IOService methods еее
bool IOFireWireIP::start(IOService *provider)
{
IOReturn ioStat = kIOReturnSuccess;
fDevice = OSDynamicCast(IOFireWireNub, provider);
if(!fDevice)
return false;
fControl = fDevice->getController();
if(!fControl)
return false;
builtIn();
fLcb = (LCB*)IOMalloc(sizeof(LCB));
if(fLcb == NULL)
return false;
memset(fLcb, 0, sizeof(LCB));
if(!initializeCBlk(CBLK_MEMORY_SIZE))
return false;
fDiagnostics_Symbol = OSSymbol::withCStringNoCopy("Diagnostics");
fDiagnostics = IOFireWireIPDiagnostics::createDiagnostics(this);
if( fDiagnostics )
{
if(fDiagnostics_Symbol)
setProperty( fDiagnostics_Symbol, fDiagnostics );
fDiagnostics->release();
}
if(ioStat == kIOReturnSuccess) {
CSRNodeUniqueID fwuid = fDevice->getUniqueID();
makeEthernetAddress(&fwuid, macAddr, GUID_TYPE);
}
if (!super::start(provider))
return false;
if (getHardwareAddress(&myAddress) != kIOReturnSuccess)
{
return false;
}
if(!createMediumState())
{
IOLog( "IOFireWireIP::start - Couldn't allocate IONetworkMedium\n" );
return false;
}
if (!attachInterface((IONetworkInterface**)&networkInterface, false ))
{
return false;
}
if(fDevice != NULL)
{
if(bOnLynx == false)
{
networkInterface->setIfnetMTU( 1 << fDevice->maxPackLog(true) );
}
else
{
networkInterface->setIfnetMTU( 1 << 9 );
}
}
transmitQueue = (IOGatedOutputQueue*)getOutputQueue();
if ( !transmitQueue )
{
IOLog( "IOFireWireIP::start - Output queue initialization failed\n" );
return false;
}
transmitQueue->retain();
if(ioStat == kIOReturnSuccess) {
ipLock = IOLockAlloc();
if(ipLock == NULL)
ioStat = kIOReturnNoMemory;
else
IOLockInitWithState(ipLock, kIOLockStateUnlocked);
}
if(ioStat == kIOReturnSuccess) {
timerSource = IOTimerEventSource::timerEventSource(
this,
(IOTimerEventSource::Action)&IOFireWireIP::watchdog);
if (timerSource == NULL)
{
IOLog( "IOFireWireIP::start - Couldn't allocate timer event source\n" );
return false;
}
if (getWorkLoop()->addEventSource(timerSource) != kIOReturnSuccess )
{
IOLog( "IOFireWireIP::start - Couldn't add timer event source\n" );
return false;
}
#ifdef FIREWIRETODO
ipRxEventSource = new IOFWIPEventSource;
if(ipRxEventSource == NULL)
{
IOLog( "IOFireWireIP::start - Couldn't allocate ipRx event source\n" );
return false;
}
if(ipRxEventSource->init(this) == false)
{
IOLog( "IOFireWireIP::start - Couldn't init ipRx event source\n" );
return false;
}
if (getWorkLoop()->addEventSource(ipRxEventSource) != kIOReturnSuccess )
{
IOLog( "IOFireWireIP::start - Couldn't add ipRx event source\n" );
return false;
}
#endif
}
if(ioStat == kIOReturnSuccess) {
fIPUnitNotifier = IOService::addNotification(gIOPublishNotification,
serviceMatching("IOFireWireIPUnit"),
&deviceAttach, this, (void*)IP1394_VERSION, 0);
}
if(ioStat == kIOReturnSuccess) {
fIPv6UnitNotifier = IOService::addNotification(gIOPublishNotification,
serviceMatching("IOFireWireIPUnit"),
&deviceAttach, this, (void*)IP1394v6_VERSION, 0);
}
if(ioStat == kIOReturnSuccess) {
fBroadcastReceiveClient = new IOFWAsyncStreamRxCommand;
if(fBroadcastReceiveClient == NULL) {
ioStat = kIOReturnNoMemory;
}
else
{
if(fBroadcastReceiveClient->initAll(0x1f, rxAsyncStream, fControl, fMaxRxIsocPacketSize, this) == false) {
ioStat = kIOReturnNoMemory;
}
}
}
if(ioStat == kIOReturnSuccess)
ioStat = createIPFifoAddress(MAX_FIFO_SIZE);
if(ioStat == kIOReturnSuccess)
ioStat = createIPConfigRomEntry();
if(ioStat == kIOReturnSuccess)
initIsocMgmtCmds();
if(ioStat == kIOReturnSuccess) {
fLcb->ownHandle.deviceID = (UInt32)fDevice;
fLcb->ownHandle.maxRec = fDevice->maxPackLog(true); fLcb->ownHandle.spd = fDevice->FWSpeed(); fLcb->ownHandle.unicastFifoHi = fIP1394Address.addressHi; fLcb->ownHandle.unicastFifoLo = fIP1394Address.addressLo;
setProperty(kIOFWHWAddr, (void *) &fLcb->ownHardwareAddress, sizeof(IP1394_HDW_ADDR));
fDevice->getNodeIDGeneration(fLcb->busGeneration, fLcb->ownNodeID);
fLcb->ownMaxSpeed = fDevice->FWSpeed();
fLcb->maxBroadcastPayload = fDevice->maxPackLog(true);
fLcb->maxBroadcastSpeed = fDevice->FWSpeed();
fLcb->ownMaxPayload = fDevice->maxPackLog(true);
}
if(ioStat != kIOReturnSuccess)
{
IOLog( "IOFireWireIP::start - failed\n" );
return false;
}
timerSource->setTimeoutMS(WATCHDOG_TIMER_MS);
fStarted = true;
networkInterface->setIfnetSoftc(this);
networkInterface->registerService();
return true;
}
bool IOFireWireIP::finalize(IOOptionBits options)
{
return super::finalize(options);
}
void IOFireWireIP::stop(IOService *provider)
{
if(fDiagnostics_Symbol != NULL)
{
fDiagnostics_Symbol->release();
fDiagnostics_Symbol = 0;
}
if(fPolicyMaker != NULL)
fPolicyMaker->deRegisterInterestedDriver(this);
if (ipLock != NULL)
{
IOLockFree(ipLock);
}
freeIsocMgmtCmds();
if (fLocalIP1394v6ConfigDirectory != NULL){
fDevice->getBus()->RemoveUnitDirectory(fLocalIP1394v6ConfigDirectory) ;
fLocalIP1394v6ConfigDirectory->release();
}
if (fLocalIP1394ConfigDirectory != NULL){
fDevice->getBus()->RemoveUnitDirectory(fLocalIP1394ConfigDirectory) ;
fLocalIP1394ConfigDirectory->release();
}
if(fwOwnAddr != NULL)
fwOwnAddr->release();
if (fIP1394AddressSpace != NULL){
fIP1394AddressSpace->deactivate();
fIP1394AddressSpace->release();
fIP1394AddressSpace = NULL;
}
if(fBroadcastReceiveClient != NULL)
{
fBroadcastReceiveClient->release();
fBroadcastReceiveClient = NULL;
}
freeIPCmdPool();
if (transmitQueue != NULL)
{
transmitQueue->release();
}
if(timerSource != NULL)
{
if (workLoop != NULL)
{
workLoop->removeEventSource(timerSource);
}
timerSource->release();
}
#ifdef FIREWIRETODO
if(ipRxEventSource != NULL)
{
ipRxEventSource->release();
}
#endif
if(fIPv6UnitNotifier != NULL)
{
fIPv6UnitNotifier->remove();
fIPv6UnitNotifier = NULL;
}
if(fIPUnitNotifier != NULL)
{
fIPUnitNotifier->remove();
fIPUnitNotifier = NULL;
}
if(fLcb != NULL)
IOFree(fLcb, sizeof(LCB));
if(fMemoryPool != NULL)
IOFree(fMemoryPool, CBLK_MEMORY_SIZE);
if (networkInterface != NULL)
{
networkInterface->release();
}
super::stop(provider);
}
void IOFireWireIP::free(void)
{
return super::free();
}
IOReturn IOFireWireIP::message(UInt32 type, IOService *provider, void *argument)
{
IOReturn res = kIOReturnUnsupported;
if( kIOReturnUnsupported == res )
{
switch (type)
{
case kIOMessageServiceIsTerminated:
res = kIOReturnSuccess;
break;
case kIOMessageServiceIsSuspended:
res = kIOReturnSuccess;
if(fStarted == true)
{
stopAsyncStreamReceiveClients();
}
break;
case kIOMessageServiceIsResumed:
res = kIOReturnSuccess;
if(fStarted == true)
{
busReset(fLcb, 0);
startAsyncStreamReceiveClients();
}
break;
case kIOMessageServiceIsRequestingClose:
res = kIOReturnSuccess;
break;
default: break;
}
}
messageClients(type);
return res;
}
#pragma mark -
#pragma mark еее IOFWController methods еее
IOReturn IOFireWireIP::setMaxPacketSize(UInt32 maxSize)
{
if (maxSize > kIOFWMaxPacketSize)
{
return kIOReturnError;
}
return kIOReturnSuccess;
}
IOReturn IOFireWireIP::getMaxPacketSize(UInt32 * maxSize) const
{
*maxSize = kIOFWMaxPacketSize;
return kIOReturnSuccess;
}
IOReturn IOFireWireIP::getHardwareAddress(IOFWAddress *ea)
{
ea->bytes[0] = macAddr[0];
ea->bytes[1] = macAddr[1];
ea->bytes[2] = macAddr[2];
ea->bytes[3] = macAddr[3];
ea->bytes[4] = macAddr[4];
ea->bytes[5] = macAddr[5];
ea->bytes[6] = macAddr[6];
ea->bytes[7] = macAddr[7];
return kIOReturnSuccess;
}
bool IOFireWireIP::configureInterface( IONetworkInterface *netif )
{
IONetworkData *nd;
if ( super::configureInterface( netif ) == false )
return false;
nd = netif->getNetworkData( kIONetworkStatsKey );
if (!nd || !(fpNetStats = (IONetworkStats *) nd->getBuffer()))
{
IOLog("IOFireWireIP: invalid network statistics\n");
return false;
}
nd = netif->getParameter( kIOFWStatsKey );
if ( !nd || !(fpEtherStats = (IOFWStats*)nd->getBuffer()) )
{
IOLog( "IOFireWireIP::configureInterface - invalid ethernet statistics\n" );
return false;
}
return true;
}
void IOFireWireIP::receivePackets(void * pkt, UInt32 pkt_len, UInt32 options)
{
if(options == true)
fPacketsQueued = true;
IOTakeLock(ipLock);
networkInterface->inputPacket((struct mbuf*)pkt, pkt_len, options);
networkStatAdd(&fpNetStats->inputPackets);
IOUnlock(ipLock);
}
IOOutputQueue* IOFireWireIP::createOutputQueue()
{
return IOGatedOutputQueue::withTarget(this, getWorkLoop(), TRANSMIT_QUEUE_SIZE);
}
bool IOFireWireIP::createWorkLoop()
{
workLoop = fDevice->getController()->getWorkLoop();
return ( workLoop != 0 );
}
IOWorkLoop* IOFireWireIP::getWorkLoop() const
{
return workLoop;
}
UInt32 IOFireWireIP::outputPacket(struct mbuf * pkt, void * param)
{
register struct firewire_header *fwh;
int status = kIOReturnSuccess;
UInt16 type;
BOOLEAN bRet = false;
fwh = mtod(pkt, struct firewire_header*);
type = htons(fwh->ether_type);
switch(type)
{
case ETHERTYPE_IPV6:
bRet = addNDPOptions(pkt);
if(bRet == true)
{
}
case ETHERTYPE_IP:
status = txIP(ifp, pkt, type);
break;
case ETHERTYPE_ARP:
txARP(ifp, pkt);
default :
freePacket(pkt);
break;
}
if(status == kIOFireWireOutOfTLabels)
{
fTxStatus = kIOReturnOutputStall;
status = kIOReturnOutputStall;
}
else
{
status = kIOReturnOutputSuccess;
}
return status;
}
IOReturn IOFireWireIP::enable(IONetworkInterface * netif)
{
if (netifEnabled)
{
IOLog("IOFireWireIP: already enabled\n");
return kIOReturnSuccess;
}
netifEnabled = true;
transmitQueue->setCapacity( TRANSMIT_QUEUE_SIZE );
transmitQueue->start();
return kIOReturnSuccess;
}
IOReturn IOFireWireIP::disable(IONetworkInterface * )
{
netifEnabled = false;
freeIPCmdPool();
transmitQueue->stop();
transmitQueue->setCapacity( 0 );
transmitQueue->flush();
return kIOReturnSuccess;
}
IOReturn IOFireWireIP::getPacketFilters( const OSSymbol *group, UInt32 *filters ) const
{
return super::getPacketFilters( group, filters );
}
IOReturn IOFireWireIP::setWakeOnMagicPacket( bool active )
{
return kIOReturnSuccess;
}
const OSString * IOFireWireIP::newVendorString() const
{
return OSString::withCString("Apple");
}
const OSString * IOFireWireIP::newModelString() const
{
return OSString::withCString("fw+");
}
const OSString * IOFireWireIP::newRevisionString() const
{
return OSString::withCString("");
}
IOReturn IOFireWireIP::setPromiscuousMode( bool active )
{
isPromiscuous = active;
return kIOReturnSuccess;
}
IOReturn IOFireWireIP::setMulticastMode( bool active )
{
multicastEnabled = active;
return kIOReturnSuccess;
}
IOReturn IOFireWireIP::setMulticastList(IOFWAddress *addrs, UInt32 count)
{
#ifdef FIREWIRETODO
IOLog("IOFireWireIP: +setMulticastList count = %lx \n", count);
for (UInt32 i = 0; i < count; i++)
{
if(addrs != NULL)
{
IOLog(" mca.addr[%lx] %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
i, addrs->bytes[0], addrs->bytes[1], addrs->bytes[2], addrs->bytes[3],
addrs->bytes[4], addrs->bytes[5], addrs->bytes[6], addrs->bytes[7]);
addrs++;
}
}
IOLog("IOFireWireIP: -setMulticastList \n");
#endif
return kIOReturnSuccess;
}
IOReturn IOFireWireIP::registerWithPolicyMaker(IOService *policyMaker)
{
IOReturn rc;
fPolicyMaker = policyMaker;
rc = policyMaker->registerPowerDriver( this, ourPowerStates, kNumOfPowerStates );
return rc;
}
unsigned long IOFireWireIP::maxCapabilityForDomainState( IOPMPowerFlags domainState )
{
if (domainState & IOPMPowerOn)
return kNumOfPowerStates - 1;
return 0;
}
unsigned long IOFireWireIP::initialPowerStateForDomainState( IOPMPowerFlags domainState )
{
if (domainState & IOPMPowerOn)
return kNumOfPowerStates - 1;
return 0;
}
unsigned long IOFireWireIP::powerStateForDomainState(IOPMPowerFlags domainState )
{
if (domainState & IOPMPowerOn)
return 1;
return 0;
}
IOReturn IOFireWireIP::setPowerState(unsigned long powerStateOrdinal,
IOService *whatDevice)
{
IOReturn status = kIOReturnSuccess;
if (powerStateOrdinal >= kNumOfPowerStates)
return IOPMNoSuchState;
if(unitCount == 0)
return IOPMAckImplied;
if ( powerStateOrdinal == 0 )
{
status = stopAsyncStreamReceiveClients();
}
else if ( powerStateOrdinal == 1 )
{
status = startAsyncStreamReceiveClients();
}
else
IOLog("IOFireWireIP: unknown powerStateOrdinal \n");
return IOPMAckImplied;
}
bool IOFireWireIP::createMediumState()
{
OSDictionary * mediumDict = OSDictionary::withCapacity(5);
if (!mediumDict)
{
return false;
}
IONetworkMedium * medium = IONetworkMedium::medium(
(IOMediumType)kIOMediumEthernetAuto |
kIOMediumOptionFullDuplex, fLcb->maxBroadcastSpeed);
if (medium)
{
mediumDict->setObject(medium->getKey(), medium);
setCurrentMedium(medium);
medium->release();
}
if (!publishMediumDictionary(mediumDict))
{
return false;
}
if( mediumDict )
{
mediumDict->release();
}
return setLinkStatus( kIONetworkLinkValid, getCurrentMedium(), 0 );
}
#pragma mark -
#pragma mark еее IOFirewireIP methods еее
void IOFireWireIP::builtIn()
{
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 << fDevice->maxPackLog(true);
}
parent = parent->getParentEntry(gIOServicePlane);
}
UInt32 IOFireWireIP::initAsyncCmdPool()
{
IOFWIPAsyncWriteCommand *cmd1 = NULL;
IOReturn status = kIOReturnSuccess;
int i = 0;
if(fAsyncCmdPool == NULL)
{
fAsyncCmdPool = IOCommandPool::withWorkLoop(getWorkLoop());
}
for(i=0; i<=MAX_ASYNC_WRITE_CMDS; i++){
FWAddress addr;
addr.addressHi = 0xdead;
addr.addressLo = 0xbabeface;
cmd1 = new IOFWIPAsyncWriteCommand;
if(!cmd1) {
status = kIOReturnNoMemory;
break;
}
if(!cmd1->initAll(fDevice, fMaxTxAsyncDoubleBuffer, addr, txCompleteBlockWrite, this, false)) {
status = kIOReturnNoMemory;
cmd1->release();
break;
}
fAsyncCmdPool->returnCommand(cmd1);
}
return status;
}
UInt32 IOFireWireIP::initAsyncStreamCmdPool()
{
IOReturn status = kIOReturnSuccess;
int i = 0;
if(fAsyncStreamTxCmdPool == NULL)
{
fAsyncStreamTxCmdPool = IOCommandPool::withWorkLoop(getWorkLoop());
}
IOFWIPAsyncStreamTxCommand *cmd2 = NULL;
for(i=0; i<=MAX_ASYNCSTREAM_TX_CMDS; i++){
cmd2 = new IOFWIPAsyncStreamTxCommand;
if(!cmd2) {
status = kIOReturnNoMemory;
break;
}
if(!cmd2->initAll(fControl, fLcb->busGeneration, 0, 0, GASP_TAG, fMaxTxAsyncDoubleBuffer,
fLcb->maxBroadcastSpeed, txCompleteAsyncStream, this)) {
status = kIOReturnNoMemory;
cmd2->release();
break;
}
fAsyncStreamTxCmdPool->returnCommand(cmd2);
}
return status;
}
void IOFireWireIP::freeIPCmdPool()
{
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;
if(fAsyncStreamTxCmdPool == NULL)
return;
IOFWIPAsyncStreamTxCommand *cmd2 = NULL;
freeCount = 0;
do{
cmd2 = (IOFWIPAsyncStreamTxCommand*)fAsyncStreamTxCmdPool->getCommand(false);
if(cmd2 != NULL)
{
freeCount++;
cmd2->release();
}
}while(cmd2 != NULL);
fAsyncStreamTxCmdPool->release();
fAsyncStreamTxCmdPool = NULL;
return;
}
IOReturn IOFireWireIP::stopAsyncStreamReceiveClients()
{
if(!fBroadcastReceiveClient)
return kIOReturnSuccess;
return fBroadcastReceiveClient->stop();
}
IOReturn IOFireWireIP::startAsyncStreamReceiveClients()
{
if(!fBroadcastReceiveClient)
return kIOReturnSuccess;
return fBroadcastReceiveClient->start(fLcb->maxBroadcastSpeed);
}
IOReturn IOFireWireIP::createIPConfigRomEntry()
{
IOReturn ioStat = kIOReturnSuccess;
IP1394_HDW_ADDR hwAddr;
fLocalIP1394ConfigDirectory = IOLocalConfigDirectory::create();
if (!fLocalIP1394ConfigDirectory){
ioStat = kIOReturnError;
}
if(ioStat == kIOReturnSuccess)
ioStat = fLocalIP1394ConfigDirectory->addEntry(kConfigUnitSpecIdKey, IP1394_SPEC_ID) ;
if(ioStat == kIOReturnSuccess)
ioStat = fLocalIP1394ConfigDirectory->addEntry(kConfigUnitSwVersionKey, IP1394_VERSION) ;
if(ioStat == kIOReturnSuccess){
CSRNodeUniqueID fwuid = fDevice->getUniqueID();
hwAddr.eui64.hi = (UInt32)(fwuid >> 32);
hwAddr.eui64.lo = (UInt32)(fwuid & 0xffffffff);
#ifdef FIREWIRETODO
a = (UInt8*)&hwAddr.eui64.hi;
a[0] = macAddr[0];
a[1] = macAddr[1];
a[2] = macAddr[2];
a[3] = macAddr[3];
a = (UInt8*)&hwAddr.eui64.lo;
a[0] = macAddr[4];
a[1] = macAddr[5];
a[2] = macAddr[6];
a[3] = macAddr[7];
#endif
hwAddr.maxRec = fDevice->maxPackLog(true);
hwAddr.spd = fDevice->FWSpeed();
hwAddr.unicastFifoHi = fIP1394Address.addressHi;
hwAddr.unicastFifoLo = fIP1394Address.addressLo;
fwOwnAddr = OSData::withBytes(&hwAddr, sizeof(IP1394_HDW_ADDR));
if(fwOwnAddr != NULL){
ioStat = fLocalIP1394ConfigDirectory->addEntry(kConfigUnitDependentInfoKey,
fwOwnAddr, NULL);
}
}
if(ioStat == kIOReturnSuccess)
ioStat = fControl->AddUnitDirectory(fLocalIP1394ConfigDirectory) ;
fLocalIP1394v6ConfigDirectory = IOLocalConfigDirectory::create();
if (!fLocalIP1394v6ConfigDirectory){
ioStat = kIOReturnError;
}
if(ioStat == kIOReturnSuccess)
ioStat = fLocalIP1394v6ConfigDirectory->addEntry(kConfigUnitSpecIdKey, IP1394_SPEC_ID) ;
if(ioStat == kIOReturnSuccess)
ioStat = fLocalIP1394v6ConfigDirectory->addEntry(kConfigUnitSwVersionKey, IP1394v6_VERSION) ;
if(fwOwnAddr != NULL)
{
ioStat = fLocalIP1394v6ConfigDirectory->addEntry(kConfigUnitDependentInfoKey,
fwOwnAddr, NULL);
}
if(ioStat == kIOReturnSuccess)
ioStat = fControl->AddUnitDirectory(fLocalIP1394v6ConfigDirectory) ;
memcpy(&fLcb->ownHardwareAddress, &hwAddr, sizeof(IP1394_HDW_ADDR));
return ioStat;
}
DRB *IOFireWireIP::createDrbWithDevice(LCB *lcb, UWIDE eui64, IOFireWireNub *fDevObj, bool itsMac)
{
DRB *drb = NULL;
CSRNodeUniqueID fwuid;
drb = getDrbFromEui64(lcb, eui64);
if (drb != NULL)
{
drb->deviceID = (UInt32)fDevObj;
fwuid = fDevObj->getUniqueID();
if(itsMac)
makeEthernetAddress(&fwuid, drb->fwaddr, GUID_TYPE);
else
getBytesFromGUID((void*)(&fwuid), drb->fwaddr, GUID_TYPE);
drb->timer = 0;
drb->itsMac = itsMac;
return drb;
}
else if ((drb = (DRB*)allocateCBlk(lcb)) == NULL)
{ IOLog(" No DRB's - failure: \n");
return NULL;
}
else
{ drb->deviceID = (UInt32)fDevObj;
fwuid = fDevObj->getUniqueID();
if(itsMac)
makeEthernetAddress(&fwuid, drb->fwaddr, GUID_TYPE);
else
getBytesFromGUID((void*)(&fwuid), drb->fwaddr, GUID_TYPE);
drb->timer = 0;
drb->lcb = lcb;
drb->eui64 = eui64;
drb->itsMac = itsMac;
drb->maxSpeed = kFWSpeed100MBit;
drb->maxSpeed = fDevObj->FWSpeed();
drb->maxPayload = fDevObj->maxPackLog(true);
linkCBlk(&lcb->activeDrb, drb);
}
return drb;
}
IOReturn IOFireWireIP::createIPFifoAddress(UInt32 fifosize)
{
IOReturn ioStat = kIOReturnSuccess;
fIP1394AddressSpace = fControl->createPseudoAddressSpace(&fIP1394Address, fifosize,
NULL,
&rxUnicast,
this);
if (fIP1394AddressSpace == NULL){
IOLog("IOFireWireIP PseudoAddressSpace failure status %d\n", ioStat);
ioStat = kIOReturnNoMemory;
}
if(ioStat == kIOReturnSuccess ){
fIP1394AddressSpace->setARxReqIntCompleteHandler(this, &rxUnicastComplete);
}
if(ioStat == kIOReturnSuccess ){
ioStat = fIP1394AddressSpace->activate();
}
if(ioStat != kIOReturnSuccess){
IOLog("IOFireWireIP PseudoAddressSpace Activate failure status %d\n", ioStat);
}
return ioStat;
}
UInt32 IOFireWireIP::getMTU()
{
UInt32 mtu = 0;
mtu = FIREWIRE_MTU;
return mtu;
}
void *IOFireWireIP::getMacAddress(char *srcBuf, UInt32 len)
{
return memcpy(srcBuf, macAddr, FIREWIRE_ADDR_LEN);
}
void IOFireWireIP::setIPAddress(register struct in_addr *sip)
{
fLcb->ownIpAddress = sip->s_addr;
}
void IOFireWireIP::getBytesFromGUID(void *guid, u_char *bufAddr, UInt8 type)
{
u_long lo=0, hi=0;
if(type == GUID_TYPE)
{
CSRNodeUniqueID *fwuid = (CSRNodeUniqueID*)guid;
hi = (u_long)(*fwuid >> 32);
lo = (u_long)(*fwuid & 0xffffffff);
}
else
{
UWIDE *eui64 = (UWIDE*)guid;
hi = eui64->hi;
lo = eui64->lo;
}
bufAddr[0] = (unsigned char)((hi >> 24) & 0x000000ff);
bufAddr[1] = (unsigned char)((hi >> 16) & 0x000000ff);
bufAddr[2] = (unsigned char)((hi >> 8) & 0x000000ff);
bufAddr[3] = (unsigned char)((hi) & 0x000000ff);
bufAddr[4] = (unsigned char)((lo >> 24) & 0x000000ff);
bufAddr[5] = (unsigned char)((lo >> 16) & 0x000000ff);
bufAddr[6] = (unsigned char)((lo >> 8) & 0x000000ff);
bufAddr[7] = (unsigned char)((lo) & 0x000000ff);
}
void IOFireWireIP::makeEthernetAddress(CSRNodeUniqueID *fwuid, u_char *bufAddr, UInt32 vendorID)
{
#ifdef FIREWIRETODO
UInt8 guids[][6] = {{0x00,0x30,0x65},
{0x00,0x03,0x93},
{0x00,0x0a,0x27},
{0x00,0x05,0x02},
{0x00,0x50,0xE4},
{0x00,0x0A,0x95}};
bool bFound = false;
#endif
getBytesFromGUID(fwuid, bufAddr, GUID_TYPE);
#ifdef FIREWIRETODO
for (UInt32 i = 0; i <= LAST(guids); i++)
if (memcmp(bufAddr, guids[i], 3) == 0)
{
(LAST(guids) == i)?i = 0:i++;
memcpy(bufAddr, guids[i], 3);
bFound = true;
break;
}
if(!bFound)
memcpy(bufAddr, guids[2], 3);
#endif
}
bool IOFireWireIP::deviceAttach(void * target, void * refCon, IOService * newService)
{
IOFireWireIP *fwIPObject;
IOFireWireIPUnit *fwIPunit;
IOFireWireNub *fDevice = NULL;
UWIDE eui64;
ARB *arb;
DRB *drb;
u_char lladdr[FIREWIRE_ADDR_LEN];
if(target == NULL || newService == NULL)
return false;
fwIPObject = OSDynamicCast(IOFireWireIP, (IOService *)target);
fwIPunit = OSDynamicCast(IOFireWireIPUnit, (IOService *)newService);
if(!fwIPObject)
return false;
fDevice = fwIPunit->getDevice();
if(!fDevice){
IOLog("Colonel ! we have problem !! Null device for legal unit %p\n", fwIPunit);
return false;
}
if(fwIPObject->fControl != fDevice->getController())
return false;
fwIPunit->setLocalNode(fwIPObject);
CSRNodeUniqueID fwuid = fDevice->getUniqueID();
if(fwIPunit->isSpecial())
{
fwIPObject->makeEthernetAddress(&fwuid, lladdr, GUID_TYPE);
bcopy((void*)lladdr, &eui64, FIREWIRE_ADDR_LEN);
}
else
{
eui64.hi = (UInt32)(fwuid >> 32);
eui64.lo = (UInt32)(fwuid & 0xffffffff);
}
drb = fwIPObject->createDrbWithDevice(fwIPObject->fLcb, eui64, fDevice, fwIPunit->isSpecial());
if(drb == NULL){
IOLog("No memory !, Can't create Device reference block\n\r");
return false;
}
fwIPunit->setDrb(drb);
arb = fwIPObject->getArbFromEui64(fwIPObject->fLcb, eui64);
if(arb != NULL)
{
arb->handle.unicast.deviceID = (UInt32)fDevice;
arb->handle.unicast.maxRec = fDevice->maxPackLog(true);
arb->handle.unicast.spd = fDevice->FWSpeed();
arb->timer = 0;
arb->itsMac = fwIPunit->isSpecial();
}
if(!fwIPunit->getUnitState())
{
fwIPObject->unitCount++;
fwIPunit->setUnitState(true);
}
fwIPObject->updateBroadcastValues(false);
fwIPObject->updateLinkStatus();
return true;
}
void IOFireWireIP::deviceDetach(void *target)
{
IOFireWireIPUnit *fwIPUnit = (IOFireWireIPUnit *)target;
DRB *drb = NULL;
ARB *arb = NULL;
int arpt_keep = (30*60);
drb = fwIPUnit->getDrb();
if(drb != NULL)
{
drb->timer = arpt_keep;
arb = getArbFromFwAddr(fLcb, drb->fwaddr);
if(arb != NULL)
arb->timer = arpt_keep;
}
if(unitCount > 0)
{
unitCount--;
}
if(unitCount == 0)
{
setLinkStatus( kIONetworkLinkValid, getCurrentMedium(), 0 );
}
updateBroadcastValues(true);
updateLinkStatus();
}
void IOFireWireIP::updateBroadcastValues(bool reset)
{
DRB *drb = NULL;
CBLK *cBlk = NULL;
IOFireWireDevice *remoteDevice = NULL;
if(reset)
{
fLcb->maxBroadcastPayload = fDevice->maxPackLog(true);
fLcb->maxBroadcastSpeed = fDevice->FWSpeed();
}
IOTakeLock(ipLock);
if (fLcb->activeDrb == NULL)
{
}
else
{
cBlk = (CBLK*)&fLcb->activeDrb;
while ((cBlk = cBlk->next) != NULL)
{
drb = (DRB*)cBlk;
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;
}
}
IOUnlock(ipLock);
}
void IOFireWireIP::updateLinkStatus()
{
if(getUnitCount() == 0)
{
setLinkStatus(kIONetworkLinkValid, getCurrentMedium(), 0);
}
else
{
setLinkStatus(kIONetworkLinkValid, getCurrentMedium(), 0);
setLinkStatus (kIONetworkLinkActive | kIONetworkLinkValid,
getCurrentMedium(),
(1 << fLcb->maxBroadcastSpeed) * 100 * 1000000);
}
fLcb->ownHardwareAddress.spd = fLcb->maxBroadcastSpeed;
setProperty(kIOFWHWAddr, (void *) &fLcb->ownHardwareAddress, sizeof(IP1394_HDW_ADDR));
}
void IOFireWireIP::txCompleteBlockWrite(void *refcon, IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd)
{
IOFireWireIP *fwIPObject = (IOFireWireIP *)refcon;
IOFWIPAsyncWriteCommand *cmd = (IOFWIPAsyncWriteCommand *)fwCmd;
struct mbuf * pkt = NULL;
UInt32 type = UNFRAGMENTED;
if(fwIPObject->fTxStatus == kIOReturnOutputStall)
{
fwIPObject->fStalls++;
fwIPObject->fTxStatus = kIOReturnOutputSuccess;
}
if(status == kIOReturnSuccess)
{
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->outputPackets);
fwIPObject->fTxUni++;
}
else
{
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->outputErrors);
fwIPObject->fCallErrs++;
}
type = cmd->getLinkFragmentType();
pkt = cmd->getMbuf();
if(pkt != NULL)
{
if(type == LAST_FRAGMENT || type == UNFRAGMENTED)
{
if(status != kIOFireWireOutOfTLabels)
{
fwIPObject->freePacket(pkt);
}
}
}
cmd->resetDescriptor();
if(fwIPObject->fAsyncCmdPool != NULL)
{
fwIPObject->fAsyncCmdPool->returnCommand(cmd);
}
else
{
IOLog("IOFWIPAsyncWriteCommand got completed after the interface is disabled !!\n");
cmd->release();
}
IOTakeLock(fwIPObject->ipLock);
fwIPObject->fUsedCmds--;
IOUnlock(fwIPObject->ipLock);
if(status != kIOFireWireOutOfTLabels && status != kIOReturnNoResources && (fwIPObject->fUsedCmds <= (gLowWaterMark+10)))
{
fwIPObject->transmitQueue->service(0x01);
}
return;
}
void IOFireWireIP::txCompleteAsyncStream(void *refcon, IOReturn status,
IOFireWireBus *bus, IOFWAsyncStreamCommand *fwCmd)
{
IOFireWireIP *fwIPObject = (IOFireWireIP *)refcon;
IOFWIPAsyncStreamTxCommand *cmd = (IOFWIPAsyncStreamTxCommand *)fwCmd;
struct mbuf * pkt = NULL;
if(status == kIOReturnSuccess)
{
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->outputPackets);
fwIPObject->fTxBcast++;
}
else
{
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->outputErrors);
}
pkt = cmd->getMbuf();
if(pkt != NULL)
fwIPObject->freePacket(pkt);
cmd->setMbuf(NULL);
if(fwIPObject->fAsyncStreamTxCmdPool != NULL)
{
fwIPObject->fAsyncStreamTxCmdPool->returnCommand(cmd);
}
else
{
IOLog("IOFWIPAsyncStreamTxCommand got completed after the interface is disabled !!\n");
cmd->release();
}
return;
}
void IOFireWireIP::txARP(struct ifnet *ifp, struct mbuf *m){
struct firewire_header *fwh;
struct mbuf *n;
UInt8 *buf;
UInt32 offset = 0;
IOFWIPAsyncStreamTxCommand *cmd = NULL;
UInt32 cmdLen = 0;
UInt32 dstBufLen = 0;
UInt32 ret = 0;
struct arp_packet *fwa_pkt;
fwh = mtod(m, struct firewire_header *);
n = m;
if(fAsyncStreamTxCmdPool == NULL)
{
initAsyncStreamCmdPool();
}
cmd = (IOFWIPAsyncStreamTxCommand*)fAsyncStreamTxCmdPool->getCommand(false);
if(cmd == NULL)
{
networkStatAdd(&(getNetStats())->outputErrors);
goto endtxARP;
}
buf = (UInt8*)cmd->getBufferFromDesc();
dstBufLen = cmd->getMaxBufLen();
offset = sizeof(struct firewire_header);
cmdLen = m->m_pkthdr.len - sizeof(struct firewire_header);
fwa_pkt = (struct arp_packet*)(buf);
bzero((caddr_t)fwa_pkt, sizeof(*fwa_pkt));
fwa_pkt->gaspHdr.sourceID = htons(fLcb->ownNodeID);
memcpy(&fwa_pkt->gaspHdr.gaspID, &gaspVal, sizeof(GASP_ID));
fwa_pkt->ip1394Hdr.etherType = htons(ETHERTYPE_ARP);
buf += (sizeof(GASP_HDR) + sizeof(IP1394_UNFRAG_HDR));
mbufTobuffer(n, &offset, buf, dstBufLen, cmdLen);
cmdLen += (sizeof(GASP_HDR) + sizeof(IP1394_UNFRAG_HDR));
ret = cmd->reinit(fLcb->busGeneration,
DEFAULT_BROADCAST_CHANNEL,
cmdLen,
fLcb->maxBroadcastSpeed,
txCompleteAsyncStream,
this);
if (ret == kIOReturnSuccess)
cmd->submit(true);
endtxARP:
return;
}
SInt32 IOFireWireIP::txIP(struct ifnet *ifp, struct mbuf *m, UInt16 type)
{
struct firewire_header *fwh;
GASP_HDR *gaspHdr;
IP1394_ENCAP_HDR *ip1394Hdr;
struct mbuf *n;
TNF_HANDLE *handle;
UInt8 *datagram;
UInt8 *buf;
FWAddress addr;
UInt16 datagramSize = 0;
ARB *arb = NULL;
IOFWIPAsyncWriteCommand *cmd = NULL;
IOFWIPAsyncStreamTxCommand *asyncStreamCmd = NULL;
UInt32 offset = 0;
UInt32 dstBufLen = 0;
UInt32 maxPayload = 0;
UInt16 residual = 0;
UInt16 drbMaxPayload = 0;
UInt16 dgl = 0;
BOOLEAN unfragmented;
UInt16 headerSize = 0;
UInt16 fragmentOffset = 0;
UInt16 fragmentSize = 0;
UInt32 cmdLen = 0;
UInt32 channel = 0;
SInt32 status = 0;
IOFireWireNub *device;
bool broadcast = false;
bool fDeferNotify = true;
bool bTxError = false;
fwh = mtod(m, struct firewire_header *);
if(bcmp(fwh->ether_dhost, fwbroadcastaddr, FIREWIRE_ADDR_LEN) == 0 ||
bcmp(fwh->ether_dhost, multicast, 3) == 0)
{
broadcast = true;
}
else
{
arb = getArbFromFwAddr(fLcb, fwh->ether_dhost);
}
if(!(m->m_flags & M_PKTHDR))
{
status = kIOReturnError;
goto endtxIP;
}
n = m;
datagram = (UInt8*)n->m_data;
datagramSize = m->m_pkthdr.len - sizeof(struct firewire_header);
if(datagramSize > fMaxPktSize)
{
fMaxPktSize = datagramSize;
}
if(broadcast)
{
channel = DEFAULT_BROADCAST_CHANNEL;
maxPayload = 1 << fLcb->ownMaxPayload;
maxPayload = MIN((UInt32)1 << fLcb->maxBroadcastPayload, maxPayload);
if (datagramSize + sizeof(IP1394_UNFRAG_HDR) > maxPayload)
{
status = ENOBUFS;
goto endtxIP;
}
if(fAsyncStreamTxCmdPool == NULL)
{
initAsyncStreamCmdPool();
}
asyncStreamCmd = (IOFWIPAsyncStreamTxCommand*)fAsyncStreamTxCmdPool->getCommand(false);
if(asyncStreamCmd == NULL)
{
status = ENOBUFS;
goto endtxIP;
}
asyncStreamCmd->setMbuf(m);
buf = (UInt8*)asyncStreamCmd->getBufferFromDesc();
dstBufLen = asyncStreamCmd->getMaxBufLen();
gaspHdr = (GASP_HDR *)buf;
gaspHdr->sourceID = htons(fLcb->ownNodeID);
memcpy(&gaspHdr->gaspID, &gaspVal, sizeof(GASP_ID));
ip1394Hdr = (IP1394_ENCAP_HDR*)((UInt8*)buf + sizeof(GASP_HDR));
ip1394Hdr->singleFragment.etherType = htons(type);
ip1394Hdr->singleFragment.reserved = htons(UNFRAGMENTED);
cmdLen = datagramSize;
offset = sizeof(struct firewire_header);
headerSize = sizeof(GASP_HDR) + sizeof(IP1394_UNFRAG_HDR);
buf = buf + headerSize;
mbufTobuffer(n, &offset, buf, dstBufLen, cmdLen);
cmdLen += headerSize;
status = asyncStreamCmd->reinit(fLcb->busGeneration,
channel,
cmdLen,
fLcb->maxBroadcastSpeed,
txCompleteAsyncStream,
this);
if(status == kIOReturnSuccess)
asyncStreamCmd->submit(true);
}
else
{
if(arb == NULL)
{
status = EHOSTUNREACH;
goto endtxIP;
}
if(arb != NULL && arb->timer > 1)
{
status = EHOSTUNREACH;
goto endtxIP;
}
handle = &arb->handle;
if(handle->unicast.deviceID == 0)
{
status = EHOSTUNREACH;
goto endtxIP;
}
residual = datagramSize;
addr.addressHi = handle->unicast.unicastFifoHi;
addr.addressLo = handle->unicast.unicastFifoLo;
device = (IOFireWireNub*)handle->unicast.deviceID;
drbMaxPayload = 1 << device->maxPackLog(true, addr);
maxPayload = 1 << fLcb->ownMaxPayload;
maxPayload = MIN((UInt32)1 << handle->unicast.maxRec, maxPayload);
maxPayload = MIN(drbMaxPayload, maxPayload);
if (!(unfragmented = ((datagramSize + sizeof(IP1394_UNFRAG_HDR)) <= maxPayload)))
{
dgl = fLcb->datagramLabel++;
}
offset = sizeof(struct firewire_header);
while (residual)
{
if(fAsyncCmdPool == NULL)
{
initAsyncCmdPool();
}
cmd = (IOFWIPAsyncWriteCommand *)fAsyncCmdPool->getCommand(false);
if(cmd == NULL)
{
status = ENOBUFS;
goto endtxIP;
}
IOTakeLock(ipLock);
fUsedCmds++;
IOUnlock(ipLock);
if(fUsedCmds >= gLowWaterMark)
{
fDeferNotify = false;
}
cmd->setMbuf(m, gDoCopy);
if (unfragmented)
{
headerSize = sizeof(IP1394_UNFRAG_HDR);
cmd->setOffset(offset, true);
cmd->setHeaderSize(headerSize);
cmd->setLinkFragmentType(UNFRAGMENTED);
cmdLen = residual;
ip1394Hdr = (IP1394_ENCAP_HDR*)cmd->getDescriptorHeader(unfragmented);
ip1394Hdr->fragment.datagramSize = htons(UNFRAGMENTED);
ip1394Hdr->singleFragment.etherType = htons(type);
ip1394Hdr->singleFragment.reserved = 0;
}
else
{
fTxFragmentPkts++;
headerSize = sizeof(IP1394_FRAG_HDR);
cmd->setHeaderSize(headerSize);
ip1394Hdr = (IP1394_ENCAP_HDR*)cmd->getDescriptorHeader(unfragmented);
cmdLen = MIN(residual, maxPayload - sizeof(IP1394_FRAG_HDR));
fragmentSize = cmdLen;
ip1394Hdr->fragment.datagramSize = htons(datagramSize - 1);
if (fragmentOffset == 0)
{
ip1394Hdr->fragment.datagramSize |= htons(FIRST_FRAGMENT << 14);
ip1394Hdr->singleFragment.etherType = htons(type);
cmd->setOffset(offset, true);
cmd->setLinkFragmentType(FIRST_FRAGMENT);
}
else
{
if (fragmentSize < residual)
{
ip1394Hdr->fragment.datagramSize |= htons(INTERIOR_FRAGMENT << 14);
cmd->setLinkFragmentType(INTERIOR_FRAGMENT);
}
else
{
ip1394Hdr->fragment.datagramSize |= htons(LAST_FRAGMENT << 14);
cmd->setLinkFragmentType(LAST_FRAGMENT);
}
ip1394Hdr->fragment.fragmentOffset = htons(fragmentOffset);
cmd->setOffset(offset, false);
}
ip1394Hdr->fragment.dgl = htons(dgl);
ip1394Hdr->fragment.reserved = 0;
}
if(handle->unicast.deviceID != 0)
{
status = cmd->initDescriptor(unfragmented, cmdLen);
if(status != kIOReturnSuccess)
goto endtxIP;
status = cmd->reinit((IOFireWireDevice*)handle->unicast.deviceID,
cmdLen+headerSize,
addr,
txCompleteBlockWrite,
this,
true);
cmd->setDeferredNotify(fDeferNotify);
if(status == kIOReturnSuccess)
cmd->submit(gDoQueue);
status = cmd->getStatus();
if(status == kIOFireWireOutOfTLabels || status == kIOReturnNoResources)
{
fSubmitErrs++;
return status;
}
else
{
bTxError = true;
}
}
fragmentOffset += cmdLen; offset += cmdLen;
residual -= cmdLen;
} }
endtxIP:
if(status != kIOReturnSuccess)
{
if(bTxError == false)
{
if(cmd != NULL)
{
cmd->resetDescriptor();
if(fAsyncCmdPool)
fAsyncCmdPool->returnCommand(cmd);
IOTakeLock(ipLock);
fUsedCmds--;
IOUnlock(ipLock);
}
freePacket(m);
networkStatAdd(&(getNetStats())->outputErrors);
}
}
return status;
}
void IOFireWireIP::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;
arb = (ARB*)&lcb->multicastArb;
while ((arb = arb->next) != NULL) {
if (arb->handle.multicast.channel == mcb->channel) {
memcpy(&ipAddress, &arb->ipAddress, sizeof(ipAddress));
IOLog(" Advertise %u.%u.%u.%u channel %u expires %u\n\r",
((UCHAR *) &ipAddress)[0], ((UCHAR *) &ipAddress)[1],
((UCHAR *) &ipAddress)[2], ((UCHAR *) &ipAddress)[3],
mcb->channel, mcb->expiration);
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);
}
}
} else {
packet->mcap.opcode = MCAP_SOLICIT;
#ifdef FIREWIRETODO
IOLog(" Solicit %u.%u.%u.%u\n\r", ((UCHAR *) &ipAddress)[0],
((UCHAR *) &ipAddress)[1], ((UCHAR *) &ipAddress)[2],
((UCHAR *) &ipAddress)[3]);
#endif
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);
asyncStreamCmd->setMbuf(NULL);
status = asyncStreamCmd->reinit(fLcb->busGeneration,
DEFAULT_BROADCAST_CHANNEL,
cmdLen,
fLcb->maxBroadcastSpeed,
txCompleteAsyncStream,
this);
if(status == kIOReturnSuccess)
asyncStreamCmd->submit(true);
}
void IOFireWireIP::rxUnicastFlush()
{
UInt32 count = 0;
IOTakeLock(ipLock);
if(fPacketsQueued = true)
{
count = networkInterface->flushInputQueue();
if(count > fMaxInputCount)
{
fMaxInputCount = count;
}
fPacketsQueued = false;
}
IOUnlock(ipLock);
return;
}
void IOFireWireIP::rxUnicastComplete(void *refcon)
{
IOFireWireIP *fwIPObject = (IOFireWireIP *)refcon;
fwIPObject->rxUnicastFlush();
return;
}
UInt32 IOFireWireIP::rxUnicast( void *refcon,
UInt16 nodeID,
IOFWSpeed &speed,
FWAddress addr,
UInt32 len,
const void *buf,
IOFWRequestRefCon requestRefcon)
{
void *datagram, *fragment;
UInt16 datagramSize;
IP1394_UNFRAG_HDR *ip1394Hdr;
IP1394_FRAG_HDR *fragmentHdr;
RCB *currRcb;
UInt16 fragmentSize;
UInt16 type;
UInt8 lf;
RCB *rcb;
CBLK *cBlk;
struct mbuf *rxMBuf;
IOFireWireIP *fwIPObject = (IOFireWireIP *)refcon;
struct firewire_header *fwh = NULL;
ip1394Hdr = (IP1394_UNFRAG_HDR *)buf;
if(fwIPObject->netifEnabled != true)
return kIOReturnSuccess;
if (ip1394Hdr->reserved == htons(UNFRAGMENTED))
{
datagram = (void *) ((ULONG) ip1394Hdr + sizeof(IP1394_UNFRAG_HDR));
datagramSize = len - sizeof(IP1394_UNFRAG_HDR);
type = ntohs(ip1394Hdr->etherType);
switch (type)
{
case ETHERTYPE_IPV6:
if (datagramSize >= IPV6_HDR_SIZE)
fwIPObject->updateNDPCache(datagram, &datagramSize);
else
break;
case ETHERTYPE_IP:
if (datagramSize >= IPV4_HDR_SIZE)
fwIPObject->rxIP(fwIPObject, datagram, datagramSize, FW_M_UCAST, type);
break;
case ETHERTYPE_ARP:
if (datagramSize >= sizeof(IP1394_ARP))
{
fwIPObject->rxARP(fwIPObject, (IP1394_ARP*)datagram, FW_M_UCAST);
}
break;
default :
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->inputErrors);
break;
}
}
else
{
fwIPObject->fRxFragmentPkts++;
fragmentHdr = (IP1394_FRAG_HDR*) ip1394Hdr; fragment = (void *) ((UInt32) fragmentHdr + sizeof(IP1394_FRAG_HDR));
fragmentSize = len - sizeof(IP1394_FRAG_HDR);
lf = htons(fragmentHdr->datagramSize) >> 14;
if ((rcb = fwIPObject->getRcb(fwIPObject->fLcb, nodeID, htons(fragmentHdr->dgl))) == NULL)
{
if ((rxMBuf = fwIPObject->getMBuf((htons(fragmentHdr->datagramSize) & 0x3FFF)
+ 1 + sizeof(firewire_header))) == NULL)
{
IOLog(" mbuf not available\n");
return kIOReturnSuccess;
}
if ((rcb = (RCB*)fwIPObject->allocateCBlk(fwIPObject->fLcb)) == NULL)
{
IOTakeLock(fwIPObject->ipLock);
cBlk = (CBLK*)&(fwIPObject->fLcb->activeRcb);
while ((cBlk = cBlk->next) != NULL)
{
currRcb = (RCB*)cBlk;
if (currRcb->timer == 1)
{
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->inputErrors);
if(currRcb->mBuf != NULL)
fwIPObject->freePacket(currRcb->mBuf, kDelayFree);
currRcb->sourceID = 0;
currRcb->dgl = 0;
currRcb->mBuf = NULL;
currRcb->residual = 0;
fwIPObject->unlinkCBlk(&(fwIPObject->fLcb->activeRcb), cBlk);
fwIPObject->deallocateCBlk(fwIPObject->fLcb, cBlk);
}
}
IOUnlock(fwIPObject->ipLock);
fwIPObject->freePacket(rxMBuf, kDelayFree);
fwIPObject->releaseFreePackets();
return kIOReturnSuccess;
}
rcb->sourceID = nodeID;
rcb->dgl = htons(fragmentHdr->dgl);
rcb->mBuf = rxMBuf;
rcb->timer = 1;
fwh = (struct firewire_header *)rxMBuf->m_data;
bzero(fwh, sizeof(struct firewire_header));
rcb->datagram = rxMBuf->m_data + sizeof(struct firewire_header);
if (lf == FIRST_FRAGMENT)
{
fwh->ether_type = htons(fragmentHdr->fragmentOffset);
}
else
{
fwh->ether_type = ETHERTYPE_IP;
}
rcb->datagramSize = (htons(fragmentHdr->datagramSize) & 0x3FFF) + 1;
rcb->residual = rcb->datagramSize;
fwIPObject->linkCBlk(&(fwIPObject->fLcb->activeRcb), rcb);
}
if (rcb->mBuf == NULL || rcb->datagram == NULL)
{
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->inputErrors);
fwIPObject->showRcb(rcb);
return kIOReturnError;
}
if (lf == FIRST_FRAGMENT)
{
rcb->etherType = htons(fragmentHdr->fragmentOffset);
fwIPObject->bufferToMbuf(rcb->mBuf,
sizeof(struct firewire_header),
(UInt8*)fragment,
MIN(fragmentSize, rcb->datagramSize));
}
else
{
fwIPObject->bufferToMbuf(rcb->mBuf,
sizeof(struct firewire_header)+htons(fragmentHdr->fragmentOffset),
(UInt8*)fragment,
MIN(fragmentSize, rcb->datagramSize - htons(fragmentHdr->fragmentOffset)));
}
rcb->residual -= MIN(fragmentSize, rcb->residual);
if (rcb->residual == 0)
{
if (rcb->etherType == ETHERTYPE_IP || rcb->etherType == ETHERTYPE_IPV6)
{
fwIPObject->receivePackets (rcb->mBuf,
rcb->mBuf->m_pkthdr.len,
true);
}
else
{
fwIPObject->networkStatAdd(&(fwIPObject->getNetStats())->inputErrors);
fwIPObject->freeMBuf(rcb->mBuf);
}
rcb->mBuf = NULL;
rcb->residual = 0;
rcb->timer = 0;
fwIPObject->unlinkCBlk(&(fwIPObject->fLcb->activeRcb), rcb);
fwIPObject->deallocateCBlk(fwIPObject->fLcb, rcb);
}
}
fwIPObject->fRxUni++;
return kIOReturnSuccess;
}
void IOFireWireIP::rxAsyncStream(DCLCommandStruct *callProc){
DCLCallProc *ptr = (DCLCallProc*)callProc;
RXProcData *proc = (RXProcData*)ptr->procData;
IOFireWireIP *fwIPObject = (IOFireWireIP*)proc->obj;
IOFWAsyncStreamRxCommand *fwRxAsyncStream;
UInt8 *buffer = proc->buffer;
void *datagram;
UInt16 datagramSize;
GASP *gasp = (GASP*)buffer;
LCB *lcb = fwIPObject->fLcb;
ISOC_DATA_PKT *pkt = (ISOC_DATA_PKT*)buffer;
UInt16 type = 0;
fwRxAsyncStream = (IOFWAsyncStreamRxCommand*)proc->thisObj;
fwRxAsyncStream->modifyDCLJumps(callProc);
if(fwIPObject->netifEnabled != true)
{
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 ETHERTYPE_IPV6:
if (datagramSize >= IPV6_HDR_SIZE)
fwIPObject->updateNDPCache(datagram, &datagramSize);
else
break;
case ETHERTYPE_IP:
if (datagramSize >= IPV4_HDR_SIZE)
fwIPObject->rxIP(fwIPObject, datagram, datagramSize, FW_M_BCAST, type);
break;
case ETHERTYPE_ARP:
if (datagramSize >= sizeof(IP1394_ARP))
{
fwIPObject->rxARP(fwIPObject, (IP1394_ARP*)datagram, FW_M_BCAST);
}
break;
case ETHER_TYPE_MCAP:
if (datagramSize >= sizeof(IP1394_MCAP))
fwIPObject->rxMCAP(lcb, htons(gasp->gaspHdr.sourceID),
(IP1394_MCAP*)datagram, datagramSize - sizeof(IP1394_MCAP));
break;
}
fwIPObject->fRxBcast++;
return;
}
void IOFireWireIP::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(lcb, groupDescr->groupAddress)) == NULL)
; else if (mcap->opcode == MCAP_SOLICIT) {
#ifdef FIREWIRETODO
IOLog(" Solicit %u.%u.%u.%u\n\r",
((UCHAR *) &groupDescr->groupAddress)[0],
((UCHAR *) &groupDescr->groupAddress)[1],
((UCHAR *) &groupDescr->groupAddress)[2],
((UCHAR *) &groupDescr->groupAddress)[3]);
#endif
mcb = &lcb->mcapState[arb->handle.multicast.channel];
if (mcb->ownerNodeID == lcb->ownNodeID) txMCAP(lcb, mcb, 0);
}
else if ((groupDescr->channel != DEFAULT_BROADCAST_CHANNEL)
&& (groupDescr->channel <= LAST(lcb->mcapState)))
{
IOLog(" Advertise %u.%u.%u.%u channel %u expires %u\n\r",
((UCHAR *) &groupDescr->groupAddress)[0],
((UCHAR *) &groupDescr->groupAddress)[1],
((UCHAR *) &groupDescr->groupAddress)[2],
((UCHAR *) &groupDescr->groupAddress)[3],
groupDescr->channel, groupDescr->expiration);
mcb = &lcb->mcapState[groupDescr->channel];
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 = &lcb->mcapState[currentChannel];
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 (arb->deletionPending && (mcb->ownerNodeID != lcb->ownNodeID)) {
unlinkCBlk(&lcb->multicastArb, arb);
deallocateCBlk(lcb, arb);
}
}
dataSize -= MIN(groupDescr->length, dataSize);
groupDescr = (MCAST_DESCR*)((ULONG) groupDescr + groupDescr->length);
}
}
IOReturn IOFireWireIP::rxIP(IOFireWireIP *fwIPObj, void *pkt, UInt32 len, UInt32 flags, UInt16 type)
{
struct mbuf *rxMBuf;
struct firewire_header *fwh = NULL;
void *datagram = NULL;
bool queuePkt = false;
if ((rxMBuf = getMBuf(len + sizeof(struct firewire_header))) != NULL)
{
IOTakeLock(ipLock);
fwh = (struct firewire_header *)rxMBuf->m_data;
datagram = rxMBuf->m_data + sizeof(struct firewire_header);
bzero(fwh, sizeof(struct firewire_header));
if (flags == FW_M_UCAST)
{
bcopy(macAddr, fwh->ether_dhost, FIREWIRE_ADDR_LEN);
queuePkt = true;
}
else
{
bcopy(fwbroadcastaddr, fwh->ether_dhost, FIREWIRE_ADDR_LEN);
queuePkt = false;
}
fwh->ether_type = type;
IOUnlock(ipLock);
bufferToMbuf(rxMBuf, sizeof(struct firewire_header), (UInt8*)pkt, len);
receivePackets(rxMBuf, rxMBuf->m_pkthdr.len, queuePkt);
}
return kIOReturnSuccess;
}
IOReturn IOFireWireIP::rxARP(IOFireWireIP *fwIPObj, IP1394_ARP *arp, UInt32 flags){
struct mbuf *rxMBuf;
struct firewire_header *fwh = NULL;
void *datagram = NULL;
if (arp->hardwareType != htons(ARP_HDW_TYPE)
|| arp->protocolType != htons(ETHERTYPE_IP)
|| arp->hwAddrLen != sizeof(IP1394_HDW_ADDR)
|| arp->ipAddrLen != IPV4_ADDR_SIZE)
{
IOLog("IOFireWireIP: rxARP ERROR in packet header\n");
return kIOReturnError;
}
if ((rxMBuf = getMBuf(sizeof(*arp) + sizeof(struct firewire_header))) != NULL)
{
IOTakeLock(ipLock);
fwh = (struct firewire_header *)rxMBuf->m_data;
datagram = rxMBuf->m_data + sizeof(struct firewire_header);
bzero(fwh, sizeof(struct firewire_header));
fwh->ether_type = ETHERTYPE_ARP;
memcpy(datagram, arp, sizeof(*arp));
IOUnlock(ipLock);
receivePackets(rxMBuf, rxMBuf->m_pkthdr.len, NULL);
}
return kIOReturnSuccess;
}
void IOFireWireIP::watchdog(IOTimerEventSource *)
{
ARB *arb, *priorArb;
DRB *drb, *priorDrb;
UNSIGNED i;
MCB *mcb;
IOFireWireIP *fwIpObj = (IOFireWireIP*)this;
LCB *lcb = fwIpObj->getLcb();
IOFWAsyncStreamRxCommand *asyncStreamRxClient;
priorDrb = (DRB *) &lcb->activeDrb;
while ((drb = priorDrb->next) != NULL)
{
if (drb->timer > 1) drb->timer--; else if (drb->timer == 1)
{ priorDrb->next = drb->next; arb = (ARB *) &lcb->unicastArb; while ((arb = arb->next) != NULL)
{
if (arb->handle.unicast.deviceID == drb->deviceID)
{
arb->handle.unicast.deviceID = kInvalidIPDeviceRefID;
fwIpObj->unlinkCBlk(&lcb->unicastArb, arb);
fwIpObj->deallocateCBlk(lcb, arb);
break; }
}
drb->deviceID = kInvalidIPDeviceRefID; fwIpObj->deallocateCBlk(lcb, drb);
continue; }
priorDrb = drb; }
for (i = 0; i <= LAST(lcb->mcapState); i++)
{
mcb = &lcb->mcapState[i];
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 == lcb->ownNodeID) {
mcb->finalWarning = 4; mcb->nextTransmit = 1; }
}
if (mcb->ownerNodeID != lcb->ownNodeID)
continue; else if (mcb->nextTransmit > 1) mcb->nextTransmit--; else if (mcb->nextTransmit == 1)
{ if (mcb->groupCount > 0) mcb->expiration = 60;
fwIpObj->txMCAP(lcb, 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; priorArb = (ARB *) &lcb->multicastArb;
while ((arb = priorArb->next) != NULL)
{
if (arb->handle.multicast.channel == mcb->channel)
{
if (arb->deletionPending)
{
priorArb->next = arb->next; fwIpObj->deallocateCBlk(lcb, arb); continue; }
else arb->handle.multicast.channel = DEFAULT_BROADCAST_CHANNEL;
}
priorArb = arb; }
}
}
}
fwIpObj->cleanFWArbCache(lcb);
timerSource->setTimeoutMS(WATCHDOG_TIMER_MS);
}
void IOFireWireIP::busReset(LCB *lcb, UInt32 flags){
CBLK *cBlk;
UInt32 i;
RCB *rcb;
lcb->ownMaxPayload = fDevice->maxPackLog(true);
fDevice->getNodeIDGeneration(lcb->busGeneration, lcb->ownNodeID);
lcb->ownMaxSpeed = fDevice->FWSpeed();
IOTakeLock(ipLock);
cBlk = (CBLK*)&lcb->activeRcb;
while ((cBlk = cBlk->next) != NULL)
{
rcb = (RCB*)cBlk;
unlinkCBlk(&lcb->activeRcb, cBlk);
networkStatAdd(&(getNetStats())->inputErrors);
if(rcb->mBuf != NULL)
freePacket(rcb->mBuf, kDelayFree);
rcb->sourceID = 0;
rcb->dgl = 0;
rcb->mBuf = NULL;
rcb->residual = 0;
deallocateCBlk(lcb, cBlk);
}
IOUnlock(ipLock);
releaseFreePackets();
for (i = 0; i <= LAST(lcb->mcapState); i++)
lcb->mcapState[i].nextTransmit = 0;
updateBroadcastValues(true);
updateLinkStatus();
return;
}
#pragma mark -
#pragma mark еее IPv6 NDP routines еее
bool IOFireWireIP::addNDPOptions(struct mbuf *m)
{
struct icmp6_hdr *icp = NULL;
struct ip6_hdr *ip6;
struct nd_neighbor_advert *nd_na = NULL;
struct nd_neighbor_solicit *nd_ns = NULL;
IP1394_NDP *fwndp = NULL;
BOOLEAN modify = false;
UInt8 *buf = NULL;
vm_address_t src = 0;
struct mbuf *temp = NULL;
int *pktLen = NULL;
long *length = NULL;
if (m->m_flags & M_PKTHDR)
{
pktLen = &m->m_pkthdr.len;
}
else
return false;
src = mtod(m, vm_offset_t);
if(src == NULL)
return false;
if(m->m_len == sizeof(firewire_header))
{
temp = m->m_next;
if(temp == NULL)
return false;
src = mtod(temp, vm_offset_t);
if(temp->m_len < (int)(sizeof(struct ip6_hdr)))
{
return false;
}
if(m_trailingspace(temp) < (int)sizeof(IP1394_NDP))
{
return false;
}
buf = (UInt8*)(src);
length = &temp->m_len;
}
else
{
if(m->m_len < (int)(sizeof(firewire_header) + sizeof(struct ip6_hdr)))
{
return false;
}
if(m_trailingspace(m) < (int)sizeof(IP1394_NDP))
{
return false;
}
buf = (UInt8*)(src + sizeof(firewire_header));
length = &m->m_len;
}
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)
{
modify = true;
}
if(fwndp->type == 2)
{
}
}
if(nd_na->nd_na_type == ND_NEIGHBOR_ADVERT)
{
fwndp = (IP1394_NDP*)((UInt8*)nd_na + sizeof(struct nd_neighbor_advert));
if(fwndp->type == 1)
{
}
if(fwndp->type == 2)
{
modify = true;
}
}
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);
*length += 8;
*pktLen += 8;
return true;
}
return false;
}
void IOFireWireIP::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(fwndp->type == 2)
{
}
}
if(nd_na->nd_na_type == ND_NEIGHBOR_ADVERT)
{
fwndp = (IP1394_NDP*)((UInt8*)nd_na + sizeof(struct nd_neighbor_advert));
if(fwndp->type == 1)
{
}
if(fwndp->type == 2)
{
update = true;
}
}
if(update && fwndp != NULL && fwndp->len > 2)
{
arb = getArbFromFwAddr(fLcb, fwndp->lladdr);
if(arb == NULL)
{
arb = (ARB*)allocateCBlk(fLcb);
if(arb == NULL)
{
return;
}
linkCBlk(&fLcb->unicastArb, 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->datagramPending = FALSE;
arb->handle.unicast.deviceID = getDeviceID(fLcb, 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 еее IOFireWireIP utility routines еее
void* IOFireWireIP::initializeCBlk(UInt32 memorySize)
{
UInt32 *memoryPool = 0;
UInt32 i = 0;
UInt32 *ptr;
fMemoryPool = memoryPool = (UInt32*)IOMalloc(memorySize);
if(memoryPool == NULL){
IOLog("IOFireWireIP:: memory pool for CBLKS not allocated \n");
return NULL;
}
memset(memoryPool, 0, sizeof(memorySize));
for (i = 0; i < N_CBLK; i++)
{
*((void **) memoryPool) = fLcb->freeCBlk;
fLcb->freeCBlk = (struct cblk*)memoryPool;
memoryPool = (UInt32 *) ((ULONG) memoryPool + MAX_CBLK_SIZE);
memorySize -= MAX_CBLK_SIZE;
}
fLcb->cFreeCBlk = fLcb->minFreeCBlk = fLcb->nCBlk = N_CBLK;
ptr = (UInt32*)&fLcb->mcapState;
memset(ptr, 0, sizeof(MCB)*MAX_CHANNEL_DES);
return memoryPool;
}
void *IOFireWireIP::allocateCBlk(LCB *lcb) {
CBLK *cBlk;
IOTakeLock(ipLock);
if ((cBlk = lcb->freeCBlk) != NULL) {
lcb->freeCBlk = cBlk->next;
lcb->cFreeCBlk--;
memset(cBlk, 0, MAX_CBLK_SIZE);
}
if ((lcb->freeCBlk == NULL) != (lcb->cFreeCBlk == 0))
IOLog("allocateCBlk error: lcb->freeCBlk %08lX lcb->cFreeCBlk %04X\n\r",
(ULONG) lcb->freeCBlk, lcb->cFreeCBlk);
IOUnlock(ipLock);
lcb->minFreeCBlk = MIN(lcb->minFreeCBlk, lcb->cFreeCBlk);
if (cBlk == NULL)
IOLog("ERROR: No CBLK available!\n\r");
return(cBlk);
}
void IOFireWireIP::deallocateCBlk(LCB *lcb, void *cBlk) {
IOTakeLock(ipLock);
if (cBlk != NULL) {
((CBLK *) cBlk)->next = lcb->freeCBlk;
lcb->freeCBlk = (CBLK *)cBlk;
lcb->cFreeCBlk++;
}
if ((lcb->freeCBlk == NULL) != (lcb->cFreeCBlk == 0))
{
IOLog("deallocateCBlk error: lcb->freeCBlk %08lX lcb->cFreeCBlk %04X\n\r",
(ULONG) lcb->freeCBlk, lcb->cFreeCBlk);
}
IOUnlock(ipLock);
}
void IOFireWireIP::cleanFWArbCache(LCB *lcb)
{
ARB *arb = (ARB *) &lcb->unicastArb;
IOTakeLock(ipLock);
while ((arb = arb->next) != NULL)
{
if(arb->datagramPending == TRUE)
{
if(arb->timer > 1)
{
arb->timer--;
}
else if (arb->timer == 1)
{
IOLog("IOFireWireIP: unresolved arb cleaned up of ipaddress 0x%lx \n", arb->ipAddress);
arb->handle.unicast.deviceID = kInvalidIPDeviceRefID;
unlinkCBlk(&lcb->unicastArb, arb);
deallocateCBlk(lcb, arb);
}
}
}
IOUnlock(ipLock);
}
UInt32 IOFireWireIP::getDeviceID(LCB *lcb, UWIDE eui64, BOOLEAN *itsMac) {
DRB *drb = getDrbFromEui64(lcb, eui64);
if (drb != NULL)
{
*itsMac = drb->itsMac;
return(drb->deviceID);
}
else
{
*itsMac = false;
return(kInvalidIPDeviceRefID);
}
}
ARB *IOFireWireIP::getArbFromFwAddr(LCB *lcb, u_char *fwaddr)
{
ARB *arb = (ARB *) &lcb->unicastArb;
IOTakeLock(ipLock);
while ((arb = arb->next) != NULL)
if (bcmp(fwaddr, arb->fwaddr, FIREWIRE_ADDR_LEN) == 0)
break;
IOUnlock(ipLock);
return(arb);
}
DRB *IOFireWireIP::getDrbFromEui64(LCB *lcb, UWIDE eui64) {
DRB *drb = (DRB *) &lcb->activeDrb;
IOTakeLock(ipLock);
while ((drb = drb->next) != NULL)
if (drb->eui64.hi == eui64.hi && drb->eui64.lo == eui64.lo)
break;
IOUnlock(ipLock);
return(drb);
}
DRB *IOFireWireIP::getDrbFromFwAddr(LCB *lcb, u_char *fwaddr)
{
DRB *drb = (DRB *) &lcb->activeDrb;
IOTakeLock(ipLock);
while ((drb = drb->next) != NULL)
if (bcmp(fwaddr, drb->fwaddr, FIREWIRE_ADDR_LEN) == 0)
break;
IOUnlock(ipLock);
return(drb);
}
ARB *IOFireWireIP::getArbFromEui64(LCB *lcb, UWIDE eui64) {
ARB *arb = (ARB *) &lcb->unicastArb;
IOTakeLock(ipLock);
while ((arb = arb->next) != NULL)
if (arb->eui64.hi == eui64.hi && arb->eui64.lo == eui64.lo)
break;
IOUnlock(ipLock);
return(arb);
}
DRB *IOFireWireIP::getDrbFromDeviceID(LCB *lcb, void *deviceID){
DRB *drb = (DRB *) &lcb->activeDrb;
IOTakeLock(ipLock);
while ((drb = drb->next) != NULL)
if (drb->deviceID == (UInt32)deviceID)
break;
IOUnlock(ipLock);
return(drb);
}
ARB *IOFireWireIP::getMulticastArb(LCB *lcb, UInt32 ipAddress){
ARB *arb = (ARB *) &lcb->multicastArb;
while ((arb = arb->next) != NULL)
if (arb->ipAddress == ipAddress)
break;
return(arb);
}
ARB *IOFireWireIP::getUnicastArb(LCB *lcb, UInt32 ipAddress){
ARB *arb = (ARB *) &lcb->unicastArb;
IOTakeLock(ipLock);
while ((arb = arb->next) != NULL)
if (arb->ipAddress == ipAddress)
break;
IOUnlock(ipLock);
return(arb);
}
RCB *IOFireWireIP::getRcb(LCB *lcb, UInt16 sourceID, UInt16 dgl){
RCB *rcb = (RCB *) &lcb->activeRcb;
IOTakeLock(ipLock);
while ((rcb = rcb->next) != NULL) {
if (rcb->sourceID == sourceID && rcb->dgl == dgl)
break;
}
IOUnlock(ipLock);
return(rcb);
}
void IOFireWireIP::linkCBlk(void *queueHead, void *cBlk) {
IOTakeLock(ipLock);
((CBLK *) cBlk)->next = (CBLK*)(*((void **) queueHead));
*((void **) queueHead) = cBlk;
IOUnlock(ipLock);
}
void IOFireWireIP::unlinkCBlk(void *queueHead, void *cBlk) {
IOTakeLock(ipLock);
while (*((void **) queueHead) != NULL)
if (*((void **) queueHead) == cBlk) {
*((void **) queueHead) = ((CBLK *) cBlk)->next;
((CBLK *) cBlk)->next = NULL;
break;
} else
queueHead = *((void **) queueHead);
IOUnlock(ipLock);
}
void IOFireWireIP::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(" datagram %p datagramSize %u residual %u\n\r", rcb->datagram, rcb->datagramSize, rcb->residual);
}
}
void IOFireWireIP::showArb(ARB *arb) {
u_char ipAddress[4];
IOLog("ARB %p\n\r", arb);
memcpy(ipAddress, &arb->ipAddress, sizeof(ipAddress));
IOLog(" IP address %u.%u.%u.%u EUI-64 %08lX %08lX\n\r", ipAddress[0],
ipAddress[1], ipAddress[2], ipAddress[3], 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);
IOLog(" Timer %d datagramPending %d\n\r", arb->timer, arb->datagramPending);
}
void IOFireWireIP::showHandle(TNF_HANDLE *handle) {
if (handle->unicast.deviceID != kInvalidIPDeviceRefID)
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 IOFireWireIP::showDrb(DRB *drb)
{
if (drb != NULL) {
IOLog("DRB 0x%p (associated with LCB 0x%p)\n\r", drb, drb->lcb);
IOLog(" Device ID %08lX EUI-64 %08lX %08lX\n\r", drb->deviceID, drb->eui64.hi, drb->eui64.lo);
IOLog(" timer %08lX maxPayload %d maxSpeed %d\n\r", drb->timer, drb->maxPayload, drb->maxSpeed);
}
}
void IOFireWireIP::showLcb() {
CBLK *cBlk;
UNSIGNED cCBlk = 0;
IOLog("LCB at %p (driver object at %p)\n\r", fLcb,
fLcb->driverObject);
IOLog(" Node ID %04X maxPayload %u maxSpeed %u busGeneration 0x%08lX\n\r",
fLcb->ownNodeID, fLcb->ownMaxPayload,
fLcb->ownMaxSpeed, fLcb->busGeneration);
IOLog(" Free CBLKs %u (of %u in pool)\n\r", fLcb->cFreeCBlk,
fLcb->nCBlk);
IOLog(" CBLK Low water mark %u\n\r", fLcb->minFreeCBlk);
if (fLcb->unicastArb == NULL)
IOLog(" No unicast ARBs\n\r");
else {
IOLog(" Unicast ARBs\n\r");
cBlk = (CBLK*)&fLcb->unicastArb;
while ((cBlk = cBlk->next) != NULL) {
cCBlk++;
IOLog(" %p\n\r", cBlk);
showArb((ARB*)cBlk);
}
}
if (fLcb->multicastArb == NULL)
IOLog(" No multicast ARBs\n\r");
else {
IOLog(" Multicast ARBs\n\r");
cBlk = (CBLK*)&fLcb->multicastArb;
while ((cBlk = cBlk->next) != NULL) {
cCBlk++;
IOLog(" %p\n\r", cBlk);
}
}
if (fLcb->activeDrb == NULL)
IOLog(" No active DRBs\n\r");
else {
IOLog(" Active DRBs\n\r");
cBlk = (CBLK*)&fLcb->activeDrb;
while ((cBlk = cBlk->next) != NULL) {
cCBlk++;
IOLog(" %p\n\r", cBlk);
showDrb((DRB*)cBlk);
}
}
if (fLcb->activeRcb == NULL)
IOLog(" No active RCBs\n\r");
else {
IOLog(" Active RCBs\n\r");
cBlk = (CBLK*)&fLcb->activeRcb;
while ((cBlk = cBlk->next) != NULL) {
cCBlk++;
IOLog(" %p\n\r", cBlk);
showRcb((RCB*)cBlk);
}
}
IOLog(" %u CBLKs in use\n\r", cCBlk);
if (cCBlk + fLcb->cFreeCBlk != fLcb->nCBlk)
IOLog(" CBLK accounting error!\n\r");
}
void IOFireWireIP::updateStatistics()
{
if(fBroadcastReceiveClient != NULL)
{
fIsoRxOverrun = fBroadcastReceiveClient->getOverrunCounter();
}
}
#pragma mark -
#pragma mark еее mbuf utility routines еее
#define IO_APPEND_MBUF(head, tail, m) { \
if (tail) { \
(tail)->m_next = (m); \
(tail) = (m); \
} \
else { \
(head) = (tail) = (m); \
(head)->m_pkthdr.len = 0; \
} \
}
#define IO_ALIGN_MBUF_START(m, mask) { \
if ( (mask) & mtod((m), vm_address_t) ) { \
(m)->m_data = (caddr_t) (( mtod((m), vm_address_t) + (mask) ) \
& ~(mask)); \
} \
}
#define IO_ALIGN_MBUF(m, size, smask, lmask) { \
IO_ALIGN_MBUF_START((m), (smask)); \
(m)->m_len = ((size) - (smask)) & ~(lmask); \
}
static struct mbuf * allocateMbuf( UInt32 size,
UInt32 how,
UInt32 smask,
UInt32 lmask )
{
struct mbuf * m;
struct mbuf * head = 0;
struct mbuf * tail = 0;
UInt32 capacity;
while ( size )
{
if ( head == 0 )
{
MGETHDR( m, how, MT_DATA );
capacity = MHLEN;
}
else
{
MGET( m, how, MT_DATA );
capacity = MLEN;
}
if ( m == 0 ) goto error;
IO_APPEND_MBUF( head, tail, m );
if ( ( size + smask + lmask ) > capacity )
{
MCLGET( m, how );
if ( (m->m_flags & M_EXT) == 0 ) goto error;
capacity = MCLBYTES;
}
IO_ALIGN_MBUF( m, capacity, smask, lmask );
if ( (UInt) m->m_len > size )
m->m_len = size;
size -= m->m_len;
head->m_pkthdr.len += m->m_len;
}
return head;
error:
if ( head ) m_freem(head);
return 0;
}
static struct mbuf * getPacket( UInt32 size,
UInt32 how,
UInt32 smask,
UInt32 lmask )
{
struct mbuf * m = NULL;
do {
if ( ( size + smask ) <= MCLBYTES )
{
if ( ( size + smask ) > MHLEN )
{
m = m_getpackets( 1, 1, how );
}
else
{
MGETHDR( m, how, MT_DATA );
}
if ( m == 0 ) break;
IO_ALIGN_MBUF_START( m, smask );
m->m_pkthdr.len = m->m_len = size;
}
else
{
m = allocateMbuf( size, how, smask, lmask );
}
}
while ( false );
return m;
}
void moveMbufWithOffset(SInt32 tempOffset, struct mbuf **srcm, vm_address_t *src, SInt32 *srcLen)
{
struct mbuf *temp = NULL;
for(;;)
{
if(tempOffset == 0)
break;
if(*srcm == NULL)
break;
if(*srcLen < tempOffset)
{
tempOffset = tempOffset - *srcLen;
temp = (*srcm)->m_next;
*srcm = temp;
if(*srcm != NULL)
*srcLen = (*srcm)->m_len;
continue;
}
else if (*srcLen > tempOffset)
{
*srcLen = (*srcm)->m_len;
*src = mtod(*srcm, vm_offset_t);
*src += tempOffset;
*srcLen -= tempOffset;
break;
}
else if (*srcLen == tempOffset)
{
temp = (*srcm)->m_next;
*srcm = temp;
if(*srcm != NULL)
{
*srcLen = (*srcm)->m_len;
*src = mtod(*srcm, vm_offset_t);
}
break;
}
}
}
struct mbuf * IOFireWireIP::getMBuf(UInt32 size)
{
struct mbuf *m;
IOTakeLock(ipLock);
m = getPacket(size, M_DONTWAIT, 0, 0);
if (m != NULL)
{
m->m_pkthdr.rcvif = ifp;
}
IOUnlock(ipLock);
return m;
}
bool IOFireWireIP::bufferToMbuf(struct mbuf *m,
UInt32 offset,
UInt8 *srcbuf,
UInt32 srcbufLen)
{
vm_address_t src, dst;
SInt32 srcLen, dstLen, copylen, tempOffset;
struct mbuf *temp;
struct mbuf *srcm;
IOTakeLock(ipLock);
temp = NULL;
srcm = NULL;
srcm = m;
srcLen = srcm->m_len;
src = mtod(srcm, vm_offset_t);
tempOffset = offset;
moveMbufWithOffset(tempOffset, &srcm, &src, &srcLen);
dstLen = srcbufLen;
copylen = dstLen;
dst = (vm_address_t)srcbuf;
for (;;) {
if (srcLen < dstLen) {
BCOPY(dst, src, srcLen);
dst += srcLen;
dstLen -= srcLen;
copylen -= srcLen;
if(copylen == 0){
temp = srcm->m_next;
srcm = temp;
break;
}
temp = srcm->m_next; assert(temp);
srcm = temp;
srcLen = srcm->m_len;
src = mtod(srcm, vm_offset_t);
}
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 = srcm->m_next;
srcm = temp;
break;
}
srcm = srcm->m_next;
if (dstLen == 0)
break;
srcLen = srcm->m_len;
src = mtod(srcm, vm_offset_t);
}
}
IOUnlock(ipLock);
return true;
}
struct mbuf *IOFireWireIP::mbufTobuffer(struct mbuf *m,
UInt32 *offset,
UInt8 *dstbuf,
UInt32 dstbufLen,
UInt32 length)
{
vm_address_t src, dst;
SInt32 srcLen, dstLen, copylen, tempOffset;
struct mbuf *temp = NULL;
struct mbuf *srcm = NULL;
srcm = m;
srcLen = srcm->m_len;
src = mtod(srcm, vm_offset_t);
tempOffset = *offset;
moveMbufWithOffset(tempOffset, &srcm, &src, &srcLen);
dstLen = length;
copylen = dstLen;
dst = (vm_address_t)dstbuf;
for (;;) {
if (srcLen < dstLen) {
BCOPY(src, dst, srcLen);
dst += srcLen;
dstLen -= srcLen;
copylen -= srcLen;
*offset = *offset + srcLen;
if(copylen == 0){
temp = srcm->m_next;
srcm = temp;
break;
}
temp = srcm->m_next; assert(temp);
srcm = temp;
srcLen = srcm->m_len;
src = mtod(srcm, vm_offset_t);
}
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 = srcm->m_next;
srcm = temp;
break;
}
srcm = srcm->m_next;
if (dstLen == 0)
break;
srcLen = srcm->m_len;
src = mtod(srcm, vm_offset_t);
}
}
return temp;
}
void IOFireWireIP::freeMBuf(struct mbuf *m) {
IOTakeLock(ipLock);
m_freem(m);
IOUnlock(ipLock);
}
void _logMbuf(struct mbuf * m)
{
UInt8 *bytePtr;
if (!m) {
IOLog("logMbuf: NULL mbuf\n");
return;
}
while (m) {
IOLog("m_next : %08x\n", (UInt) m->m_next);
IOLog("m_nextpkt: %08x\n", (UInt) m->m_nextpkt);
IOLog("m_len : %d\n", (UInt) m->m_len);
IOLog("m_data : %08x\n", (UInt) m->m_data);
IOLog("m_type : %08x\n", (UInt) m->m_type);
IOLog("m_flags : %08x\n", (UInt) m->m_flags);
if (m->m_flags & M_PKTHDR)
IOLog("m_pkthdr.len : %d\n", (UInt) m->m_pkthdr.len);
if (m->m_flags & M_EXT) {
IOLog("m_ext.ext_buf : %08x\n", (UInt) m->m_ext.ext_buf);
IOLog("m_ext.ext_size: %d\n", (UInt) m->m_ext.ext_size);
}
IOLog("m_data -> \t\t") ;
if(m->m_data != NULL){
bytePtr = (UInt8*)m->m_data;
for(SInt32 index=0; index < min(m->m_len, 12); index++)
{
if ((index & 0x3) == 0)
{
IOLog(" ") ;
if ((index & 0x7) == 0)
{
IOLog(" ") ;
if ((index & 0xF) == 0)
IOLog("\n\t\t") ;
}
}
IOLog("%02X", (unsigned char)bytePtr[index]) ;
}
IOLog("\n\n") ;
}
m = m->m_next;
}
IOLog("\n");
}
void _logPkt(void *pkt, UInt16 len)
{
UInt8 *bytePtr;
bytePtr = (UInt8*)pkt;
IOLog("pkt {\n") ;
for(SInt32 index=0; index<len; index++)
{
if ((index & 0x3) == 0)
{
IOLog(" ") ;
if ((index & 0x7) == 0)
{
IOLog(" ") ;
if ((index & 0xF) == 0)
IOLog("\n\t\t") ;
}
}
IOLog("%02X", (unsigned char)bytePtr[index]) ;
}
IOLog("}\n\n") ;
}
#pragma mark -
#pragma mark еее firewire irm routines еее
UInt32 IOFireWireIP::initIsocMgmtCmds()
{
fReadCmd = new IOFWReadQuadCommand;
if(fReadCmd)
fReadCmd->initAll(fControl, 0, FWAddress(), NULL, 0, NULL, NULL);
fLockCmd = new IOFWCompareAndSwapCommand;
if(fLockCmd)
fLockCmd->initAll(fControl, 0, FWAddress(), NULL, NULL, 0, NULL, NULL);
return fReadCmd != NULL && fLockCmd != NULL;
}
void IOFireWireIP::freeIsocMgmtCmds()
{
if(fReadCmd)
{
fReadCmd->release();
}
if(fLockCmd)
{
fLockCmd->release();
}
}
void IOFireWireIP::getChan31()
{
UInt32 newVal ;
FWAddress addr(kCSRRegisterSpaceBaseAddressHi, kCSRBandwidthAvailable) ;
UInt32 oldIRM[3] ;
UInt32 channel ;
IOReturn err = kIOReturnSuccess;
UInt32 generation;
fControl->getIRMNodeID(generation, addr.nodeID);
fReadCmd->reinit(generation, addr, oldIRM, 3);
fReadCmd->setMaxPacket(4);
err = fReadCmd->submit();
channel = 31;
if (!err)
{
UInt32* oldPtr;
if(channel < 32)
{
addr.addressLo = kCSRChannelsAvailable31_0;
oldPtr = &oldIRM[1];
newVal = *oldPtr & ~(1<<(31 - channel));
}
else
{
addr.addressLo = kCSRChannelsAvailable63_32;
oldPtr = &oldIRM[2];
newVal = *oldPtr & ~( (UInt64)1 << (63 - channel) );
}
fLockCmd->reinit(generation, addr, oldPtr, &newVal, 1);
err = fLockCmd->submit();
if (!err && !fLockCmd->locked(oldPtr))
err = kIOReturnCannotLock ;
}
}
UInt32 IOFireWireIP::acquireChannel(UInt32 *pChannel, Boolean autoReAllocate, UInt32 resourceAllocationFlags)
{
UInt32 newVal ;
FWAddress addr(kCSRRegisterSpaceBaseAddressHi, kCSRBandwidthAvailable) ;
UInt32 oldIRM[3] ;
UInt32 channel = 0;
IOReturn err = kIOReturnSuccess;
UInt64 inAllowedChans;
UInt32 generation;
inAllowedChans = ~(UInt64)0;
IOLog(" %s %d\n", __FILE__, __LINE__);
if(autoReAllocate & kDoNotAllocate) {
}
else {
fControl->getIRMNodeID(generation, addr.nodeID);
fReadCmd->reinit(generation, addr, oldIRM, 3);
fReadCmd->setMaxPacket(4);
err = fReadCmd->submit();
if (!err)
{
inAllowedChans &= (UInt64)(oldIRM[2]) | ((UInt64)oldIRM[1] << 32);
}
#ifdef FIREWIRETODO // Should be moved to channels available function and can set the available channels
if (!err)
{
for(channel=0; channel<64; channel++)
{
if( inAllowedChans & ((UInt64)1 << ( 63 - channel )) )
break;
}
if(channel == 64) {
IOLog("IOFireWireIP: No resources, will use 0x1f chan");
err = kIOReturnNoResources;
}
}
#endif
if (!err)
{
inAllowedChans &= (UInt64)(oldIRM[2]) | ((UInt64)oldIRM[1] << 32);
}
if (!err)
{
channel = *pChannel;
if( inAllowedChans & ((UInt64)1 << ( 63 - channel )) != 0){
IOLog("IOFireWireIP: No resources, will use 0x1f chan");
err = kIOReturnNoResources;
}
}
if (!err)
{
UInt32* oldPtr;
if(channel < 32)
{
addr.addressLo = kCSRChannelsAvailable31_0;
oldPtr = &oldIRM[1];
newVal = *oldPtr & ~(1<<(31 - channel));
}
else
{
addr.addressLo = kCSRChannelsAvailable63_32;
oldPtr = &oldIRM[2];
newVal = *oldPtr & ~( (UInt64)1 << (63 - channel) );
}
fLockCmd->reinit(generation, addr, oldPtr, &newVal, 1);
err = fLockCmd->submit();
if (!err && !fLockCmd->locked(oldPtr))
err = kIOReturnCannotLock ;
}
if (!err)
{
if(channel >= 32)
fReAllocateChannel.hi |= (kChannelPrime >> (channel - 32));
else
fReAllocateChannel.lo |= (kChannelPrime >> channel);
}
}
return err;
}
void IOFireWireIP::releaseChannel(UInt32 channel,UInt32 releaseFlags)
{
FWAddress addr(kCSRRegisterSpaceBaseAddressHi, kCSRBandwidthAvailable);
UInt32 generation = 0;
UInt32 newVal;
UInt32 oldVal;
IOReturn result = kIOReturnSuccess;
bool tryAgain;
bool claim = false;
UInt32 fChannel = channel;
IOLog(" %s %d\n", __FILE__, __LINE__);
if(channel == DEFAULT_BROADCAST_CHANNEL)
return;
if (!(releaseFlags & kDoNotDeallocate)) {
if(fChannel != 64) {
UInt32 mask;
if(fChannel <= 31) {
addr.addressLo = kCSRChannelsAvailable31_0;
mask = 1 << (31-fChannel);
}
else {
addr.addressLo = kCSRChannelsAvailable63_32;
mask = 1 << (63-fChannel);
}
fReadCmd->reinit(generation, addr, &oldVal, 1);
result = fReadCmd->submit();
if(kIOReturnSuccess != result) {
return;
}
do {
if(claim) {
newVal = oldVal & ~mask;
if(newVal == oldVal) {
result = kIOReturnNoSpace;
break;
}
}
else {
newVal = oldVal | mask;
}
fLockCmd->reinit(generation, addr, &oldVal, &newVal, 1);
result = fLockCmd->submit();
if(kIOReturnSuccess != result) {
IOLog("channel update result 0x%x\n", result);
break;
}
tryAgain = !fLockCmd->locked(&oldVal);
} while (tryAgain);
}
if(channel >= 32)
fReAllocateChannel.hi &= ~(kChannelPrime >> (channel - 32));
else
fReAllocateChannel.lo &= ~(kChannelPrime >> channel);
}
else
{
}
}
void IOFireWireIP::reclaimChannels()
{
UInt32 channel = 0;
UInt32 chnlBit;
UInt32 *pChannelReg;
IOReturn err = kIOReturnSuccess ;
pChannelReg = &fReAllocateChannel.lo;
for(channel = 0; ;)
{
for (chnlBit = kChannelPrime; chnlBit != 0; chnlBit >>= 1, channel++)
{
if ((*pChannelReg & chnlBit) != 0)
{
IOLog(" %s %d\n", __FILE__, __LINE__);
err = acquireChannel(&channel, TRUE, 0);
if(err != kIOReturnSuccess)
channelNotification(channel, kDoNotNotifyOnFailure);
else
channelNotification(channel, kNotifyOnSuccess);
}
}
if (pChannelReg == &fReAllocateChannel.hi)
break;
pChannelReg = &fReAllocateChannel.hi;
}
}
void IOFireWireIP::channelNotification(UInt32 channel, UInt32 flags) {
ARB *arb, *priorArb;
MCB *mcb;
IOFWAsyncStreamRxCommand *asyncStreamRxClient;
IOLog(" %s %d\n", __FILE__, __LINE__);
mcb = &fLcb->mcapState[channel];
if (mcb->ownerNodeID != fLcb->ownNodeID) releaseChannel(mcb->channel, kDoNotDeallocate);
else if (flags & kNotifyOnSuccess) mcb->nextTransmit = 1; else { releaseChannel(mcb->channel, kDoNotDeallocate);
mcb->ownerNodeID = MCAP_UNOWNED;
asyncStreamRxClient = (IOFWAsyncStreamRxCommand *)mcb->asyncStreamID;
if(asyncStreamRxClient != NULL)
asyncStreamRxClient->release();
mcb->asyncStreamID = kInvalidAsyncStreamRefID;
mcb->expiration = mcb->nextTransmit = mcb->finalWarning = 0;
priorArb = (ARB *) &fLcb->multicastArb;
while ((arb = priorArb->next) != NULL) {
if (arb->handle.multicast.channel == mcb->channel)
if (arb->deletionPending) {
priorArb->next = arb->next;
deallocateCBlk(fLcb, arb);
continue;
} else
arb->handle.multicast.channel = DEFAULT_BROADCAST_CHANNEL;
priorArb = arb;
}
mcb->groupCount = 0;
}
}