// Copyright (c) 2006-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:
// IP Connection Provider state definitions.
// 
//

/**
 @file
 @internalComponent
*/

#define SYMBIAN_NETWORKING_UPS

#include "IPCpr.h"
#include "ipcpr_states.h"
#include "IPMessages.h"
#include <comms-infras/ss_nodemessages.h>
#include <comms-infras/ss_nodemessages_internal_esock.h>
#include <comms-infras/ss_datamonitoringprovider.h>

#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
#include <comms-infras/ss_nodemessages_scpr.h>
#include <tcprecvwin.h>
#include <cs_genevent.h>
#include <comms-infras/ss_protopt.h>
#include <in_sock.h>
#endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW

using namespace Messages;
using namespace MeshMachine;
using namespace ESock;
using namespace IpCprActivities;
using namespace IpCprStates;

#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
using namespace TcpAdaptiveReceiveWindow;
#endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW

const TInt KNifEMCompatibilityLayerEntireSubConnectionUid = 0;
const TInt KNifEMCompatibilityLayerFakeSubConnectionId = 1;

DEFINE_SMELEMENT( TAwaitingPolicyParams, NetStateMachine::MState, IpCprStates::TContext)
TBool IpCprStates::TAwaitingPolicyParams::Accept()
    {
	return iContext.iMessage.IsMessage<TCFIPMessage::TPolicyParams>();
    }
/**
Security policies
*/

_LIT_SECURITY_POLICY_C1(KIpCprStopSecurityPolicy, ECapabilityNetworkControl);
    
/**
IpCpr Stop capability check transition
*/
DEFINE_SMELEMENT( TCheckStopCapabilities, NetStateMachine::MStateTransition, IpCprStates::TContext)
void IpCprStates::TCheckStopCapabilities::DoL()
    {
    MPlatsecApiExt* platsec = reinterpret_cast<MPlatsecApiExt*>(address_cast<TNodeId>(iContext.iSender).Node().FetchNodeInterfaceL(MPlatsecApiExt::KInterfaceId));
    TInt err = platsec->CheckPolicy(KIpCprStopSecurityPolicy);
	User::LeaveIfError(err);
    }

/**

*/
DEFINE_SMELEMENT( TSendPolicyParams, NetStateMachine::MStateTransition, IpCprStates::TContext)
void IpCprStates::TSendPolicyParams::DoL()
    {
	TCFIPMessage::TPolicyParams& policyParams = message_cast<TCFIPMessage::TPolicyParams>(iContext.iMessage);
	// change originator to current ipcpr
//	policyParams.iSender = iContext.Node()();

	RNodeInterface* ctrlProvider = iContext.Node().ControlProvider();


	if(ctrlProvider)
		{
		ctrlProvider->PostMessage(iContext.NodeId(), policyParams);
		}
	else
		{
		User::Leave(KErrCorrupt);
		}
    }

DEFINE_SMELEMENT( TAwaitingSubConnDataTransferred, NetStateMachine::MState, IpCprStates::TContext)
TBool IpCprStates::TAwaitingSubConnDataTransferred::Accept()
	{
	return(iContext.iMessage.IsMessage<TCFMessage::TSubConnDataTransferred>());
	}

DEFINE_SMELEMENT( TProcessSubConnDataTransferred, NetStateMachine::MStateTransition, IpCprStates::TContext)
void IpCprStates::TProcessSubConnDataTransferred::DoL()
	{
	TCFMessage::TSubConnDataTransferred& msg = message_cast<TCFMessage::TSubConnDataTransferred>(iContext.iMessage);

	RNodeInterface* ctrlClient = iContext.Node().GetFirstClient<TDefaultClientMatchPolicy>(TClientType(TCFClientType::ECtrl));
	if(ctrlClient) // Ditch the notifications if there's no one to send to.
		{
		TTime now;
		now.UniversalTime();

		if(msg.iValue1 == KNifEMCompatibilityLayerEntireSubConnectionUid)
			{
		    TSubConnectionClosedEvent wholeConnEvent;
		    wholeConnEvent.iSubConnectionUniqueId = KNifEMCompatibilityLayerEntireSubConnectionUid ;
		    wholeConnEvent.iTotalUplinkDataVolume = msg.iValue2;
		    wholeConnEvent.iTotalDownlinkDataVolume = msg.iValue3;
		    wholeConnEvent.iTimeClosed = now;
			TCFInternalEsock::TSubConnectionClosedEvent wholeConnMsg(wholeConnEvent);
			ctrlClient->PostMessage(iContext.NodeId(), wholeConnMsg);
			}
		else
			{
			TSubConnectionClosedEvent defaultSubConnEvent;
			defaultSubConnEvent.iSubConnectionUniqueId = KNifEMCompatibilityLayerEntireSubConnectionUid;
			defaultSubConnEvent.iTotalUplinkDataVolume = msg.iValue2;
			defaultSubConnEvent.iTotalDownlinkDataVolume = msg.iValue3;
			defaultSubConnEvent.iTimeClosed = now;
			TCFInternalEsock::TSubConnectionClosedEvent subConnMsg(defaultSubConnEvent);
			ctrlClient->PostMessage(iContext.NodeId(), subConnMsg);
			}
		}
	}


