/*****************************************************************************
* Copyright (c) 1990-98 Digi International Inc., All Rights Reserved
* 
* This software contains proprietary and confidential information of Digi
* International Inc.  By accepting transfer of this copy, Recipient agrees
* to retain this software in confidence, to prevent disclosure to others,
* and to make no use of this software other than that for which it was
* delivered.  This is an unpublished copyrighted work of Digi International
* Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly
* prohibited.
* 
* Restricted Rights Legend
*
* Use, duplication, or disclosure by the Government is subject to
* restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in
* Technical Data and Computer Software clause at DFARS 252.227-7031 or
* subparagraphs (c)(1) and (2) of the Commercial Computer Software -
* Restricted Rights at 48 CFR 52.227-19, as applicable.
*
* Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
*
*****************************************************************************/
// ProtocolX25.cpp: implementation of the CProtocolX25 class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ProtocolX25.h"
#include "resource.h"
#include "ObjectFactory.h"
#include "reghelpers.h"
#include "utils.h"
#include "line.h"		// the parent trap
#include "x25reg.h"
#include "x25incs.h"
#include "x25cfg.h"
#include "WanRouterReg.h"
#include "router.h"
#include "adapter.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNAMIC(CProtocolX25, CProtocol)
// define the static variables
// need to maintain a total count of PVC's across all instances of this object
#if !defined NT5
INT_PTR CProtocolX25::PVCCount = 0;				// # of PVC channels
#endif // #if !defined NT5

// following statics to help out with the router object which is shared across all instances
// NOTE: NOTE: This is only utilized for NT4
// For W2K, the router is not used, if it is ever used for W2K, multiple instance issues need correcting
CX25Router* CProtocolX25::m_pRouter = NULL; // the one and only one router object
int CProtocolX25::m_nReferenceCount = 0;    // how many instances of CProtocolX25;
CConfigObject* CProtocolX25::m_pInstance = NULL;  // ptr to a particular CProtocolX25 instance

