telephonyprotocols/rawipnif/src/BcaIoController.cpp
branchRCL_3
changeset 7 fe8b59ab9fa0
parent 6 fc69e1e37771
child 19 630d2f34d719
--- a/telephonyprotocols/rawipnif/src/BcaIoController.cpp	Mon Mar 15 12:45:06 2010 +0200
+++ b/telephonyprotocols/rawipnif/src/BcaIoController.cpp	Wed Mar 31 23:24:02 2010 +0300
@@ -21,12 +21,23 @@
 
 #include <e32uid.h>
 #include <nifmbuf.h>
+#include <e32svr.h>
+#include <u32hal.h>
 
 #include "Constants.h"
 #include "BcaIoController.h"
 #include "Sender.h"
 #include "Receiver.h"
 
+const TUint KDefaultSendQueueSize=5;
+
+#ifdef __EABI__
+// Patch data is used and KMaxTxIPPacketSize and KMaxRxIPPacketSize can be modified to a different value in RawIpNif.iby file
+extern const TInt KMaxSendQueueLen = KDefaultSendQueueSize;
+extern const TInt KMaxTxIPPacketSize = KMaxIPPacket + KIPTagHeaderLength;
+extern const TInt KMaxRxIPPacketSize = KMaxIPPacket + KIPTagHeaderLength;
+#endif
+
 CBcaIoController::CBcaIoController(MControllerObserver& aObserver,
 	CBttLogger* aTheLogger)
 /**
@@ -35,14 +46,17 @@
  * @param aObserver Reference to the observer of this state machine
  * @param aTheLogger The logging object
  */
-	: 
-	  CBcaController(aObserver, aTheLogger),
-	  iMBca(NULL),
-	  iSender(NULL),
-	  iReceiver(NULL),
-	  iLoader(NULL)	  
-	{
-	}
+    : iTheLogger(aTheLogger),
+      iSendState(EIdle),
+      iFlowBlocked(EFalse),
+      iNumPacketsInSendQueue(0),
+      iObserver(aObserver),
+      iMBca(NULL),
+      iSender(NULL),
+      iReceiver(NULL),
+      iLoader(NULL)	  
+    {
+    }
 
 CBcaIoController* CBcaIoController::NewL(MControllerObserver& aObserver, CBttLogger* aTheLogger)
 /**
@@ -53,25 +67,49 @@
  * @param aTheLogger The logging object
  * @return A newly constructed CBcaIoController object
  */
-	{
-	CBcaIoController* self = new (ELeave) CBcaIoController(aObserver, aTheLogger);
-	CleanupStack::PushL(self);
-	self->ConstructL();
-	CleanupStack::Pop(self);
-	return self;
-	}
+    {
+    CBcaIoController* self = new (ELeave) CBcaIoController(aObserver, aTheLogger);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    return self;
+    }
 
 void CBcaIoController::ConstructL()
 /**
  * Second-phase constructor. Creates all the state objects it owns.
  */
-	{
-	_LOG_L1C1(_L8("CBcaIoController::ConstructL"));
-	BaseConstructL();
-	iSender = CSender::NewL(*this, iTheLogger, iMaxTxPacketSize);
-	iReceiver = CReceiver::NewL(*this, iTheLogger, iMaxRxPacketSize);
-	iLoader = new (ELeave) CBcaControl(*this, iTheLogger);
-	}
+    {
+    _LOG_L1C1(_L8("CBcaIoController::ConstructL"));
+
+#ifdef RAWIP_HEADER_APPENDED_TO_PACKETS
+    iIPTagHeader = new (ELeave) CIPTagHeader(iTheLogger);
+#endif // RAWIP_HEADER_APPENDED_TO_PACKETS
+
+#if defined __EABI__
+    // Default value for queue length
+    iMaxSendQueueLen = KMaxSendQueueLen;
+    // Default value for Tx and Rx packet size
+    iMaxTxPacketSize = KMaxTxIPPacketSize;
+    iMaxRxPacketSize = KMaxRxIPPacketSize;
+#else // WINS
+    // Set default values in case patch is not present in epocrawip.ini
+    iMaxSendQueueLen = KDefaultSendQueueSize;    
+    iMaxTxPacketSize = KMaxIPPacket + KIPTagHeaderLength;
+    iMaxRxPacketSize = KMaxIPPacket + KIPTagHeaderLength;
+           
+    // for the emulator process is patched via the epocrawip.ini file
+    UserSvr::HalFunction(EHalGroupEmulator,EEmulatorHalIntProperty,(TAny*)"rawip_KMaxSendQueueLen",&iMaxSendQueueLen);
+    UserSvr::HalFunction(EHalGroupEmulator,EEmulatorHalIntProperty,(TAny*)"rawip_KMaxTxIPPacketSize",&iMaxTxPacketSize);
+    UserSvr::HalFunction(EHalGroupEmulator,EEmulatorHalIntProperty,(TAny*)"rawip_KMaxRxIPPacketSize",&iMaxRxPacketSize);
+#endif
+    
+    // end note
+    
+    iSender = CSender::NewL(*this, iTheLogger, iMaxTxPacketSize);
+    iReceiver = CReceiver::NewL(*this, iTheLogger, iMaxRxPacketSize);
+    iLoader = new (ELeave) CBcaControl(*this, iTheLogger);
+    }
 
 
 CBcaIoController::~CBcaIoController()
