/*++
*******************************************************************************
* 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				*
*																										*
*******************************************************************************

Module Name:

   dxbx25.c

Abstract:

   X25 specific initialization routines.

Author:

   Michael Zarns

--*/
#include "digidxb.h"
#pragma hdrstop
#include "ll_proto.h"
#include "ll_control.h"
#include "x25_proto.h"
#include "x25_control.h"
#include "dxbreg.h"
#include "x25reg.h"

NTSTATUS
dxbLapbSetSnid(
	IN HANDLE hLapb,
	IN ULONG  MuxId,
	IN ULONG  Snid )
/*++

Description:

	Tell Lapb about the snid.

Parameters:

	hLapb
		Handle to previously opened stream to firmware LAPB device.

	MuxId
		Id returned from Link request

	Snid
		SubNetwork ID identifies the port

Return Value:

	STATUS_SUCCESS, or failure status

--*/
{
	NTSTATUS Status;
	ULONG Error;
	struct ll_snioc SetSnid = {0};

	DigiDump( DIGIINITLOUD, ( "DXB!dxbLapbSetSnid: Enter, Snid 0x%x\n", Snid ) );

	SetSnid.lli_type  = LI_SNID;
	SetSnid.lli_snid  = Snid;
	SetSnid.lli_index = MuxId;
   Status = DsIoctl( hLapb, L_SETSNID, &SetSnid, sizeof SetSnid, &Error );

	DigiDump( DIGIINITLOUD, ( "DXB!dxbLapbSetSnid: Leave, Status 0x%x, Error 0x%x\n", Status, Error ) );
	return Status;
}


NTSTATUS
dxbLapbTune(
	IN PDXB_DEVICE_EXTENSION pExt,
	IN HANDLE                hKeyLine,
	IN USHORT                iPort,
	IN ULONG                 Snid )
