linklayerprotocols/slipnif/SRC/SLIP.CPP
changeset 0 af10295192d8
child 5 1422c6cd3f0c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linklayerprotocols/slipnif/SRC/SLIP.CPP	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,558 @@
+// Copyright (c) 1997-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:
+//
+
+/**
+ @file SLIP.CPP
+*/
+
+#include <nifmbuf.h>
+#include <in_iface.h>
+#include <cdblen.h>
+#include "SLIP.H"
+#include "SLIP_VER.H"
+
+const TUint KSlashChar='\\'; //< back slash character
+
+//
+// SLIP ESock bits
+//
+
+CSlip::CSlip(CNifIfFactory& aFactory)
+	: CNifIfLink(aFactory)
+/**
+Constructor
+*/
+	{
+	__DECLARE_NAME(_S("CSlip"));
+	}
+
+CSlip::~CSlip()
+/**
+Destructor
+*/
+	{
+	}
+
+void CSlip::Info(TNifIfInfo& aInfo) const
+	{
+
+	FillInInfo(aInfo);
+	}
+
+void CSlip::FillInInfo(TNifIfInfo& aInfo)
+	{
+	aInfo.iVersion = TVersion(KSlipMajorVersionNumber, KSlipMinorVersionNumber, KSlipBuildVersionNumber);
+	aInfo.iFlags = KNifIfIsBase | KNifIfUsesNotify | KNifIfIsLink | KNifIfCreatedByFactory;
+   _LIT(KSlip, "slip");
+	aInfo.iName = KSlip;
+	aInfo.iProtocolSupported=KProtocolInetIp;
+	}
+
+void CSlip::BindL(TAny* aId)
+	{
+	if (iIpProtocol)
+		User::Leave(KErrAlreadyExists);
+	iIpProtocol = (CProtocolBase*)aId;
+	}
+
+TInt CSlip::Send(RMBufChain& aPacket, TAny*)
+	{
+	iSendPktQ.Append(aPacket);
+	iSendMBufs += aPacket.NumBufs()-1;
+	if (!(iFlags & KSlipSendInUse))
+		DoSend();
+
+	return (iFlags & KSlipSendInUse) ? 0 : 1;
+	}
+
+TInt CSlip::State()
+	{
+
+    return (iFlags & KSlipIsUp) ? ((iFlags & KSlipSendBusy) ? EIfBusy : EIfUp) : EIfDown;
+	}
+
+TInt CSlip::Control(TUint aLevel, TUint aName, TDes8& aOption, TAny* /*aSource*/)
+	{
+	if (aLevel!=KSOLInterface)
+		return KErrNotSupported;
+
+	switch (aName)
+		{
+	case KSoIfInfo:
+		{
+		TSoIfInfo& opt = *(TSoIfInfo*)aOption.Ptr();
+		TNifIfInfo info;
+		FillInInfo(info);
+
+		opt.iName = info.iName;
+		TPortName port;
+
+		TBuf<KCommsDbSvrMaxColumnNameLength> columnName=TPtrC(MODEM);
+		columnName.Append(TChar(KSlashChar));
+		columnName.Append(TPtrC(MODEM_CSY_NAME));		
+		iNotify->ReadDes(columnName, port);
+		port.LowerCase();
+		_LIT(portNameFormat,"::%S");
+		opt.iName.AppendFormat(portNameFormat, &port);
+
+		opt.iFeatures = KIfIsPointToPoint | KIfIsDialup;
+		opt.iMtu = KSlipDefaultMtu;
+		opt.iSpeedMetric = (iFlags & KSlipIsUp) ? SpeedMetric() : 0;
+		return KErrNone;
+		}
+
+	case KSoIfHardwareAddr:
+		return KErrNotSupported;
+
+	case KSoIfConfig:
+		return KErrNotSupported;
+		}
+		
+	return KErrNotSupported;
+	}
+
+//
+// SLIP NifMan bits
+//
+
+CNifIfBase* CSlip::GetBinderL(const TDesC& aName)
+/**
+Interface Manager call to create a new Binder protocol
+which SLIP ignores
+
+@param aName new binder protocol
+*/
+	{
+	
+   _LIT(KDescIp, "ip");
+   _LIT(KDescIcmp, "icmp");
+	if(aName.CompareF(KDescIp) && aName.CompareF(KDescIcmp))
+		User::Leave(KErrNotSupported);
+
+	return 0;
+	}
+
+TInt CSlip::Start()
+/**
+Interface Manager call to start and claim the io port
+*/
+	{
+	TInt res=PacketModeOn();
+	if(res!=KErrNone)
+		return res;
+	iFlags |= KSlipIsUp;
+	iRecvBuf.SetMax();
+	CommRead(iRecvBuf);
+	iIpProtocol->StartSending((CProtocolBase*)this);
+	iNotify->LinkLayerUp();
+	iNotify->IfProgress(EIfProgressLinkUp, KErrNone);
+	return KErrNone;
+	}
+
+void CSlip::Stop(TInt aReason, MNifIfNotify::TAction aAction)
+/**
+Interface Manager call to stop and release the io port
+*/
+	{
+	iFlags &= ~KSlipIsUp;
+	PacketModeOff();
+	iSendPktQ.Free();
+	iSendPkt.Free();
+	iSendMBuf->Free();
+	iSendMBuf = NULL;
+	iRecvQ.Free();
+	iRecvMBuf->Free();
+	iRecvMBuf = NULL;
+	iRecvLen = 0;
+	iFlags &= KSlipRecvEscPend;
+	iNotify->LinkLayerDown(aReason, aAction);
+	iNotify->IfProgress(EIfProgressLinkDown, aReason);
+	}
+
+//
+// SLIP Internal
+//
+
+void CSlip::DoSend()
+	{
+	TBool flowon = EFalse;
+	
+	TUint8* bptr = (TUint8*)iSendBuf.Ptr();
+	TUint8* bend = (bptr+iSendBuf.MaxLength())-1; // -1 allows no check in switch below
+
+	TUint8* mptr = NULL;	// CSW: set to NULL for ASSERT below
+	TUint8* mend = NULL;	// CSW: set to NULL for ASSERT below
+
+	if (iSendMBuf!=NULL)
+		{
+		mptr = iSendMPtr;
+		mend = iSendMBuf->EndPtr();
+		}
+	
+	while (bptr<bend)
+		{
+		if (iSendMBuf==NULL)
+			{
+			if (iSendMBuf = iSendPkt.Remove(), iSendMBuf==NULL)
+				{
+				// End of frame
+				*bptr++ = KSlipEndCh;
+				RMBufPacket pkt;				
+				if (!iSendPktQ.Remove(pkt))
+					goto SendIt;
+				pkt.Unpack();
+				pkt.FreeInfo();
+				iSendPkt.Assign(pkt);
+				iSendMBuf = iSendPkt.Remove();
+				}
+			else
+				{
+				if ((iFlags & KSlipSendBusy) && iSendMBufs<=iSendLoWat)
+					{
+					// Deferred Flow Enable
+					flowon = ETrue;
+					iFlags &= ~KSlipSendBusy;
+					}
+
+				mptr = iSendMBuf->Ptr();
+				mend = iSendMBuf->EndPtr();
+				if (mptr==mend)
+					{
+					iSendMBuf->Free();
+					iSendMBuf = NULL;
+					continue; // with next MBuf
+					}
+				}
+			}
+		__ASSERT_DEBUG( mptr, SlipPanic( PanicSlipAssert1 ) );
+		switch (*mptr)
+			{
+		case KSlipEndCh:
+			*bptr++ = KSlipEscCh;
+			*bptr++ = KSlipEscEndCh;
+			break;
+		case KSlipEscCh:
+			*bptr++ = KSlipEscCh;
+			*bptr++ = KSlipEscEscCh;
+			break;
+		default:
+			*bptr++ = *mptr;
+			break;
+			}
+
+		if (++mptr==mend)
+			{
+			iSendMBuf->Free();
+			iSendMBuf = NULL;
+			}
+		}
+
+SendIt:
+		iSendMPtr = mptr;
+		TInt n = bend-bptr;
+		if (n>0)
+			{
+			iSendBuf.SetLength(bend-bptr);
+			CommWrite(iSendBuf);
+			iFlags |= KSlipSendInUse;
+			}
+
+		if (flowon)
+			iIpProtocol->StartSending((CProtocolBase*)this);
+	}
+
+void CSlip::CommWriteComplete(TInt aStatus)
+	{
+	iFlags &= ~KSlipSendInUse;
+	switch (aStatus)
+		{
+	case KErrCommsLineFail:
+		LinkDown(aStatus);
+		break;
+	default:
+		if (iFlags & KSlipIsUp)
+			DoSend();
+		}
+	}
+
+void CSlip::CommReadComplete(TInt aStatus)
+	{
+	switch (aStatus)
+		{
+	case KErrCommsFrame:
+	case KErrCommsOverrun:
+	case KErrCommsParity:
+		iRecvQ.Free();
+		iRecvLen = 0;
+		iRecvMBuf->Free();
+		iRecvMBuf = NULL;
+		iFlags &= KSlipRecvEscPend;
+		break;
+	case KErrNone:
+		DoRecv();
+		break;
+	case KErrCommsLineFail:
+	default:
+		LinkDown(aStatus);
+		break;
+		}
+	if (iFlags & KSlipIsUp)
+		{
+		iRecvBuf.SetMax();
+		CommRead(iRecvBuf);
+		}
+	}
+
+
+void CSlip::DoRecv()
+	{
+	TUint8* bptr = (TUint8*)iRecvBuf.Ptr();
+	TUint8* bend = bptr+iRecvBuf.Length();
+	if (bend==bptr)
+		return;
+
+	TUint8* mptr = NULL;	// CSW: set to NULL for ASSERT below
+	TUint8* mend = NULL;	// CSW: set to NULL for ASSERT below
+	TUint8 c;
+	
+	TInt ret;
+	
+	if (iRecvMBuf!=NULL)
+		{
+		mptr = iRecvMBuf->Ptr();
+		mend = iRecvMBuf->EndPtr();
+		}
+
+	while (bptr<bend)
+		{
+		if (!(iFlags & KSlipRecvEscPend))
+			c = *bptr++;
+		else
+			{
+			c = KSlipEscCh;
+			iFlags &= ~KSlipRecvEscPend;
+			}
+
+		switch (c)
+			{
+		case KSlipEndCh:
+			// State is END_RECVD
+			if (iRecvLen>0)
+				{
+				__ASSERT_DEBUG( mptr, SlipPanic( PanicSlipAssert3 ) );
+				__ASSERT_DEBUG( mend, SlipPanic( PanicSlipAssert4 ) );
+				iRecvMBuf->SetLength(mend-mptr);
+				RMBufPacket pkt;
+				TRAPD(mem, pkt.CreateL(iRecvQ, iRecvLen));
+				if(mem!=KErrNone)
+					{
+					//We are out of memory
+					return;
+					}
+				pkt.Pack();
+				iIpProtocol->Process(pkt, (CProtocolBase*)this);
+				iRecvMBuf = NULL; // Force a new allocation
+				iRecvLen = 0;
+				}
+			break;			
+		case KSlipEscCh:
+			// State is ESC_RECVD
+			if (bptr==bend)
+				{
+				iFlags |= KSlipRecvEscPend;
+				__ASSERT_DEBUG( mptr, SlipPanic( PanicSlipAssert5 ) );
+				iRecvMPtr = mptr;
+				return;
+				}
+			c = *bptr++;
+			if (c==KSlipEscEndCh)
+				c = KSlipEndCh;
+			else if (c==KSlipEscEscCh)
+				c = KSlipEscCh;
+			// Fall through...
+		default:
+			// Allocation defered to here to ensure that
+			// no data is lost due to pre-allocs failing.
+			if (iRecvMBuf==NULL)
+				{
+				TRAP(ret, iRecvMBuf = RMBuf::AllocL());
+				if (ret!=KErrNone)
+					{
+					// Junk the packet so far
+					iRecvQ.Free();
+					iRecvLen = 0;
+					iFlags &= ~KSlipRecvEscPend;
+					return;
+					}
+				else
+					{
+					mptr = iRecvMBuf->Ptr();
+					mend = iRecvMBuf->EndPtr();
+					}
+				}
+			__ASSERT_DEBUG( mptr, SlipPanic( PanicSlipAssert6 ) );
+			__ASSERT_DEBUG( mend, SlipPanic( PanicSlipAssert7 ) );
+			*mptr++ = c;
+			iRecvLen++;
+			if (mptr==mend)
+				{
+				iRecvQ.Append(iRecvMBuf);
+				iRecvMBuf = NULL; // Force a new allocation
+				}
+			break;
+			}
+		}
+		iFlags &= KSlipRecvEscPend;
+		__ASSERT_DEBUG( mptr, SlipPanic( PanicSlipAssert8 ) );
+		iRecvMPtr = mptr;
+	}
+
+
+void CSlip::LinkDown(TInt aReason)
+	{
+
+	if(aReason!=KErrCommsLineFail)
+		{
+		iNotify->LinkLayerDown(aReason, MNifIfNotify::EDisconnect);
+		iNotify->IfProgress(EIfProgressLinkDown, aReason);
+		}
+	else
+		iNotify->LinkLayerDown(aReason, MNifIfNotify::EReconnect);
+	}
+
+TInt CSlip::SpeedMetric()
+	{
+	switch (iOrigConfig().iRate)
+		{
+	case EBps50:
+		return 50;
+	case EBps75:
+		return 75;
+	case EBps110:
+		return 110;
+	case EBps134:
+		return 134;
+	case EBps150:
+		return 150;
+	case EBps300:
+		return 300;
+	case EBps600:
+		return 600;
+	case EBps1200:
+		return 1200;
+	case EBps1800:
+		return 1800;
+	case EBps2000:
+		return 2000;
+	case EBps2400:
+		return 2400;
+	case EBps3600:
+		return 3600;
+	case EBps4800:
+		return 4800;
+	case EBps7200:
+		return 7200;
+	case EBps9600:
+		return 9600;
+	case EBps19200:
+		return 19200;
+	case EBps38400:
+		return 38400;
+	case EBps57600:
+		return 57600;
+	case EBps115200:
+		return 115200;
+//	case EBps230400:
+//		return 230400;
+//	case EBps460800:
+//		return 230400;
+//	case EBps921600:
+//		return 921600;
+	case EBpsSpecial:
+		return iOrigConfig().iSpecialRate;
+	default:
+		;
+		}
+	return 0;
+	}
+
+TInt CSlip::PacketModeOn()
+/**
+Configure the comm port for our needs
+*/
+	{
+	TInt err;
+	if (iFlags & KSlipCommConfigOk)
+		return KErrNone;	
+
+	TName port;
+	TBuf<KCommsDbSvrMaxColumnNameLength> columnName=TPtrC(MODEM);
+	columnName.Append(TChar(KSlashChar));
+	columnName.Append(TPtrC(MODEM_PORT_NAME));		
+	iNotify->ReadDes(columnName, port);
+
+	if (err = CommOpen(port, ECommShared), err!=KErrNone)
+		return err;
+	
+	iCommPort.Config(iOrigConfig);
+	TCommConfig cbuf = iOrigConfig;
+	TCommConfigV01 &cfg=cbuf();
+	cfg.iTerminatorCount = 1;
+	cfg.iTerminator[0] = KSlipEndCh;
+	cfg.iHandshake |= (0
+		//	| KConfigObeyCTS
+		//	| KConfigFailCTS
+			| KConfigObeyDSR
+			| KConfigFailDSR
+			| KConfigObeyDCD
+			| KConfigFailDCD
+		//	| KConfigFreeRTS
+		//	| KConfigFreeDTR
+			);
+	if (err = iCommPort.SetConfig(cbuf), err!=KErrNone)
+		{
+		CommClose();
+		return err;
+		}
+
+	iFlags |= KSlipCommConfigOk;
+	return KErrNone;
+	}
+
+TInt CSlip::PacketModeOff()
+	{
+	TInt err = KErrNone;
+	
+	if (iFlags & KSlipCommConfigOk)
+		{
+		CommCancel();
+		iFlags &= ~KSlipCommConfigOk;
+		err = iCommPort.SetConfig(iOrigConfig);
+		CommClose();
+		}
+	return err;
+	}
+
+TInt CSlip::Notification(TAgentToNifEventType /*aEvent*/, void * /*aInfo*/)
+	{
+	// no timers in SLIP, so nothing to do!
+	return KErrNone;
+	}
+
+void CSlip::Restart(CNifIfBase*)
+/**
+SLIP doesn't support different network-layer binders, so we can't restart one!
+*/
+	{}