summaryrefslogtreecommitdiffstats
path: root/private/ntos/nbt/vxd/chic.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/nbt/vxd/chic.c1787
1 files changed, 1787 insertions, 0 deletions
diff --git a/private/ntos/nbt/vxd/chic.c b/private/ntos/nbt/vxd/chic.c
new file mode 100644
index 000000000..af3fe87e6
--- /dev/null
+++ b/private/ntos/nbt/vxd/chic.c
@@ -0,0 +1,1787 @@
+/**********************************************************************/
+/** Microsoft Windows **/
+/** Copyright(c) Microsoft Corp., 1994 **/
+/**********************************************************************/
+
+/*
+
+ chic.c
+
+ Contains VxD code that is specific to Chicago
+
+
+ FILE HISTORY:
+ Johnl 14-Mar-1994 Created
+
+*/
+
+#include <nbtprocs.h>
+#include <tdiinfo.h>
+#include <llinfo.h>
+#include <ipinfo.h>
+#include <dhcpinfo.h>
+#include <nbtinfo.h>
+
+#ifdef CHICAGO
+
+//******************* Pageable Routine Declarations ****************
+//
+// any digit 0 to 9 and '.' are legal characters in an ipaddr
+//
+#define IS_IPADDR_CHAR( ch ) ( (ch >= '0' && ch <= '9') || (ch == '.') )
+
+#define MAX_ADAPTER_DESCRIPTION_LENGTH 128
+
+const char szXportName[] = "MSTCP";
+
+//
+// asking ndis to open,read,close for every single parameter slows down
+// bootup: don't open if it's already open
+//
+NDIS_HANDLE GlobalNdisHandle = NULL;
+
+//
+// This flag is set to TRUE when the first adapter is initialized. It
+// indicates that NBT globals (such as node type, scode ID etc) have
+// had the opportunity to be set by DHCP.
+//
+BOOL fGlobalsInitialized = FALSE;
+
+//
+// As each adapter gets added, the Lana offset is added
+//
+UCHAR iLanaOffset = 0;
+
+VOID GetMacAddr( ULONG IpAddress, UCHAR MacAddr[] );
+BOOL StopAllNameQueries( tDEVICECONTEXT *pDeviceContext );
+BOOL CancelAllDelayedEvents( tDEVICECONTEXT *pDeviceContext );
+extern tTIMERQ TimerQ;
+
+BOOL GetNdisParam( LPSTR pszKey,
+ ULONG * pVal,
+ NDIS_PARAMETER_TYPE ParameterType );
+
+
+//******************* Pageable Routine Declarations ****************
+#ifdef ALLOC_PRAGMA
+#pragma CTEMakePageable(PAGE, IPNotification)
+#pragma CTEMakePageable(PAGE, DestroyDeviceObject)
+#pragma CTEMakePageable(PAGE, SaveNameDnsServerAddrs)
+#pragma CTEMakePageable(PAGE, GetDnsServerAddress)
+#pragma CTEMakePageable(PAGE, GetNameServerAddress)
+#pragma CTEMakePageable(PAGE, GetMacAddr)
+#pragma CTEMakePageable(PAGE, VxdReadIniString)
+#pragma CTEMakePageable(PAGE, GetProfileInt)
+#pragma CTEMakePageable(PAGE, VxdOpenNdis)
+#pragma CTEMakePageable(PAGE, GetNdisParam)
+#pragma CTEMakePageable(PAGE, VxdCloseNdis)
+#pragma CTEMakePageable(PAGE, StopAllNameQueries)
+#pragma CTEMakePageable(PAGE, VxdUnload)
+#pragma CTEMakePageable(PAGE, ReleaseNbtConfigMem)
+#endif
+
+
+/*******************************************************************
+
+ NAME: IPNotification
+
+ SYNOPSIS: Called by the IP driver when a new Lana needs to be created
+ or destroyed for an IP address.
+
+ ENTRY: pDevNode - Plug'n'Play context
+ IpAddress - New ip address
+ IpMask - New ip mask
+ fNew - Are we creating or destroying this Lana?
+
+ NOTES: This routine is only used by Chicago
+
+ HISTORY:
+ Johnl 17-Mar-1994 Created
+
+********************************************************************/
+
+TDI_STATUS IPNotification( ULONG IpAddress,
+ ULONG IpMask,
+ PVOID pDevNode,
+ USHORT IPContext,
+ BOOL fNew )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ ULONG IpNS[COUNT_NS_ADDR];
+ ULONG IpDns[COUNT_NS_ADDR];
+ int iLana;
+ UCHAR RequestedLana;
+ int i;
+ int iEmpty;
+ UCHAR PreviousNodeType;
+ UCHAR MacAddr[6];
+
+ CTEPagedCode();
+
+ KdPrint(("IPNotification entered\r\n"));
+
+ if ( !IpAddress )
+ {
+ return TDI_SUCCESS ;
+ }
+
+ if ( fNew )
+ {
+ //
+ // parameters nodetype, scope and bcastaddr are systemwide, not per
+ // adapter: so read only once.
+ //
+ if ( !fGlobalsInitialized )
+ {
+ PreviousNodeType = NodeType;
+
+ //
+ // This will re-read the DHCPable parameters now that we have
+ // a potential DHCP source
+ //
+ VxdOpenNdis();
+ ReadParameters2( pNbtGlobConfig, NULL );
+ VxdCloseNdis();
+
+ if (PreviousNodeType & PROXY)
+ {
+ NodeType |= PROXY;
+ }
+
+
+ fGlobalsInitialized = TRUE;
+ }
+
+ //
+ // Get the name servers for this device context (ip address)
+ //
+ GetNameServerAddress( IpAddress, IpNS);
+
+ //
+ // Get the DNS servers for this device context (ip address)
+ //
+ GetDnsServerAddress( IpAddress, IpDns);
+
+ //
+ // Find a free spot in our Lana table
+ //
+
+ for ( iEmpty = 0; iEmpty < NBT_MAX_LANAS; iEmpty++)
+ {
+ if (LanaTable[iEmpty].pDeviceContext == NULL)
+ goto Found;
+ }
+
+ //
+ // Lana table is full so bail
+ //
+ CDbgPrint(DBGFLAG_ERROR,("IPNotification: LanaTable full\r\n"));
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+Found:
+
+ GetMacAddr( IpAddress, MacAddr );
+
+ status = CreateDeviceObject( pNbtGlobConfig,
+ htonl( IpAddress ),
+ htonl( IpMask ),
+ IpNS[0],
+ IpNS[1],
+ IpDns[0],
+ IpDns[1],
+ MacAddr,
+ 0 );
+ if (status != STATUS_SUCCESS)
+ {
+ CDbgPrint(DBGFLAG_ERROR,("IPNotification: CreateDeviceObject Failed\r\n"));
+ return status;
+ }
+
+ //
+ // We first try and ask for a specific Lana from vnetbios based on
+ // our Lanabase and how many other Lanas we've already added. If
+ // this fails, then we will ask for Any Lana. If the LANABASE
+ // parameter is not specified, then request Any Lana.
+ //
+
+ if ( LanaBase != VXD_ANY_LANA )
+ RequestedLana = LanaBase + iLanaOffset++ ;
+ else
+ RequestedLana = VXD_ANY_LANA;
+
+RetryRegister:
+ if ( (iLana = RegisterLana2( pDevNode, RequestedLana )) == 0xff )
+ {
+ if ( RequestedLana == VXD_ANY_LANA )
+ {
+ //
+ // We couldn't get *any* lanas so bail
+ //
+ CDbgPrint(DBGFLAG_ERROR,("IPNotification: RegisterLana2 Failed\r\n"));
+ DestroyDeviceObject( pNbtGlobConfig, htonl(IpAddress));
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ //
+ // Somebody may already have this Lana so beg for another one
+ //
+ RequestedLana = VXD_ANY_LANA;
+ goto RetryRegister;
+ }
+ }
+
+ KdPrint(("IPNotification: using Lana %d\r\n", iLana ));
+ LanaTable[iEmpty].pDeviceContext =
+ (tDEVICECONTEXT*)pNbtGlobConfig->DeviceContexts.Blink ;
+ LanaTable[iEmpty].pDeviceContext->iLana = iLana;
+
+ //
+ // remove our child (redir, that is!) and reenumerate our devnode
+ // so redir knows we are there!
+ //
+ ReconfigureDevnode( pDevNode );
+ }
+ else
+ {
+ status = DestroyDeviceObject( pNbtGlobConfig,
+ htonl(IpAddress) );
+
+ }
+
+ return status;
+}
+
+/*******************************************************************
+
+ NAME: DestroyDeviceObject
+
+ SYNOPSIS: Destroys the specified device
+
+ ENTRY: pConfig - Global config structure
+ IpAddr - Destroy the adapter with this address
+
+ NOTES: This routine is only used by Chicago
+
+ HISTORY:
+ Johnl 17-Mar-1994 Created
+
+********************************************************************/
+
+NTSTATUS DestroyDeviceObject(
+ tNBTCONFIG *pConfig,
+ ULONG IpAddr
+ )
+{
+ LIST_ENTRY * pEntry;
+ LIST_ENTRY * pHead;
+ tDEVICECONTEXT * pDeviceContext;
+ tDEVICECONTEXT * pTmpDeviceContext;
+ tDEVICECONTEXT * pNextDeviceContext;
+ tCLIENTELE * pClientEle;
+ tADDRESSELE * pAddress;
+ tNAMEADDR * pNameAddr;
+ tCONNECTELE * pConnEle;
+ tLOWERCONNECTION * pLowerConn;
+ PRCV_CONTEXT prcvCont;
+ tRCVELE * pRcvEle ;
+ tTIMERQENTRY * pTimer;
+ COMPLETIONCLIENT pClientCompletion;
+ PVOID Context;
+ tDGRAM_SEND_TRACKING * pTracker;
+ CTELockHandle OldIrq;
+ int i;
+
+
+ CTEPagedCode();
+
+ //
+ // Find which device is going away
+ // Also, find out a device object that is still active: we need that info
+ // to update some of the address ele's.
+ //
+ pDeviceContext = NULL;
+ pNextDeviceContext = NULL;
+
+ for ( pEntry = pConfig->DeviceContexts.Flink;
+ pEntry != &pConfig->DeviceContexts;
+ pEntry = pEntry->Flink )
+ {
+ pTmpDeviceContext = CONTAINING_RECORD( pEntry, tDEVICECONTEXT, Linkage);
+ if ( pTmpDeviceContext->IpAddress == IpAddr )
+ pDeviceContext = pTmpDeviceContext;
+ else
+ pNextDeviceContext = pTmpDeviceContext;
+ }
+
+ if (pDeviceContext == NULL)
+ return STATUS_INVALID_PARAMETER;
+
+ //
+ // don't accept anymore ncbs on this device
+ //
+ pDeviceContext->fDeviceUp = FALSE;
+
+ //
+ // Close all the connections
+ //
+ NbtNewDhcpAddress( pDeviceContext, 0, 0);
+
+ if ( --NbtConfig.AdapterCount == 1)
+ NbtConfig.MultiHomed = FALSE;
+
+ ASSERT(IsListEmpty(&pDeviceContext->LowerConnFreeHead));
+
+ //
+ // if we are destroying the last device then
+ //
+ if ( NbtConfig.AdapterCount == 0)
+ {
+ //
+ // Kill off all of the Receive any from any NCBs
+ //
+ while ( !IsListEmpty( &pDeviceContext->RcvAnyFromAnyHead ))
+ {
+ pEntry = RemoveHeadList( &pDeviceContext->RcvAnyFromAnyHead ) ;
+ prcvCont = CONTAINING_RECORD( pEntry, RCV_CONTEXT, ListEntry ) ;
+ ASSERT( prcvCont->Signature == RCVCONT_SIGN ) ;
+ CTEIoComplete( prcvCont->pNCB, STATUS_NETWORK_NAME_DELETED, 0 ) ;
+ }
+
+ //
+ // Kill off all of the Receive any datagrams from any
+ //
+ while ( !IsListEmpty(&pDeviceContext->RcvDGAnyFromAnyHead))
+ {
+ pEntry = RemoveHeadList( &pDeviceContext->RcvDGAnyFromAnyHead ) ;
+ pRcvEle = CONTAINING_RECORD( pEntry, tRCVELE, Linkage ) ;
+ CTEIoComplete( pRcvEle->pIrp, STATUS_NETWORK_NAME_DELETED, 0 ) ;
+ CTEMemFree( pRcvEle ) ;
+ }
+ }
+
+ //
+ // if any name queries are in progress, stop them now
+ //
+ StopAllNameQueries( pDeviceContext );
+
+ CancelAllDelayedEvents( pDeviceContext );
+
+ //
+ // walk through all names and see if any is being registered on this
+ // device context: if so, stop and complete it!
+ //
+ for (i=0;i < NbtConfig.pLocalHashTbl->lNumBuckets ;i++ )
+ {
+ pHead = &NbtConfig.pLocalHashTbl->Bucket[i];
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
+ pEntry = pEntry->Flink;
+
+ if (pNameAddr->NameTypeState & STATE_RESOLVING)
+ {
+ pTimer = pNameAddr->pTimer;
+
+ //
+ // if the name registration was started for this name on this device
+ // context, stop the timer. (Completion routine will take care of
+ // doing registration on other device contexts if applicable)
+ //
+ if (pTimer)
+ {
+ pTracker = pTimer->Context;
+ ASSERT(pTracker->pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT);
+ if (pTracker->pDeviceContext == pDeviceContext)
+ {
+ ASSERT(pTracker->pNameAddr == pNameAddr)
+
+ pNameAddr->pTimer = NULL;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ StopTimer(pTimer,&pClientCompletion,&Context);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ if (pClientCompletion)
+ {
+ (*pClientCompletion)(Context,STATUS_NETWORK_NAME_DELETED);
+ }
+
+ DbgPrint("DestroyDeviceObject: stopped name reg timer") ;
+ }
+ }
+
+ }
+ }
+ }
+
+
+ //
+ // walk through all the client ele's this device context has and clean
+ // up all the mess this clientele created!
+ //
+ for ( i = 0 ; i <= pDeviceContext->cMaxNames ; i++ )
+ {
+ pClientEle = pDeviceContext->pNameTable[i];
+
+ if ( !pClientEle )
+ continue;
+
+ VxdCleanupAddress( pDeviceContext,
+ NULL,
+ pClientEle,
+ (UCHAR)i,
+ TRUE );
+ }
+
+ //
+ // close all the TDI handles
+ //
+ CloseAddressesWithTransport(pDeviceContext);
+
+ //
+ // if a call was started, but aborted then we could have some memory here!
+ //
+ while (!IsListEmpty(&pDeviceContext->UpConnectionInUse))
+ {
+ pEntry = RemoveHeadList(&pDeviceContext->UpConnectionInUse);
+ pConnEle = CONTAINING_RECORD(pEntry,tCONNECTELE,Linkage);
+ CTEMemFree( pConnEle );
+ }
+
+ while (!IsListEmpty(&pDeviceContext->LowerConnection))
+ {
+ pEntry = RemoveHeadList(&pDeviceContext->LowerConnection);
+ pLowerConn = CONTAINING_RECORD(pEntry,tLOWERCONNECTION,Linkage);
+ CTEMemFree( pLowerConn );
+ }
+
+ //
+ // Remove the device from our Lana table and Vnetbios
+ //
+ for ( i = 0; i < NBT_MAX_LANAS; i++)
+ {
+ if (LanaTable[i].pDeviceContext == pDeviceContext)
+ {
+ DeregisterLana(LanaTable[i].pDeviceContext->iLana);
+ LanaTable[i].pDeviceContext = NULL;
+ KdPrint(("DestroyDeviceObject: deregistered Lana %d\r\n",pDeviceContext->iLana));
+ break;
+ }
+ }
+
+ RemoveEntryList( &pDeviceContext->Linkage);
+
+ //
+ // Walk through the AddressHead list. If any addresses exist and they
+ // point to old device context, put the next device context. Also, update
+ // adapter mask to reflect that this device context is now gone.
+ //
+ KdPrint(("DestroyDeviceObject: setting AddrEle,NameAddr fields\r\n"));
+ pHead = pEntry = &NbtConfig.AddressHead;
+ while ((pEntry = pEntry->Flink) != pHead)
+ {
+ pAddress = CONTAINING_RECORD(pEntry,tADDRESSELE,Linkage);
+ ASSERT (pAddress->Verify == NBT_VERIFY_ADDRESS);
+ if (pAddress->pDeviceContext == pDeviceContext)
+ {
+ pAddress->pDeviceContext = pNextDeviceContext;
+ }
+
+ pAddress->pNameAddr->AdapterMask &= ~pDeviceContext->AdapterNumber;
+ }
+
+ if (pDeviceContext->pNameTable)
+ CTEMemFree( pDeviceContext->pNameTable );
+
+ if (pDeviceContext->pSessionTable)
+ CTEMemFree( pDeviceContext->pSessionTable );
+
+ CTEMemFree( pDeviceContext );
+
+ return STATUS_SUCCESS;
+}
+
+
+/*******************************************************************
+
+ NAME: SaveNameDnsServerAddrs
+
+ SYNOPSIS: Get the name server and dns server addrs from the registry
+ and save it in Nbtconfig. We do this so that when a new
+ adapter comes in or lease gets renewed (particularly the
+ latter), we don't have to go read the registry becuase it
+ may not be safe to do so.
+ This routine will have to be modified if setup ever changes
+ to allow configuration of name/dns servers per lana.
+
+ ENTRY: Nothing
+
+
+ HISTORY:
+ Koti 20-Nov-1994 Created
+
+********************************************************************/
+
+VOID SaveNameDnsServerAddrs( VOID )
+{
+ UCHAR i ;
+ PUCHAR pchSrv = "NameServer$" ;
+ PUCHAR pchDnsSrv = "NameServer" ;
+ PUCHAR pchSrvNum;
+ LPTSTR pchString ;
+ PUCHAR pchCurrent, pchNext;
+ BOOL fOneMore=TRUE;
+ ULONG IpNameServers[COUNT_NS_ADDR];
+
+ CTEPagedCode();
+
+ //
+ // Get Name Server ipaddrs
+ //
+
+ pchSrvNum = pchSrv + 10 ; // to overwrite '$' with 1,2,3 etc.
+
+ for ( i = 0; i < COUNT_NS_ADDR; i++)
+ {
+ IpNameServers[i] = LOOP_BACK;;
+ *pchSrvNum = '1' + i;
+
+ // call GetNdisParam directly so that we don't query dhcp here
+ // if ( !CTEReadIniString( NULL, pchSrv, &pchString ) )
+ //
+ if ( GetNdisParam( pchSrv, (ULONG *)&pchString, NdisParameterString ) )
+ {
+ if ( ConvertDottedDecimalToUlong( pchString, &IpNameServers[i] ))
+ {
+ DbgPrint("SaveNameDnsServerAddrs: bad name srv addr\r\n") ;
+ IpNameServers[i] = LOOP_BACK;
+ }
+ CTEFreeMem( pchString ) ;
+ }
+ }
+
+ //
+ // store the name server ipaddrs (potentially 0 if not defined in registry)
+ //
+ NbtConfig.lRegistryNameServerAddress = IpNameServers[0];
+ NbtConfig.lRegistryBackupServer = IpNameServers[1];
+
+
+ //
+ // Now get Dns Server ipaddrs
+ //
+
+ //
+ // initialize all of them to worst case
+ //
+ for ( i = 0; i < COUNT_NS_ADDR; i++)
+ {
+ IpNameServers[i] = LOOP_BACK;
+ }
+
+
+ // call GetNdisParam directly so that we don't query dhcp here
+ // if ( !CTEReadIniString( NULL, pchDnsSrv, &pchString ) )
+ //
+ if ( GetNdisParam( pchDnsSrv, (ULONG *)&pchString, NdisParameterString ) )
+ {
+ //
+ // we are generating (upto) COUNT_NS_ADDR pointers each pointing to
+ // one ipaddr. The string in system.ini looks like:
+ // NameServer = 11.101.4.26,200.200.200.200,1.2.3.4,1.91.245.10
+ //
+ pchNext = pchCurrent = pchString;
+
+ if ( IS_IPADDR_CHAR(*pchCurrent) ) // make sure at least one ipaddr defnd
+ {
+ i = 0;
+ while( (i < COUNT_NS_ADDR) && fOneMore )
+ {
+ while( IS_IPADDR_CHAR(*pchNext) )
+ pchNext++;
+
+ if ( *pchNext == ',' ) // ',' is the separator between 2 addrs
+ {
+ *pchNext = '\0';
+ pchNext++;
+ }
+ else
+ {
+ fOneMore = FALSE; // reached end of line
+ }
+
+ //
+ // as long as at least the first one ipaddr gets converted properly,
+ // ignore errors in others
+ //
+ if ( ConvertDottedDecimalToUlong( pchCurrent, &IpNameServers[i] ))
+ {
+ DbgPrint("SaveNameDnsServerAddrs: bad dns srv addr\r\n") ;
+ IpNameServers[i] = LOOP_BACK;
+ }
+
+ i++;
+
+ pchCurrent = pchNext; // go, convert the next one
+ }
+ }
+
+ if( pchString != NULL )
+ {
+ CTEFreeMem( pchString ) ;
+ }
+ }
+
+ //
+ // store the dns server ipaddrs (potentially 0 if not defined in registry)
+ //
+ NbtConfig.lRegistryDnsServerAddress = IpNameServers[0];
+ NbtConfig.lRegistryDnsBackupServer = IpNameServers[1];
+
+}
+
+
+/*******************************************************************
+
+ NAME: GetDnsServerAddress
+
+ SYNOPSIS: Gets the DNS server ipaddrs from the registry.
+ Or, if DHCP is installed and the DNS server addresses aren't
+ found, we get them from DHCP
+
+ ENTRY: IpAddr - If we can get from DHCP, get form this address
+ pIpDnsServer - Receives addresses if found (otherwise 0)
+
+ NOTES: This routine is only used by Snowball
+
+ HISTORY:
+ Koti 18-Oct-1994 Created
+
+********************************************************************/
+
+void GetDnsServerAddress( ULONG IpAddr, PULONG pIpDnsServer)
+{
+
+ UCHAR i ;
+ UINT OptId;
+ TDI_STATUS tdistatus ;
+ ULONG Buff[COUNT_NS_ADDR] ;
+ ULONG Size;
+
+ CTEPagedCode();
+
+
+ for ( i = 0; i < COUNT_NS_ADDR; i++)
+ {
+ pIpDnsServer[i] = LOOP_BACK ;
+ }
+
+ pIpDnsServer[0] = NbtConfig.lRegistryDnsServerAddress;
+ pIpDnsServer[1] = NbtConfig.lRegistryDnsBackupServer;
+
+ //
+ // if it was defined in the registry, we are done
+ //
+ if ( pIpDnsServer[0] != LOOP_BACK || pIpDnsServer[1] != LOOP_BACK )
+ {
+ return;
+ }
+
+ //
+ // it was not defined in the registry: try getting them from DHCP
+ //
+ Size = sizeof( Buff ) ;
+
+ OptId = 6; // DNS Option
+
+ tdistatus = DhcpQueryOption( IpAddr,
+ OptId,
+ &Buff,
+ &Size ) ;
+
+ switch ( tdistatus )
+ {
+ case TDI_SUCCESS:
+ case TDI_BUFFER_OVERFLOW: // May be more then one our buffer will hold
+ for ( i = 0; i < COUNT_NS_ADDR; i++ )
+ {
+ if ( Size >= (sizeof(ULONG)*(i+1)))
+ pIpDnsServer[i] = htonl(Buff[i]) ;
+ }
+ break ;
+
+ case TDI_INVALID_PARAMETER: // Option not found
+ break;
+
+ default:
+ ASSERT( FALSE ) ;
+ break ;
+ }
+
+ KdPrint(("GetDnsServerAddress: Primary: %x, backup: %x\r\n",
+ pIpDnsServer[0], pIpDnsServer[1] )) ;
+
+}
+
+
+/*******************************************************************
+
+ NAME: GetNameServerAddress
+
+ SYNOPSIS: Gets the Win server for the specified Lana.
+
+ Or, if DHCP is installed and the Name server addresses aren't
+ found, we get them from DHCP
+
+ ENTRY: IpAddr - If we can get from DHCP, get form this address
+ pIpNameServer - Receives addresses if found (otherwise 0)
+
+ NOTES: This routine is only used by Snowball
+
+ HISTORY:
+ Johnl 21-Oct-1993 Created
+
+********************************************************************/
+
+void GetNameServerAddress( ULONG IpAddr,
+ PULONG pIpNameServer)
+{
+ UCHAR i ;
+ UINT OptId;
+ TDI_STATUS tdistatus ;
+ ULONG Buff[COUNT_NS_ADDR] ;
+ ULONG Size;
+
+ CTEPagedCode();
+
+
+ for ( i = 0; i < COUNT_NS_ADDR; i++)
+ {
+ pIpNameServer[i] = LOOP_BACK ;
+ }
+
+ pIpNameServer[0] = NbtConfig.lRegistryNameServerAddress;
+ pIpNameServer[1] = NbtConfig.lRegistryBackupServer;
+
+ //
+ // if it was defined in the registry, we are done
+ //
+ if ( pIpNameServer[0] != LOOP_BACK || pIpNameServer[1] != LOOP_BACK )
+ {
+ return;
+ }
+
+
+ //
+ // not defined in the registry: try to get it from dhcp
+ //
+
+ OptId = 44; // NBNS Option
+
+ Size = sizeof( Buff ) ;
+
+ tdistatus = DhcpQueryOption( IpAddr,
+ OptId,
+ &Buff,
+ &Size ) ;
+
+ switch ( tdistatus )
+ {
+ case TDI_SUCCESS:
+ case TDI_BUFFER_OVERFLOW: // May be more then one our buffer will hold
+ for ( i = 0; i < COUNT_NS_ADDR; i++ )
+ {
+ if ( Size >= (sizeof(ULONG)*(i+1)))
+ pIpNameServer[i] = htonl(Buff[i]) ;
+ }
+ break ;
+
+ case TDI_INVALID_PARAMETER: // Option not found
+ break ;
+
+ default:
+ ASSERT( FALSE ) ;
+ break ;
+ }
+
+ KdPrint(("GetNameServerAddress: Primary: %x, backup: %x\r\n",
+ pIpNameServer[0], pIpNameServer[1] )) ;
+
+}
+
+
+/*******************************************************************
+
+ NAME: GetMacAddr
+
+ SYNOPSIS: Gets the mac address for the give ipaddr
+
+ ENTRY: IpAddress - the address for which to find mac addr
+ MacAddr - the array where to store mac addr
+
+ HISTORY:
+ Koti 19-Oct-1994 Created
+
+********************************************************************/
+
+VOID GetMacAddr( ULONG IpAddress, UCHAR MacAddr[] )
+{
+
+ TDI_STATUS tdistatus ;
+ int i, j, k ;
+ uchar Context[CONTEXT_SIZE] ;
+ TDIObjectID ID ;
+ TDIEntityID EList[MAX_TDI_ENTITIES] ;
+ ULONG Size ;
+ UINT NumReturned ;
+ NDIS_BUFFER ndisbuff ;
+ IFEntry *ifeAdapterInfo[MAX_TDI_ENTITIES];
+ UINT AdptNum;
+
+ CTEPagedCode();
+
+
+ //
+ // initialize to 0, in case things don't work out
+ //
+ memset( MacAddr, 0, 6 ) ;
+
+ //
+ // The first thing to do is get the list of available entities, and make
+ // sure that there are some interface entities present.
+ //
+ ID.toi_entity.tei_entity = GENERIC_ENTITY;
+ ID.toi_entity.tei_instance = 0;
+ ID.toi_class = INFO_CLASS_GENERIC;
+ ID.toi_type = INFO_TYPE_PROVIDER;
+ ID.toi_id = ENTITY_LIST_ID;
+
+ Size = sizeof(EList);
+ InitNDISBuff( &ndisbuff, &EList, Size, NULL ) ;
+ memset(Context, 0, CONTEXT_SIZE);
+
+ tdistatus = TdiVxdQueryInformationEx( 0,
+ &ID,
+ &ndisbuff,
+ &Size,
+ Context);
+
+ if (tdistatus != TDI_SUCCESS)
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetMacAddr: Querying entity list failed\r\n")) ;
+ return;
+ }
+
+ NumReturned = (uint)Size/sizeof(TDIEntityID);
+
+ AdptNum = 0;
+ //
+ // first find out info about the adapters
+ //
+ for (i = 0; i < NumReturned; i++)
+ {
+ //
+ // if this entity/instance describes an adapter
+ //
+ if ( EList[i].tei_entity == IF_ENTITY )
+ {
+ DWORD isMib;
+
+
+ ID.toi_entity.tei_entity = EList[i].tei_entity ;
+ ID.toi_entity.tei_instance = EList[i].tei_instance;
+ ID.toi_class = INFO_CLASS_GENERIC ;
+ ID.toi_type = INFO_TYPE_PROVIDER;
+ ID.toi_id = ENTITY_TYPE_ID ;
+
+ Size = sizeof( isMib );
+ InitNDISBuff( &ndisbuff, &isMib, Size, NULL ) ;
+ memset(Context, 0, CONTEXT_SIZE);
+ tdistatus = TdiVxdQueryInformationEx( 0,
+ &ID,
+ &ndisbuff,
+ &Size,
+ Context);
+ if ( tdistatus != TDI_SUCCESS )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetMacAddr: Getting isMib failed\r\n")) ;
+ return ;
+ }
+
+ //
+ // Does this entity support MIB
+ //
+ if (isMib != IF_MIB)
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetMacAddr: skipping non-MIB entity\r\n")) ;
+ continue;
+ }
+
+ //
+ // MIB requests supported - query the adapter info
+ //
+
+ Size = sizeof(IFEntry) + MAX_ADAPTER_DESCRIPTION_LENGTH + 1;
+
+ ifeAdapterInfo[AdptNum] = (IFEntry *)CTEAllocInitMem(Size);
+
+ if ( ifeAdapterInfo[AdptNum] == NULL )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetMacAddr: Couldn't allocate AdapterInfo buffer\r\n")) ;
+ for ( k=0; k<AdptNum; k++ )
+ {
+ CTEFreeMem( ifeAdapterInfo[k] ) ;
+ }
+ return;
+ }
+
+ ID.toi_class = INFO_CLASS_PROTOCOL;;
+ ID.toi_id = IF_MIB_STATS_ID;
+
+ Size = sizeof(IFEntry) + MAX_ADAPTER_DESCRIPTION_LENGTH + 1;
+ InitNDISBuff( &ndisbuff, ifeAdapterInfo[AdptNum], Size, NULL ) ;
+ memset(Context, 0, CONTEXT_SIZE);
+ tdistatus = TdiVxdQueryInformationEx( 0,
+ &ID,
+ &ndisbuff,
+ &Size,
+ Context);
+ if ( tdistatus != TDI_SUCCESS )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetMacAddr: Getting IF type failed\r\n")) ;
+ for ( k=0; k<AdptNum; k++ )
+ {
+ CTEFreeMem( ifeAdapterInfo[k] ) ;
+ }
+ return ;
+ }
+
+ AdptNum++;
+ }
+ }
+
+ //
+ // now that we know about the adapters, get the ipaddrs
+ //
+ for (i = 0; i < NumReturned; i++)
+ {
+ if ( EList[i].tei_entity == CL_NL_ENTITY )
+ {
+ IPSNMPInfo IPStats ;
+ IPAddrEntry * pIAE ;
+ ULONG NLType ;
+ ULONG IpNameServer[COUNT_NS_ADDR];
+ ULONG IpDnsServer[COUNT_NS_ADDR];
+
+ //
+ // Does this entity support IP?
+ //
+
+ ID.toi_entity.tei_entity = EList[i].tei_entity ;
+ ID.toi_entity.tei_instance = EList[i].tei_instance;
+ ID.toi_class = INFO_CLASS_GENERIC ;
+ ID.toi_type = INFO_TYPE_PROVIDER;
+ ID.toi_id = ENTITY_TYPE_ID ;
+
+ Size = sizeof( NLType );
+ InitNDISBuff( &ndisbuff, &NLType, Size, NULL ) ;
+ memset(Context, 0, CONTEXT_SIZE);
+ tdistatus = TdiVxdQueryInformationEx( 0,
+ &ID,
+ &ndisbuff,
+ &Size,
+ Context);
+ if ( tdistatus != TDI_SUCCESS )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetMacAddr: Getting NL type failed\r\n")) ;
+ for ( k=0; k<AdptNum; k++ )
+ {
+ CTEFreeMem( ifeAdapterInfo[k] ) ;
+ }
+ return ;
+ }
+
+ if ( NLType != CL_NL_IP )
+ continue ;
+
+ //
+ // We've got an IP driver so get it's address table
+ //
+
+ ID.toi_class = INFO_CLASS_PROTOCOL ;
+ ID.toi_id = IP_MIB_STATS_ID;
+ Size = sizeof(IPStats);
+ InitNDISBuff( &ndisbuff, &IPStats, Size, NULL ) ;
+ memset(Context, 0, CONTEXT_SIZE);
+ tdistatus = TdiVxdQueryInformationEx( 0,
+ &ID,
+ &ndisbuff,
+ &Size,
+ Context);
+ if ( tdistatus != TDI_SUCCESS )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetMacAddr: Getting IPStats failed\r\n")) ;
+ continue ;
+ }
+
+ if ( IPStats.ipsi_numaddr < 1 )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetMacAddr: No IP Addresses installed\r\n")) ;
+ continue ;
+ }
+
+ Size = sizeof(IPAddrEntry) * IPStats.ipsi_numaddr ;
+ if ( !(pIAE = (IPAddrEntry*) CTEAllocInitMem( Size )) )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetMacAddr: Couldn't allocate IP table buffer\r\n")) ;
+ continue ;
+ }
+
+ ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID ;
+ InitNDISBuff( &ndisbuff, pIAE, Size, NULL ) ;
+ memset( Context, 0, CONTEXT_SIZE ) ;
+ tdistatus = TdiVxdQueryInformationEx( 0,
+ &ID,
+ &ndisbuff,
+ &Size,
+ Context);
+ if ( tdistatus != TDI_SUCCESS )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetMacAddr: Getting IP address table failed\r\n")) ;
+ CTEFreeMem( pIAE ) ;
+ continue ;
+ }
+
+ // ASSERT( Size/sizeof(IPAddrEntry) >= IPStats.ipsi_numaddr ) ;
+
+ //
+ // We have the IP address table for this IP driver. Look for
+ // our IP address
+ //
+
+ for ( j = 0 ; j < IPStats.ipsi_numaddr ; j++ )
+ {
+ //
+ // find our ipaddress
+ //
+ if ( pIAE[j].iae_addr != IpAddress )
+ {
+ continue ;
+ }
+
+ //
+ // now find out the mac address for this ipaddr
+ //
+ for ( k=0; k<AdptNum; k++ )
+ {
+ if ( ifeAdapterInfo[k]->if_index == pIAE[j].iae_index )
+ {
+ CTEMemCopy( MacAddr, ifeAdapterInfo[k]->if_physaddr, 6 );
+ break;
+ }
+ }
+ }
+
+ if (pIAE)
+ {
+ CTEFreeMem( pIAE ) ;
+ }
+ }
+ }
+
+ for ( k=0; k<AdptNum; k++ )
+ {
+ CTEFreeMem( ifeAdapterInfo[k] ) ;
+ }
+
+}
+
+
+/*******************************************************************
+
+ NAME: VxdReadIniString
+
+ SYNOPSIS: Vxd stub for CTEReadIniString
+
+ ENTRY: pchKey - Key value to look for in the NBT section
+ ppchString - Pointer to buffer found string is returned in
+
+ EXIT: ppchString will point to an allocated buffer
+
+ RETURNS: STATUS_SUCCESS if found
+
+ NOTES: The client must free ppchString when done with it
+
+ HISTORY:
+ Johnl 30-Aug-1993 Created
+
+********************************************************************/
+
+NTSTATUS VxdReadIniString( LPSTR pchKey, LPSTR * ppchString )
+{
+ CTEPagedCode();
+
+ if ( GetNdisParam( pchKey, (ULONG *)ppchString, NdisParameterString ) )
+ {
+ return STATUS_SUCCESS ;
+ }
+ else
+ {
+ //
+ // Does DHCP have it?
+ //
+
+ if ( *ppchString = (char *) GetDhcpOption( pchKey, 0 ) )
+ {
+ return STATUS_SUCCESS ;
+ }
+ }
+
+ return STATUS_UNSUCCESSFUL ;
+}
+
+/*******************************************************************
+
+ NAME: GetProfileInt
+
+ SYNOPSIS: Gets the specified value from the registry or DHCP
+
+ ENTRY: pchKey - Key value to look for in the NBT section
+ Default - Default value if not in registry or DHCP
+ Min - Minimum value can be
+
+ RETURNS: Registry Value or Dhcp value or default value
+
+ NOTES:
+
+ HISTORY:
+ Johnl 23-Mar-1994 Created
+
+********************************************************************/
+
+ULONG GetProfileInt( PVOID p, LPSTR pchKey, ULONG Default, ULONG Min )
+{
+ ULONG Val = Default;
+
+ CTEPagedCode();
+
+ //
+ // Is the value in the registry?
+ //
+ if ( !GetNdisParam( pchKey, &Val, NdisParameterInteger ) )
+ {
+ //
+ // No, Check DHCP
+ //
+ Val = GetDhcpOption( pchKey, Default );
+ }
+
+ if ( Val < Min )
+ {
+ Val = Min;
+ }
+
+ return Val;
+}
+
+ULONG GetProfileHex( PVOID p, LPSTR pchKey, ULONG Default, ULONG Min )
+{
+ return GetProfileInt( p, pchKey, Default, Min);
+}
+
+/*******************************************************************
+
+ NAME: VxdOpenNdis
+
+ SYNOPSIS: Prepare Ndis to read entries from the registry. Ndis
+ basically opens the registry and gives a handle back
+ which we store in GlobalNdisHandle.
+
+ ENTRY: Nothing (GlobalNdisHandle is global)
+ RETURNS: TRUE if things worked well
+ FALSE if some error occured
+
+ HISTORY:
+ Koti Nov. 20, 94
+
+********************************************************************/
+
+BOOL VxdOpenNdis( VOID )
+{
+
+ NDIS_STATUS Status;
+ NDIS_STRING Name;
+
+ CTEPagedCode();
+
+
+ ASSERT( !GlobalNdisHandle );
+
+ // Open the config information.
+ Name.Length = strlen(szXportName) + 1;
+ Name.MaximumLength = Name.Length;
+ Name.Buffer = (PUCHAR)szXportName;
+
+ NdisOpenProtocolConfiguration(&Status, &GlobalNdisHandle, &Name);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ // Unable to open the configuration. Fail now.
+ GlobalNdisHandle = NULL;
+ ASSERT(0);
+ return FALSE;
+ }
+
+ return TRUE;
+
+}
+/*******************************************************************
+
+ NAME: GetNdisParam
+
+ SYNOPSIS: Gets the value from the MSTCP protocol sectio of the registry
+
+ ENTRY: pchKey - Key value to look for in the NBT section
+ pVal - Retrieved parameter
+ ParameterType - Type of parameter (string, int)
+
+ RETURNS: TRUE if the value was found, FALSE otherwise
+
+ NOTES: If the parameter is a string parameter, then this routine
+ will allocate memory which the client is responsible for
+ freeing.
+
+ HISTORY:
+ Johnl 23-Mar-1994 Created
+
+********************************************************************/
+
+BOOL GetNdisParam( LPSTR pszKey,
+ ULONG * pVal,
+ NDIS_PARAMETER_TYPE ParameterType )
+{
+ NDIS_STATUS Status;
+ NDIS_STRING Name;
+ uint i;
+ PNDIS_CONFIGURATION_PARAMETER Param;
+ BOOL fRet = FALSE;
+
+ CTEPagedCode();
+
+
+ ASSERT( GlobalNdisHandle );
+
+ Name.Length = strlen(pszKey) + 1;
+ Name.MaximumLength = Name.Length;
+ Name.Buffer = pszKey;
+ NdisReadConfiguration(&Status, &Param, GlobalNdisHandle, &Name,
+ ParameterType);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if ( ParameterType == NdisParameterString)
+ {
+ LPSTR lpstr = CTEAllocInitMem( Param->ParameterData.StringData.Length + 1 ) ;
+
+ if ( lpstr )
+ {
+ strcpy( lpstr, Param->ParameterData.StringData.Buffer );
+ *pVal = (ULONG) lpstr;
+ fRet = TRUE;
+ }
+ }
+ else
+ {
+ *pVal = Param->ParameterData.IntegerData;
+ fRet = TRUE;
+ }
+ }
+
+ return fRet ;
+}
+
+/*******************************************************************
+
+ NAME: VxdCloseNdis
+
+ SYNOPSIS: Close the handle that we opened in VxdOpenNdis
+
+ ENTRY: Nothing (GlobalNdisHandle is global)
+
+ HISTORY:
+ Koti Nov. 20, 94
+
+********************************************************************/
+
+VOID VxdCloseNdis( VOID )
+{
+
+ CTEPagedCode();
+
+ ASSERT(GlobalNdisHandle);
+
+ if (GlobalNdisHandle != NULL)
+ {
+ NdisCloseConfiguration(GlobalNdisHandle);
+ GlobalNdisHandle = NULL;
+ }
+}
+
+
+/*******************************************************************
+
+ NAME: StopAllNameQueries
+
+ SYNOPSIS: This routine is called when the device context is going
+ away. It finds out all the name queries that are in
+ progress (started by someone on this device context) and
+ stops them.
+
+ ENTRY: pDeviceContext - the device context that is going away.
+
+ RETURNS: TRUE if at least one name query was found and stopped
+ FALSE if there wasn't any query in progress
+
+ HISTORY:
+ Koti Nov. 19, 94
+
+********************************************************************/
+
+BOOL
+StopAllNameQueries( tDEVICECONTEXT *pDeviceContext )
+{
+
+ tDGRAM_SEND_TRACKING *pTracker;
+ NBT_WORK_ITEM_CONTEXT *Context;
+ PVOID pClientCompletion;
+ PVOID pClientContext;
+ tNAMEADDR *pNameAddr;
+ tTIMERQENTRY *pTimer;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ CTELockHandle OldIrq;
+
+ CTEPagedCode();
+
+ //
+ // first check to see if any names are on the pending list: all name
+ // queries over the network will be here (WINS, broadcast, DNS)
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ pHead = &NbtConfig.PendingNameQueries;
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
+
+ pEntry = pEntry->Flink;
+
+ pTimer = pNameAddr->pTimer;
+ if (pTimer)
+ {
+ pTracker = (tDGRAM_SEND_TRACKING *)pTimer->Context;
+
+ ASSERT (pTracker->pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT);
+
+ if (pTracker->pDeviceContext == pDeviceContext)
+ {
+ StopTimer(pTimer,(COMPLETIONCLIENT *)&pClientCompletion,&Context);
+ if (pClientCompletion)
+ {
+ //
+ // Remove from the pending list
+ //
+ RemoveEntryList(&pNameAddr->Linkage);
+ InitializeListHead(&pNameAddr->Linkage);
+
+ pNameAddr->pTimer = NULL;
+ NbtDereferenceName(pNameAddr);
+
+ //
+ // complete client's ncb. If requests were queued on
+ // the same name by other clients, this will start new
+ // name queries for those clients
+ //
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ CompleteClientReq(pClientCompletion,
+ (tDGRAM_SEND_TRACKING *)Context,
+ STATUS_NETWORK_NAME_DELETED);
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ DbgPrint("StopAllNameQueries: stopped net name query") ;
+ }
+ }
+ }
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ //
+ // now check if any names are on the lmhosts queue: all name queries
+ // waiting for lmhosts (and/or hosts) parsing will be here
+ //
+
+ Context = NULL;
+ if (LmHostQueries.ResolvingNow && LmHostQueries.Context)
+ {
+ Context = (NBT_WORK_ITEM_CONTEXT *)LmHostQueries.Context;
+ pTracker = Context->pTracker;
+
+ ASSERT (pTracker->pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT);
+ if (pTracker->pDeviceContext == pDeviceContext)
+ {
+ LmHostQueries.Context = NULL;
+
+ pClientCompletion = Context->ClientCompletion;
+ pClientContext = Context->pClientContext;
+
+ // name did not resolve, so delete from table
+ RemoveName(pTracker->pNameAddr);
+
+ DereferenceTracker(pTracker);
+
+ CompleteClientReq(pClientCompletion,
+ pClientContext,
+ STATUS_NETWORK_NAME_DELETED);
+ DbgPrint("StopAllNameQueries: stopped lmhosts query in progress") ;
+ }
+ }
+
+ //
+ // now walk through the queued items and cancel all the relevant ones
+ //
+ pHead = &LmHostQueries.ToResolve;
+ pEntry = pHead->Flink;
+
+ while (pEntry != pHead)
+ {
+ Context = CONTAINING_RECORD(pEntry,NBT_WORK_ITEM_CONTEXT,Item.List);
+ pEntry = pEntry->Flink;
+
+ pTracker = Context->pTracker;
+
+ ASSERT (pTracker->pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT);
+ if (pTracker->pDeviceContext == pDeviceContext)
+ {
+ RemoveEntryList(&Context->Item.List);
+
+ pClientCompletion = Context->ClientCompletion;
+ pClientContext = Context->pClientContext;
+
+ // name did not resolve, so delete from table
+ RemoveName(pTracker->pNameAddr);
+
+ DereferenceTracker(pTracker);
+
+ CompleteClientReq(pClientCompletion,
+ pClientContext,
+ STATUS_NETWORK_NAME_DELETED);
+ DbgPrint("StopAllNameQueries: cancelled lmhosts queries in queue") ;
+ }
+ }
+
+}
+
+
+/*******************************************************************
+
+ NAME: VxdUnload
+
+ SYNOPSIS: This is where we are asked to unload. We destroy all
+ the device objects and then unload ourselves if the
+ message came from vtcp.
+
+ ENTRY: pchModuleName - name of the module that is going away.
+ We take action only if vtcp is going away
+ (in which case, pchModuleName is "MSTCP")
+
+ RETURNS: STATUS_SUCCESS if things went ok
+
+ HISTORY:
+ Koti Oct 5, 94
+
+********************************************************************/
+
+NTSTATUS
+VxdUnload( LPSTR pchModuleName )
+{
+
+ LIST_ENTRY * pEntry;
+ tDEVICECONTEXT * pDeviceContext;
+ NTSTATUS status;
+
+ CTEPagedCode();
+
+ KdPrint(("VxdUnload entered\r\n"));
+
+ if ( (pchModuleName == NULL) ||
+ (strcmp(pchModuleName,szXportName) != 0) )
+ {
+ CDbgPrint(DBGFLAG_ERROR,("VxdUnload: Unload msg not from MSTCP\r\n"));
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // all devices will be destroyed by the time VxdUnload is called: this is
+ // just being paranoid
+ //
+ for ( pEntry = pNbtGlobConfig->DeviceContexts.Flink;
+ pEntry != &pNbtGlobConfig->DeviceContexts;
+ )
+ {
+ pDeviceContext = CONTAINING_RECORD( pEntry, tDEVICECONTEXT, Linkage);
+ pEntry = pEntry->Flink;
+
+ status = DestroyDeviceObject(pNbtGlobConfig, pDeviceContext->IpAddress);
+
+ if (status != STATUS_SUCCESS)
+ {
+ ASSERT(0);
+ }
+ }
+
+ //
+ // events such as name refresh etc. have been scheduled to be executed
+ // later: cancel all those
+ //
+ CancelAllDelayedEvents( NULL );
+
+ //
+ // Tell IP not to use the handler anymore
+ //
+ IPRegisterAddrChangeHandler( IPNotification, FALSE);
+
+
+ ReleaseNbtConfigMem();
+
+
+ //
+ // we don't provide any service, so don't pass our name
+ //
+ CTEUnload( (char *)NULL );
+}
+
+
+
+/*******************************************************************
+
+ NAME: ReleaseNbtConfigMem
+
+ SYNOPSIS: This is where we release all the memory that was allocated
+ at init/run time via ifs mgr.
+ We also stop the various timers.
+
+ HISTORY:
+ Koti Oct 14, 94
+
+********************************************************************/
+
+VOID ReleaseNbtConfigMem( VOID )
+{
+
+ PLIST_ENTRY pHead, pEntry;
+ tTIMERQENTRY *pTimerEntry;
+ tDGRAM_SEND_TRACKING *pTrack;
+ tADDRESSELE *pAddress;
+ tCLIENTELE *pClientEle;
+ tCONNECTELE *pConnEle;
+ tLOWERCONNECTION *pLowerConn;
+ tNAMEADDR *pNameAddr;
+ CTELockHandle OldIrq;
+ int i;
+
+
+ KdPrint(("ReleaseNbtConfigMem entered\r\n"));
+
+ CTEPagedCode();
+
+
+ //
+ // stop the timer that used to look for timed-out ncb's
+ //
+ StopTimeoutTimer();
+
+ //
+ // if any other timers are active, stop them
+ //
+ if (!IsListEmpty(&TimerQ.ActiveHead))
+ {
+ pHead = &TimerQ.ActiveHead;
+ pEntry = pHead->Flink;
+ while( pEntry != pHead )
+ {
+ pTimerEntry = CONTAINING_RECORD(pEntry,tTIMERQENTRY,Linkage);
+ pEntry = pEntry->Flink;
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ StopTimer(pTimerEntry,NULL,NULL);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+ }
+
+ //
+ // free all the timers on the free list
+ //
+ while (!IsListEmpty(&TimerQ.FreeHead))
+ {
+ pEntry = RemoveHeadList(&TimerQ.FreeHead);
+ pTimerEntry = CONTAINING_RECORD(pEntry,tTIMERQENTRY,Linkage);
+ CTEMemFree(pTimerEntry);
+ }
+
+
+ // free the various buffers
+
+ if ( pFileBuff )
+ CTEMemFree( pFileBuff );
+
+ if ( NbtConfig.pHosts )
+ CTEMemFree( NbtConfig.pHosts );
+
+ if (NbtConfig.pScope)
+ CTEMemFree( NbtConfig.pScope );
+
+ if (NbtConfig.pLmHosts)
+ CTEMemFree(NbtConfig.pLmHosts);
+
+ if (NbtConfig.pDomainName)
+ CTEMemFree(NbtConfig.pDomainName);
+
+ if (NbtConfig.pDNSDomains)
+ CTEMemFree(NbtConfig.pDNSDomains);
+
+
+ //
+ // NbtDereferenceAddress might have freed the addresses. But if
+ // ReleaseNameOnNet returned pending we wouldn't have freed the addressele
+ // yet, waiting for NameReleaseDone to be called. Well, we are about to
+ // be unloaded so free such instances now!
+ //
+ while (!IsListEmpty(&NbtConfig.AddressHead))
+ {
+ pEntry = RemoveHeadList(&NbtConfig.AddressHead);
+ pAddress = CONTAINING_RECORD(pEntry,tADDRESSELE,Linkage);
+ while (!IsListEmpty(&pAddress->ClientHead))
+ {
+ pEntry = RemoveHeadList(&pAddress->ClientHead);
+ pClientEle = CONTAINING_RECORD(pEntry,tCLIENTELE,Linkage);
+ while (!IsListEmpty(&pClientEle->ConnectActive))
+ {
+ pEntry = RemoveHeadList(&pClientEle->ConnectActive);
+ pConnEle = CONTAINING_RECORD(pEntry,tCONNECTELE,Linkage);
+ pLowerConn = pConnEle->pLowerConnId;
+ if (pLowerConn)
+ CTEMemFree(pLowerConn);
+ CTEMemFree(pConnEle);
+ }
+ CTEMemFree(pClientEle);
+ }
+ CTEMemFree( pAddress );
+ }
+
+
+ // free the DomainList
+ while (!IsListEmpty(&DomainNames.DomainList))
+ {
+ pEntry = RemoveHeadList(&DomainNames.DomainList);
+ pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
+ if (pNameAddr->pIpList)
+ CTEMemFree(pNameAddr->pIpList);
+ CTEMemFree(pNameAddr);
+ }
+
+
+ // free pLocalHashTbl
+ if (NbtConfig.pLocalHashTbl)
+ {
+ //
+ // we should have freed all the entries by now. It's possible though
+ // that we sent a name release which returned pending, so we are
+ // still hanging on to the nameaddr. If there is any such instance,
+ // free it now (when else? we are about to be unloaded now!)
+ //
+ for(i=0;i<NbtConfig.pLocalHashTbl->lNumBuckets;i++)
+ {
+ while (!IsListEmpty(&(NbtConfig.pLocalHashTbl->Bucket[i])))
+ {
+ pEntry = RemoveHeadList(&(NbtConfig.pLocalHashTbl->Bucket[i]));
+ pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
+ CTEMemFree(pNameAddr);
+ }
+ }
+ CTEMemFree( NbtConfig.pLocalHashTbl );
+ }
+
+
+ // free pRemoteHashTbl
+ if (NbtConfig.pRemoteHashTbl)
+ {
+ for(i=0;i<NbtConfig.pRemoteHashTbl->lNumBuckets;i++)
+ {
+ while (!IsListEmpty(&(NbtConfig.pRemoteHashTbl->Bucket[i])))
+ {
+ pEntry = RemoveHeadList(&(NbtConfig.pRemoteHashTbl->Bucket[i]));
+ pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
+ CTEMemFree(pNameAddr);
+ }
+ }
+ CTEMemFree( NbtConfig.pRemoteHashTbl );
+ }
+
+
+ // free up the DgramTrackerFreeQ
+ while (!IsListEmpty(&NbtConfig.DgramTrackerFreeQ))
+ {
+ pEntry = RemoveHeadList(&NbtConfig.DgramTrackerFreeQ);
+ pTrack = CONTAINING_RECORD(pEntry,tDGRAM_SEND_TRACKING,Linkage);
+ CTEMemFree( pTrack );
+ }
+
+ //
+ // shouldn't see any pending name queries at this point, but just in case!
+ //
+ while (!IsListEmpty(&NbtConfig.PendingNameQueries))
+ {
+ pEntry = RemoveHeadList(&NbtConfig.PendingNameQueries);
+ pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
+ CTEMemFree( pNameAddr );
+ }
+
+
+ // free the SessionBufferFreeList list (allocated, not used)
+ while( !IsListEmpty(&NbtConfig.SessionBufferFreeList) )
+ {
+ pEntry = RemoveHeadList(&NbtConfig.SessionBufferFreeList);
+ CTEMemFree( pEntry );
+ }
+
+
+ // free SendContextFreeList (allocated, not used)
+ while( !IsListEmpty(&NbtConfig.SendContextFreeList) )
+ {
+ pEntry = RemoveHeadList(&NbtConfig.SendContextFreeList);
+ CTEMemFree( pEntry );
+ }
+
+
+ // free RcvContextFreeList (allocated, not used)
+ while( !IsListEmpty(&NbtConfig.RcvContextFreeList) )
+ {
+ pEntry = RemoveHeadList(&NbtConfig.RcvContextFreeList);
+ CTEMemFree( pEntry );
+ }
+
+#ifdef DBG
+ if( !IsListEmpty(&DbgMemList) )
+ {
+ KdPrint(("ReleaseNbtConfigMem: memory leak!\r\n"));
+ if (DbgLeakCheck)
+ {
+ ASSERT(0);
+ }
+ }
+#endif
+
+}
+
+#endif // CHICAGO