/*++

Description:

	Configure (or Tune) Lapb on the specified port.  Read line configuration from 
	registry and send it down to the adapter.  

Parameters:

	pExt
		Device extension identifying the adapter being configured

	hKeyLine
		Handle to Port registry key containing configuration parameters

	iPort
		Zero-based index of the port being configured

	Snid
		SubNetwork ID identifies the port

Return Value:

	STATUS_SUCCESS or failure status.

--*/
{
	NTSTATUS Status;
	struct lapb_tnioc Tune = {0};
	HANDLE hKeyLapb;
	ULONG Error = 0;
	HANDLE hStream;

	DigiDump( DIGIINITLOUD, ( "DXB!dxbLapbTune: Enter, device %S, Port 0x%x\n", pExt->Name.Buffer, iPort ) );

	Tune.lli_type = LI_LAPBTUNE;
	Tune.lli_snid = Snid;

	Status = DigiRegOpenSubkey( &hKeyLapb, hKeyLine, DXB_REGKEY_LAPB );
	if ( NT_SUCCESS( Status ) )
	{
		Status = DigiRegQueryDword( hKeyLapb, DXB_REGVAL_LAPB_N2, &Tune.lapb_tune.N2, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyLapb, DXB_REGVAL_LAPB_T1, &Tune.lapb_tune.T1, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyLapb, DXB_REGVAL_LAPB_TPF, &Tune.lapb_tune.Tpf, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyLapb, DXB_REGVAL_LAPB_TREJ, &Tune.lapb_tune.Trej, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyLapb, DXB_REGVAL_LAPB_TBUSY, &Tune.lapb_tune.Tbusy, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyLapb, DXB_REGVAL_LAPB_TIDLE, &Tune.lapb_tune.Tidle, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyLapb, DXB_REGVAL_LAPB_ACK_DELAY, &Tune.lapb_tune.ack_delay, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyLapb, DXB_REGVAL_LAPB_NOTACK_MAX, &Tune.lapb_tune.notack_max, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyLapb, DXB_REGVAL_LAPB_TX_WINDOW, &Tune.lapb_tune.tx_window, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyLapb, DXB_REGVAL_LAPB_TX_PROBE, &Tune.lapb_tune.tx_probe, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyLapb, DXB_REGVAL_LAPB_MAX_I_LEN, &Tune.lapb_tune.max_I_len, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyLapb, DXB_REGVAL_LAPB_LLCONFORM, &Tune.lapb_tune.llconform, DigiRegFlagRequired, 0 );
		DigiRegCloseKey( hKeyLapb );
	}

	Status = DsOpen( pExt->hDsDevice, "LAPB", NULL, NULL, 0, &hStream, &Error );
	if ( NT_SUCCESS( Status ) )
	{
	   DigiDump( DIGICONFIG, ( "DXB: Lapb line config, line %d:\n"
		                       "   lli_type   = 0x%x\n"
		                       "   lli_snid   = 0x%x\n"
	                          "   N2         = 0x%x\n"
	                          "   T1         = 0x%x\n"
	                          "   Tpf        = 0x%x\n"
	                          "   Trej       = 0x%x\n"
	                          "   Tbusy      = 0x%x\n"
	                          "   Tidle      = 0x%x\n"
	                          "   ack_delay  = 0x%x\n"
	                          "   notack_max = 0x%x\n"
	                          "   tx_window  = 0x%x\n"
	                          "   tx_probe   = 0x%x\n"
	                          "   max_I_len  = 0x%x\n"
	                          "   llconform  = 0x%x\n",
							  iPort,
	                          Tune.lli_type,
	                          Tune.lli_snid,
	                          Tune.lapb_tune.N2,
	                          Tune.lapb_tune.T1,
	                          Tune.lapb_tune.Tpf,
	                          Tune.lapb_tune.Trej,
	                          Tune.lapb_tune.Tbusy,
	                          Tune.lapb_tune.Tidle,
	                          Tune.lapb_tune.ack_delay,
	                          Tune.lapb_tune.notack_max,
	                          Tune.lapb_tune.tx_window,
	                          Tune.lapb_tune.tx_probe,
	                          Tune.lapb_tune.max_I_len,
	                          Tune.lapb_tune.llconform ) );
		
		Status = DsIoctl( hStream, L_SETTUNE, &Tune, sizeof Tune, &Error );
		if ( NT_ERROR( Status ) )
		{
			DigiDump( DIGIERROR, ( "Dxb!LapbTune: DsIoctl failed, Status 0x%x, Error 0x%x\n", Status, Error ) );
		}

		(void)DsClose( hStream );
	}

	DigiDump( DIGIINITLOUD, ( "DXB!dxbLapbTune: Leave, Status 0x%x\n", Status ) );
	return Status;
}


NTSTATUS
dxbX25SetSnid(
	IN PDXB_DEVICE_EXTENSION pExt,
	IN ULONG                 MuxId,
	IN ULONG                 Snid )
/*++

Description:

	Sends the adapter an FRI_SETSNID ioctl.

Parameters:

	pExt
		Device extension defining adapter being configured

	MuxId
		Id returned from Link request

	Snid
		SubNetwork ID identifies the port

Return Value:

	STATUS_SUCCESS, or failure status

--*/
{
	NTSTATUS Status;
	FRI_SETSNID_t SetSnid = {0};
	ULONG Error;
	HANDLE hStream;

	DigiDump( DIGIINITLOUD, ( "DXB!dxbX25SetSnid: Enter, device %S, Snid 0x%x\n", pExt->Name.Buffer, Snid ) );

	SetSnid.fri_snid = Snid;
	SetSnid.fri_index = MuxId;

	Status = DsOpen( pExt->hDsDevice, "FR", NULL, NULL, 0, &hStream, &Error );
	if ( NT_ERROR( Status ) )
		goto Exit;

	Status = DsIoctl( hStream, FRI_SETSNID, &SetSnid, sizeof SetSnid, &Error );

	(void)DsClose( hStream );

Exit:
	DigiDump( DIGIINITLOUD, ( "DXB!dxbX25SetSnid: Leave, Status 0x%x\n", Status ) );
	return Status;
}