#define SNIDSTART		'A'
#define X25SERVICE_INDEX 0
CProtocolX25::CProtocolX25(HKEY const hKeyRoot, CString const strRegPath, CConfigObject const * const pParent) : CProtocol(hKeyRoot, strRegPath, pParent)
{
	// LAPB items
	m_LAPB.N2 = DXB_REGVAL_LAPB_N2_DEFAULT;
	m_LAPB.T1 = DXB_REGVAL_LAPB_T1_DEFAULT;
	m_LAPB.Tpf = DXB_REGVAL_LAPB_TPF_DEFAULT;
	m_LAPB.Trej = DXB_REGVAL_LAPB_TREJ_DEFAULT;
	m_LAPB.Tbusy = DXB_REGVAL_LAPB_TBUSY_DEFAULT;
	m_LAPB.Tidle = DXB_REGVAL_LAPB_TIDLE_DEFAULT;
	m_LAPB.ack_delay = DXB_REGVAL_LAPB_ACK_DELAY_DEFAULT;
	m_LAPB.notack_max = DXB_REGVAL_LAPB_NOTACK_MAX_DEFAULT;
	m_LAPB.tx_window = DXB_REGVAL_LAPB_TX_WINDOW_DEFAULT;
	m_LAPB.tx_probe = DXB_REGVAL_LAPB_TX_PROBE_DEFAULT;
	m_LAPB.llconform = DXB_REGVAL_LAPB_LLCONFORM_DEFAULT;
	// X25 items
	m_X25.accessdelay = DXB_REGVAL_X25_ACCESSDELAY_DEFAULT;
	m_X25.ACKDELAY =	DXB_REGVAL_X25_ACKDELAY_DEFAULT;
	m_X25.CUG_CONTROL = DXB_REGVAL_X25_CUG_DEFAULT;
	m_X25.connectvalue = DXB_REGVAL_X25_CONNECT_DEFAULT;
	m_X25.dbit_control = DXB_REGVAL_X25_DBIT_DEFAULT;
	m_X25.dnic2 = DXB_REGVAL_X25_INTLDNIC2_DEFAULT;
	m_X25.dnic1 = DXB_REGVAL_X25_INTLDNIC1_DEFAULT;
	m_X25.HTC = DXB_REGVAL_X25_HTC_DEFAULT;
	m_X25.HOC = DXB_REGVAL_X25_HOC_DEFAULT;
	m_X25.HIC = DXB_REGVAL_X25_HIC_DEFAULT;
	m_X25.HPC = DXB_REGVAL_X25_HPC_DEFAULT;
	m_X25.intl_prioritised = DXB_REGVAL_X25_INTLPRIORITY_DEFAULT;
	m_X25.intl_addr_recogn = DXB_REGVAL_X25_INTLADDRREC_DEFAULT;
	m_X25.idlevalue = DXB_REGVAL_X25_IDLE_DEFAULT;
	m_X25.ll_class = DXB_REGVAL_X25_LLCLASS_DEFAULT;
	m_X25.locminthclass = DXB_REGVAL_X25_LOCMINTHCLASS_DEFAULT;
	m_X25.locdefthclass = DXB_REGVAL_X25_LOCDEFTHCLASS_DEFAULT;
	m_X25.locmaxthclass = DXB_REGVAL_X25_LOCMAXTHCLASS_DEFAULT;
	m_X25.localdelay = DXB_REGVAL_X25_LOCALDELAY_DEFAULT;
	m_X25.LOCDEFWSIZE = DXB_REGVAL_X25_LOCDEFWND_DEFAULT;
	m_X25.LOCMAXWSIZE = DXB_REGVAL_X25_LOCMAXWND_DEFAULT;
	m_X25.LOCDEFPKTSIZE = DXB_REGVAL_X25_LOCDEFPKT_DEFAULT;
	m_X25.LOCMAXPKTSIZE = DXB_REGVAL_X25_LOCMAXPKT_DEFAULT;
	m_X25.LTC = DXB_REGVAL_X25_LTC_DEFAULT;
	m_X25.LOC = DXB_REGVAL_X25_LOC_DEFAULT;
	m_X25.LIC = DXB_REGVAL_X25_LIC_DEFAULT;
	m_X25.LPC = DXB_REGVAL_X25_LPC_DEFAULT;
	m_X25.L3PLPMODE = DXB_REGVAL_X25_MODE_DEFAULT;
	m_X25.MAXNSDULEN = DXB_REGVAL_X25_MAXNSDU_DEFAULT;
	m_X25.Net_Mode = DXB_REGVAL_X25_NET_MODE_DEFAULT;
	m_X25.prty_pkt_forced_value = DXB_REGVAL_X25_INTLPKTFORCEDVAL_DEFAULT;
	m_X25.prty_encode_control = DXB_REGVAL_X25_INTLENCODECONTROL_DEFAULT;
	m_X25.remminthclass = DXB_REGVAL_X25_REMMINTHCLASS_DEFAULT;
	m_X25.remdefthclass = DXB_REGVAL_X25_REMDEFTHCLASS_DEFAULT;
	m_X25.remmaxthclass = DXB_REGVAL_X25_REMMAXTHCLASS_DEFAULT;
	m_X25.R23value = DXB_REGVAL_X25_R23_DEFAULT;
	m_X25.R22value = DXB_REGVAL_X25_R22_DEFAULT;
	m_X25.R20value = DXB_REGVAL_X25_R20_DEFAULT;
	m_X25.REMDEFWSIZE = DXB_REGVAL_X25_REMDEFWND_DEFAULT;
	m_X25.REMMAXWSIZE = DXB_REGVAL_X25_REMMAXWND_DEFAULT;
	m_X25.REMDEFPKTSIZE = DXB_REGVAL_X25_REMDEFPKT_DEFAULT;
	m_X25.REMMAXPKTSIZE = DXB_REGVAL_X25_REMMAXPKT_DEFAULT;
	m_X25.src_addr_control = DXB_REGVAL_X25_INTLSRCADDRCTRL_DEFAULT;
	m_X25.SNMODES = DXB_REGVAL_X25_SNMODES_DEFAULT;
	m_X25.SUB_MODES = DXB_REGVAL_X25_SUB_MODES_DEFAULT;
	m_X25.TotalRASPorts = DXB_REGVAL_X25_TOTALRASPORTS_DEFAULT;
	m_X25.thclass_type = DXB_REGVAL_X25_THCLASSTYPE_DEFAULT;
	m_X25.thclass_neg_to_def = DXB_REGVAL_X25_THCLASSNEG_DEFAULT;
	m_X25.Tvalue = DXB_REGVAL_X25_T_DEFAULT;
	m_X25.T26value = DXB_REGVAL_X25_T26_DEFAULT;
	m_X25.T25value = DXB_REGVAL_X25_T25_DEFAULT;
	m_X25.T23value = DXB_REGVAL_X25_T23_DEFAULT;
	m_X25.T22value = DXB_REGVAL_X25_T22_DEFAULT;
	m_X25.T21value = DXB_REGVAL_X25_T21_DEFAULT;
	m_X25.T20value = DXB_REGVAL_X25_T20_DEFAULT;
	m_X25.THISGFI = DXB_REGVAL_X25_GFI_DEFAULT;
	m_X25.X25_VSN = DXB_REGVAL_X25_VERSION_DEFAULT;
	m_X25.Alias = DXB_REGVAL_X25_ALIAS_DEFAULT;
	m_X25.lsap_address = DXB_REGVAL_X25_X25ADDRESS_DEFAULT;

	memset(m_X25.thclass_wmap,0,sizeof(m_X25.thclass_wmap));
	memset(m_X25.thclass_pmap,0,sizeof(m_X25.thclass_pmap));

	int vanum = ((CAdapter*)(GetParent()->GetParent()))->GetVAdapterNum();
	char tch = SNIDSTART + ((CLine*)GetParent())->GetLineNumber();
	m_X25.Alias.Format("%d%c", vanum, tch);
	TRACE("Alias=%s\n",m_X25.Alias);

	m_strDeviceName = ((CAdapter*)(GetParent()->GetParent()))->GetDeviceName();
	TRACE("DeviceName = %s\n",m_strDeviceName);

	m_pwsSheet = NULL;
	m_pwpLapbPage = NULL;
	m_pwpGeneralPage = NULL;
	m_pwpChannelPage = NULL;

#if defined NT5
	// For NT5, PVC Count is related only to the line's instance of X25 protocol
	PVCCount = 0;				// # of PVC channels
#endif // #if !defined NT5

	try
	{

		// Get protocol parameters
		AffirmThrow(GetParameters());

		// solve the identity crisis
		SetIdentity(DXB_REGVAL_PROTOCOL_ENUM_X25);
		// Set our Display Name
		CString szDisplayName;
		AffirmThrow(szDisplayName.LoadString(IDS_X25ProtocolName));
		SetDisplayName(szDisplayName);

	   // define our abilities
	   // we don't allow adding/deleting childs from the GUI. Defining the
	   // protocol automatically creates the service which is simply 
	   // a holding object allowing us to create PVC's.
		SetAbility(CConfigObject::DOPROPERTIES);
	
		// get our static config data
		AffirmThrow(CProtocol::GetConfigData());
		// Get LineSpeed from parent
		m_dwLineSpeed = ((CLine*)pParent)->GetLineSpeed();
		m_astrServices.Copy(m_astrServicesAllowed);
       // Give birth to our children

		for (int i = 0; i < m_astrServices.GetSize(); i++)
		{
			m_apChildren.SetAtGrow(i, NULL);

         // This registry path thingie needs a little explanation!
         //    Here's the layout so far:
         //       ...\DigiDxb?\Parameters\N           (where ? = the adapter instance, and
         //                                                  N = 0, 1, ... # of lines)
         //    The line service parameters reside at:
         //       ...\DigiDxb?\Parameters\XXXX\N      (where XXXX = the service name)
         //    So, pass in the hKey we were told to start at, and the XXXX\N reg path.

			CString strServiceRegPath = m_astrServices[i] + TEXT("\\") + strRegPath;
			AffirmThrow(NewConfigObject(&m_apChildren[i], CConfigObject::SERVICE, m_astrServices[i], hKeyRoot, strServiceRegPath, this));
			AffirmThrow(m_apChildren[i] != NULL);
		}

		CreateRouter();
		m_nReferenceCount++;
#if defined NT5
		PVCCount += m_apChildren[0]->GetChildCount();
#else // #if defined NT5
		CProtocolX25::PVCCount += m_apChildren[0]->GetChildCount();
#endif // #if defined NT5

	}
	catch (CAffirmException ae)
	{
	}
	

}

