--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/telephonyprotocols/secondarypdpcontextumtsdriver/spudman/src/mux.cpp Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +1,375 @@
+// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// SPUD data multiplexer
+//
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include "mux.h"
+#include <nifmbuf.h>
+#include <in6_if.h>
+
+// Flow control constants expected by the upper protocol stack
+const TInt KStopSending = 0;
+const TInt KContinueSending = 1;
+
+#ifdef __FLOG_ACTIVE
+#define SPUDMUX_LOG(x) iBindMan->SpudMan()->x
+#else
+#define SPUDMUX_LOG(x)
+#endif
+
+
+//
+// CSpudMux
+//
+
+
+CSpudMux::CSpudMux(CSpudMan& aNifBase)
+ : CNifIfBase(aNifBase)
+ {
+ }
+
+CSpudMux::~CSpudMux()
+ {
+ // Notify BindMan to delete the pointer to this object
+ if (iBindMan)
+ {
+ iBindMan->MuxClosed();
+ }
+ }
+
+/**
+Constructs the mux object
+
+@param aBindMan Reference to BindMan object
+*/
+void CSpudMux::Construct(CBindMan& aBindMan)
+ {
+ iBindMan = &aBindMan;
+
+ // Create a unique interface name
+ iIfName.Format(_L("%S[0x%08x]"), &KSpudName, this);
+ }
+
+/**
+Binds SPUD to the TCP/IP stack.
+
+@param aId Pointer to network stack object (CProtocolBase*)
+@leave KErrInUse if SPUD is already bound
+*/
+void CSpudMux::BindL(TAny* aId)
+ {
+ iBindMan->SetProtocolBaseL(static_cast<CProtocolBase*>(aId));
+ }
+
+
+/**
+Fills in the info object with NIF information.
+
+@param aInfo object to hold information on return
+*/
+void CSpudMux::Info(TNifIfInfo& aInfo) const
+ {
+ // Get the binder for the first (default) lower NIF.
+ CSpudBinderRef* ref = NULL;
+ TRAPD(err, ref = iBindMan->GetAnyRefL());
+ if (err == KErrNone)
+ {
+ // Read the protocol supported value from the lower NIF
+ ref->NifBase()->Info(aInfo);
+ ASSERT((aInfo.iFlags & (KNifIfIsBase | KNifIfUsesNotify | KNifIfCreatedByLink)) == (KNifIfIsBase | KNifIfUsesNotify | KNifIfCreatedByLink));
+ }
+ else
+ {
+ aInfo.iProtocolSupported=KProtocolUnknown;
+ }
+
+ // Overwrite these values with our own
+ aInfo.iName.Copy(iIfName);
+ aInfo.iVersion = TVersion(KSpudMajorVersionNumber, KSpudMinorVersionNumber, KSpudBuildVersionNumber);
+ aInfo.iFlags = KNifIfIsBase | KNifIfUsesNotify | KNifIfCreatedByLink;
+ }
+
+/**
+Takes packets from the IP stack and demultiplexes them by sending each on to
+the appropriate lower NIF for processing. The packets are assumed to be
+ordered correctly, as appropriate for the QoS guarantees given to each.
+This function's responsibility is to pass each packet to the appropriate
+lower NIF for processing, where each lower NIF handles a single PDP context.
+
+@param aPacket MBuf chain containing packet
+@param aSource Passed unchanged to lower NIF
+@return 1 for a successful send, 0 to tell upper layer to flow off
+*/
+TInt CSpudMux::Send(RMBufChain& aPacket, TAny* aSource)
+ {
+ // GUQoS places the context ID for the outgoing packet into the Port field
+ // in the RMBufChain info header.
+ const RMBufPktInfo* info = RMBufPacket::PeekInfoInChain(aPacket);
+ TUint contextId(info->iDstAddr.Port());
+ if (contextId >= static_cast<TUint>(KMaxPdpContexts))
+ {
+ // Context ID is illegal; use 0 instead and try to continue
+ SPUDMUX_LOG(__FLOG_1(_L("CSpudMux::Send context id %d is out of range; using 0 instead"), contextId));
+ contextId = 0;
+ }
+ const TContextId id(static_cast<TContextId>(contextId));
+
+ // Get the binder for the appropriate lower NIF.
+ CSpudBinderRef* ref = NULL;
+ TRAPD(err, ref = iBindMan->GetRefL(id));
+ if (err != KErrNone)
+ {
+ // That's odd--GUQoS is sending to an invalid context.
+ // Redirect it to the first valid context instead.
+ SPUDMUX_LOG(__FLOG_1(_L("CSpudMux::Send context id %d is invalid; searching for another"), id));
+ TRAPD(err, ref = iBindMan->GetAnyRefL());
+ if (err != KErrNone)
+ {
+ // Something is really wrong here! No contexts available at all!
+ SPUDMUX_LOG(__FLOG_0(_L("Nowhere to send data! Dropping packet")));
+ return err;
+ }
+ }
+ TInt rc = ref->NifBase()->Send(aPacket, aSource);
+
+ // See if NIF is flowing off data on this context
+ if ((rc == KStopSending) && iBindMan->SpudMan()->AreQoSEventsEnabled())
+ {
+ // Send flow off indication via GUQoS instead
+ iBindMan->SpudMan()->StopSending(id);
+ rc = KContinueSending; // Successful send indication
+ }
+ return rc;
+ }
+
+/**
+Processes notifications from agent.
+
+@param aEvent event type
+@param aInfo data associated with event
+@return error code
+*/
+TInt CSpudMux::Notification(TAgentToNifEventType aEvent, void* aInfo)
+ {
+ SPUDMUX_LOG(__FLOG_1(_L("CSpudMux::Notification received event %d"), aEvent));
+ TInt rc = KErrNotSupported;
+ switch (aEvent)
+ {
+ case EAgentToNifEventTypeModifyInitialTimer:
+ case EAgentToNifEventTypeDisableTimers:
+ case EAgentToNifEventTypeEnableTimers:
+ // Send notification to all lower NIFs
+ rc = KErrNotReady;
+ TContextId i;
+ for (i=0; i < KMaxPdpContexts; ++i)
+ {
+ CSpudBinderRef* ref = NULL;
+ TRAP(rc, ref = iBindMan->GetRefL(i));
+ if (rc == KErrNone)
+ {
+ rc = ref->NifBase()->Notification(aEvent, aInfo);
+ }
+ }
+ break;
+
+ case EAgentToNifEventTypeDisableConnection:
+ SPUDMUX_LOG(__FLOG_0(_L("CSpudMux::Notification received EAgentToNifEventTypeDisableConnection")));
+ // TODO: How to handle this event? Just fall through and ignore for now.
+ default:
+ break;
+ }
+
+ return rc;
+ }
+
+/**
+Returns the current state of the interface
+
+@return TIfStatus indicating the current state of the interface
+*/
+TInt CSpudMux::State()
+ {
+ // Get the binder for the first (default) lower NIF.
+ CSpudBinderRef* ref = NULL;
+ TRAPD(err, ref = iBindMan->GetAnyRefL());
+ if (err != KErrNone)
+ {
+ return EIfDown;
+ }
+
+ // Use the state of the first lower NIF as the state of the SPUD
+ return ref->NifBase()->State();
+ }
+
+/**
+Controls the NIF
+
+@param aLevel The intended level for this control option
+@param aName The name of the control option
+@param aOption Any data associated with this control option, contained within a TPckg(Buf)
+@param aSource If provided, an identifier for the source of the control option; by default, zero
+@return KErrNone if successful; otherwise one of the standard Symbian OS error codes
+*/
+TInt CSpudMux::Control(TUint aLevel, TUint aName, TDes8& aOption, TAny* aSource)
+ {
+ if (aLevel==KSOLInterface)
+ {
+ switch (aName)
+ {
+ // From elsewhere
+ case KSoIfInfo:
+ case KSoIfInfo6:
+ case KSoIfConfig:
+ case KSoIfCompareAddr:
+ case KSoIfGetConnectionInfo:
+ case KSoIfHardwareAddr:
+ {
+ // Get the binder for the first (default) lower NIF.
+ CSpudBinderRef* ref = NULL;
+ TRAPD(err, ref = iBindMan->GetAnyRefL());
+ if (err != KErrNone)
+ {
+ return err;
+ }
+ return ref->NifBase()->Control(aLevel, aName, aOption, aSource);
+ }
+
+ default:
+ // Unknown event
+ // Assume it's for GUQoS, so let SpudMan handle it and error out the unknown ones
+ // These include:
+ // KSoIfControllerPlugIn
+ // KRegisterEventHandler
+ // KContextSetEvents
+ // KNifSetDefaultQoS
+ // KContextCreate
+ // KContextDelete
+ // KContextActivate
+ // KContextQoSSet
+ // KContextTFTModify
+ // KContextModifyActive
+ return iBindMan->SpudMan()->GuqosInput(aName, aOption);
+ }
+ }
+ return KErrNotSupported;
+ }
+
+//
+// CSpudProtocol
+//
+
+
+CSpudProtocol::CSpudProtocol()
+ {
+ }
+
+CSpudProtocol::~CSpudProtocol()
+ {
+ }
+
+/**
+Constructs the SpudProtocol object
+
+@param aBindMan reference to BindMan object
+*/
+void CSpudProtocol::Construct(CBindMan& aBindMan)
+ {
+ iBindMan = &aBindMan;
+ }
+
+void CSpudProtocol::SetProtocolBaseL(CProtocolBase* aProtocolBase)
+ {
+ if(iProtocolBase)
+ {
+ SPUDMUX_LOG(__FLOG_0(_L("CSpudProtocol::SetProtocolBaseL already bound to protocol")));
+ User::Leave(KErrInUse);
+ }
+
+ iProtocolBase = aProtocolBase;
+ ASSERT(iProtocolBase);
+ }
+
+
+void CSpudProtocol::Identify(TServerProtocolDesc *aDesc) const
+ {
+ ASSERT(iProtocolBase);
+ iProtocolBase->Identify(aDesc);
+ }
+
+/**
+Receives an indication that the lower NIF is ready to send packets.
+
+@param aProtocol CNifIfBase pointer of lower NIF
+*/
+void CSpudProtocol::StartSending(CProtocolBase* aProtocol)
+ {
+ TContextId id = KAllContexts;
+ TRAPD(rc, id = iBindMan->FindContextIdL(reinterpret_cast<CNifIfBase*>(aProtocol)));
+ __ASSERT_ALWAYS(rc == KErrNone, iBindMan->SpudMan()->Panic());
+ iBindMan->SpudMan()->StartSending(id);
+ }
+
+/**
+Receives PDU from the lower NIF and passes it to the upper protocol layer.
+
+@param aChain Datagram to process
+@param aSourceProtocol CNifIfBase pointer of lower NIF (ignored)
+*/
+void CSpudProtocol::Process(RMBufChain& aChain, CProtocolBase* /*aSourceProtocol*/)
+ {
+ ASSERT(iProtocolBase);
+ iProtocolBase->Process(aChain, reinterpret_cast<CProtocolBase*>(iBindMan->SpudMux()));
+ }
+
+/**
+Receives PDU from the lower NIF and passes it to the upper protocol layer.
+
+@param aPDU Datagram to process
+@param aFrom Source address
+@param aTo Destination address
+@param aSourceProtocol (ignored)
+*/
+void CSpudProtocol::Process(TDes8& aPDU, TSockAddr* aFrom, TSockAddr* aTo, CProtocolBase* /*aSourceProtocol*/)
+ {
+ ASSERT(iProtocolBase);
+ iProtocolBase->Process(aPDU, aFrom, aTo, reinterpret_cast<CProtocolBase*>(iBindMan->SpudMux()));
+ }
+
+/**
+Propagates error conditions up the stack, eventually to socket service providers.
+
+@param aError The error code
+@param aSourceProtocol (ignored)
+*/
+void CSpudProtocol::Error(TInt aError, CProtocolBase* /*aSourceProtocol*/)
+ {
+ ASSERT(iProtocolBase);
+ iProtocolBase->Error(aError, reinterpret_cast<CProtocolBase*>(iBindMan->SpudMux()));
+ }
+
+/**
+Calls StartSending on the upper network protocol.
+*/
+void CSpudProtocol::DoStartSending() const
+ {
+ ASSERT(iProtocolBase);
+ iProtocolBase->StartSending(reinterpret_cast<CProtocolBase*>(iBindMan->SpudMux()));
+ }
+