@@ -79,10 +117,16 @@
  * Destructor.
  */
 	{
+    iSendQueue.Free();
+    iNumPacketsInSendQueue = 0;
+    
 	delete iReceiver;
 	delete iSender;
 	delete iLoader;
-
+	
+#ifdef RAWIP_HEADER_APPENDED_TO_PACKETS
+    delete iIPTagHeader;
+#endif // RAWIP_HEADER_APPENDED_TO_PACKETS
 	}
 
 /** sets the BCA Stack name
@@ -103,7 +147,7 @@
 	{
 	_LOG_L1C1(_L8("CBcaIoController::StartL is called."));
 
-	InitialiseBcaL();
+    iLoader->StartLoadL();
 	}
 
 void CBcaIoController::Stop(TInt aError)
@@ -118,7 +162,7 @@
 	//Stop all the active objects
 	iReceiver->Cancel();
 
-	if(GetSendState() == ESending)
+	if (iSendState == ESending)
 		{
 		iSender->Cancel();
 		}
@@ -129,61 +173,269 @@
     iLoader->ShutdownBca(aError);  
 	}
 
-void CBcaIoController::InitialiseBcaL()
-/**
- *  Load & Initialise Bca.
- */
-	{
-	_LOG_L1C1(_L8("<<CBcaIoController::InitialiseBcaL"));
-    iLoader->StartLoadL();
-	}
 
-void CBcaIoController::BcaProcess(TDesC8& aPdu)
+ESock::MLowerDataSender::TSendResult CBcaIoController::Send(RMBufChain& aPdu)
 /**
- *  This method will pass on the received data to CRawIPNifMain. 
+ *  This method is called by CRawIPFlow in order to send a packet down
+ *  to the BCA. 
  *
- * @param aPdu a data packet
+ *  @param aPdu a data packet
  */