CProtocolX25::~CProtocolX25()
{
	delete m_pwpLapbPage;
	delete m_pwpGeneralPage;
	delete m_pwpChannelPage;
	if ((--CProtocolX25::m_nReferenceCount) == 0)
	{
		if (m_pRouter)
			DeleteConfigObject( (CConfigObject**)&m_pRouter );
		m_pRouter = NULL;
		m_pInstance = NULL;
	}
	
}

void CProtocolX25::SetX25LAPBConfig()
{
   // Copy the current settings into the working structs
	m_WorkingLAPB = m_LAPB;
	m_WorkingX25 = m_X25;
}

void CProtocolX25::GetX25LAPBConfig()
{
   // Copy the working settings into our current structs
	m_LAPB = m_WorkingLAPB;
	m_X25 = m_WorkingX25;
}

BOOL CProtocolX25::ReadWriteLapbParams(REGMODE emode)
{
	HKEY hsubkey;
	// if we are reading and the key does not exist, we don't want to wipe
	// out our defaults. Do nothing.
	if (emode == READ && !RegKeyExists(m_hKey,DXB_REGKEY_LAPB))
	{
		return TRUE;	
	}
	//
	// open the FRAME RELAY section
	if (!RegCreateKey(m_hKey,DXB_REGKEY_LAPB,&hsubkey))
		return FALSE;

	ASSERT(hsubkey != NULL);

	REGSTRUCT lapb[] = {
		{DXB_REGVAL_LAPB_N2,&(m_LAPB.N2)},
		{DXB_REGVAL_LAPB_T1,&(m_LAPB.T1)},
		{DXB_REGVAL_LAPB_TPF, &(m_LAPB.Tpf)},
		{DXB_REGVAL_LAPB_TREJ,&(m_LAPB.Trej)},
		{DXB_REGVAL_LAPB_TBUSY,&(m_LAPB.Tbusy)},
		{DXB_REGVAL_LAPB_TIDLE,&(m_LAPB.Tidle)},
		{DXB_REGVAL_LAPB_ACK_DELAY,&(m_LAPB.ack_delay)},
		{DXB_REGVAL_LAPB_NOTACK_MAX,&(m_LAPB.notack_max)},
		{DXB_REGVAL_LAPB_TX_WINDOW,&(m_LAPB.tx_window)},
		{DXB_REGVAL_LAPB_TX_PROBE,&(m_LAPB.tx_probe)},
		{DXB_REGVAL_LAPB_LLCONFORM,&(m_LAPB.llconform)},
		{DXB_REGVAL_LAPB_MAX_I_LEN,&(m_LAPB.max_l_len)},
	};

	ReadWriteRegItems(hsubkey,lapb,sizeof(lapb)/sizeof(lapb[0]),emode);
	RegCloseKey(hsubkey);
	return TRUE;
}

