linklayerprotocols/ethernetnif/IRLAN/IRLANCTL.CPP
changeset 0 af10295192d8
child 5 1422c6cd3f0c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linklayerprotocols/ethernetnif/IRLAN/IRLANCTL.CPP	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,1017 @@
+// 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:
+// Irlan connection control engine 
+// 
+//
+
+/**
+ @file
+*/
+
+#include <nifman.h>
+#include <nifvar.h>
+#include <nifutl.h>
+#include <es_mbuf.h>
+#include <in_pkt.h>
+#include <ir_sock.h>
+#include "PKTDRV.H"
+#include "ETHINTER.H"
+#include "IRLAN.H"
+#include "IRLANUTL.H"
+#include "INTSOCK.H"
+#include "IRLANBUF.H"
+#include "IRLANDAT.H"
+#include "irlantimer.h"
+
+//#define __TRACEWIN__
+#ifdef __TRACEWIN__
+  #include <log.h>
+#else
+  #define LOG(a)
+#endif
+
+/**
+Create a new CIrlanControlEngine object.
+@param aPktDrv A pointer to CIrlanPktDrv object.
+@return A pointer to CIrlanControlEngine object.
+*/
+CIrlanControlEngine *CIrlanControlEngine::NewL(CIrlanPktDrv* aPktDrv)
+{
+#ifdef __TRACEWIN__
+	LOG(Log::Printf(_L("IRLAN	CIrlanControlEngine::NewL\r\n")));
+#endif
+	CIrlanControlEngine *cc=new (ELeave) CIrlanControlEngine;
+	CleanupStack::PushL(cc);
+	cc->ConstructL(aPktDrv);
+	CActiveScheduler::Add(cc);
+	CleanupStack::Pop();
+	return cc;
+}
+
+/**
+Think this should be a deferred deletion here especially
+if IrLAN is already connected.
+Destructor.
+*/
+CIrlanControlEngine::~CIrlanControlEngine()
+{
+	LOG(Log::Printf(_L("IRLAN	~CIrlanControlEngine\r\n")));
+	CIrlanParameter *par;
+	TDblQueIter<CIrlanParameter> i(iIrlanParameterList);
+	while (par=i++,par!=NULL)
+		{
+		par->iLink.Deque();
+		delete par;
+		}
+	iDataSendQ.Free();
+
+	if (iTimers)
+		iTimers->StopIrlanControlEngineTimer();
+	delete iTimers;
+	if (iSender)
+		{
+		iSender->Cancel();
+		delete iSender;
+		}
+	if (iReceiver)
+		{
+		iReceiver->Cancel();
+		delete iReceiver;
+		}
+	delete iHostResolver;   // do close on this too?
+	delete iNetDatabase;	// do close on this too?
+	if (iDataSock)
+		iDataSock->Close();
+	if (iControlSock)
+		iControlSock->Close();
+
+	delete iRecvBuffer;
+	CActive::Cancel();
+}
+
+/**
+Default constructor
+*/
+CIrlanControlEngine::CIrlanControlEngine()
+	:CActive(EIrlanControlPriority)
+	,iRecvBufPtr(NULL,0)
+{
+}
+
+/**
+The CIrlanControlEngine::ConstructL performs all the memory allocating initialisations.
+@param aNotify A pointer to CIrlanPktDrv object.
+*/
+void CIrlanControlEngine::ConstructL(CIrlanPktDrv* aNotify)
+{
+#ifdef __TRACEWIN__
+	LOG(Log::Printf(_L("IRLAN	CIrlanControlEngine::ConstructL\r\n")));
+#endif
+	iRecvBufLength=KIrlanBufSize;
+	iTimers=CIrlanControlEngineTimers::NewL(this);
+	iRecvBuffer=HBufC8::NewMaxL(iRecvBufLength);
+	TPtr8 temp=iRecvBuffer->Des();
+	iRecvBufPtr.Set(temp);
+	iNotify=aNotify;
+    iIrlanParameterList.SetOffset(_FOFF(CIrlanParameter,iLink));
+}
+
+/**
+Handles Errors.
+*/
+void CIrlanControlEngine::HandleErrorL()
+{
+#ifdef __TRACEWIN__
+	LOG(Log::Printf(_L("IRLAN	Error in CIrlanControlEngine::RunL\r\n")));
+#endif
+   	switch (iState)
+		{
+	case E_Idle:
+	case E_Query:
+	case E_Conn:
+		PassiveIdleTransitionL();
+		iState=E_PassiveIdle;
+		iDiscoveredDevice=0;
+		break;
+	case E_Data:
+		{
+		iState=E_Idle;
+		iDiscoveredDevice=0;
+		TPtr8 dest(&iHWAddr[0],6,6);
+		dest.FillZ(6);
+		// Tear down the link stuff.
+		delete iSender;
+		iSender=0;
+		delete iReceiver;
+		iReceiver=0;
+		break;
+		}
+	default:
+		break;
+		}
+}
+
+/**
+Irlan state machine - on hitting this RunL, either iStatus is KErrNone in which case
+we have completed OK and can try the next stage or it isn't in which case we must
+handle the error appropriately.  The state machine is only rearmed if the phase action
+produces some error.  Otherwise, it is left up to the IrDA PRT to call back via the
+socket/hostresolver/netDB notifer and for the request to be completed that way.
+*/
+void CIrlanControlEngine::RunL()
+{
+#ifdef __TRACEWIN__
+	PrintState();
+#endif
+	RMBufChain pkt;
+	TInt ret=KErrNone;
+	if (iStatus!=KErrNone)
+		{
+		HandleErrorL();
+		return;
+		}
+	switch (iState)
+		{
+	case E_Idle:
+		if (iDiscoveredDevice)
+			{// An IrDA discovery has been successfully completed.
+//			iHostResolver.Close();
+			TRAP(ret,QueryRemoteIASL());
+			User::LeaveIfError(ret);
+			iState=E_Query;
+			break;
+			}
+		ret=AttemptingDiscoveryL();
+		// a KErrNone here indicates we're doing a discovery...
+		// any other error will be picked up as a PassiveIdleTransition
+		break;
+	case E_PassiveIdle:
+		// the remote side has successfully connected to us
+		// now we wait on receipt of remote command frames
+		QueueWaitForControlCommand();
+		iState=E_Info;
+		break;
+	case E_Query:
+		// A query on remote device's IAS has successfully completed.
+  		iOpenRetries=0;
+  		ret=ConnectToProviderL();
+  		iState=E_Conn;
+  		break;
+	case E_Conn:
+		// Completed OK - send the GetInfoCmd
+		ret=GetInfoCmd();
+		iState=E_Info;
+		break;
+	case E_Info:
+		// Need to parse response from this query if it comes.
+		switch (iAccessType)
+			{
+		case EAccessPoint:
+			if (iAwaitingResponse)
+				{
+				ParseInfoReply();
+				ret=GetMediaCmd();
+				iState=E_Media;
+				break;
+				}
+			QueueWaitForControlResponse();
+			break;
+		case EPeerToPeer:
+			if (iAwaitingCommand)
+				{
+				ParseControlCommand();  // also sends the reply
+				break;
+				}
+			QueueWaitForControlCommand();
+			break;
+		case EHosted:
+			break;
+			}
+		break;
+	case E_Media:
+		if (iAwaitingResponse)
+			{
+			ret=ParseMediaReply();
+			User::LeaveIfError(ret);
+			ret=OpenDataCmd();
+			iState=E_Open;
+			break;
+			}
+		QueueWaitForControlResponse();
+		break;
+	case E_Open:
+		if (iAwaitingResponse)
+			{
+			ParseOpenDataReply();
+			// WE'RE ONLY SUPPORTING ACCESS MODE IRLAN AT PRESENT
+			__ASSERT_DEBUG(iAccessType==EAccessPoint,IrlanUtil::Fault(EIrlanInvalidIrlanMode));
+			ret=GetDirectedFilterConfigCmd();
+			iState=E_FilterConfig;
+			break;
+			}
+		QueueWaitForControlResponse();
+		break;
+	case E_FilterConfig:
+		// This is an extra state I've added to handle filter config stuff
+		if (iAwaitingResponse)
+			{
+			ParseDirectedFilterConfigReply();
+			ret=SetDirectedFilterOperationCmd();
+			iState=E_FilterOperation;
+			break;
+			}
+		QueueWaitForControlResponse();
+		break;
+	case E_FilterOperation:
+		// This is an extra state I've added to handle filter operation stuff
+		if (iAwaitingResponse)
+			{
+			ParseDirectedFilterOperationReply();
+			ret=SetBroadcastFilterOperationCmd();
+			iState=E_FilterBroadcast;
+			break;
+			}
+		QueueWaitForControlResponse();
+		break;
+	case E_FilterBroadcast:
+		// This is an extra state I've added to handle broadcast filter stuff
+		if (iAwaitingResponse)
+			{
+			ParseBroadcastFilterOperationReply();
+			ConnectToDataChannelL();
+			break;
+			}
+		QueueWaitForControlResponse();
+		break;
+	case E_Wait:
+		// Only needed if acting as a provd.
+		break;
+	case E_Arb:
+		// Only needed if acting as a provd.
+		break;
+	case E_Data:
+		// Once we're here, we can send/receive ethernet packets as data over IrLAN.
+		iSender=CIrlanSender::NewL(this,iDataSock);
+		iReceiver=CIrlanReceiver::NewL(this,iDataSock);
+ 		iReceiver->QueueRead();
+		if (iDataSendQ.Remove(pkt))
+			{
+			iSender->QueueSend(pkt);
+			pkt.Free();
+			}
+        iNotify->LinkLayerUp(); //bring up the tcpip stack ect.
+		return;
+	case E_Close:
+
+		break;
+	case E_Sync:
+		break;
+	default:
+		IrlanUtil::Panic(EIrlanErrorState);
+		break;
+		}
+	if (ret!=KErrNone)
+	  	ActivateStateMachine(ret);
+}
+
+
+/**
+Process the packet received from the LinkLayer.
+*/
+void CIrlanControlEngine::ProcessReceivedPacketL()
+{
+	RMBufPacket pkt;
+
+	pkt.CreateL(iRecvBufPtr,0);
+	pkt.Pack();
+	iNotify->Process(pkt);	// We had a read queued and that has completed
+}
+
+
+/**
+Starts up the state machine in E_Idle state - will lead to a discovery attempt.
+*/
+void CIrlanControlEngine::StartL()
+{
+	TInt ret;
+	iHostResolver=CInternalHostResolver::NewL();
+	if ((ret=iHostResolver->OpenL(_L("IrTinyTP"),this))!=KErrNone)
+		{
+		LOG(Log::Printf(_L("IRLAN	CInternalHostResolver::OpenL failed with err=%d\r\n"),ret));
+		User::Leave(ret);
+		}
+	iState=E_Idle;
+	iProtocol=iHostResolver->iProtocol;
+	ActivateStateMachine();
+}
+
+/**
+cancellation of an outstanding request.
+*/
+void CIrlanControlEngine::DoCancel()
+{
+	switch (iState)
+		{
+	case E_Data:
+		iSender->DoCancel();
+		iReceiver->DoCancel();
+		break;
+	default:
+		break;
+		}
+}
+
+/** 
+Protocol inspects return
+It blocks sending if it receives a return <= 0
+This value should be propogated up through the stack
+@internalComponent
+*/
+const TInt KStopSending		= 0;
+
+/**
+Protocol inspects return to indicate Keep sending the data.
+@internalComponent
+*/
+const TInt KContinueSending	= 1;
+
+/**
+Sender Class is generic and does not want to know about RMBuf's
+Copy to a Heap Buffer and Free the packet. EtherII MAC layer comments
+Say we should free the packet buffer
+RMBuf could contain a chain so get into a contiguous buffer
+@param aPdu		A reference to the packet to be sent (really an RMBufPkt)
+@param aSource  A pointer to the source protocol.
+@return 0 Tells the higher layer to stop sending the data.
+		1 Tells higher layer that it can continue sending more data.
+*/
+TInt CIrlanControlEngine::Send(RMBufChain& aPdu, TAny*)
+{
+	if (iState!=E_Data)
+		{// Not ready to send the packet.
+		aPdu.Free();
+		return KStopSending;
+		}
+	// Need to stick the packet in a queue and kick the sender...
+	iDataSendQ.Append(aPdu);
+	iSender->KickSender();
+	return KContinueSending;
+}
+
+
+/**
+This kicks off the state machine active object.  Completion in RunL..
+@param aStat The active object Request complete status.
+*/
+void CIrlanControlEngine::ActivateStateMachine(TInt aStat)
+{
+	TRequestStatus *pS=&iStatus;
+	User::RequestComplete(pS,aStat);
+	SetActive();
+}
+
+//*************************** NOTIFIERS **********************************
+
+/**
+Upcall from SAP - more data arrived
+Indicates that new data is available on a service access point
+*/
+void CIrlanControlEngine::NewData(TUint /*aCount*/)
+{
+}
+
+/**
+Upcall from SAP - flow control on
+Indicates that new buffer space is available on a service 
+*/
+void CIrlanControlEngine::CanSend()
+{
+	if (iState==E_Data)
+		{
+#ifdef __TRACEWIN__
+	LOG(Log::Printf(_L("IRLAN	CanSend received from SAP\r\n")));
+#endif
+		// if there's any data in the queue, force send it!
+		if (!iDataSendQ.IsEmpty())
+			iSender->KickSender();
+		return;
+		}
+}
+
+/**
+This returns the hardware address pulled out of response to
+IrLAN FILTER_OPERATION/DYNAMIC request.
+@return NULL Failure.
+		(NULL Terminated Binary String) The Hardware Address of the interface. LAN Device 
+		Specific
+@note this will not contain the correct MAC address until IRLAN recives a control frame.
+*/
+TUint8* CIrlanControlEngine::GetInterfaceAddress()
+{
+	return &iHWAddr[0];
+}
+
+/**
+Upcall from SAP.  Notify layer above
+Indicates that a connection attempt has completed successfully
+*/
+void CIrlanControlEngine::ConnectComplete()
+{
+#ifdef __TRACEWIN__
+	LOG(Log::Printf(_L("IRLAN	Control channel connect complete 1\r\n")));
+#endif
+	ActivateStateMachine();
+}
+
+#pragma warning (disable:4100)
+/**
+Upcall from SAP.  Notify layer above
+Indicates that a connection attempt has completed successfully
+@param aConnectData Connect data (if supported)  
+*/
+void CIrlanControlEngine::ConnectComplete(const TDesC8& /*aConnectData*/)
+{
+	PrintState();
+	TInt ret=KErrNone;
+	switch (iState)
+		{
+	case E_Conn:
+		// Successful completion of control channel connect.
+#ifdef __TRACEWIN__
+	LOG(Log::Printf(_L("IRLAN	Control channel connect complete 2 data len=%d\r\n"),aConnectData.Length()));
+#endif
+		break;
+	case E_FilterBroadcast:
+		// Successful completion of data channel connect.
+#ifdef __TRACEWIN__
+	LOG(Log::Printf(_L("IRLAN	Control channel connect complete 2 data len=%d\r\n"),aConnectData.Length()));
+#endif
+	    iState=E_Data;			// READY TO TRY AND SEND/RECEIVE PACKETS!
+		break;
+	default:
+		ret=KErrNotSupported;
+		break;
+		}
+	ActivateStateMachine(ret);
+}
+#pragma warning (default:4100)
+
+/**
+Upcall from SAP.  Notify layer above
+Indicates that a connection attempt has completed successfully
+@param aSSP The new SSP for passive opens 
+*/
+void CIrlanControlEngine::ConnectComplete(CServProviderBase& aSSP)
+{
+#ifdef __TRACEWIN__
+	LOG(Log::Printf(_L("IRLAN	Control channel connect complete 3 - not supported!!\r\n")));
+#endif
+	iAcceptControlSock=CInternalSocket::NewL(&aSSP,this);
+	ActivateStateMachine();
+}
+
+/**
+Upcall from SAP.  Notify layer above
+Indicates that a connection attempt has completed successfully
+@param aSSP The new SSP for passive opens 
+@param aConnectData Connect data (if supported)  
+*/
+void CIrlanControlEngine::ConnectComplete(CServProviderBase& aSSP,
+  const TDesC8& /*aConnectData*/)
+{
+#ifdef __TRACEWIN__
+	LOG(Log::Printf(_L("IRLAN	Control channel connect complete on accept socket\r\n")));
+#endif
+	iAcceptControlSock=CInternalSocket::NewL(&aSSP,this);
+	ActivateStateMachine();
+}
+
+/**
+Upcall from SAP.  Notify layer above.
+Indicates that the SAP has finished closing down
+@param aDelete     Delete SAP 
+*/
+void CIrlanControlEngine::CanClose(TDelete /*aDelete*/)
+{
+}
+
+/**
+Upcall from SAP.  Notify layer above.
+Indicates that the SAP has finished closing down
+@param aDisconnectData Any user data carried on the disconnect frame 
+@param aDelete         Delete SAP 
+*/
+void CIrlanControlEngine::CanClose(const TDesC8& /*aDisconnectData*/,TDelete /*aDelete*/)
+{
+}
+
+/**
+Upcall from SAP - Error notification.
+@param aError			The error code
+@param anOperationMask  A bitmask of TOperationBitmasks values specifying which pending operations are
+						affected by the Error up-call
+*/
+void CIrlanControlEngine::Error(TInt /*anError*/,TUint /*anOperationMask*/)
+{
+}
+
+/**
+Upcall from SAP - Not supported
+Indicates that the other end of a connection has disconnected. 
+*/
+void CIrlanControlEngine::Disconnect(void)
+{
+}
+
+/**
+Indicates that the other end of a connection has disconnected
+
+@param aDisconnectData User data in the disconnect frame.
+*/
+void CIrlanControlEngine::Disconnect(TDesC8& /*aDisconnectData*/)
+{
+}
+
+/**
+Upcall from SAP.  Notify layer above
+Indicates that the currently pending Ioctl has completed
+@param aBuf Any data requested by the Ioctl operation.
+*/
+void CIrlanControlEngine::IoctlComplete(TDesC8 * /*aBuf*/)
+{
+}
+
+void CIrlanControlEngine::NoBearer(const TDesC8& /*aConnectionParams*/)
+{
+}
+
+void CIrlanControlEngine::Bearer(const TDesC8& /*aConnectionInfo*/)
+{
+}
+
+/**
+Depending on error AND STATE!!, need to take corresponding action.
+Notifier call back from IrDA PRT
+This is where the request completes - it has already filled
+in the name record passed through to GetByName so leave that.
+@param aErr Error code.
+*/
+void CIrlanControlEngine::QueryComplete(TInt aError)
+{
+	PrintState();
+	switch (iState)
+		{
+	case E_Idle:
+		if (aError==KErrNone)	// Successful discovery
+			{// iLog already filled in - pull out the device.
+			TIrdaSockAddr addr(iLog().iAddr);
+			// Check it has IrLAN set in it's discovery hint bits.
+			iDiscoveredDevice=addr.GetRemoteDevAddr();
+#ifdef __TRACEWIN__
+			TUint numHintBytes=addr.GetServiceHintByteCount();
+			TUint8 hintByte1=addr.GetFirstServiceHintByte();
+			LOG(Log::Printf(_L("IRLAN	!!!!!!!!!!!!! SUCCESSFUL DISCOVERY !!!!!!!!!!!!!!!\r\n")));
+			LOG(Log::Printf(_L("IRLAN	Remote machine dev addr=0x%08x\r\n"),iDiscoveredDevice));
+			LOG(Log::Printf(_L("IRLAN	Remote no. of service hint bytes is %d\r\n"),numHintBytes));
+			LOG(Log::Printf(_L("IRLAN	Remote first service hint byte is 0x%02x\r\n"),hintByte1));
+			if (numHintBytes>1)
+				{
+				LOG(Log::Printf(_L("IRLAN	Remote second service hint byte is 0x%02x\r\n"),
+					addr.GetSecondServiceHintByte()));
+				}
+			LOG(Log::Printf(_L("IRLAN	Remote machine name is \"%s\"\r\n"),iLog().iName.PtrZ()));
+#endif
+			}
+		else					// Nothing discovered
+			aError=KErrNone;	// This will ensure continued attempts.
+		break;
+	case E_Query:
+		if (aError==KErrNone)
+			{// IAS QUERY COMPLETED SUCCESSFULLY.
+			iResults.Copy(iQuery);
+			PrintIASResults();
+			if (iResults.Type()==EIASDataInteger)
+				{
+				aError=iResults.GetInteger(iIrlanControlPortNum);
+				}
+			}
+		else
+			{// IAS QUERY COMPLETED UNSUCCESSFULLY.
+			PrintIASError(aError);
+			// Need to take corrective action!! (Done in HandleErrorL).
+			}
+		break;
+	default:
+		break;
+		}
+	ActivateStateMachine(aError);	// Kick off state machine again.
+}
+
+//********************** IRLAN STATE MACHINE ACTIONS ************************
+
+TInt CIrlanControlEngine::PassiveIdleTransitionL()
+{
+#ifdef __TRACEWIN__
+	LOG(Log::Printf(_L("IRLAN	PASSIVE IDLE STATE TRANSITION\r\n")));
+#endif
+	// first - queue the IAS db entry.
+	TIASDatabaseEntry iasentry;
+	if (!iNetDatabase)
+		{
+		iNetDatabase=CInternalNetDB::NewL();
+		User::LeaveIfError(iNetDatabase->OpenL(TINYTP_PROTOCOL,this));
+		}
+	iasentry.SetClassName(IRLAN_CLASSNAME);
+	iasentry.SetAttributeName(TINYTP_ATTRNAME);
+	iasentry.SetToInteger(9);
+	iNetDatabase->Add(iasentry);
+#ifdef __TRACEWIN__
+	LOG(Log::Printf(_L("IrLAN	PEER service registered on port 9\r\n")));
+#endif
+
+	iListenSock=new (ELeave) CInternalSocket();
+	User::LeaveIfError(iListenSock->OpenL(TINYTP_PROTOCOL,this));
+	TIrdaSockAddr addr(iLog().iAddr);
+	addr.SetPort(0x09);					    // This is where IrLAN PEER is.
+	iListenSock->SetLocalName(addr);
+	iListenSock->WaitForConnect(2);
+
+	iAccessType=EPeerToPeer;
+	/*
+	ret=iAcceptor->Open();
+	sock1.Accept(sock2,iStatus);	// the order of this accept call has changed in esock
+	User::WaitForRequest(stat3);
+	// second - do a listen and accept on corresponding port.
+	*/
+
+	return KErrNone;
+}
+
+TInt CIrlanControlEngine::AttemptingDiscoveryL()
+{
+#ifdef __TRACEWIN__
+	LOG(Log::Printf(_L("IRLAN	ATTEMPTING DISCOVERY\r\n")));
+#endif
+	if (!iDiscoveryAttempts)
+		{
+		iLog().iName=_S("*");
+		iDiscoveryAttempts++;
+	    TInt ret=iHostResolver->GetByName(iLog());
+		return ret;
+		}
+	else
+		{
+		if (iDiscoveryAttempts>=5)
+			{// need to drop into passive idle state
+			return KErrNotFound;
+			}
+		// 1 sec between discoveries
+		TCallBack callback(CIrlanControlEngine::IrlanControlEngineTimerExpired,this);
+		iTimers->StartIrlanControlEngineTimer(callback,1000000L);
+		}
+	return KErrNone;  // don't want to reactivate state machine
+}
+
+TInt CIrlanControlEngine::IrlanControlEngineTimerExpired(TAny *aIrlan)
+{
+	CIrlanControlEngine *cc=(CIrlanControlEngine *)aIrlan;
+	switch (cc->iState)
+		{
+	case E_Idle:
+		// discovery timer has completed.  try a discovery.
+		cc->iTimers->DoIrlanControlEngineTimerExpired();
+		cc->iDiscoveryAttempts++;
+		cc->iHostResolver->GetByName(cc->iLog());
+		break;
+	default:
+		break;
+		}
+	return 0;
+}
+
+/**
+Need to find out if the remote supports IrLAN.  Note that this will involve
+kicking up the IrLAP/IAS connections.  Requires opening up a net database.
+@return TRUE if the Classname, AttributeType and the Device is present otherwise some error code.
+*/
+TInt CIrlanControlEngine::QueryRemoteIASL()
+{
+	TInt ret;
+#ifdef __TRACEWIN__
+	LOG(Log::Printf(_L("IRLAN	QUERY REMOTE IAS\r\n")));
+#endif
+	TRAP(ret,iNetDatabase=CInternalNetDB::NewL());
+	User::LeaveIfError(ret);
+	if ((ret=iNetDatabase->OpenL(TINYTP_PROTOCOL,this))!=KErrNone)
+		{
+#ifdef __TRACEWIN__
+		LOG(Log::Printf(_L("IRLAN	CInternalNetDB::OpenL failed with err=%d\r\n"),ret));
+#endif
+		User::Leave(ret);
+		}
+	return DoIASQuery(IRLAN_CLASSNAME,TINYTP_ATTRNAME,iDiscoveredDevice);
+}
+
+/**
+Need to connect to the IrLAN port number held in iIrlanPortNumber.  Requires
+opening up a control socket.
+@return TRUE if Success otherwise any error code.
+*/
+TInt CIrlanControlEngine::ConnectToProviderL()
+{
+	TInt ret;
+#ifdef __TRACEWIN__
+	LOG(Log::Printf(_L("IRLAN	CONNECT TO PROVIDER\r\n")));
+#endif
+	iControlSock=new (ELeave) CInternalSocket();
+	if ((ret=iControlSock->OpenL(TINYTP_PROTOCOL,this))!=KErrNone)
+		{
+#ifdef __TRACEWIN__
+		LOG(Log::Printf(_L("IRLAN	CInternalSocket::OpenL failed with err=%d\r\n"),ret));
+#endif
+		User::Leave(ret);
+		}
+	return DoControlConnect();
+}
+
+/**
+Need to connect to the IrLAN port number held in iIrlanPortNumber.  Requires
+opening up a control socket.
+@return TRUE if Success otherwise any error code.
+*/
+TInt CIrlanControlEngine::ConnectToDataChannelL()
+{
+	TInt ret;
+#ifdef __TRACEWIN__
+	LOG(Log::Printf(_L("IRLAN	CONNECT TO DATA CHANNEL\r\n")));
+#endif
+	iDataSock=new (ELeave) CInternalSocket();
+	if ((ret=iDataSock->OpenL(TINYTP_PROTOCOL,this))!=KErrNone)
+		{
+#ifdef __TRACEWIN__
+		LOG(Log::Printf(_L("IRLAN	CInternalSocket::OpenL failed with err=%d\r\n"),ret));
+#endif
+		User::Leave(ret);
+		}
+	return DoDataConnect();
+}
+
+//*************************** UTILITY FUNCTIONS **********************************
+
+/**
+Searchs a parameter in the parameter List.
+@return A pointer to CIrlanParameter class
+*/
+CIrlanParameter* CIrlanControlEngine::LookUpParameter(const TDesC8& aName)
+{
+	CIrlanParameter *par;
+	TDblQueIter<CIrlanParameter> i(iIrlanParameterList);
+
+	while (par=i++,par!=NULL)
+		{
+		if (par->Match(aName))
+			return par;
+		}
+	return NULL;
+}
+
+void CIrlanControlEngine::SendIrlanResponseFrame(RMBufChain& aPdu)
+{
+	TInt ret;
+	ret =iAcceptControlSock->Write(aPdu,NULL,iStatus,0);
+	if (ret!=KErrNone)
+		{// what do we do here - panic?
+#ifdef __TRACEWIN__
+		LOG(Log::Printf(_L("IRLAN	Failure on iControlSock Send\r\n")));
+#endif
+		return;
+		}
+	SetActive();
+	aPdu.Free();
+}
+
+void CIrlanControlEngine::SendIrlanControlFrame(RMBufChain& aPdu)
+{
+	TInt ret;
+	ret =iControlSock->Write(aPdu,NULL,iStatus,0);
+	if (ret!=KErrNone)
+		{// what do we do here - panic?
+#ifdef __TRACEWIN__
+		LOG(Log::Printf(_L("IRLAN	Failure on iControlSock Send\r\n")));
+#endif
+		return;
+		}
+	SetActive();
+	aPdu.Free();
+}
+
+void CIrlanControlEngine::QueueWaitForControlCommand()
+{
+	// gotta do something with new data here....
+
+	iRecvBufPtr.SetLength(iRecvBufLength);
+	TRAPD(ret,iAcceptControlSock->Recv(iRecvBufPtr,NULL,iStatus,0));
+	if (ret !=KErrNone)
+		{
+#ifdef __TRACEWIN__		
+		LOG(Log::Printf(_L("IRLAN	Failure on iControlSock Recv - Control Command : %d\r\n"),ret));
+#endif		
+		}
+	iAwaitingCommand=ETrue;
+	SetActive();
+}
+
+void CIrlanControlEngine::QueueWaitForControlResponse()
+{
+	iRecvBufPtr.SetLength(iRecvBufLength);
+	TInt ret;
+	ret =iControlSock->Recv(iRecvBufPtr,NULL,iStatus,0);
+	if (ret !=KErrNone)
+		{
+#ifdef __TRACEWIN__
+		LOG(Log::Printf(_L("IRLAN	Failure on iControlSock Recv\r\n")));
+#endif
+		return;
+		}
+	iAwaitingResponse=ETrue;
+	SetActive();
+}
+
+/**
+Asynchronous IAS query.  RTimer timeout of 5 seconds on the query.
+@param aClassName		The Class Name.
+@param aAttributeName	Attribute name.
+@param aRemDevAddr		Remote device address.
+@return Error code.
+*/
+TInt CIrlanControlEngine::DoIASQuery(const TDesC8& aClassName,
+  const TDesC8& aAttributeName,TUint aRemDevAddr)
+{
+	TInt ret;
+#ifdef __TRACEWIN__
+	LOG(Log::Printf(_L("IRLAN	IAS Query on \"%S\"|\"%S\"\r\n"),&aClassName,&aAttributeName));
+#endif
+	// Remember that netDB's return results in SAME buffer.
+	iQuery.Set(aClassName,aAttributeName,aRemDevAddr);
+	ret=iNetDatabase->Query(iQuery);
+	return ret;
+}
+
+TInt CIrlanControlEngine::DoControlConnect()
+{
+	TSockAddr addr;
+	// Set home port number.
+	TUint8 home=KIrlanHomeControlPort;
+	addr.SetPort(home);
+	TInt ret=iControlSock->SetLocalName(addr);
+	if (ret!=KErrNone)
+		return ret;
+	addr.SetPort(TUint8(iIrlanControlPortNum));
+	// Enable segmentation/reassembly.
+	TPckgBuf<TUint> param(1024);	// Set segmentation/reassembly size
+	// const TUint KTinyTPLocalSegmentSize=7: This value is advertised to the
+	// remote machine as the max amount of data we can reassemble
+	// const TUint KTinyTPRemoteSegmentSize=8: Remote machine is unable
+	// to reassemble more data than this.
+	if ((ret=iControlSock->SetOption(KLevelIrmux,KTinyTPLocalSegSizeOpt,param))!=KErrNone)
+		return ret;
+#ifdef __TRACEWIN__
+	LOG(Log::Printf(_L("IRLAN	Control channel connect on SLSAP=%d,DLSAP=%d\r\n"),
+	  home,iIrlanControlPortNum));
+#endif
+	return iControlSock->Connect(addr);
+}
+
+TInt CIrlanControlEngine::DoDataConnect()
+{
+	TSockAddr addr;
+	// Set home port number.
+	TUint8 home=KIrlanHomeDataPort;
+	addr.SetPort(home);
+	TInt ret=iDataSock->SetLocalName(addr);
+	if (ret!=KErrNone)
+		return ret;
+	addr.SetPort(TUint8(iIrlanDataPortNum));
+	// Enable segmentation/reassembly.
+	TPckgBuf<TUint> param(1518);	// Set segmentation/reassembly size
+	if ((ret=iDataSock->SetOption(KLevelIrmux,KTinyTPLocalSegSizeOpt,param))!=KErrNone)
+		return ret;
+#ifdef __TRACEWIN__
+	LOG(Log::Printf(_L("IRLAN	Control channel connect on SLSAP=%d,DLSAP=%d\r\n"),
+	  home,iIrlanDataPortNum));
+#endif
+	return iDataSock->Connect(addr);
+}
+
+//######################################################################################
+
+/**
+Constructor.
+@param aCIrlan A pointer to CIrlanControlEngine object.
+*/
+CIrlanControlEngineTimers::CIrlanControlEngineTimers(CIrlanControlEngine *aCIrlan)
+{
+	__DECLARE_NAME(_S("CIrlanControlEngineTimers"));
+	iIrlanControlEngine=aCIrlan;
+	iIrlanControlEngineTimerH=NULL;
+}
+
+/**
+Destructor.
+*/
+CIrlanControlEngineTimers::~CIrlanControlEngineTimers()
+{
+	if (iIrlanControlEngineTimerH)
+		StopIrlanControlEngineTimer();
+}
+
+/**
+Initialise the value of iIrlanControl for static member functions
+@param aCIrlan A pointer to CIrlanControlEngine object.
+@return A pointer to CIrlanControlEngineTimers class.
+*/
+CIrlanControlEngineTimers *CIrlanControlEngineTimers::NewL(CIrlanControlEngine *aCIrlan)
+{
+	return new (ELeave) CIrlanControlEngineTimers(aCIrlan);
+}
+
+/**
+Invoked to start the Internal Socket timer Can either complete as a call back to the
+static CIrlanControlEngine::IrlanControlEngineTimerExpired or can cancel.
+@param aCallBack Encapsulates a general call-back function.
+@param aTimeout Time out period
+*/
+void CIrlanControlEngineTimers::StartIrlanControlEngineTimer(TCallBack aCallBack,TInt aTimeout)
+{
+	if (iIrlanControlEngineTimerH)
+		StopIrlanControlEngineTimer();
+	iIrlanControlEngineTimer.Set(aCallBack);
+	iIrlanControlEngineTimerH=&iIrlanControlEngineTimer;
+	IrlanTimer::Queue(aTimeout,iIrlanControlEngineTimer);
+}
+
+/**
+Invoked to stop a previously queued Internal Socket timer
+*/
+void CIrlanControlEngineTimers::StopIrlanControlEngineTimer()
+{
+	if (iIrlanControlEngineTimerH)
+		IrlanTimer::Remove(iIrlanControlEngineTimer);
+	iIrlanControlEngineTimerH=NULL;
+}
+
+void CIrlanControlEngineTimers::DoIrlanControlEngineTimerExpired()
+{
+	iIrlanControlEngineTimerH=NULL;
+}