NTSTATUS
dxbX25SnIdent(
	IN PDXB_DEVICE_EXTENSION pExt,
	IN HANDLE                hKeyLine,
	IN ULONG                 MuxId,
	IN ULONG                 Snid,
	IN HANDLE				 hStream )
/*++

Description:

	Configure (or Tune) X25 on the specified port.  Read line configuration from 
	registry and send it down to the adapter.  

Parameters:

	pExt
		Device extension identifying the adapter being configured

	hKeyLine
		Handle to previously opened Line registry key

	MuxId
		Id returned from Link request

	Snid
		SubNetwork ID to be assigned to this port

Return Value:

	STATUS_SUCCESS or failure status.

--*/
{
	NTSTATUS Status;
	struct xll_reg SnIdent = {0};
	ULONG Error;
	HANDLE hKeyX25;


	DigiDump( DIGIINITLOUD, ( "DXB!dxbX25SnIdent: device %S, Snid 0x%x, MuxId 0x%x\n", pExt->Name.Buffer, Snid, MuxId ) );

	SnIdent.lmuxid               = MuxId;
	SnIdent.lreg.ll_type         = LL_REG;
	SnIdent.lreg.ll_snid         = Snid;
	SnIdent.lreg.ll_normalSAP    = 0x7E;
	SnIdent.lreg.ll_loopbackSAP  = 0x70;

	Status = DigiRegOpenSubkey( &hKeyX25, hKeyLine, DXB_REGKEY_X25 );
	if ( NT_SUCCESS( Status ) )
	{
		Status = DigiRegQueryDword( hKeyX25, DXB_REGVAL_X25_LLCLASS, &SnIdent.lreg.ll_class, DigiRegFlagRequired, 0 );
		DigiRegCloseKey( hKeyX25 );
	}

/*
	if ( NT_SUCCESS( Status ) )
		Status = DsOpen( pExt->hDsDevice, "X250", NULL, NULL, 0, &hStream, &Error );
*/
	if ( NT_SUCCESS( Status ) )
	{
		Status = DsIoctl( hStream, N_snident, &SnIdent, sizeof SnIdent, &Error );
//		(void)DsClose( hStream );
		if ( NT_ERROR( Status ) )
		{
			DigiDump( DIGIERROR, ( "Dxb!X25SnIdent: DsIoctl failed, Status 0x%x, Error 0x%x\n", Status, Error ) );
		}
	}

	DigiDump( DIGIINITLOUD, ( "DXB!dxbX25SnIdent: Leave, Status 0x%x\n", Status ) );
	return Status;
}


NTSTATUS
dxbX25Tune(
	IN PDXB_DEVICE_EXTENSION pExt,
	IN HANDLE                hKeyLine,
	IN USHORT                iPort,
	IN ULONG                 Snid ,
	IN	HANDLE				 hStream)