BOOL CProtocolX25::ReadWriteX25Params(REGMODE emode)
{
	HKEY hsubkey;
	// if we are reading and the key does not exist, we don't want to wipe
	// out our defaults. Do nothing.
	if (emode == READ && !RegKeyExists(m_hKey,DXB_REGKEY_X25))
	{
		return TRUE;	
	}
	//
	// open the X25 section
	if (!RegCreateKey(m_hKey,DXB_REGKEY_X25,&hsubkey))
		return FALSE;

	ASSERT(hsubkey != NULL);

	REGSTRUCT x25[] = {

		{DXB_REGVAL_X25_NET_MODE, &(m_X25.Net_Mode)},
		{DXB_REGVAL_X25_VERSION, &(m_X25.X25_VSN)},
		{DXB_REGVAL_X25_MODE, &(m_X25.L3PLPMODE)},
		{DXB_REGVAL_X25_LPC, &(m_X25.LPC)},
		{DXB_REGVAL_X25_HPC, &(m_X25.HPC)},
		{DXB_REGVAL_X25_LIC, &(m_X25.LIC)},
		{DXB_REGVAL_X25_HIC, &(m_X25.HIC)},
		{DXB_REGVAL_X25_LOC, &(m_X25.LOC)},
		{DXB_REGVAL_X25_HOC, &(m_X25.HOC)},
		{DXB_REGVAL_X25_LTC, &(m_X25.LTC)},
		{DXB_REGVAL_X25_HTC, &(m_X25.HTC)},
		{DXB_REGVAL_X25_GFI, &(m_X25.THISGFI)},
		{DXB_REGVAL_X25_LOCMAXPKT, &(m_X25.LOCMAXPKTSIZE)},
		{DXB_REGVAL_X25_LOCDEFPKT, &(m_X25.LOCDEFPKTSIZE)},
		{DXB_REGVAL_X25_REMMAXPKT, &(m_X25.REMMAXPKTSIZE)},
		{DXB_REGVAL_X25_REMDEFPKT, &(m_X25.REMDEFPKTSIZE)},
		{DXB_REGVAL_X25_LOCMAXWND, &(m_X25.LOCMAXWSIZE)},
		{DXB_REGVAL_X25_LOCDEFWND, &(m_X25.LOCDEFWSIZE)},
		{DXB_REGVAL_X25_REMMAXWND, &(m_X25.REMMAXWSIZE)},
		{DXB_REGVAL_X25_REMDEFWND, &(m_X25.REMDEFWSIZE)},
		{DXB_REGVAL_X25_MAXNSDU, &(m_X25.MAXNSDULEN)},
		{DXB_REGVAL_X25_ACKDELAY, &(m_X25.ACKDELAY)},
		{DXB_REGVAL_X25_T20, &(m_X25.T20value)},
		{DXB_REGVAL_X25_T21, &(m_X25.T21value)},
		{DXB_REGVAL_X25_T22, &(m_X25.T22value)},
		{DXB_REGVAL_X25_T23, &(m_X25.T23value)},
		{DXB_REGVAL_X25_T25, &(m_X25.T25value)},
		{DXB_REGVAL_X25_T26, &(m_X25.T26value)},
		{DXB_REGVAL_X25_T, &(m_X25.Tvalue)},
		{DXB_REGVAL_X25_IDLE, &(m_X25.idlevalue)},
		{DXB_REGVAL_X25_CONNECT, &(m_X25.connectvalue)},
		{DXB_REGVAL_X25_R20, &(m_X25.R20value)},
		{DXB_REGVAL_X25_R22, &(m_X25.R22value)},
		{DXB_REGVAL_X25_R23, &(m_X25.R23value)},
		{DXB_REGVAL_X25_LOCALDELAY, &(m_X25.localdelay)},
		{DXB_REGVAL_X25_ACCESSDELAY, &(m_X25.accessdelay)},
		{DXB_REGVAL_X25_LOCMAXTHCLASS, &(m_X25.locmaxthclass)},
		{DXB_REGVAL_X25_LOCDEFTHCLASS, &(m_X25.locdefthclass)},
		{DXB_REGVAL_X25_LOCMINTHCLASS, &(m_X25.locminthclass)},
		{DXB_REGVAL_X25_REMMAXTHCLASS, &(m_X25.remmaxthclass)},
		{DXB_REGVAL_X25_REMDEFTHCLASS, &(m_X25.remdefthclass)},
		{DXB_REGVAL_X25_REMMINTHCLASS, &(m_X25.remminthclass)},
		{DXB_REGVAL_X25_CUG, &(m_X25.CUG_CONTROL)},
		{DXB_REGVAL_X25_SUB_MODES, &(m_X25.SUB_MODES)},
		{DXB_REGVAL_X25_SNMODES, &(m_X25.SNMODES)},
		{DXB_REGVAL_X25_INTLADDRREC, &(m_X25.intl_addr_recogn)},
		{DXB_REGVAL_X25_INTLPRIORITY, &(m_X25.intl_prioritised)},
		{DXB_REGVAL_X25_INTLDNIC1, &(m_X25.dnic1)},
		{DXB_REGVAL_X25_INTLDNIC2, &(m_X25.dnic2)},
		{DXB_REGVAL_X25_INTLENCODECONTROL, &(m_X25.prty_encode_control)},
		{DXB_REGVAL_X25_INTLPKTFORCEDVAL, &(m_X25.prty_pkt_forced_value)},
		{DXB_REGVAL_X25_INTLSRCADDRCTRL, &(m_X25.src_addr_control)},
		{DXB_REGVAL_X25_DBIT, &(m_X25.dbit_control)},
		{DXB_REGVAL_X25_THCLASSNEG, &(m_X25.thclass_neg_to_def)},
		{DXB_REGVAL_X25_THCLASSTYPE, &(m_X25.thclass_type)},
		{DXB_REGVAL_X25_LLCLASS, &(m_X25.ll_class)},
		{DXB_REGVAL_X25_TOTALRASPORTS,&(m_X25.TotalRASPorts)},
	};

	ReadWriteRegItems(hsubkey,x25,sizeof(x25)/sizeof(x25[0]),emode);
	if (emode == READ)
	{
		DWORD dwsize = sizeof(m_X25.thclass_pmap);
		RegReadBinaryValue(hsubkey,DXB_REGVAL_X25_THCLASSPKTMAP, m_X25.thclass_pmap,dwsize);
		dwsize = sizeof(m_X25.thclass_wmap);
		RegReadBinaryValue(hsubkey,DXB_REGVAL_X25_THCLASSWNDMAP, m_X25.thclass_wmap,dwsize);
		RegReadStrValue(hsubkey,DXB_REGVAL_X25_X25ADDRESS,m_X25.lsap_address);
//		RegReadStrValue(hsubkey,DXB_REGVAL_X25_ALIAS, m_X25.Alias);
	}
	else
	{
		RegWriteBinaryValue(hsubkey,DXB_REGVAL_X25_THCLASSPKTMAP, m_X25.thclass_pmap,sizeof(m_X25.thclass_pmap));
		RegWriteBinaryValue(hsubkey,DXB_REGVAL_X25_THCLASSWNDMAP, m_X25.thclass_wmap,sizeof(m_X25.thclass_wmap));

		RegWriteStrValue(hsubkey,DXB_REGVAL_X25_X25ADDRESS,m_X25.lsap_address);
		RegWriteStrValue(hsubkey,DXB_REGVAL_X25_ALIAS, m_X25.Alias);
	}

	return TRUE;
}