-	{
-	_LOG_L1C1(_L8(">>CBcaIoController::Process"));
+    {
+    _LOG_L1C1(_L8(">>CBcaIoController::Send"));
+
+    // Check if flow is shutting down
+    if (iSendState == EShuttingDown)
+        {
+        _LOG_L2C1(_L8("    ERROR: Nif is shutting down"));
+        
+        // when the flow is destroyed the memory for this packet will be 
+        // cleaned up - just tell the layers above to stop sending.
+        aPdu.Free();
+        
+        return ESock::MLowerDataSender::ESendBlocked;
+        }
+    
+    // check that this packet isnt too big - If it is, we dont want to send it or
+    // add it to our queue
+    if ((aPdu.Length() - aPdu.First()->Length()) > iMaxTxPacketSize)
+        {
+        _LOG_L2C1(_L8("Packet is too large - discarding"));
+        _LOG_L1C1(_L8("<<CSender::Send -> Error"));
 
-	Process(aPdu);
+        // in debug panic - this should not happen, MTU on the uplink should
+        // be strictly enforced
+        __ASSERT_DEBUG(ETrue,Panic(KFlowInvalidULPacketSize));
+        
+        aPdu.Free();
+       
+        // may be counter intuitive, however the only options here are either 
+        // send accepted or blocked (MLowerDataSender).
+        
+        _LOG_L2C1(_L8("<<CBcaIoController::Send - return ContinueSending"));
+        return ESock::MLowerDataSender::ESendAccepted;
+        }
+    
+    // transmit flow control.
+    if (iFlowBlocked)
+        {
+        // Transmit is off for this flow - we must have received a block
+        // message from our control.  append this message to the queue
+        // and tell the layer above it to kindly stop sending.
+        _LOG_L1C1(_L8("    Sender blocked, appending packet to queue"));
+        
+        AppendToSendQueue(aPdu);
+        
+        // may be a bit counter-intuitive, however, even if the flow is blocked
+        // there is no reason not to ask for more data as long as our send
+        // queue isn't full.
+        
+        if (IsSendQueueFull())
+            {
+            _LOG_L2C1(_L8("<<CBcaIoController::Send - return StopSending"));
+            return ESock::MLowerDataSender::ESendBlocked;
+            }
+        else
+            {
+            _LOG_L2C1(_L8("<<CBcaIoController::Send - return ContinueSending"));
+            return ESock::MLowerDataSender::ESendAccepted;       
+            }
+        }
+    
+    // transmit is on for this flow.  send a packet or queue it
+    // if we're already sending one.
 
-	_LOG_L1C1(_L8("<<CBcaIoController::Process"));
-	}
+    if (iSendState == ESending)
+        // If this happens, it means that TCP/IP has sent us an IP packet
+        // while we're still sending the previous one. 
+        {    
+        _LOG_L1C1(_L8("    Sender busy, appending packet to queue"));
+        AppendToSendQueue(aPdu);
+        
+        if (IsSendQueueFull())
+            {
+            _LOG_L2C1(_L8("<<CBcaIoController::Send - return StopSending"));
+            return ESock::MLowerDataSender::ESendBlocked;
+            }
+        }
+    else
+        {
+        // if we're idle, then we must not be sending.  If we're not idle
+        // then the SendComplete() will handle sending any additional 
+        // packets that might have been queued onto the send queue.
+    
+        // Update module state
+        _LOG_L2C1(_L8("     set State to ESending"));
+        iSendState = ESending;
+         
+        iSender->Send(aPdu);
+        }
 
-void CBcaIoController::BcaSend(RMBufChain& aPdu)
+    // if our send queue isn't full, then the send is accepted
+    // otherwise, block this flow until we have room for the next
+    // packet
+    
+    _LOG_L2C1(_L8("<<CBcaIoController::Send - return ContinueSending"));
+
+    return ESock::MLowerDataSender::ESendAccepted;
+    }
+	
+void CBcaIoController::SendComplete()
 /**
- *  This method is called by CRawIPNifMain in order to send a packet down
- * to the BCA. The CSender active object will be activated by calling the send
- * method.
- *
- *	@param aPdu a data packet
+ *  A packet has finished sending - check to see if we need
+ *  to process more packets.
  */