DEFINE_SMELEMENT( TSendInitialSubConnectionOpenedEvent, NetStateMachine::MStateTransition, IpCprStates::TContext)
void IpCprStates::TSendInitialSubConnectionOpenedEvent::DoL()
	{
	RNodeInterface* ctrlClient = iContext.Node().GetFirstClient<TDefaultClientMatchPolicy>(TClientType(TCFClientType::ECtrl));
	if(ctrlClient) // Ditch the notifications if there's no one to send to.
		{
	    TSubConnectionOpenedEvent wholeConnEvent;
	    wholeConnEvent.iSubConnectionUniqueId = KNifEMCompatibilityLayerEntireSubConnectionUid ;
		TCFInternalEsock::TSubConnectionOpenedEvent wholeConnMsg(wholeConnEvent);
		ctrlClient->PostMessage(iContext.NodeId(), wholeConnMsg);
		}
	}

DEFINE_SMELEMENT( TSendSubsequentSubConnectionOpenedEvent, NetStateMachine::MStateTransition, IpCprStates::TContext)
void IpCprStates::TSendSubsequentSubConnectionOpenedEvent::DoL()
	{
	RNodeInterface* ctrlClient = iContext.Node().GetFirstClient<TDefaultClientMatchPolicy>(TClientType(TCFClientType::ECtrl));
	if(ctrlClient) // Ditch the notifications if there's no one to send to.
		{
    	// If it's the default subconnection then use the fake subconnection id.
    	// Otherwise cook one up from the pointer of the SCPR.
    	TUint subConnectionUniqueId = KNifEMCompatibilityLayerFakeSubConnectionId;
    	TUint dataClientCount = iContext.Node().CountClients<TDefaultClientMatchPolicy>(TClientType(TCFClientType::EData));
    	if(dataClientCount > 1)
    		{
    		subConnectionUniqueId = reinterpret_cast<TUint>(address_cast<TNodeId>(iContext.iSender).Ptr());
    		}

	    TSubConnectionOpenedEvent defaultSubConnEvent;
	    defaultSubConnEvent.iSubConnectionUniqueId = subConnectionUniqueId;
	    TCFInternalEsock::TSubConnectionOpenedEvent subConnMsg(defaultSubConnEvent);
	    ctrlClient->PostMessage(iContext.NodeId(), subConnMsg);
    	}
	}


#ifndef SYMBIAN_NETWORKING_UPS

_LIT_SECURITY_POLICY_C1(KIpCprStartSecurityPolicy, ECapabilityNetworkServices);

/**
IpCpr Start capability check transition
*/
DEFINE_SMELEMENT( TCheckStartCapabilities, NetStateMachine::MStateTransition, IpCprStates::TContext)
void IpCprStates::TCheckStartCapabilities::DoL()
    {
    MPlatsecApiExt* platsec = iContext.iCFMessageSig.FetchPlatsecApiInterfaceL();
    TInt err = platsec->CheckPolicy(KIpCprStartSecurityPolicy);
	User::LeaveIfError(err);
    }

#endif  //SYMBIAN_NETWORKING_UPS

#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
/*
Constructor for the new parameter set to be sent in parameter bundle while requesting for bearer type.
@param aFamily - Specified the family the parameterset belongs to
	    aType - Specifies the type
@return object of type XBearerInfo
*/
EXPORT_C XBearerInfo* XBearerInfo::NewL(RParameterFamily aFamily, RParameterFamily::TParameterSetType aType)
{
	//call NewL
	XBearerInfo *obj = XBearerInfo::NewL();
	CleanupStack::PushL(obj);
	
	//add the parameterset to the family specified.
	aFamily.AddParameterSetL(obj, aType);
	CleanupStack::Pop(obj);
	
	return obj;	
}