// write LAPB/X.25 protocol params to registry
BOOL CProtocolX25::SetParameters()
{
#define PADEXTRABYTES 5
	BOOL bSuccess = FALSE;
	TRACE("\n In ProtocolX25::SetParameters\n");
	try
	{
		AffirmThrow(CProtocol::SetParameters());
		
		DWORD max = __max((1 << m_X25.REMMAXPKTSIZE), (1 << m_X25.LOCMAXPKTSIZE));
		int ext = PADEXTRABYTES;
		if (m_X25.THISGFI == G_128) 
			ext++;
		DWORD LLClass = m_X25.ll_class;
		if ((LLClass == LC_LAPBXDCE) ||	(LLClass == LC_LAPBXDTE))
			ext++;
		// set the max frame size
		m_LAPB.max_l_len = max+ext;
		((CLine*)GetParent())->SetMaxFrameSize(max+ext);

		m_X25.TotalRASPorts = CountChannels(SVC);
		AffirmThrow(ReadWriteLapbParams(WRITE));		
		AffirmThrow(ReadWriteX25Params(WRITE));
		// this may write multiple times. Benign, but needs explaining
		// the router object is shared across multiple instances of protocol objects
		// We need to make sure that the latest parameters are written to the registry
		// so, when any protocol object writes its changes, the router writes them as well
		// and if subsequent changes are made to the router before another instance of
		// the protocol object receives this message, the router changes will then have
		// been committed. This will only happen if on the same adapter, X.25 is running
		// on more than 1 line. 
		if (m_pRouter)
			AffirmThrow(m_pRouter->SetParameters());
		bSuccess = TRUE;
	}
	catch(CAffirmException ae)
	{
	}
	return bSuccess;
#undef PADEXTRABYTES
}

// read frame relay protocol params from registry
BOOL CProtocolX25::GetParameters()
{
	BOOL bSuccess = FALSE;
	try
	{
		AffirmThrow(CProtocol::GetParameters());
		ReadWriteLapbParams(READ);
		ReadWriteX25Params(READ);
		bSuccess = TRUE;
	}
	catch(CAffirmException ae)
	{
	}
	return bSuccess;

}

BOOL CProtocolX25::RemoveParameters(BOOL fRemoveKey)
{

    BOOL fSuccess = FALSE;

    try
	{
		if (m_pRouter)
		{
			DWORD dwSnid = ((CLine*)GetParent())->GetSnid();

			TCHAR Buffer[20];
			ultoa(dwSnid,Buffer,10);
			CString strSnid(Buffer);
			m_pRouter->RemoveRoutingAlias(m_strDeviceName,strSnid);
			m_pRouter->SetParameters();
		}
		// remove the LAPB & X25 sub keys.
		RegDelKey(m_hKey,DXB_REGKEY_LAPB);

		// For now the following line of code should not be called.
		// The INF file needs to read the Alias Value from the X25
		// registry key to remove the aliases from the WAN adapter.
		// The INF will then remove the key. In the future, as we 
		// move to NT5.0 this line of code should be called.  The
		// WAN adapter will be updated by this the GUI.
	//	RegDelKey(m_hKey,DXB_REGKEY_X25);
		AffirmThrow(CProtocol::RemoveParameters(fRemoveKey));
		fSuccess = TRUE;
	}
	catch (CAffirmException ae)
	{
	}

	return fSuccess;
}

BOOL CProtocolX25::AddWizardPages(CConfigWizSheet * const pSheet)
{
	BOOL bSuccess = FALSE;
	try
	{
		AffirmThrow(pSheet != NULL);
		m_pwsSheet = pSheet;
		AffirmThrow(AddWizLapbPage());
		bSuccess = TRUE;
	}
	catch (CAffirmException ae)
	{
	}
	return bSuccess;
}

BOOL CProtocolX25::NextWizardPage(int const State)
{
	BOOL bSuccess = FALSE;
	try
	{
		switch(State)
		{
		case WP_LAPBSEQUENCE:
			// extract LAPB sequence data
			GetInfoFromWizLapbPage();
			AffirmThrow(AddWizGeneralPage());
			break;
		case WP_X25GENERAL:
			// extract General Page information
			GetInfoFromWizGeneralPage();
			AffirmThrow(AddWizChannelPage());
			break;
		case WP_X25CHANNELS:
			{
			// extract Channel Page information
			GetInfoFromWizChannelPage();
			// call the service to add its pages
			for (int i=0;i<GetChildCount();i++)
				AffirmThrow(m_apChildren[i]->AddWizardPages(m_pwsSheet));
			}
			break;

		default: 
			AffirmThrow(FALSE);
			break;
		}
		bSuccess = TRUE;
	}
	catch(CAffirmException ae)
	{
	}

	return bSuccess;
}

// router madness::
// We want the router to show up in the display. So if the router has been
// created we add it to our child array. Then call the base class method. And
// then we remove it from our child array. We only store the router pointer in
// the very first instance of the protocol class.
BOOL CProtocolX25::BuildDisplayTree(CTreeNode * const pNode)
{
	BOOL bSuccess = FALSE;
	try
	{
		BOOL bRouterAdded = FALSE;
		AffirmThrow(pNode != NULL);
		if (m_pRouter)
		{
			if (m_pInstance == NULL)
				m_pInstance = this;
			if (this == m_pInstance)
			{
				m_apChildren.Add(m_pRouter);
				bRouterAdded = TRUE;
		   }
		}

      // The services under X.25 Protocol may or may not add a display node
      // Account for these (don't throw if a child doesn't add)
      pNode->SetDisplayName(GetDisplayName());
      pNode->SetConfigObject(this);
      for (int i = 0; i < m_apChildren.GetSize(); i++)
      {
         CTreeNode Node;
         AffirmThrow(m_apChildren[i] != NULL);
         if(m_apChildren[i]->BuildDisplayTree(&Node))
            pNode->AddBranch(Node);
      }

      if (bRouterAdded)
		{
			INT_PTR count = GetChildCount()-1;
			m_apChildren.RemoveAt(count);
		}
		bSuccess = TRUE;
	}
	catch(CAffirmException ae)
	{
	}

	return bSuccess;
}