-	{
-	_LOG_L1C1(_L8("CBcaIoController::BcaSend"));
+    {
+    _LOG_L1C1(_L8(">>CBcaIoController::SendComplete"));
+
+    // if we've been blocked while in the middle of a 
+    // send - don't continue sending, this will happen
+    // when the flow is resumed.
+
+    iSendState = EIdle;
 
-	iSender->Send(aPdu);
-	}
+    // are we available to transmit?
+    
+    if (iFlowBlocked == EFalse)
+        {
+        // flow transmit is on
+    
+        TBool resumeSending = EFalse;
+    
+        // if the queue is full, it means that while a packet was
+        // outstanding in BCA, we've filled up our send queue and
+        // informed the upper layers to stop sending.
+        
+        if (IsSendQueueFull())
+            {
+            resumeSending = ETrue;
+            }
+        
+        // if the queue has anything inside it, we need to send the 
+        // first packet in the queue.  note: the resumeSending check is to 
+        // short circuit this so we don't check the queue length twice
+        // in the case that it is full
+        
+        if ((resumeSending) || (!IsSendQueueEmpty()))
+            {
+            iSendState = ESending;
+            
+            RMBufChain tmpPdu;
+            _LOG_L1C1(_L8("    Packet removed from queue to send"));
+            RemoveFromSendQueue(tmpPdu);
+            
+            // Update module state
+            _LOG_L2C1(_L8("     set State to ESending"));
+          
+            iSender->Send(tmpPdu);
+            
+            // if the queue was full, again, we told the upper layers
+            // to stop sending, we need to resume this flow.  order is
+            // important as we don't want to get a packet before we've 
+            // given one to BCA to send.
+            if (resumeSending)
+                {
+                iObserver.ResumeSending();
+                }
+            }
+        }
+    
+    _LOG_L1C1(_L8("<<CBcaIoController::SendComplete"));
+    }
+
+
+void CBcaIoController::ResumeSending()
+/**
+ *  Flow is being unblocked this will resume sending.
+ */
+    {
+    _LOG_L1C1(_L8(">>CBcaIoController::ResumeSending"));
 
-TInt CBcaIoController::BcaSendBufferLength()
-	{
-	return iSender->SendBufferLength();
-	}
+    // allows for normal SendComplete behaviour if there is
+    // a packet outstanding with BCA
+    iFlowBlocked = EFalse;
+    
+    // If the send state is idle, then there isn't a packet
+    // outstanding, check the send queue to see if there are
+    // packets to send.
+    
+    if (iSendState == EIdle)
+        {
+        // flow transmit is on
+    
+        TBool resumeSending = EFalse; 
+        
+        if (IsSendQueueFull())
+            {
+            resumeSending = ETrue;
+            }
+    
+        // if the queue has anything inside it, we need to send the 
+        // first packet in the queue.  note: the resumeSending check is to 
+        // short circuit this so we don't check the queue length twice
+        // in the case that it is full
+        
+        if ((resumeSending) || (!IsSendQueueEmpty()))
+            {
+            RMBufChain tmpPdu;
+            _LOG_L1C1(_L8("    Packet removed from queue to send"));
+            RemoveFromSendQueue(tmpPdu);
+            
+            // Update module state
+            _LOG_L2C1(_L8("     set State to ESending"));
+            iSendState = ESending;
+          
+            iSender->Send(tmpPdu);
+            
+            // if the queue was full, again, we told the upper layers
+            // to stop sending, we need to resume this flow.  order is
+            // important as we don't want to get a packet before we've 
+            // given one to BCA to send.
+            if (resumeSending)
+                {
+                iObserver.ResumeSending();
+                }
+            }
+        }
+    
+    _LOG_L1C1(_L8("<<CBcaIoController::ResumeSending"));
+    }
 
-void CBcaIoController::BcaSendComplete()	
+#ifdef RAWIP_HEADER_APPENDED_TO_PACKETS
+void CBcaIoController::SetType(TUint16 aType)
+    {
 /**
- *  This method is called after a packet was sent to the board. 
- *  If allowed by flow contol flags the NIF can signal the TCP/IP
- *  protocol indicating that is available to send more packets.
+ *  Used to specify the type of the IP header.
+ */
+    _LOG_L1C1(_L8("CBcaController::SetType"));
+    
+    iIPTagHeader->SetType(aType);   
+    }
+
+void CBcaIoController::AddHeader(TDes8& aDes)
+/**
+ *  Used to add the IP header to the packet before sending to the BCA.
  */
-	{
-	_LOG_L1C1(_L8("CBcaController::SendComplete"));
+    {
+    _LOG_L1C1(_L8("CBcaController::AddHeader"));
+
+    iIPTagHeader->AddHeader(aDes);
+    }
 
-	SendComplete();
-	}
+TUint16 CBcaIoController::RemoveHeader(RMBufChain& aPdu)
+/**
+ *  Used to remove the IP header from the received the packet before sending to the 
+ *  TCP/IP layer.  
+ * @return The IP header that has been removed from the packet
+ */
+    {
+    _LOG_L1C1(_L8("CBcaController::RemoveHeader"));
 
-	
+    return (iIPTagHeader->RemoveHeader(aPdu));
+    }   
+#endif // RAWIP_HEADER_APPENDED_TO_PACKETS
+
+
 CBcaControl::CBcaControl(CBcaIoController& aObserver, CBttLogger* aTheLogger)
 /**
  * Constructor. Performs standard active object initialisation.