/*
Constructs object of XBearerInfo
@return object of type XBearerInfo
*/
EXPORT_C XBearerInfo* XBearerInfo::NewL()
{
	return new(ELeave)XBearerInfo();
}

//Attribute table for data members of XBearerInfo class. Needed because the class derieves from SMetaData
START_ATTRIBUTE_TABLE(XBearerInfo, XBearerInfo::EUid, XBearerInfo::EId)
	REGISTER_ATTRIBUTE(XBearerInfo, iBearerType, TMetaNumber)
END_ATTRIBUTE_TABLE()

/**
 * State Transition which initialises the Parameter bundle to request for the bearer type.
 */
DEFINE_SMELEMENT(IpCprStates::TInitialiseParams, NetStateMachine::MStateTransition, IpCprStates::TContext)
void IpCprStates::TInitialiseParams::DoL()
    {
   	RCFParameterFamilyBundle newBundle;
	//create new bundle
	newBundle.CreateL();
	if(!iContext.Node().iParameterBundle.IsNull())
		{
		iContext.Node().iParameterBundle.Close();
		}
	iContext.Node().iParameterBundle.Open(newBundle);
	//Create new family
	RParameterFamily family = newBundle.CreateFamilyL(KBearerInfo);
	//construct object to be added to the parameterset
	//coverity[returned_pointer]
	// We are trying to initializing the family parameter and returning the pointer to XbearerInfo object.
	XBearerInfo *bearerInfo = XBearerInfo::NewL(family, RParameterFamily::ERequested);
   }

/**
 * State Transition which receives the response message to the bearer type request.
 * Extracts the bearer type and updates it in the NetMCPR
 */
DEFINE_SMELEMENT(IpCprStates::TUpdateProvisionConfigAtStartup, NetStateMachine::MStateTransition, IpCprStates::TContext)
void IpCprStates::TUpdateProvisionConfigAtStartup::DoL()
    {
	//Cast the message to response type
    TCFScpr::TGetParamsResponse& paramResponse = message_cast<TCFScpr::TGetParamsResponse>(iContext.iMessage);
	if( (! paramResponse.iFamilyBundle.IsNull()))
		{
		//Open the bundle
		iContext.Node().GetParameterBundle().Open(paramResponse.iFamilyBundle);
		CleanupClosePushL(iContext.Node().GetParameterBundle());
		//Get the family ie. KBearerInfo
		RParameterFamily family = iContext.Node().GetParameterBundle().FindFamily(KBearerInfo);	
		if(!family.IsNull())
			{
			//Find the parameter set
			XBearerInfo *bearerTypePtr = static_cast<XBearerInfo*>(family.FindParameterSet(STypeId::CreateSTypeId(KIpBearerInfoUid, KIpBearerInfoParameterType), RParameterFamily::ERequested));
			if(bearerTypePtr)
				{
				//Set the bearer type in NetMCPR
				CTCPReceiveWindowSize* winSizePtr =	const_cast<CTCPReceiveWindowSize *>(static_cast<const CTCPReceiveWindowSize *>(iContext.Node().AccessPointConfig().FindExtension(STypeId::CreateSTypeId(CTCPReceiveWindowSize::ERealmId,CTCPReceiveWindowSize::iId))));
				CSAPSetOpt* protOptPtr = const_cast<CSAPSetOpt *>(static_cast<const CSAPSetOpt *>(iContext.Node().AccessPointConfig().FindExtension(STypeId::CreateSTypeId(CSAPSetOpt::EUid,CSAPSetOpt::ETypeId))));
				//Set TCP Receive window value.
				if(winSizePtr && protOptPtr)
					{
					winSizePtr->SetTcpWin(bearerTypePtr->GetBearerType());
					protOptPtr->AddProtocolOptionL(KSolInetTcp, KSoTcpRecvWinAuto, winSizePtr->GetTcpWin());
					protOptPtr->AddProtocolOptionL(KSolInetTcp, KSoTcpMaxRecvWin, winSizePtr->GetTcpMaxWin());
					}		
				}
			}
		// Decrease reference count by calling close of the reference passed in CleanupClosePushL at line no 261
		CleanupStack::PopAndDestroy();
		}
    }

