testexecmgmt/ucc/Source/mncontroller/CSMncontroller.cpp
changeset 0 3da2a79470a7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testexecmgmt/ucc/Source/mncontroller/CSMncontroller.cpp	Mon Mar 08 15:04:18 2010 +0800
@@ -0,0 +1,1151 @@
+/*
+* Copyright (c) 2005-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:   
+* This file was autogenerated by rpcgen, but should be modified by the developer.
+* Make sure you don't use the -component_mod flag in future or this file will be overwritten.
+* Wed Oct 01 09:46:52 2003
+* System Includes
+*
+*/
+
+
+
+
+#include <stdio.h>
+#include <signal.h>
+#ifndef WIN32
+#include <unistd.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+/****************************************************************************************
+ * 
+ * Local Includes
+ * 
+ ***************************************************************************************/
+#include "CSvcMncontroller.h"
+#include "CSMncontroller.h"
+#include "standard_unix.h"
+#include "strncpynt.h"
+
+
+/****************************************************************************************
+ * 
+ * Definitions
+ * 
+ ***************************************************************************************/
+#define TEMPLATE_CONFIG_FILE			"dynmnd.template.conf"
+#define MOBILE_AGENT_COMMAND_LINE		"./dynmnd --fg --debug --config "
+#define MAXCOMMANDLINELENGTH			(31 + 256 + 1)
+#define MAXFOREIGNAGENTCOUNT			32
+#define MAXINTERFACECONFIGENTRY			(IFNAMSIZ + 128)
+
+
+/****************************************************************************************
+ * 
+ * Implementation
+ * 
+ ***************************************************************************************/
+CSMncontroller::CSMncontroller()
+{
+	iDynamicsCallTimeout = -1;
+	iAgentProcess = NULL;
+}
+
+CSMncontroller::~CSMncontroller()
+{
+	assert( iAgentProcess == NULL );
+}
+
+int CSMncontroller::GetKey()
+{
+	return iKey;
+}
+
+void CSMncontroller::SetKey( int aKey )
+{
+	iKey = aKey;
+}
+
+
+/****************************************************************************************
+ * 
+ * PUBLIC FUNCTION: cstr_createagent
+ * 
+ ***************************************************************************************/
+TResult CSMncontroller::cstr_createagent( void )
+{
+	TResult rv;
+	int errcode;
+	TDCFError terr;
+
+	// initialise the return value
+	rv.iServiceResult = ERR_NONE;
+	rv.iSubComponentResult = 0;
+	rv.iData0 = 0;
+	rv.iData1 = 0;
+
+	// create a local copy of the configuration file
+	terr = iDynamicsConfigFile.SetReferenceFile( TEMPLATE_CONFIG_FILE );
+	if( terr != DCE_NONE ) {
+		rv.iServiceResult = ERR_CONFIG_FILE_ERROR;
+		rv.iSubComponentResult = (int)terr;
+		return rv;
+	}
+	terr = iDynamicsConfigFile.CreateLocalCopy( &errcode );
+	if( terr != DCE_NONE ) {
+		rv.iServiceResult = ERR_CONFIG_FILE_ERROR;
+		rv.iSubComponentResult = (int)terr;
+		return rv;
+	}
+
+	// done - success
+	return rv;
+}
+
+
+/****************************************************************************************
+ * 
+ * PUBLIC FUNCTION: dstr_removeagent
+ * 
+ ***************************************************************************************/
+int CSMncontroller::dstr_removeagent( int aArgs, int *aDeleteInstance )
+{
+	int rv = ERR_NONE, errcode;
+	TDCFError terr;
+
+	// make sure that the proces isn't running
+	if( iAgentProcess != NULL ) {
+		*aDeleteInstance = 0;
+		rv = ERR_INVALIDSTATE;
+		return rv;
+	}
+
+	// clean up the config file
+	terr = iDynamicsConfigFile.RemoveLocalCopy( &errcode );
+	if( terr != DCE_NONE ) {
+		rv = ERR_CONFIG_FILE_ERROR;
+		return rv;
+	}
+
+	// done - success
+	return rv;
+}
+
+
+/****************************************************************************************
+ * 
+ * PUBLIC FUNCTION: startmobileagent
+ * 
+ ***************************************************************************************/
+TResult CSMncontroller::startmobileagent( int aArgs )
+{
+	TResult rv;
+	int errcode;
+	TCAProcessError perr;
+	char command_line_str[MAXCOMMANDLINELENGTH];
+
+	// initialise the return value
+	rv.iServiceResult = ERR_NONE;
+	rv.iSubComponentResult = 0;
+	rv.iData0 = 0;
+	rv.iData1 = 0;
+
+	// check that there is currently no process
+	if( iAgentProcess != NULL ) {
+		rv.iServiceResult = ERR_INVALIDSTATE;
+		return rv;
+	}
+
+	// create the new process object
+	iAgentProcess = new CAProcess();
+	assert( iAgentProcess != NULL );
+
+	// construct the command line
+	snprintf( command_line_str, MAXCOMMANDLINELENGTH, "%s%s", MOBILE_AGENT_COMMAND_LINE, iDynamicsConfigFile.GetLocalFilename() );
+
+	// start the actual process
+	perr = iAgentProcess->StartProcess( command_line_str, &errcode, false, false, false ); 
+	if( perr != CAE_NONE ) {
+		rv.iServiceResult = ERR_START_PROCESS_ERROR;
+		rv.iSubComponentResult = (int)perr;
+		delete iAgentProcess;
+		iAgentProcess = NULL;
+		return rv;
+	}
+
+	// done - success
+	rv.iServiceResult = ERR_NONE;
+	return rv;
+}
+
+
+/****************************************************************************************
+ * 
+ * PUBLIC FUNCTION: stopmobileagent
+ * 
+ ***************************************************************************************/
+TResult CSMncontroller::stopmobileagent( int aArgs )
+{
+	TResult rv;
+	TCAProcessError perr;
+	TProcessStatus pstatus;
+
+	// initialise the return value
+	rv.iServiceResult = ERR_NONE;
+	rv.iSubComponentResult = 0;
+	rv.iData0 = 0;
+	rv.iData1 = 0;
+
+	// if the process isn't started then invalid state
+	if( iAgentProcess == NULL ) {
+	  rv.iServiceResult = ERR_INVALIDSTATE;
+	  return rv;
+	}
+
+	// if the process isn't running then it has died outside the scope of this controller, clean up the state, return an error since
+	// this is noteworthy and should be either expected or not happen.
+	perr = iAgentProcess->GetProcessStatus( &pstatus );
+	assert( perr == CAE_NONE );
+	if( pstatus != PS_STARTED ) {
+	  assert( (pstatus == PS_STOPPED) || (pstatus == PS_ABANDONNED) );
+	  delete iAgentProcess;
+	  iAgentProcess = NULL;
+	  rv.iServiceResult = ERR_PROCESS_TERMINATED_OUTSIDE_SCOPE;
+	  return rv;
+	}
+
+	// request the process to stop
+	perr = iAgentProcess->RequestStop( SIGTERM );
+	if( perr != CAE_NONE ) {
+	  rv.iServiceResult = ERR_STOP_PROCESS_ERROR;
+	  rv.iSubComponentResult = (int)perr;
+	  return rv;
+	}
+
+	// wait for the process to stop
+	perr = iAgentProcess->WaitForProcessToTerminate( -1 );
+	if( perr != CAE_NONE ) {
+	  rv.iServiceResult = ERR_WAIT_PROCESS_ERROR;
+	  rv.iSubComponentResult = (int)perr;
+	  return rv;
+	}
+
+	// remove the process
+	delete iAgentProcess;
+	iAgentProcess = NULL;
+
+	// done - success
+	return rv;
+}
+
+
+/****************************************************************************************
+ * 
+ * PUBLIC FUNCTION: getmobileagentstatus
+ * 
+ ***************************************************************************************/
+TResult CSMncontroller::getmobileagentstatus( int aArgs )
+{
+	TResult rv;
+	TCAProcessError perr;
+	TProcessStatus pstatus;
+
+	// init the rv - note that we include the result even though it is always ERR_NONE
+	// here because the stub may return an error
+	memset( &rv, 0, sizeof(rv) );
+	rv.iServiceResult = ERR_NONE;
+
+	// if the process doesn't exist then we return PS_INVALID
+	if( iAgentProcess == NULL ) {
+		rv.iData0 = PS_INVALID;
+		return rv;
+	}
+
+	// otherwise just return whatever iAgentProcess->GetProcessStatus() returns
+	perr = iAgentProcess->GetProcessStatus( &pstatus );
+	assert( perr == CAE_NONE );
+	rv.iData0 = (int)pstatus;
+	return rv;
+}
+
+
+/****************************************************************************************
+ * 
+ * PUBLIC FUNCTION: setsingleoption
+ * 
+ ***************************************************************************************/
+TResult CSMncontroller::setsingleoption( TOptionDesc aArgs )
+{
+	TResult rv;
+	int errcode;
+	TDCFError cerr;
+
+	// initialise the return value
+	rv.iServiceResult = ERR_NONE;
+	rv.iSubComponentResult = 0;
+	rv.iData0 = 0;
+	rv.iData1 = 0;
+
+	// make sure that the process isn't running
+	if( iAgentProcess != NULL ) {
+		rv.iServiceResult = ERR_INVALIDSTATE;
+		return rv;
+	}
+
+	// modify the config file
+	cerr = iDynamicsConfigFile.SetSingleOption( aArgs.iOptionToken, aArgs.iOptionValue, &errcode );
+	if( cerr != DCE_NONE ) {
+		rv.iServiceResult = ERR_CONFIG_FILE_ERROR;
+		rv.iSubComponentResult = (int)cerr;
+		rv.iData0 = errcode;
+		return rv;
+	}
+
+	// return success
+	rv.iServiceResult = ERR_NONE;
+	return rv;
+}
+
+
+/****************************************************************************************
+ * 
+ * PUBLIC FUNCTION: removesingleoption
+ * 
+ ***************************************************************************************/
+TResult CSMncontroller::removesingleoption( TOptionDesc aArgs )
+{
+	TResult rv;
+	int errcode;
+	TDCFError cerr;
+
+	// initialise the return value
+	rv.iServiceResult = ERR_NONE;
+	rv.iSubComponentResult = 0;
+	rv.iData0 = 0;
+	rv.iData1 = 0;
+
+	// make sure that the process isn't running
+	if( iAgentProcess != NULL ) {
+		rv.iServiceResult = ERR_INVALIDSTATE;
+		return rv;
+	}
+
+	// modify the config file
+	cerr = iDynamicsConfigFile.RemoveSingleOption( aArgs.iOptionToken, &errcode );
+	if( cerr != DCE_NONE ) {
+		rv.iServiceResult = ERR_CONFIG_FILE_ERROR;
+		rv.iSubComponentResult = (int)cerr;
+		rv.iData0 = errcode;
+		return rv;
+	}
+
+	// return success
+	rv.iServiceResult = ERR_NONE;
+	return rv;
+}
+
+
+/****************************************************************************************
+ * 
+ * PUBLIC FUNCTION: addlistoption
+ * 
+ ***************************************************************************************/
+TResult CSMncontroller::addlistoption( TOptionDesc aArgs )
+{
+	TResult rv;
+	int errcode;
+	TDCFError cerr;
+
+	// initialise the return value
+	rv.iServiceResult = ERR_NONE;
+	rv.iSubComponentResult = 0;
+	rv.iData0 = 0;
+	rv.iData1 = 0;
+
+	// make sure that the process isn't running
+	if( iAgentProcess != NULL ) {
+		rv.iServiceResult = ERR_INVALIDSTATE;
+		return rv;
+	}
+
+	// modify the config file
+	cerr = iDynamicsConfigFile.AddListOption( aArgs.iOptionBlockStart, aArgs.iOptionBlockEnd, aArgs.iOptionValue, &errcode );
+	if( cerr != DCE_NONE ) {
+		rv.iServiceResult = ERR_CONFIG_FILE_ERROR;
+		rv.iSubComponentResult = (int)cerr;
+		rv.iData0 = errcode;
+		return rv;
+	}
+
+	// return success
+	rv.iServiceResult = ERR_NONE;
+	return rv;
+}
+
+
+/****************************************************************************************
+ * 
+ * PUBLIC FUNCTION: removelistoption
+ * 
+ ***************************************************************************************/
+TResult CSMncontroller::removelistoption( TOptionDesc aArgs )
+{
+	TResult rv;
+	int errcode;
+	TDCFError cerr;
+
+	// initialise the return value
+	rv.iServiceResult = ERR_NONE;
+	rv.iSubComponentResult = 0;
+	rv.iData0 = 0;
+	rv.iData1 = 0;
+
+	// make sure that the process isn't running
+	if( iAgentProcess != NULL ) {
+		rv.iServiceResult = ERR_INVALIDSTATE;
+		return rv;
+	}
+
+	// modify the config file
+	cerr = iDynamicsConfigFile.RemoveListOption( aArgs.iOptionBlockStart, aArgs.iOptionBlockEnd, aArgs.iOptionToken, &errcode );
+	if( cerr != DCE_NONE ) {
+		rv.iServiceResult = ERR_CONFIG_FILE_ERROR;
+		rv.iSubComponentResult = (int)cerr;
+		rv.iData0 = errcode;
+		return rv;
+	}
+
+	// return success
+	rv.iServiceResult = ERR_NONE;
+	return rv;
+}
+
+
+/****************************************************************************************
+ * 
+ * PUBLIC FUNCTION: getcareofaddress
+ * 
+ ***************************************************************************************/
+TResult CSMncontroller::sethomeaddress( THomeAddressDesc aArgs )
+{
+	TResult rv;
+	char dynamics_config[MAXINTERFACECONFIGENTRY];
+	struct in_addr home_address, home_network_address, home_agent_address;
+	TDCFError terr;
+	int errcode;
+
+	// initialise the return value
+	rv.iServiceResult = ERR_NONE;
+	rv.iSubComponentResult = 0;
+	rv.iData0 = 0;
+	rv.iData1 = 0;
+
+	// make sure that the process isn't running
+	if( iAgentProcess != NULL ) {
+		rv.iServiceResult = ERR_INVALIDSTATE;
+		return rv;
+	}
+
+	// validate the arguments
+	if( aArgs.iHomeAddress == -1 ) {
+	  rv.iServiceResult = ERR_INVALIDARG;
+	  rv.iData0 = 2;
+	  return rv;
+	}
+	if( (aArgs.iHomeAddressPrefix < 1) || (aArgs.iHomeAddressPrefix > 31) ) {
+		rv.iServiceResult = ERR_INVALIDARG;
+		rv.iData0 = 3;
+		return rv;
+	}
+	if( aArgs.iHomeAgentAddress == -1 ) {
+	  rv.iServiceResult = ERR_INVALIDARG;
+	  rv.iData0 = 4;
+	  return rv;
+	}
+
+	// if the home address specified is zero, then we take this as meaning that the user
+	// wants to reset the interface back to it's original (PPP configured) address. This
+	// doesn't effect the entries in the configuration file at all
+	if( aArgs.iHomeAddress == 0 ) {
+	  return rv;
+	}
+
+	// set the home address on the interface
+	rv = SetInterfaceAddress( aArgs.iInterfaceName, aArgs.iHomeAddress );
+	if( rv.iServiceResult != ERR_NONE ) {
+	  return rv;
+	}
+
+	// set the home address in the dynamics config file
+	home_address.ADDRESS_INTEGER = aArgs.iHomeAddress;
+	snprintf( dynamics_config, MAXINTERFACECONFIGENTRY, "MNHomeIPAddress %s", inet_ntoa(home_address) );
+	terr = iDynamicsConfigFile.SetSingleOption( "MNHomeIPAddress", dynamics_config, &errcode );
+	if( terr != DCE_NONE ) {
+		rv.iServiceResult = ERR_CONFIG_FILE_ERROR;
+		rv.iSubComponentResult = (int)terr;
+		rv.iData0 = errcode;
+		return rv;
+	}
+
+	// set the home network prefix in the dynamics config file
+	home_network_address = GetNetworkAddressFromHostAddress( aArgs.iHomeAddress, aArgs.iHomeAddressPrefix );
+	snprintf( dynamics_config, MAXINTERFACECONFIGENTRY, "HomeNetPrefix %s/%d", inet_ntoa(home_network_address), aArgs.iHomeAddressPrefix );
+	terr = iDynamicsConfigFile.SetSingleOption( "HomeNetPrefix", dynamics_config, &errcode );
+	if( terr != DCE_NONE ) {
+		rv.iServiceResult = ERR_CONFIG_FILE_ERROR;
+		rv.iSubComponentResult = (int)terr;
+		rv.iData0 = errcode;
+		return rv;
+	}
+
+	// set the home agent address 
+	home_agent_address.ADDRESS_INTEGER = aArgs.iHomeAgentAddress;
+	snprintf( dynamics_config, MAXINTERFACECONFIGENTRY, "HAIPAddress %s", inet_ntoa(home_agent_address) );
+	fprintf( stderr, "DEBUG: setting option '%s'\n", dynamics_config );
+	terr = iDynamicsConfigFile.SetSingleOption( "HAIPAddress", dynamics_config, &errcode );
+	if( terr != DCE_NONE ) {
+		rv.iServiceResult = ERR_CONFIG_FILE_ERROR;
+		rv.iSubComponentResult = (int)terr;
+		rv.iData0 = errcode;
+		return rv;
+	}
+
+	// done
+	return rv;
+}
+
+
+/****************************************************************************************
+ * 
+ * PUBLIC FUNCTION: getcareofaddress
+ * 
+ ***************************************************************************************/
+TResult CSMncontroller::getcareofaddress( int aArgs )
+{
+	TResult rv;
+	struct in_addr addr = { 0 };
+	TDynamicsCallInfo cres;
+	TCAProcessError perr;
+	TProcessStatus pstatus;
+
+	// initialise the return value
+	rv.iServiceResult = ERR_NONE;
+	rv.iSubComponentResult = 0;
+	rv.iData0 = 0;
+	rv.iData1 = 0;
+
+	// check that the agent was running
+	if( iAgentProcess == NULL ) {
+		rv.iServiceResult = ERR_INVALIDSTATE;
+		return rv;
+	}
+
+	// check that the agent is still runnning
+	perr = iAgentProcess->GetProcessStatus( &pstatus );
+	assert( perr == CAE_NONE );
+	if( pstatus != PS_STARTED ) {
+		rv.iServiceResult = ERR_INVALIDSTATE;
+		return rv;
+	}
+
+	// use the dynamics command wrapper to make the call
+	cres = iDynamicsCommand.MobileNodeAgentGetCareofAddress( &addr );
+	
+	// if the call failed then set the TResult correctly
+	if( cres.iResult != DC_SUCCESS ) {
+		rv.iServiceResult = ERR_DYNAMICS_CALL_FAILED;
+		rv.iSubComponentResult = cres.iResult;
+		rv.iData0 = cres.iErrorCode;
+		rv.iData1 = cres.iErrorDetail;
+		return rv;
+	}
+
+	// otherwise pack up the successful return info
+	rv.iServiceResult = ERR_NONE;
+	rv.iData0 = addr.ADDRESS_INTEGER;
+	return rv;
+}
+
+
+/****************************************************************************************
+ * 
+ * PUBLIC FUNCTION: getstatus
+ * 
+ ***************************************************************************************/
+TMobileNodeStatus CSMncontroller::getstatus( int aArgs )
+{
+	TMobileNodeStatus rv;
+	TCAProcessError perr;
+	TProcessStatus pstatus;
+	TDynamicsCallInfo cres;
+	TMobileNodeAgentStatusInfo mobile_node_status;
+
+	// init the return value
+	memset( &rv, 0, sizeof(rv) );
+	rv.iCallResult.iServiceResult = ERR_NONE;
+
+	// check that the agent was running
+	if( iAgentProcess == NULL ) {
+		rv.iCallResult.iServiceResult = ERR_INVALIDSTATE;
+		return rv;
+	}
+
+	// check that the agent is still runnning
+	perr = iAgentProcess->GetProcessStatus( &pstatus );
+	assert( perr == CAE_NONE );
+	if( pstatus != PS_STARTED ) {
+		rv.iCallResult.iServiceResult = ERR_INVALIDSTATE;
+		return rv;
+	}
+
+	// make the call
+	cres = iDynamicsCommand.MobileNodeAgentGetStatus( &mobile_node_status );
+	if( cres.iResult != DC_SUCCESS ) {
+		rv.iCallResult.iServiceResult = ERR_DYNAMICS_CALL_FAILED;
+		rv.iCallResult.iSubComponentResult = cres.iResult;
+		rv.iCallResult.iData0 = cres.iErrorCode;
+		rv.iCallResult.iData1 = cres.iErrorDetail;
+		return rv;
+	}
+
+	// copy the data from mobile_node_status to the rv
+	rv.iColocatedAddress = mobile_node_status.iColocatedAddress;
+	rv.iConnected = mobile_node_status.iConnected;
+	rv.iForeignAgentAddress = mobile_node_status.iForeignAgentAddress;
+	rv.iHomeAddress = mobile_node_status.iHomeAddress;
+	rv.iHomeAgentAddress = mobile_node_status.iHomeAgentAddress;
+	memcpy( rv.iInfoText, mobile_node_status.iInfoText, X_MAXINFOLEN );
+	memcpy( rv.iLastErrorString, mobile_node_status.iLastErrorString, X_MAXERRORSTRING );
+	rv.iLifetimeRemaining = mobile_node_status.iLifetimeRemaining;
+	rv.iLocalAddress = mobile_node_status.iLocalAddress;
+	rv.iReplyCode = mobile_node_status.iReplyCode;
+	rv.iSecondsSinceLastReply = mobile_node_status.iSecondsSinceLastReply;
+	rv.iSecondsSinceLastRequest = mobile_node_status.iTunnelMode;
+	rv.iTunnelUp = mobile_node_status.iTunnelUp;
+	return rv;
+}
+
+
+/****************************************************************************************
+ * 
+ * PUBLIC FUNCTION: connect
+ * 
+ ***************************************************************************************/
+TResult CSMncontroller::connect( TTunnelingModeDesc aArgs )
+{
+	TResult rv;
+	TDynamicsCallInfo cres;
+	TCAProcessError perr;
+	TProcessStatus pstatus;
+
+	// initialise the return value
+	rv.iServiceResult = ERR_NONE;
+	rv.iSubComponentResult = 0;
+	rv.iData0 = 0;
+	rv.iData1 = 0;
+
+	// check that the agent was running
+	if( iAgentProcess == NULL ) {
+		rv.iServiceResult = ERR_INVALIDSTATE;
+		return rv;
+	}
+
+	// check that the agent is still runnning
+	perr = iAgentProcess->GetProcessStatus( &pstatus );
+	assert( perr == CAE_NONE );
+	if( pstatus != PS_STARTED ) {
+		rv.iServiceResult = ERR_INVALIDSTATE;
+		return rv;
+	}
+
+	// call the wrapper
+	cres = iDynamicsCommand.MobileNodeAgentConnect();
+	if( cres.iResult != DC_SUCCESS ) {
+		rv.iServiceResult = ERR_DYNAMICS_CALL_FAILED;
+		rv.iSubComponentResult = cres.iResult;
+		rv.iData0 = cres.iErrorCode;
+		rv.iData1 = cres.iErrorDetail;
+		return rv;
+	}
+
+	// success
+	return rv;
+}
+
+
+/****************************************************************************************
+ * 
+ * PUBLIC FUNCTION: disconnect
+ * 
+ ***************************************************************************************/
+TResult CSMncontroller::disconnect( int aArgs )
+{
+	TResult rv;
+	TDynamicsCallInfo cres;
+	TCAProcessError perr;
+	TProcessStatus pstatus;
+
+	// initialise the return value
+	rv.iServiceResult = ERR_NONE;
+	rv.iSubComponentResult = 0;
+	rv.iData0 = 0;
+	rv.iData1 = 0;
+
+	// check that the agent was running
+	if( iAgentProcess == NULL ) {
+		rv.iServiceResult = ERR_INVALIDSTATE;
+		return rv;
+	}
+
+	// check that the agent is still runnning
+	perr = iAgentProcess->GetProcessStatus( &pstatus );
+	assert( perr == CAE_NONE );
+	if( pstatus != PS_STARTED ) {
+		rv.iServiceResult = ERR_INVALIDSTATE;
+		return rv;
+	}
+
+	// call the wrapper
+	cres = iDynamicsCommand.MobileNodeAgentDisconnect();
+	if( cres.iResult != DC_SUCCESS ) {
+		rv.iServiceResult = ERR_DYNAMICS_CALL_FAILED;
+		rv.iSubComponentResult = cres.iResult;
+		rv.iData0 = cres.iErrorCode;
+		rv.iData1 = cres.iErrorDetail;
+		return rv;
+	}
+
+	// success
+	return rv;
+}
+
+
+/****************************************************************************************
+ * 
+ * PUBLIC FUNCTION: confirm
+ * 
+ ***************************************************************************************/
+TResult CSMncontroller::confirm( int aArgs )
+{
+	TResult rv;
+	TDynamicsCallInfo cres;
+	TCAProcessError perr;
+	TProcessStatus pstatus;
+
+	// initialise the return value
+	rv.iServiceResult = ERR_NONE;
+	rv.iSubComponentResult = 0;
+	rv.iData0 = 0;
+	rv.iData1 = 0;
+
+	// check that the agent was running
+	if( iAgentProcess == NULL ) {
+		rv.iServiceResult = ERR_INVALIDSTATE;
+		return rv;
+	}
+
+	// check that the agent is still runnning
+	perr = iAgentProcess->GetProcessStatus( &pstatus );
+	assert( perr == CAE_NONE );
+	if( pstatus != PS_STARTED ) {
+		rv.iServiceResult = ERR_INVALIDSTATE;
+		return rv;
+	}
+
+	// call the wrapper
+	cres = iDynamicsCommand.MobileNodeAgentConfirm();
+	if( cres.iResult != DC_SUCCESS ) {
+		rv.iServiceResult = ERR_DYNAMICS_CALL_FAILED;
+		rv.iSubComponentResult = cres.iResult;
+		rv.iData0 = cres.iErrorCode;
+		rv.iData1 = cres.iErrorDetail;
+		return rv;
+	}
+
+	// success
+	return rv;
+}
+
+
+/****************************************************************************************
+ * 
+ * PUBLIC FUNCTION: rescaninterfaces
+ * 
+ ***************************************************************************************/
+TResult CSMncontroller::rescaninterfaces( int aArgs )
+{
+	TResult rv;
+	TDynamicsCallInfo cres;
+	TCAProcessError perr;
+	TProcessStatus pstatus;
+
+	// initialise the return value
+	rv.iServiceResult = ERR_NONE;
+	rv.iSubComponentResult = 0;
+	rv.iData0 = 0;
+	rv.iData1 = 0;
+
+	// check that the agent was running
+	if( iAgentProcess == NULL ) {
+		rv.iServiceResult = ERR_INVALIDSTATE;
+		return rv;
+	}
+
+	// check that the agent is still runnning
+	perr = iAgentProcess->GetProcessStatus( &pstatus );
+	assert( perr == CAE_NONE );
+	if( pstatus != PS_STARTED ) {
+		rv.iServiceResult = ERR_INVALIDSTATE;
+		return rv;
+	}
+
+	// call the wrapper
+	cres = iDynamicsCommand.MobileNodeAgentRescan();
+	if( cres.iResult != DC_SUCCESS ) {
+		rv.iServiceResult = ERR_DYNAMICS_CALL_FAILED;
+		rv.iSubComponentResult = cres.iResult;
+		rv.iData0 = cres.iErrorCode;
+		rv.iData1 = cres.iErrorDetail;
+		return rv;
+	}
+
+	// success
+	return rv;
+}
+
+
+/****************************************************************************************
+ *
+ * PUBLIC FUNCTION: setfapolicy - aPolicyDesc is a bitfield with each bit representing
+ * a particular policy that should be turned on or off. The values for each
+ * policy are in the interface file (.x). We try and set the policy for each
+ * bit regardless of whether some calls fail. The result is the OR of all the
+ * results (i.e. if one fails the op fails). To get more info about which
+ * succeeded you can just call getpolicy.
+ *
+ ***************************************************************************************/
+TResult CSMncontroller::setfapolicy( TPolicyRequest aArgs )
+{
+	TResult rv;
+	TDynamicsCallInfo cres;
+	TCAProcessError perr;
+	TProcessStatus pstatus;
+
+	// initialise the return value
+	rv.iServiceResult = ERR_NONE;
+	rv.iSubComponentResult = 0;
+	rv.iData0 = 0;
+	rv.iData1 = 0;
+
+	// check that the agent was running
+	if( iAgentProcess == NULL ) {
+		rv.iServiceResult = ERR_INVALIDSTATE;
+		return rv;
+	}
+
+	// check that the agent is still runnning
+	perr = iAgentProcess->GetProcessStatus( &pstatus );
+	assert( perr == CAE_NONE );
+	if( pstatus != PS_STARTED ) {
+		rv.iServiceResult = ERR_INVALIDSTATE;
+		return rv;
+	}
+
+	// call the wrapper
+	cres = iDynamicsCommand.MobileNodeAgentSetPolicy( aArgs.iPolicy );
+	if( cres.iResult != DC_SUCCESS ) {
+		rv.iServiceResult = ERR_DYNAMICS_CALL_FAILED;
+		rv.iSubComponentResult = cres.iResult;
+		rv.iData0 = cres.iErrorCode;
+		rv.iData1 = cres.iErrorDetail;
+		return rv;
+	}
+
+	// success
+	return rv;
+}
+
+
+/****************************************************************************************
+ * 
+ * PUBLIC FUNCTION: getfapolicy
+ * 
+ ***************************************************************************************/
+TResult CSMncontroller::getfapolicy( int aArgs )
+{
+	TResult rv;
+	TDynamicsCallInfo cres;
+	int policy_vector;
+	TCAProcessError perr;
+	TProcessStatus pstatus;
+
+	// initialise the return value
+	rv.iServiceResult = ERR_NONE;
+	rv.iSubComponentResult = 0;
+	rv.iData0 = 0;
+	rv.iData1 = 0;
+
+	// check that the agent was running
+	if( iAgentProcess == NULL ) {
+		rv.iServiceResult = ERR_INVALIDSTATE;
+		return rv;
+	}
+
+	// check that the agent is still runnning
+	perr = iAgentProcess->GetProcessStatus( &pstatus );
+	assert( perr == CAE_NONE );
+	if( pstatus != PS_STARTED ) {
+		rv.iServiceResult = ERR_INVALIDSTATE;
+		return rv;
+	}
+
+	// call the wrapper
+	cres = iDynamicsCommand.MobileNodeAgentGetPolicy( &policy_vector );
+	if( cres.iResult != DC_SUCCESS ) {
+		rv.iServiceResult = ERR_DYNAMICS_CALL_FAILED;
+		rv.iSubComponentResult = cres.iResult;
+		rv.iData0 = cres.iErrorCode;
+		rv.iData1 = cres.iErrorDetail;
+		return rv;
+	}
+
+	// success
+	rv.iServiceResult = ERR_NONE;
+	rv.iData0 = policy_vector;
+	return rv;
+}
+
+
+/****************************************************************************************
+ * 
+ * PUBLIC FUNCTION: listforeignagents
+ * 
+ ***************************************************************************************/
+TForeignAgentList CSMncontroller::listforeignagents( int aArgs )
+{
+	TDynamicsCallInfo cres;
+	TCAProcessError perr;
+	TProcessStatus pstatus;
+	int foreign_agent_count = MAXFOREIGNAGENTCOUNT, i;
+	TMobileNodeForeignAgentInfo foreign_agent_list[MAXFOREIGNAGENTCOUNT];
+	TForeignAgentList rv = { 0, NULL };
+
+	// check that the agent was running
+	if( iAgentProcess == NULL ) {
+		return rv;
+	}
+
+	// check that the agent is still runnning
+	perr = iAgentProcess->GetProcessStatus( &pstatus );
+	assert( perr == CAE_NONE );
+	if( pstatus != PS_STARTED ) {
+		return rv;
+	}
+
+	// call the dynamics wrapper
+	cres = iDynamicsCommand.MobileNodeAgentGetForeignAgentList( &foreign_agent_count, foreign_agent_list);
+	if( cres.iResult != DC_SUCCESS ) {
+		return rv;
+	}
+
+	// allocate the memory 
+	rv.TForeignAgentList_len = foreign_agent_count;
+	rv.TForeignAgentList_val = (TForeignAgentInfo*)calloc( foreign_agent_count, sizeof(TForeignAgentInfo) );
+	assert( rv.TForeignAgentList_val != NULL );
+
+	// copy the entries - all entries default to 0 due to calloc()
+	for( i = 0; i < foreign_agent_count; i++ ) {
+		(rv.TForeignAgentList_val)[i].iCallResult.iServiceResult = ERR_NONE;
+		(rv.TForeignAgentList_val)[i].iForeignAgentAddress = (foreign_agent_list[i]).iForeignAgentAddress;
+		(rv.TForeignAgentList_val)[i].iInterfaceIndex = (foreign_agent_list[i]).iInterfaceIndex;
+		(rv.TForeignAgentList_val)[i].iInUse = (foreign_agent_list[i]).iInUse;
+		(rv.TForeignAgentList_val)[i].iLastAdvertisement = (foreign_agent_list[i]).iLastAdvertisement;
+		(rv.TForeignAgentList_val)[i].iPriority = (foreign_agent_list[i]).iPriority;
+		memcpy( (rv.TForeignAgentList_val)[i].iInterfaceName, (foreign_agent_list[i]).iInterfaceName, X_MAXINTERFACENAMELEN );
+		memcpy( (rv.TForeignAgentList_val)[i].iNAI, (foreign_agent_list[i]).iNAI, X_MAXNAILEN );
+	}
+
+	// done - success
+	return rv;
+}
+
+
+/****************************************************************************************
+ * 
+ * PUBLIC FUNCTION: getforeignagentinfo
+ * 
+ ***************************************************************************************/
+TForeignAgentInfo CSMncontroller::getforeignagentinfo( TForeignAgentInfoRequest aArgs )
+{
+	TDynamicsCallInfo cres;
+	TCAProcessError perr;
+	TProcessStatus pstatus;
+	TMobileNodeForeignAgentInfo foreign_agent_info;
+	TForeignAgentInfo rv;
+
+	// init the result
+	memset( &rv, 0, sizeof(rv) );
+	rv.iCallResult.iServiceResult = ERR_NONE;
+
+	// check that the agent was running
+	if( iAgentProcess == NULL ) {
+		rv.iCallResult.iServiceResult = ERR_INVALIDSTATE;
+		return rv;
+	}
+
+	// check that the agent is still runnning
+	perr = iAgentProcess->GetProcessStatus( &pstatus );
+	assert( perr == CAE_NONE );
+	if( pstatus != PS_STARTED ) {
+		rv.iCallResult.iServiceResult = ERR_INVALIDSTATE;
+		return rv;
+	}
+
+	// call the dynamics wrapper
+	cres = iDynamicsCommand.MobileNodeAgentGetForeignAgentInfo( aArgs.iForeignAgentID, &foreign_agent_info );
+	if( cres.iResult != DC_SUCCESS ) {
+		rv.iCallResult.iServiceResult = ERR_DYNAMICS_CALL_FAILED;
+		rv.iCallResult.iSubComponentResult = cres.iResult;
+		rv.iCallResult.iData0 = cres.iErrorCode;
+		rv.iCallResult.iData1 = cres.iErrorDetail;
+		return rv;
+	}
+
+	// set the result
+	rv.iForeignAgentAddress = foreign_agent_info.iForeignAgentAddress;
+	rv.iInterfaceIndex = foreign_agent_info.iInterfaceIndex;
+	rv.iInUse = foreign_agent_info.iInUse;
+	rv.iLastAdvertisement = foreign_agent_info.iLastAdvertisement;
+	rv.iPriority = foreign_agent_info.iPriority;
+	memcpy( rv.iInterfaceName, foreign_agent_info.iInterfaceName, X_MAXINTERFACENAMELEN );
+	memcpy( rv.iNAI, foreign_agent_info.iNAI, X_MAXNAILEN );
+
+	// done - success
+	return rv;
+}
+
+
+/****************************************************************************************
+ * 
+ * PUBLIC FUNCTION: settimeout
+ * 
+ ***************************************************************************************/
+void CSMncontroller::settimeout( TTimeoutRequest aArgs )
+{
+	iDynamicsCallTimeout = aArgs.iTimeout;
+	iDynamicsCommand.SetTimeout( aArgs.iTimeout );
+}
+
+
+/****************************************************************************************
+ * 
+ * PRIVATE FUNCTION: SetInterfaceAddress
+ * 
+ ***************************************************************************************/
+TResult CSMncontroller::SetInterfaceAddress( char *aInterfaceName, int aAddress )
+{
+	TResult rv;
+	int sockfd, err;
+	struct ifreq ifr;
+	struct sockaddr_in destination_address, *saddr;
+
+	// check parameters
+	assert( aInterfaceName );
+
+	// init the response
+	rv.iServiceResult = ERR_NONE;
+	rv.iSubComponentResult = 0;
+	rv.iData0 = 0;
+	rv.iData1 = 0;
+
+	// create a socket to make ioctl calls on
+	sockfd = socket( AF_INET, SOCK_DGRAM, 0 );
+	if( sockfd <= 0 ) {
+		rv.iServiceResult = ERR_SET_INTERFACE_ADDRESS_ERROR;
+		rv.iSubComponentResult = SIE_SOCKET_FAILED;
+		rv.iData0 = errno;
+		return rv;
+	}	
+
+	// setup the request
+	STRNCPY_NULL_TERMINATE( ifr.ifr_name, aInterfaceName, IFNAMSIZ );
+
+	// get the current pointopoint address
+	err = ioctl( sockfd, SIOCGIFDSTADDR, &ifr );
+	if( err == -1 ) {
+		rv.iServiceResult = ERR_SET_INTERFACE_ADDRESS_ERROR;
+		rv.iSubComponentResult = SIE_IOCTL_GET_DESTINATION_ADDRESS_FAILED;
+		rv.iData0 = errno;
+		return rv;
+	}
+	destination_address = (*((struct sockaddr_in*)(&(ifr.ifr_dstaddr))));
+
+	// set the interface address
+	saddr = (struct sockaddr_in*)(&(ifr.ifr_addr));
+	saddr->sin_family = AF_INET;
+	saddr->sin_port = 0;
+	saddr->sin_addr.ADDRESS_INTEGER = aAddress;
+	err = ioctl( sockfd, SIOCSIFADDR, &ifr );
+	if( err == -1 ) {
+		rv.iServiceResult = ERR_SET_INTERFACE_ADDRESS_ERROR;
+		rv.iSubComponentResult = SIE_IOCTL_SET_ADDRESS_FAILED;
+		rv.iData0 = errno;
+		return rv;
+	}
+  
+	// setting the interface address seems to also set the the pointopoint (destination) 
+	// address to the same thing, so set it back to what it was or routing won't work
+	saddr = (struct sockaddr_in*)(&(ifr.ifr_dstaddr));
+	*saddr = destination_address; 
+	err = ioctl( sockfd, SIOCSIFDSTADDR, &ifr );
+	if( err == -1 ) {
+		rv.iServiceResult = ERR_SET_INTERFACE_ADDRESS_ERROR;
+		rv.iSubComponentResult = SIE_IOCTL_SET_DESTINATION_ADDRESS_FAILED;
+		rv.iData0 = errno;
+		return rv;
+	}
+
+	// done
+	return rv;
+}
+
+
+/****************************************************************************************
+ * 
+ * PRIVATE FUNCTION: GetNetworkAddressFromHostAddress
+ * 
+ ***************************************************************************************/
+struct in_addr CSMncontroller::GetNetworkAddressFromHostAddress( int aAddress, int aNetmask )
+{
+	struct in_addr rv;
+	int netmask, i;
+
+	// create the netmask
+	for( netmask = 0, i = 0; i < aNetmask; i++ ) {
+	    netmask |= 1<<(31-i);
+	}
+
+	// get the 
+	rv.ADDRESS_INTEGER = ntohl( aAddress );
+	rv.ADDRESS_INTEGER &= netmask;
+	rv.ADDRESS_INTEGER = htonl( rv.ADDRESS_INTEGER );
+
+	// done
+	return rv;
+}