#define CHOICE_LAPB_MOD8	0
#define CHOICE_LAPB_MOD128	1
BOOL CProtocolX25::AddWizLapbPage()
{
	BOOL bSuccess = FALSE;
	try
	{
		// add the LAPB page
		if (!m_pwpLapbPage)
		{
			CString strTitle,strInstructions;
			strTitle.LoadString(IDS_WIZLAPBTITLE);
			strInstructions.LoadString(IDS_WIZLAPBINS);
			m_pwpLapbPage = new CWizPageRadioButtons(this,WP_LAPBSEQUENCE,strTitle,strInstructions);
			AffirmThrow(m_pwpLapbPage != NULL);
			m_pwpLapbPage->SetHelpID(IDH_WIZ_LAPBPAGE);
		}	
		
		CStringArray astrValues;
		CString strTemp((LPCTSTR)IDS_LAPBMOD8);
		astrValues.SetAtGrow(CHOICE_LAPB_MOD8,strTemp);

		strTemp.LoadString(IDS_LAPBMOD128);
		astrValues.SetAtGrow(CHOICE_LAPB_MOD128,strTemp);

		int choice = CHOICE_LAPB_MOD8;
		switch(m_X25.ll_class)
		{
			case LC_LAPBDCE :	
			case LC_LAPBDTE :	
				break;
			case LC_LAPBXDCE :	
			case LC_LAPBXDTE :	
				choice = CHOICE_LAPB_MOD128; break;
			default: AffirmThrow(FALSE);
		}
		m_pwpLapbPage->SetValues(astrValues,choice);
		m_pwsSheet->InsertPage(m_pwpLapbPage);
		bSuccess = TRUE;
	}
	catch(CAffirmException ae)
	{
	}

	return bSuccess;
}

// extract information from LapbWizard page
void CProtocolX25::GetInfoFromWizLapbPage()
{
	DWORD LLClass = 0;

	int choice = m_pwpLapbPage->GetChoice();
	switch(m_X25.L3PLPMODE) {
		case L3PLPMODE_DCE: 
			LLClass = (choice == CHOICE_LAPB_MOD8) ? LC_LAPBDCE : LC_LAPBXDCE;
			break;
		case L3PLPMODE_DTE: 
		case L3PLPMODE_DXE: 
			LLClass = (choice == CHOICE_LAPB_MOD8) ? LC_LAPBDTE : LC_LAPBXDTE;
			break;
		}

	m_X25.ll_class = LLClass;	

}

// Add the General X.25 page where user provides, Mode,Version and local address
// info
BOOL CProtocolX25::AddWizGeneralPage()
{
	BOOL bSuccess = FALSE;
	try
	{
		if (!m_pwpGeneralPage)
		{
			m_pwpGeneralPage = new CX25General(this, WP_X25GENERAL, &m_WorkingX25);
			AffirmThrow(m_pwpGeneralPage != NULL);
		}
		SetX25LAPBConfig();
		m_pwsSheet->InsertPage(m_pwpGeneralPage);
		bSuccess = TRUE;
	}
	catch(CAffirmException ae)
	{
	}

	return bSuccess;
}

void CProtocolX25::GetInfoFromWizGeneralPage()
{
	GetX25LAPBConfig();
	CreateRouter();
}

// Add the channel page where user can provide PVC/SVC information
BOOL CProtocolX25::AddWizChannelPage()
{
	BOOL bSuccess = FALSE;
	try
	{
		SetX25LAPBConfig();
		if (!m_pwpChannelPage)
		{
			m_pwpChannelPage = new CX25Channel(this,WP_X25CHANNELS, &m_WorkingX25);
			AffirmThrow(m_pwpChannelPage != NULL);
		}
		m_pwpChannelPage->m_nPortLimit = GetPortLimit();
		m_pwsSheet->InsertPage(m_pwpChannelPage);
		bSuccess = TRUE;
	}
	catch(CAffirmException ae)
	{
	}

	return bSuccess;
}

// retrieve information from the ChannelPage
void CProtocolX25::GetInfoFromWizChannelPage()
{
	GetX25LAPBConfig();
	CreateRouter();
	m_apChildren[0]->ParentUpdate();
}