/**
 * State Transition to update the NetMCPR with bearer type recd. after receiving the modulation change notification.
 * Receives the TPlaneNotification message containting the new bearer.
 */
DEFINE_SMELEMENT(IpCprStates::TUpdateProvisionConfigAtModulation, NetStateMachine::MStateTransition, IpCprStates::TContext)
void IpCprStates::TUpdateProvisionConfigAtModulation::DoL()
    {
	
    TInt index = 0;
	//Cast the message to TPlaneNotification
    TCFSubConnControlClient::TPlaneNotification& paramsChanged = message_cast<TCFSubConnControlClient::TPlaneNotification>(iContext.iMessage);
    
	//Obtain the pointer to CEventParamsGranted class from the message
    const CEventParamsGranted * event = static_cast<const CEventParamsGranted*>(paramsChanged.iRefCountOwnedNotification->Ptr());
    
	//Obtain the parameter set
 	const XBearerInfo * msg = static_cast<const XBearerInfo *>(event->FindParameterSet(KBearerInfo, index));
	
	//Set the bearer type at NetMCPR
	CTCPReceiveWindowSize* winSizePtr =	const_cast<CTCPReceiveWindowSize *>(static_cast<const CTCPReceiveWindowSize *>(iContext.Node().AccessPointConfig().FindExtension(STypeId::CreateSTypeId(CTCPReceiveWindowSize::ERealmId,CTCPReceiveWindowSize::iId))));
	CSAPSetOpt* protOptPtr = const_cast<CSAPSetOpt *>(static_cast<const CSAPSetOpt *>(iContext.Node().AccessPointConfig().FindExtension(STypeId::CreateSTypeId(CSAPSetOpt::EUid,CSAPSetOpt::ETypeId))));
	
	// Set the TCP receive window and maximum value
	if(winSizePtr && protOptPtr)
		{
		winSizePtr->SetTcpWin((const_cast<XBearerInfo*>(msg))->GetBearerType());
		protOptPtr->UpdateProtocolOption(KSolInetTcp, KSoTcpRecvWinAuto, winSizePtr->GetTcpWin());
		protOptPtr->UpdateProtocolOption(KSolInetTcp, KSoTcpMaxRecvWin, winSizePtr->GetTcpMaxWin());
		}
    
    //Decrease the ref count
    paramsChanged.iRefCountOwnedNotification->Close();
    
	}

/**
 * StateTransition which sends request message containing the Parameter bundle to self.
 * When sent to self, it is sent to the service providers.
 */
DEFINE_SMELEMENT(IpCprStates::TSendParamsToSelf, NetStateMachine::MStateTransition, IpCprStates::TContext)
void IpCprStates::TSendParamsToSelf::DoL()
    {
   	ASSERT( ! iContext.Node().GetParameterBundle().IsNull()); // params initialised already
	iContext.iNodeActivity->PostRequestTo(iContext.NodeId(), TCFScpr::TGetParamsRequest(iContext.Node().GetParameterBundle()).CRef());
    }
    
    
/**
 * StateTransition to send bearer characteristics to data clients. The TCP Receive window size is obtained from 
 * Lookup Table using the bearer type obtained. Send the window size data clients. In this case, it will be sent 
 * before TStartDataClient.
 */
DEFINE_SMELEMENT(TSendTransportNotificationToDataClients, NetStateMachine::MStateTransition, IpCprStates::TContext)
void IpCprStates::TSendTransportNotificationToDataClients::DoL()
	{
		
	//Send TTransportNotification message to the data clients. 
	//Initialise the iter variable which will know all data clients.
	//Exclude data clients that are ELeaving otherwise the PostMessage() below will panic.
	
   	TClientIter<TDefaultClientMatchPolicy> iter = iContext.Node().GetClientIter<TDefaultClientMatchPolicy>(TClientType(TCFClientType::EData), TClientType(0, TCFClientType::ELeaving));
	TInt dataCliNum = NULL;
	RNodeInterface* dataClient = iter[dataCliNum];
	//Initialise message with window sizes
	TCFMessage::TTransportNotification message; 
  
  	while (dataClient)
   		{
		//Post messages to the data client.
 		dataClient->PostMessage(iContext.NodeId(), message);
 		dataCliNum++;
 		dataClient = iter[dataCliNum];
   		}
}

#endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
