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