BOOL CProtocolX25::DoProperties()
{
	BOOL bSuccess = FALSE;
	try
	{
		SetX25LAPBConfig();

		CPropertySheet sheet(IDS_X25CONFIG);
		sheet.EnableStackedTabs(FALSE);

      TRACE("CProtocolX25::DoProperties:Instantiating Pages\n");

      CLAPB m_LAPBPage(&m_WorkingLAPB, &m_WorkingX25);
      CLAPBNetwork m_LAPBNetwork(&m_WorkingLAPB);
      CX25General m_General(&m_WorkingX25);
      CX25Channel m_Channel(&m_WorkingX25);
      CX25PacketInfo m_PacketInfo(&m_WorkingX25);
      CX25SubModes m_SubModes(&m_WorkingX25);
      CX25SNModes m_SNModes(&m_WorkingX25);
      CX25ThroughPutClass m_TPutClass(&m_WorkingX25);
      CX25International m_International(&m_WorkingX25);
      CX25Timer m_Timer(&m_WorkingX25);
      CX25Counters m_Counters(&m_WorkingX25);


		// ****************************************************
		// ATTENTION:  The order in which the following 
		// property pages are added is extremely important
		// and should not be changed. Especially the first
		// 2 entries. If for some reason the order needs to 
		// changed, make sure to make the appropriate change
		// in X25CFG.CPP within the DDX routines for CX25General
		// and CX25Channel
		// *****************************************************
      TRACE("CProtocolX25::DoProperties:Adding Pages\n");

		sheet.AddPage(&m_General);
		sheet.AddPage(&m_Channel);
		// its ok to mix up the order here
		sheet.AddPage(&m_PacketInfo);
		sheet.AddPage(&m_LAPBPage);
		sheet.AddPage(&m_LAPBNetwork);
		sheet.AddPage(&m_SubModes);
		sheet.AddPage(&m_SNModes);
		sheet.AddPage(&m_TPutClass);
		sheet.AddPage(&m_International);
		sheet.AddPage(&m_Timer);
		sheet.AddPage(&m_Counters);

		// for the channels page set the upper end limit of # of channels allowed
		m_Channel.m_nPortLimit = GetPortLimit();
		
      TRACE("CProtocolX25::DoProperties:Calling DoModal()\n");
		if (sheet.DoModal() == IDOK)
		{
			// copy back the modified data
			GetX25LAPBConfig();
			// inform the child service that stuff has changed. Its going to 
			// turn around and query information from us
			m_apChildren[0]->ParentUpdate();
			CreateRouter();

			bSuccess = TRUE;
		}
	}
	catch(CAffirmException ae)
	{
	}

	return bSuccess;
}

CString CProtocolX25::GetInformationText(void)
{
	CString strInfo;
	int AvailableSVCs;
#if defined NT5
	AvailableSVCs = ((m_cMaxPorts - PVCCount) < CountChannels(SVC)) ? (m_cMaxPorts - PVCCount) : CountChannels(SVC);
#else // #if defined NT5
	AvailableSVCs = ((m_cMaxPorts - CProtocolX25::PVCCount) < CountChannels(SVC)) ? (m_cMaxPorts - CProtocolX25::PVCCount) : CountChannels(SVC);
#endif // #if defined NT5

	UINT nstrIDs[] = {IDS_DCE,IDS_DTE,IDS_DXE};
	CString strL3PLPMODE((LPCTSTR)nstrIDs[m_X25.L3PLPMODE]);
	CString strReverseChg((m_X25.SUB_MODES & SUB_REVCHARGE)?(LPCTSTR)IDS_ACCEPT:(LPCTSTR)IDS_REFUSE);
	strInfo.Format(IDS_X25INFO_FMT,
					strL3PLPMODE,
#if defined NT5
					PVCCount,
#else // #if defined NT5
					CProtocolX25::PVCCount,
#endif // #if defined NT5
					AvailableSVCs,
					strReverseChg);

	return strInfo;
}

// return the line speed associated with this protocol.
DWORD CProtocolX25::GetLineSpeed() const
{
	return m_dwLineSpeed;
}
// Decide if another PVC can be added on this protocol. The protocol may run
// on N different lines but over the entire adapter, it can only support 
// MAXPVC pvc's. This count is further clamped by ports available on the adapter
BOOL CProtocolX25::AllocPVC()
{
	BOOL bSuccess = FALSE;
	int nErrmsgPorts = m_cMaxPorts;
	try
	{
		AffirmThrow(m_X25.LPC != 0);
		// are we within our MaxPorts limit
#if defined NT5
		if (PVCCount < m_cMaxPorts)
#else // #if defined NT5
		if (CProtocolX25::PVCCount < m_cMaxPorts)
#endif // #if defined NT5

		{
			// get the total # of PVC's configured for this instance of the protocol
			// by the getting # of children(ports) or our child service
			INT_PTR nPortsConfigured = m_apChildren[0]->GetChildCount();
			// first make sure that we are within the defined PVC range 
			// for this instance
			nErrmsgPorts = (m_X25.HPC - m_X25.LPC + 1);
			if (nPortsConfigured < (m_X25.HPC - m_X25.LPC + 1))
			{
#if defined NT5
					PVCCount++;
#else // #if defined NT5
					CProtocolX25::PVCCount++;
#endif // #if defined NT5
					bSuccess = TRUE;
				}
			}
		}
	catch(CAffirmException ae)
	{
	}
	if (!bSuccess)
	{
		CString strMsgFmt((LPCTSTR)IDS_VCLIMIT);
		CString strErrMsg;
		strErrMsg.Format(strMsgFmt,nErrmsgPorts);
		AfxMessageBox(strErrMsg);
	}

	return bSuccess;
}

void CProtocolX25::DeAllocPVC()
{
#if defined NT5
	ASSERT(PVCCount > 0);
	PVCCount--;
#else // #if defined NT5
	ASSERT(CProtocolX25::PVCCount > 0);
	CProtocolX25::PVCCount--;
#endif // #if defined NT5
}


// Get current window size
DWORD CProtocolX25::GetWindowSize() const
{
	return((m_X25.THISGFI==G_8)? GFI_G8_WINDOWSIZE:GFI_G128_WINDOWSIZE);
}

// return the starting PVC channel # and the # of PVC channels configured
void CProtocolX25::GetPVCChannelData(DWORD& start,DWORD& count) const
{
	start = m_X25.LPC;
	count = (m_X25.HPC)?m_X25.HPC - m_X25.LPC+1 : 0;
}