/*++

Description:

	Configure (or Tune) X25 on the specified port.  Read line configuration from 
	registry and send it down to the adapter.  

Parameters:

	pExt
		Device extension identifying the adapter being configured

	hKeyLine
		Handle to Port registry key containing configuration parameters

	iPort
		Zero-based index of the port being configured

	Snid
		SubNetwork ID identifies the port

Return Value:

	STATUS_SUCCESS or failure status.

--*/
{
	NTSTATUS Status;
	struct wlcfg Tune = {0};
	HANDLE hKeyX25;
	ULONG Error = 0;
	unsigned int i = 0;

	DigiDump( DIGIINITLOUD, ( "DXB!dxbX25Tune: Enter, device %S, Port 0x%x\n", pExt->Name.Buffer, iPort ) );

	Tune.U_SN_ID = Snid;
	Status = DigiRegOpenSubkey( &hKeyX25, hKeyLine, DXB_REGKEY_X25 );
	if ( NT_SUCCESS( Status ) )
	{
		Status = DigiRegQueryDword( hKeyX25, L"Net_Mode", &Tune.NET_MODE, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"X25_VSN", &Tune.X25_VSN, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"L3PLPMODE", &Tune.L3PLPMODE, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"LPC", &Tune.LPC, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"HPC", &Tune.HPC, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"LIC", &Tune.LIC, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"HIC", &Tune.HIC, DigiRegFlagRequired, 0 );
		if (NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"LTC", &Tune.LTC, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"HTC", &Tune.HTC, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"LOC", &Tune.LOC, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"HOC", &Tune.HOC, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"THISGFI", &Tune.THISGFI, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"LOCMAXPKTSIZE", &Tune.LOCMAXPKTSIZE, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"REMMAXPKTSIZE", &Tune.REMMAXPKTSIZE, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"LOCDEFPKTSIZE", &Tune.LOCDEFPKTSIZE, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"REMDEFPKTSIZE", &Tune.REMDEFPKTSIZE, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"LOCMAXWSIZE", &Tune.LOCMAXWSIZE, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"REMMAXWSIZE", &Tune.REMMAXWSIZE, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"LOCDEFWSIZE", &Tune.LOCDEFWSIZE, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"REMDEFWSIZE", &Tune.REMDEFWSIZE, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"MAXNSDULEN", &Tune.MAXNSDULEN, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"ACKDELAY", &Tune.ACKDELAY, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"T20value", &Tune.T20value, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"T21value", &Tune.T21value, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"T22value", &Tune.T22value, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"T23value", &Tune.T23value, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"Tvalue", &Tune.Tvalue, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"T25value", &Tune.T25value, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"T26value", &Tune.T26value, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"idlevalue", &Tune.idlevalue, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"connectvalue", &Tune.connectvalue, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"R20value", &Tune.R20value, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"R22value", &Tune.R22value, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"R23value", &Tune.R23value, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"localdelay", &Tune.localdelay, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"accessdelay", &Tune.accessdelay, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"locmaxthclass", &Tune.locmaxthclass, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"remmaxthclass", &Tune.remmaxthclass, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"locdefthclass", &Tune.locdefthclass, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"remdefthclass", &Tune.remdefthclass, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"locminthclass", &Tune.locminthclass, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"remminthclass", &Tune.remminthclass, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"CUG_CONTROL", &Tune.CUG_CONTROL, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"SUB_MODES", &Tune.SUB_MODES, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"SNMODES", &Tune.psdn_local.SNMODES, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"intl_addr_recogn", &Tune.psdn_local.intl_addr_recogn, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"intl_prioritised", &Tune.psdn_local.intl_prioritised, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"dnic1", &Tune.psdn_local.dnic1, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"dnic2", &Tune.psdn_local.dnic2, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"prty_encode_control", &Tune.psdn_local.prty_encode_control, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"prty_pkt_forced_value", &Tune.psdn_local.prty_pkt_forced_value, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"src_addr_control", &Tune.psdn_local.src_addr_control, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"dbit_control",  &Tune.psdn_local.dbit_control, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"thclass_neg_to_def", &Tune.psdn_local.thclass_neg_to_def, DigiRegFlagRequired, 0 );
		if ( NT_SUCCESS( Status ) )
			Status = DigiRegQueryDword( hKeyX25, L"thclass_type", &Tune.psdn_local.thclass_type, DigiRegFlagRequired, 0 );

		Tune.local_address.lsap_add[0] = (UCHAR)( Snid );
		Tune.local_address.lsap_add[1] = (UCHAR)( Snid >> 8 );
		Tune.local_address.lsap_len = 4; 

      {
         UNICODE_STRING tempUnicode = {0};
		   if ( NT_SUCCESS( Status ) )
			   Status = DigiRegQuerySz( hKeyX25, L"lsap_address", &tempUnicode, DigiRegFlagRequired, 0 );
		   if (  NT_SUCCESS( Status ) )
		   {
			   
			   PUCHAR lsapaddr		;
			   ULONG len = tempUnicode.Length / sizeof (WCHAR) ;
			   UCHAR digit;
			   PWCHAR pwData = tempUnicode.Buffer;

			   lsapaddr = Tune.local_address.lsap_add ;

			   for(i=0; i<len; ++i)
			   {
				   digit = *pwData++ - '0' ;
				   if (i & 1)
					   *lsapaddr++ |= digit;
				   else
					   *lsapaddr = digit << 4;
			   }

		      Tune.local_address.lsap_len = len;	
		   }						
         if ( tempUnicode.Buffer )
			   DigiRegFreeString( &tempUnicode );
      }

      DigiRegCloseKey( hKeyX25 );
	}

	if 	 ( NT_SUCCESS( Status ) )
	{
		Tune.NPCchannels = Tune.HPC - Tune.LPC + 1;
		Tune.NICchannels = Tune.HIC - Tune.LIC + 1;
		Tune.NTCchannels = Tune.HTC - Tune.LTC + 1;
		Tune.NOCchannels = Tune.HOC - Tune.LOC + 1;
		Tune.Nochnls = Tune.NPCchannels + Tune.NICchannels +
                                 Tune.NTCchannels +
                                 Tune.NOCchannels;
	}

	if ( NT_SUCCESS( Status ) )
	{
	   DigiDump( DIGICONFIG, ( "DXB!X25Tune: X25 line config, line %d:\n"
		                       "   U_SN_ID   = 0x%x\n"
		                       "   NET_MODE  = 0x%x\n"
		                       "   X25_VSN   = 0x%x\n"
		                       "   L3PLPMODE = 0x%x\n"
		                       "   LPC       = 0x%x\n"
									  // TODO: Dump the rest here!
								"   HPC = %u\n"
								"   LIC = %u\n"
								"   HIC = %u\n"
	                          "   LTC = %u\n"
    	                      "   HTC = %u\n"
        	                  "   LOC = %u\n"
            	              "   HOC = %u\n"
                	          "   NPCchannels = %u\n"
                    	      "   NICchannels = %u\n"
                        	  "   NTCchannels = %u\n"
	                          "   NOCchannels = %u\n"
    	                      "   Nochnls = %u\n",
        	                  
							  iPort,		
	                          Tune.U_SN_ID,
	                          Tune.NET_MODE,
	                          Tune.X25_VSN,
	                          Tune.L3PLPMODE,
	                          Tune.LPC,
							  Tune.HPC,
                          Tune.LIC,
                          Tune.HIC,
                          Tune.LTC,
                          Tune.HTC,
                          Tune.LOC,
                          Tune.HOC,
                          Tune.NPCchannels,
                          Tune.NICchannels,
                          Tune.NTCchannels,
                          Tune.NOCchannels,
                          Tune.Nochnls
                          

										// TODO: ...and here!
	                          ) );


		DigiDump( DIGICONFIG, ( "DXB!X25Tune: X25 line config, line %d:\n"
		                      "   THISGFI = %u\n"
            	              "   LOCMAXPKTSIZE = %u\n"
                	          "   REMMAXPKTSIZE = %u\n"
                    	      "   LOCDEFPKTSIZE = %u\n"
                        	  "   REMDEFPKTSIZE = %u\n"
	                          "   LOCMAXWSIZE = %u\n"
    	                      "   REMMAXWSIZE = %u\n"
        	                  "   LOCDEFWSIZE = %u\n"
            	              "   REMDEFWSIZE = %u\n"
                	          "   MAXNSDULEN = %u\n"
                    	      "   ACKDELAY = %u\n",

						  iPort,	
                          Tune.THISGFI,
                          Tune.LOCMAXPKTSIZE,
                          Tune.REMMAXPKTSIZE,
                          Tune.LOCDEFPKTSIZE,
                          Tune.REMDEFPKTSIZE,
                          Tune.LOCMAXWSIZE,
                          Tune.REMMAXWSIZE,
                          Tune.LOCDEFWSIZE,
                          Tune.REMDEFWSIZE,
                          Tune.MAXNSDULEN,
                          Tune.ACKDELAY


										// TODO: ...and here!
	                          ) );





DigiDump( DIGICONFIG, ("   T20value = %u\n"
                          "   T21value = %u\n"
                          "   T22value = %u\n"
                          "   T23value = %u\n"
                          "   Tvalue = %u\n"
                          "   T25value = %u\n"
                          "   T26value = %u\n"
                          "   idlevalue = %u\n"
                          "   connectvalue = %u\n"
                          "   R20value = %u\n"
                          "   R22value = %u\n"
                          "   R23value = %u\n"
                          "   localdelay = %u\n"
                          "   accessdelay = %u\n"
                          "   locmaxthclass = %u\n"
                          "   remmaxthclass = %u\n"
                          "   locdefthclass = %u\n"
                          "   remdefthclass = %u\n"
                          "   locminthclass = %u\n"
                          "   remminthclass = %u\n"
                          "   CUG_CONTROL = %u\n"
                          "   SUB_MODES = %u\n",
                          Tune.T20value,
                          Tune.T21value,
                          Tune.T22value,
                          Tune.T23value,
                          Tune.Tvalue,
                          Tune.T25value,
                          Tune.T26value,
                          Tune.idlevalue,
                          Tune.connectvalue,
                          Tune.R20value,
                          Tune.R22value,
                          Tune.R23value,
                          Tune.localdelay,
                          Tune.accessdelay,
                          Tune.locmaxthclass,
                          Tune.remmaxthclass,
                          Tune.locdefthclass,
                          Tune.remdefthclass,
                          Tune.locminthclass,
                          Tune.remminthclass,
                          Tune.CUG_CONTROL,
                          Tune.SUB_MODES) );
   DigiDump( DIGICONFIG, ("   psdn_local.SNMODES = %u\n"
                          "   psdn_local.intl_addr_recogn = %u\n"
                          "   psdn_local.intl_prioritised = %u\n"
                          "   psdn_local.dnic1 = %u\n"
                          "   psdn_local.dnic2 = %u\n"
                          "   psdn_local.prty_encode_control = %u\n"
                          "   psdn_local.prty_pkt_forced_value = %u\n"
                          "   psdn_local.src_addr_control = %u\n"
                          "   psdn_local.dbit_control = %u\n"
                          "   psdn_local.thclass_neg_to_def = %u\n"
                          "   psdn_local.thclass_type = %u\n"
                          "   local_address.lsap_len = %u\n",
                          Tune.psdn_local.SNMODES,
                          Tune.psdn_local.intl_addr_recogn,
                          Tune.psdn_local.intl_prioritised,
                          Tune.psdn_local.dnic1,
                          Tune.psdn_local.dnic2,
                          Tune.psdn_local.prty_encode_control,
                          Tune.psdn_local.prty_pkt_forced_value,
                          Tune.psdn_local.src_addr_control,
                          Tune.psdn_local.dbit_control,
                          Tune.psdn_local.thclass_neg_to_def,
                          Tune.psdn_local.thclass_type,
                          Tune.local_address.lsap_len) );

	if ( Tune.local_address.lsap_len )
	{
		// Display the address
		DigiDump( DIGICONFIG, ("   local_address.lsap_add = ") );
		for( i = 0; (int)i < (Tune.local_address.lsap_len-1)/2; i++ )
		{
		   DigiDump( DIGICONFIG, ("%c-", Tune.local_address.lsap_add[i]) );
		}
		DigiDump( DIGICONFIG, ("%c", Tune.local_address.lsap_add[i]) );

		// Oh yeah, and once more in hex
		DigiDump( DIGICONFIG, ("   (") );
		for( i = 0; (int)i < (Tune.local_address.lsap_len-1)/2; i++ )
		{
		   DigiDump( DIGICONFIG, ("%x-", Tune.local_address.lsap_add[i]) );
		}
		DigiDump( DIGICONFIG, ("%x)\n", Tune.local_address.lsap_add[i]) );
	}

		Status = DsIoctl( hStream, N_snconfig, &Tune, sizeof Tune, &Error );
		if ( NT_ERROR( Status ) )
		{
			DigiDump( DIGIERROR, ( "Dxb!X25Tune: DsIoctl failed, Status 0x%x, Error 0x%x\n", Status, Error ) );
		}
	}

	DigiDump( DIGIINITLOUD, ( "DXB!dxbX25Tune: Leave, Status 0x%x\n", Status ) );
	return Status;
}