// provide the Remote/Local Window/Packet sizes
void CProtocolX25::GetPacketandWindowData(int& RemWindow,int& RemPacket,int& LocWindow,int& LocPacket) const
{
	RemWindow = m_X25.REMDEFWSIZE;
	RemPacket = m_X25.REMDEFPKTSIZE;
	LocWindow = m_X25.LOCDEFWSIZE;
	LocPacket = m_X25.LOCDEFPKTSIZE;

}

// create the router object. There is one and only one routing object shared
// by all instances of CProtocolX25. 
void CProtocolX25::CreateRouter()
{

#ifndef NT5

	try
	{
		if (m_pRouter == NULL)
		{
			// the router object key is created at the peer level of lines/services
			//
			CConfigObject* pObject;
			AffirmThrow(NewConfigObject(&pObject, CConfigObject::ROUTER, 
				DXB_REGVAL_ROUTER_TYPE_WANX, m_hKeyRoot, WAN_ROUTE_REGKEY, this));
			m_pRouter = (CX25Router*)pObject;
		}

		// the SNID parameter passed in to the router needs to be a linenumber
		// The line number is 0 based whereas the SNID is 1 based.

		DWORD dwSnid = ((CLine*)GetParent())->GetSnid();

		TCHAR Buffer[20];
		ultoa(dwSnid,Buffer,10);
		CString strSnid(Buffer);

		m_pRouter->AddAlias(m_strDeviceName,strSnid,m_X25.Alias);
		int svc = CountChannels(SVC);
		m_pRouter->SetAliasNumPorts(m_X25.Alias,svc);
			
		
	}
	catch(CAffirmException ae)
	{
	}

#endif

}



// return a count of SVC's, PVC's or both configured for this protocol.
// the PVC count is really a count of the range and not the actual # of
// PVC's configured.
int CProtocolX25::CountChannels(CHANNELTYPE ctype) 
{
	int pvc = (m_X25.HPC == 0)?0:m_X25.HPC - m_X25.LPC + 1;
	int svc = (m_X25.HIC == 0)?0:m_X25.HIC - m_X25.LIC + 1;
	svc +=	  (m_X25.HOC == 0)?0:m_X25.HOC - m_X25.LOC + 1;
	svc +=	  (m_X25.HTC == 0)?0:m_X25.HTC - m_X25.LTC + 1;
	return((ctype == BOTH)?svc+pvc:((ctype == SVC)?svc:pvc));
}

// overridden method. Called when the protocol has been placed into the trash
// heap. We remove all ports configured as well as set all channel counts to 0.
// This method will be called when the user is switching to some other protocol
// we take the brute force approach which requires the user if reselecting this
// protocol again, to reconfigure all valid parameters.
// (The other apporach is to delete the PVC's but restore them back - as many 
//  as possible if the protocol is reselected.But how often does the user really
//  does this operation)
void CProtocolX25::ObjectToTrash(void)
{
	if (m_pRouter)
	{
		DWORD dwSnid = ((CLine*)GetParent())->GetSnid();

		TCHAR Buffer[20];
		ultoa(dwSnid,Buffer,10);
		CString strSnid(Buffer);
		m_pRouter->RemoveRoutingAlias(m_strDeviceName,strSnid);
	}

	if (this == m_pInstance)
		m_pInstance = NULL;

	// delete all ports that are configured on this protocol
	for(int i=0;i<GetChildCount();i++)
	{
		CConfigObject* pChild = GetChild(i);
		int grandchildren = (int)pChild->GetChildCount();
		// need to remove all ports configured on this service.
		// doing a DeleteChild() will reduce the array size by 1 
		// for each call. If we work up to increasing indices for GetChild
		// that will break. e.g. 2 ports (0,1). Do a get(0)/delete. Now size of
		// array is 1. Doing a get(1) will break since there is only 1 child 
		// so work backwards from higher index to lower. This will keep index
		// in sync with # of entries in array

		for(int j=0;j<grandchildren;j++)
			pChild->DeleteChild(pChild->GetChild(grandchildren-(j+1)));
	}
	// set all our channel counts to 0 in case we bring this protocol back
	// from trash 
	m_X25.LTC = DXB_REGVAL_X25_LTC_DEFAULT;
	m_X25.LOC = DXB_REGVAL_X25_LOC_DEFAULT;
	m_X25.LIC = DXB_REGVAL_X25_LIC_DEFAULT;
	m_X25.LPC = DXB_REGVAL_X25_LPC_DEFAULT;
	m_X25.HTC = DXB_REGVAL_X25_HTC_DEFAULT;
	m_X25.HOC = DXB_REGVAL_X25_HOC_DEFAULT;
	m_X25.HIC = DXB_REGVAL_X25_HIC_DEFAULT;
	m_X25.HPC = DXB_REGVAL_X25_HPC_DEFAULT;

}

// overridden method. Called when the protocol has been assigned back to the parent
// from the trash list
void CProtocolX25::ObjectFromTrash(void)
{
	CreateRouter();
}

//  total # of channels defined (SVC+PVC)
//  NOTE: The # of PVC's configured can be less than total # of PVC's
// defined
INT_PTR CProtocolX25::GetConfiguredPorts()
{
	return CountChannels(BOTH);
}

// returns an upper limit which is the max # of ports that can be configured
// for this instance of the protocol. This limit would include both PVC & SVC's
int CProtocolX25::GetPortLimit()
{
		CAdapter* pAdapter = (CAdapter*)(GetParent()->GetParent());
		ASSERT(pAdapter != NULL);
		int nLimit = (int)pAdapter->GetAdapterMaxPorts();
		// get all other configured ports except for what this instance owns
		nLimit -= (int)( pAdapter->GetConfiguredPorts() - GetConfiguredPorts());
		if (nLimit > m_cMaxPorts)
			nLimit = m_cMaxPorts;
		return nLimit;
}