1570 lines
39 KiB
C
1570 lines
39 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
browsenet.c
|
||
|
||
Abstract:
|
||
|
||
Code to manage network requests.
|
||
|
||
Author:
|
||
|
||
Larry Osterman (LarryO) 24-Mar-1992
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
|
||
|
||
CRITICAL_SECTION NetworkCritSect = {0};
|
||
|
||
LIST_ENTRY
|
||
ServicedNetworks = {0};
|
||
|
||
ULONG
|
||
NumberOfServicedNetworks = 0;
|
||
|
||
|
||
NET_API_STATUS
|
||
BrDumpNetworksWorker(
|
||
IN PNETWORK Network,
|
||
IN PVOID Context
|
||
);
|
||
|
||
|
||
|
||
VOID
|
||
BrInitializeNetworks(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Initialization for this source file.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
Status of operation.
|
||
|
||
Note: no need to wrap in try-finally since caller is.
|
||
|
||
--*/
|
||
{
|
||
InitializeListHead(&ServicedNetworks);
|
||
InitializeCriticalSection(&NetworkCritSect);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
BOOL
|
||
BrMapToDirectHost(
|
||
IN PUNICODE_STRING InputNetbiosTransportName,
|
||
OUT WCHAR DirectHostTransportName[MAX_PATH+1]
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine maps from a Netbios transport and the corresponding
|
||
direct host transport.
|
||
|
||
The Netbios transport is PNPed since the redir binds to it. The direct host
|
||
transport is not PNPed since the redir doesn't bind to it. This routine
|
||
maps from on to the other to allow both transports to be bound from the
|
||
same PNP event.
|
||
|
||
Arguments:
|
||
|
||
InputNetbiosTransportName - Transport name to map.
|
||
|
||
DirectHostTransportName - Corresponding mapped transport name
|
||
|
||
Return Value:
|
||
|
||
|
||
TRUE iff there is a mapped equivalent name.
|
||
|
||
--*/
|
||
{
|
||
|
||
//
|
||
// Only mapp if mapping is configured.
|
||
//
|
||
|
||
EnterCriticalSection(&BrInfo.ConfigCritSect);
|
||
|
||
if (BrInfo.DirectHostBinding != NULL ) {
|
||
LPTSTR_ARRAY TStrArray = BrInfo.DirectHostBinding;
|
||
UNICODE_STRING IpxTransportName;
|
||
UNICODE_STRING NetbiosTransportName;
|
||
|
||
while (!NetpIsTStrArrayEmpty(TStrArray)) {
|
||
|
||
RtlInitUnicodeString(&IpxTransportName, TStrArray);
|
||
|
||
TStrArray = NetpNextTStrArrayEntry(TStrArray);
|
||
|
||
ASSERT (!NetpIsTStrArrayEmpty(TStrArray));
|
||
|
||
if (!NetpIsTStrArrayEmpty(TStrArray)) {
|
||
|
||
RtlInitUnicodeString(&NetbiosTransportName, TStrArray);
|
||
|
||
//
|
||
// If the current name matches the one passed,
|
||
// return the mapped name to the caller.
|
||
//
|
||
|
||
if ( RtlEqualUnicodeString( &NetbiosTransportName,
|
||
InputNetbiosTransportName,
|
||
TRUE )) {
|
||
wcscpy( DirectHostTransportName,
|
||
IpxTransportName.Buffer );
|
||
LeaveCriticalSection(&BrInfo.ConfigCritSect);
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
TStrArray = NetpNextTStrArrayEntry(TStrArray);
|
||
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
LeaveCriticalSection(&BrInfo.ConfigCritSect);
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
NET_API_STATUS
|
||
BrCreateNetworks(
|
||
PDOMAIN_INFO DomainInfo
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create all of the networks for a particular domain.
|
||
|
||
Arguments:
|
||
|
||
DomainInfo - Specifies the domain being browsed.
|
||
|
||
Return Value:
|
||
|
||
Status of operation.
|
||
|
||
--*/
|
||
{
|
||
NET_API_STATUS NetStatus;
|
||
PLMDR_TRANSPORT_LIST TransportList = NULL ;
|
||
PLMDR_TRANSPORT_LIST TransportEntry;
|
||
BOOLEAN ConfigCritSectLocked = FALSE;
|
||
|
||
BrPrint(( BR_NETWORK, "%ws: Creating networks for domain\n", DomainInfo->DomUnicodeDomainName ));
|
||
|
||
//
|
||
// Get the list of transports from the datagram receiver.
|
||
//
|
||
NetStatus = BrGetTransportList(&TransportList);
|
||
|
||
if ( NetStatus != NERR_Success ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Create a Network for each of the transports.
|
||
//
|
||
TransportEntry = TransportList;
|
||
|
||
while (TransportEntry != NULL) {
|
||
|
||
//
|
||
// Don't do the Direct Host IPX transport here.
|
||
//
|
||
|
||
if ( (TransportEntry->Flags & LMDR_TRANSPORT_IPX) == 0 ) {
|
||
UNICODE_STRING TransportName;
|
||
|
||
TransportName.Buffer = TransportEntry->TransportName;
|
||
TransportName.Length = (USHORT)TransportEntry->TransportNameLength;
|
||
//
|
||
// We know the bowser sticks in a null at the end, so the max length
|
||
// is the length + 1.
|
||
//
|
||
TransportName.MaximumLength = (USHORT)TransportEntry->TransportNameLength+sizeof(WCHAR);
|
||
|
||
NetStatus = BrCreateNetwork(
|
||
&TransportName,
|
||
TransportEntry->Flags,
|
||
NULL,
|
||
DomainInfo );
|
||
|
||
if ( NetStatus != NERR_Success ) {
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
|
||
if (TransportEntry->NextEntryOffset == 0) {
|
||
TransportEntry = NULL;
|
||
} else {
|
||
TransportEntry = (PLMDR_TRANSPORT_LIST)((PCHAR)TransportEntry+TransportEntry->NextEntryOffset);
|
||
}
|
||
|
||
}
|
||
|
||
NetStatus = NERR_Success;
|
||
|
||
Cleanup:
|
||
|
||
if ( ConfigCritSectLocked ) {
|
||
LeaveCriticalSection(&BrInfo.ConfigCritSect);
|
||
}
|
||
if ( TransportList != NULL ) {
|
||
MIDL_user_free(TransportList);
|
||
}
|
||
|
||
return NetStatus;
|
||
}
|
||
|
||
NET_API_STATUS
|
||
BrCreateNetwork(
|
||
IN PUNICODE_STRING TransportName,
|
||
IN ULONG TransportFlags,
|
||
IN PUNICODE_STRING AlternateTransportName OPTIONAL,
|
||
IN PDOMAIN_INFO DomainInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine allocates memory to hold a network structure, and initializes
|
||
all of its associated data structures.
|
||
|
||
Arguments:
|
||
|
||
TransportName - The name of the transport to add.
|
||
|
||
TransportFlags - Flags describing characteristics of the transport
|
||
|
||
AlternateTransportName - If specified, this is the name of an alternate
|
||
transport similar to the one being created.
|
||
|
||
DomainInfo - Specifies the domain being browsed.
|
||
|
||
|
||
Return Value:
|
||
|
||
Status of operation (mostly status of allocations).
|
||
|
||
--*/
|
||
{
|
||
NET_API_STATUS NetStatus;
|
||
PNETWORK Network;
|
||
BOOLEAN NetworkLockInitialized = FALSE;
|
||
BOOLEAN ResponseCacheLockInitialized = FALSE;
|
||
BOOLEAN CanCallBrDestroyNetwork = FALSE;
|
||
|
||
BOOLEAN ConfigCritSectLocked = FALSE;
|
||
|
||
BrPrint(( BR_NETWORK,
|
||
"%ws: %ws: Creating network.\n",
|
||
DomainInfo->DomUnicodeDomainName,
|
||
TransportName->Buffer ));
|
||
|
||
|
||
//
|
||
// Check to see if the transport already exists.
|
||
//
|
||
|
||
if ((Network = BrFindNetwork( DomainInfo, TransportName)) != NULL) {
|
||
BrDereferenceNetwork( Network );
|
||
return NERR_AlreadyExists;
|
||
}
|
||
|
||
//
|
||
// If this transport is explicitly on our list of transports to unbind,
|
||
// simply ignore the transport.
|
||
//
|
||
|
||
if (BrInfo.UnboundBindings != NULL) {
|
||
LPTSTR_ARRAY TStrArray = BrInfo.UnboundBindings;
|
||
|
||
while (!NetpIsTStrArrayEmpty(TStrArray)) {
|
||
LPWSTR NewTransportName;
|
||
|
||
#define NAME_PREFIX L"\\Device\\"
|
||
#define NAME_PREFIX_LENGTH 8
|
||
|
||
//
|
||
// The transport name in the registry is only optionally prefixed with \device\
|
||
//
|
||
|
||
if ( _wcsnicmp( NAME_PREFIX, TStrArray, NAME_PREFIX_LENGTH) == 0 ) {
|
||
NewTransportName = TransportName->Buffer;
|
||
} else {
|
||
NewTransportName = TransportName->Buffer + NAME_PREFIX_LENGTH;
|
||
}
|
||
|
||
if ( _wcsicmp( TStrArray, NewTransportName ) == 0 ) {
|
||
BrPrint(( BR_NETWORK, "Binding is marked as unbound: %s (Silently ignoring)\n", TransportName->Buffer ));
|
||
return NERR_Success;
|
||
}
|
||
|
||
TStrArray = NetpNextTStrArrayEntry(TStrArray);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
//
|
||
// Create the transport.
|
||
//
|
||
|
||
try {
|
||
|
||
//
|
||
// Allocate the NETWORK structure.
|
||
//
|
||
|
||
Network = MIDL_user_allocate(sizeof(NETWORK));
|
||
|
||
if (Network == NULL) {
|
||
try_return(NetStatus = ERROR_NOT_ENOUGH_MEMORY);
|
||
}
|
||
|
||
RtlZeroMemory( Network, sizeof(NETWORK) );
|
||
|
||
|
||
|
||
//
|
||
// Initialize those fields that must be initialized before we can call
|
||
// BrDeleteNetwork (on failure).
|
||
//
|
||
|
||
RtlInitializeResource(&Network->Lock);
|
||
|
||
NetworkLockInitialized = TRUE;
|
||
Network->Role = BrDefaultRole;
|
||
|
||
// One for being in ServiceNetworks. One for this routine's reference.
|
||
Network->ReferenceCount = 2;
|
||
|
||
|
||
Network->NetworkName.Buffer = MIDL_user_allocate(TransportName->MaximumLength);
|
||
|
||
if (Network->NetworkName.Buffer == NULL) {
|
||
try_return(NetStatus = ERROR_NOT_ENOUGH_MEMORY);
|
||
}
|
||
|
||
Network->NetworkName.MaximumLength = TransportName->MaximumLength;
|
||
RtlCopyUnicodeString(&Network->NetworkName, TransportName);
|
||
Network->NetworkName.Buffer[Network->NetworkName.Length/sizeof(WCHAR)] = UNICODE_NULL;
|
||
|
||
|
||
RtlZeroMemory( Network->UncMasterBrowserName, sizeof( Network->UncMasterBrowserName ));
|
||
|
||
if ( TransportFlags & LMDR_TRANSPORT_WANNISH ) {
|
||
Network->Flags |= NETWORK_WANNISH;
|
||
}
|
||
|
||
if ( TransportFlags & LMDR_TRANSPORT_RAS ) {
|
||
Network->Flags |= NETWORK_RAS;
|
||
}
|
||
|
||
if ( TransportFlags & LMDR_TRANSPORT_PDC ) {
|
||
Network->Flags |= NETWORK_PDC;
|
||
}
|
||
|
||
InitializeInterimServerList(&Network->BrowseTable,
|
||
BrBrowseTableInsertRoutine,
|
||
BrBrowseTableUpdateRoutine,
|
||
BrBrowseTableDeleteRoutine,
|
||
BrBrowseTableAgeRoutine);
|
||
|
||
Network->LastBowserDomainQueried = 0;
|
||
|
||
InitializeInterimServerList(&Network->DomainList,
|
||
BrDomainTableInsertRoutine,
|
||
BrDomainTableUpdateRoutine,
|
||
BrDomainTableDeleteRoutine,
|
||
BrDomainTableAgeRoutine);
|
||
|
||
InitializeListHead(&Network->OtherDomainsList);
|
||
|
||
InitializeCriticalSection(&Network->ResponseCacheLock);
|
||
ResponseCacheLockInitialized = TRUE;
|
||
|
||
InitializeListHead(&Network->ResponseCache);
|
||
|
||
Network->TimeCacheFlushed = 0;
|
||
|
||
Network->NumberOfCachedResponses = 0;
|
||
|
||
EnterCriticalSection(&NetworkCritSect);
|
||
Network->DomainInfo = DomainInfo;
|
||
DomainInfo->ReferenceCount ++;
|
||
InsertHeadList(&ServicedNetworks, &Network->NextNet);
|
||
NumberOfServicedNetworks += 1;
|
||
|
||
//
|
||
// Create a worker thread for this network
|
||
//
|
||
BrWorkerCreateThread( NumberOfServicedNetworks );
|
||
|
||
LeaveCriticalSection(&NetworkCritSect);
|
||
|
||
|
||
//
|
||
// Mark that we can now call BrDeleteNetwork upon failure.
|
||
//
|
||
// Continue initializing the network.
|
||
//
|
||
|
||
CanCallBrDestroyNetwork = TRUE;
|
||
|
||
NetStatus = BrCreateTimer(&Network->UpdateAnnouncementTimer);
|
||
|
||
if (NetStatus != NERR_Success) {
|
||
try_return(NetStatus);
|
||
}
|
||
|
||
NetStatus = BrCreateTimer(&Network->BackupBrowserTimer);
|
||
|
||
if (NetStatus != NERR_Success) {
|
||
try_return(NetStatus);
|
||
}
|
||
|
||
NetStatus = BrCreateTimer(&Network->MasterBrowserTimer);
|
||
|
||
if (NetStatus != NERR_Success) {
|
||
try_return(NetStatus);
|
||
}
|
||
|
||
NetStatus = BrCreateTimer(&Network->MasterBrowserAnnouncementTimer);
|
||
|
||
if (NetStatus != NERR_Success) {
|
||
try_return(NetStatus);
|
||
}
|
||
|
||
|
||
//
|
||
// Handle the alternate transport.
|
||
//
|
||
|
||
if (ARGUMENT_PRESENT(AlternateTransportName)) {
|
||
PNETWORK AlternateNetwork = BrFindNetwork( DomainInfo, AlternateTransportName);
|
||
|
||
//
|
||
// If we didn't find an alternate network, or if that network
|
||
// already has an alternate network, return an error.
|
||
//
|
||
|
||
if ( AlternateNetwork == NULL ) {
|
||
BrPrint(( BR_CRITICAL,
|
||
"%ws: %ws: Creating network. Can't find alternate net %ws\n",
|
||
DomainInfo->DomUnicodeDomainName,
|
||
TransportName->Buffer,
|
||
AlternateTransportName ));
|
||
try_return(NetStatus = NERR_InternalError);
|
||
}
|
||
|
||
if (AlternateNetwork->AlternateNetwork != NULL) {
|
||
BrDereferenceNetwork( AlternateNetwork );
|
||
try_return(NetStatus = NERR_InternalError);
|
||
}
|
||
|
||
Network->Flags |= NETWORK_IPX;
|
||
|
||
//
|
||
// Link the two networks together.
|
||
//
|
||
|
||
Network->AlternateNetwork = AlternateNetwork;
|
||
|
||
AlternateNetwork->AlternateNetwork = Network;
|
||
BrDereferenceNetwork( AlternateNetwork );
|
||
|
||
} else {
|
||
Network->AlternateNetwork = NULL;
|
||
}
|
||
|
||
//
|
||
// Since the Rdr doesn't support this transport,
|
||
// we actually have to bind ourselves.
|
||
//
|
||
// Bind for Direct host IPX and for emulated domains.
|
||
//
|
||
|
||
if ( (Network->Flags & NETWORK_IPX) || DomainInfo->IsEmulatedDomain ) {
|
||
NetStatus = BrBindToTransport( TransportName->Buffer,
|
||
DomainInfo->DomUnicodeDomainName,
|
||
DomainInfo->DomUnicodeComputerName );
|
||
|
||
if ( NetStatus != NERR_Success ) {
|
||
BrPrint(( BR_CRITICAL,
|
||
"%ws: %ws: Creating network. Can't bind to transport\n",
|
||
DomainInfo->DomUnicodeDomainName,
|
||
TransportName->Buffer ));
|
||
try_return( NetStatus );
|
||
}
|
||
|
||
|
||
Network->Flags |= NETWORK_BOUND;
|
||
|
||
}
|
||
|
||
//
|
||
// Post a WaitForRoleChange FsControl on each network the bowser
|
||
// driver supports. This FsControl will complete when a "tickle"
|
||
// packet is received on the machine, or when a master browser loses
|
||
// an election.
|
||
//
|
||
|
||
NetStatus = PostWaitForRoleChange(Network);
|
||
|
||
if (NetStatus != NERR_Success) {
|
||
BrPrint(( BR_CRITICAL,
|
||
"%ws: %ws: Creating network. Can't post wait for role change: %ld\n",
|
||
DomainInfo->DomUnicodeDomainName,
|
||
TransportName->Buffer,
|
||
NetStatus ));
|
||
try_return(NetStatus);
|
||
}
|
||
|
||
EnterCriticalSection(&BrInfo.ConfigCritSect);
|
||
ConfigCritSectLocked = TRUE;
|
||
|
||
//
|
||
// If MaintainServerList says to automatically determine mastership,
|
||
// post queryies to the driver.
|
||
//
|
||
|
||
if (BrInfo.MaintainServerList == 0) {
|
||
|
||
//
|
||
// Post a BecomeBackup FsControl API on each network the bowser
|
||
// driver supports. This FsControl will complete when the master
|
||
// for the net wants this client to become a backup server.
|
||
//
|
||
|
||
NetStatus = PostBecomeBackup( Network );
|
||
|
||
if (NetStatus != NERR_Success) {
|
||
BrPrint(( BR_CRITICAL,
|
||
"%ws: %ws: Creating network. Can't post become backup.\n",
|
||
DomainInfo->DomUnicodeDomainName,
|
||
TransportName->Buffer,
|
||
NetStatus ));
|
||
try_return(NetStatus);
|
||
}
|
||
|
||
//
|
||
// Post a BecomeMaster FsControl on each network the bowser driver
|
||
// supports. This FsControl will complete when this machine becomes
|
||
// a master browser server.
|
||
//
|
||
|
||
NetStatus = PostBecomeMaster( Network );
|
||
|
||
if (NetStatus != NERR_Success) {
|
||
BrPrint(( BR_CRITICAL,
|
||
"%ws: %ws: Creating network. Can't post become master.\n",
|
||
DomainInfo->DomUnicodeDomainName,
|
||
TransportName->Buffer,
|
||
NetStatus ));
|
||
try_return(NetStatus);
|
||
}
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// If this machine is running as domain master browser server, post an
|
||
// FsControl to retreive master browser announcements.
|
||
//
|
||
|
||
if ( Network->Flags & NETWORK_PDC ) {
|
||
NetStatus = PostGetMasterAnnouncement ( Network );
|
||
|
||
if (NetStatus != NERR_Success) {
|
||
BrPrint(( BR_CRITICAL,
|
||
"%ws: %ws: Creating network. Can't post get master announcment.\n",
|
||
DomainInfo->DomUnicodeDomainName,
|
||
TransportName->Buffer,
|
||
NetStatus ));
|
||
// This isn't fatal. We automatically try again later.
|
||
} else {
|
||
BrPrint(( BR_NETWORK, "%ws: %ws: GetMasterAnnouncement posted.\n",
|
||
DomainInfo->DomUnicodeDomainName,
|
||
TransportName->Buffer ));
|
||
}
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// If we are on either a domain master, or on a lanman/NT machine,
|
||
// force an election on all our transports to make sure that we're
|
||
// the master
|
||
//
|
||
|
||
if ( (Network->Flags & NETWORK_PDC) != 0 || BrInfo.IsLanmanNt) {
|
||
NetStatus = BrElectMasterOnNet( Network, (PVOID)EVENT_BROWSER_ELECTION_SENT_LANMAN_NT_STARTED );
|
||
|
||
if (NetStatus != NERR_Success) {
|
||
BrPrint(( BR_CRITICAL,
|
||
"%ws: %ws: Creating network. Can't Elect Master.\n",
|
||
DomainInfo->DomUnicodeDomainName,
|
||
TransportName->Buffer,
|
||
NetStatus ));
|
||
// This isn't fatal.
|
||
} else {
|
||
BrPrint(( BR_NETWORK, "%ws: %ws: Election forced on startup.\n",
|
||
DomainInfo->DomUnicodeDomainName,
|
||
TransportName->Buffer ));
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// This machine's browser has MaintainServerList set to either 0 or 1.
|
||
//
|
||
//
|
||
// If MaintainServerList = Auto,
|
||
// then asynchronously get the master server name for each network
|
||
// to ensure someone is the master.
|
||
//
|
||
// Ignore failures since this is just priming the domain.
|
||
//
|
||
|
||
EnterCriticalSection(&BrInfo.ConfigCritSect);
|
||
if (BrInfo.MaintainServerList == 0) {
|
||
|
||
BrGetMasterServerNameAysnc( Network );
|
||
|
||
BrPrint(( BR_NETWORK, "%ws: %ws: Find Master queued.\n",
|
||
DomainInfo->DomUnicodeDomainName,
|
||
TransportName->Buffer ));
|
||
|
||
//
|
||
// if we're a Lan Manager/NT machine, then we need to always be a backup
|
||
// browser.
|
||
//
|
||
|
||
//
|
||
// MaintainServerList == 1 means Yes
|
||
//
|
||
|
||
} else if (BrInfo.MaintainServerList == 1){
|
||
|
||
//
|
||
// Become a backup server now.
|
||
//
|
||
|
||
NetStatus = BrBecomeBackup( Network );
|
||
|
||
if (NetStatus != NERR_Success) {
|
||
BrPrint(( BR_CRITICAL,
|
||
"%ws: %ws: Creating network. Can't BecomeBackup.\n",
|
||
DomainInfo->DomUnicodeDomainName,
|
||
TransportName->Buffer,
|
||
NetStatus ));
|
||
// This isn't fatal.
|
||
} else {
|
||
BrPrint(( BR_NETWORK, "%ws: %ws: Became Backup.\n",
|
||
DomainInfo->DomUnicodeDomainName,
|
||
TransportName->Buffer ));
|
||
}
|
||
|
||
}
|
||
LeaveCriticalSection(&BrInfo.ConfigCritSect);
|
||
|
||
|
||
//
|
||
// If this isn't already an alternate transport,
|
||
// and there is a configured alternate transport for this transport,
|
||
// create the alternate transport now.
|
||
//
|
||
|
||
if (!ARGUMENT_PRESENT(AlternateTransportName)) {
|
||
WCHAR DirectHostName[MAX_PATH+1];
|
||
UNICODE_STRING DirectHostNameString;
|
||
|
||
if ( BrMapToDirectHost( TransportName, DirectHostName ) ) {
|
||
|
||
RtlInitUnicodeString(&DirectHostNameString, DirectHostName );
|
||
|
||
BrPrint(( BR_NETWORK, "%ws: %ws: Try adding alternate transport %ws.\n",
|
||
DomainInfo->DomUnicodeDomainName,
|
||
TransportName->Buffer,
|
||
DirectHostName ));
|
||
|
||
//
|
||
// There is a direct host binding on this machine. We want to add
|
||
// the direct host transport to the browser.
|
||
//
|
||
|
||
NetStatus = BrCreateNetwork(
|
||
&DirectHostNameString,
|
||
0, // No special flags
|
||
TransportName,
|
||
DomainInfo );
|
||
|
||
if (NetStatus != NERR_Success) {
|
||
BrPrint(( BR_CRITICAL, "%ws: %ws: Couldn't add alternate transport %ws. %ld\n",
|
||
DomainInfo->DomUnicodeDomainName,
|
||
TransportName->Buffer,
|
||
DirectHostName,
|
||
NetStatus ));
|
||
try_return(NetStatus);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
NetStatus = NERR_Success;
|
||
|
||
try_exit:NOTHING;
|
||
} finally {
|
||
|
||
if ( AbnormalTermination() ) {
|
||
NetStatus = NERR_InternalError;
|
||
}
|
||
|
||
if ( ConfigCritSectLocked ) {
|
||
LeaveCriticalSection(&BrInfo.ConfigCritSect);
|
||
ConfigCritSectLocked = FALSE;
|
||
}
|
||
|
||
if (NetStatus != NERR_Success) {
|
||
|
||
if (Network != NULL) {
|
||
|
||
//
|
||
// If we've initialized to the point where we can call
|
||
// we can call BrDeleteNetwork, do so.
|
||
//
|
||
|
||
if ( CanCallBrDestroyNetwork ) {
|
||
(VOID) BrDeleteNetwork( Network, NULL );
|
||
|
||
//
|
||
// Otherwise, just delete what we've created.
|
||
//
|
||
} else {
|
||
|
||
if (ResponseCacheLockInitialized) {
|
||
DeleteCriticalSection(&Network->ResponseCacheLock);
|
||
}
|
||
|
||
if (NetworkLockInitialized) {
|
||
RtlDeleteResource(&Network->Lock);
|
||
}
|
||
|
||
if (Network->NetworkName.Buffer != NULL) {
|
||
MIDL_user_free(Network->NetworkName.Buffer);
|
||
}
|
||
|
||
MIDL_user_free(Network);
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// We're done creating the network.
|
||
// Remove this routines reference to it.
|
||
//
|
||
|
||
} else {
|
||
|
||
BrDereferenceNetwork( Network );
|
||
}
|
||
|
||
}
|
||
return NetStatus;
|
||
}
|
||
|
||
VOID
|
||
BrUninitializeNetworks(
|
||
IN DWORD BrInitState
|
||
)
|
||
{
|
||
DeleteCriticalSection(&NetworkCritSect);
|
||
|
||
NumberOfServicedNetworks = 0;
|
||
|
||
}
|
||
|
||
PNETWORK
|
||
BrReferenceNetwork(
|
||
PNETWORK PotentialNetwork
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will look up a network given a potential pointer to the network.
|
||
|
||
This routine is useful if a caller has a pointer to a network but
|
||
hasn't incremented the reference count. For instance,
|
||
BrIssueAsyncBrowserIoControl calls the async completion routines like that.
|
||
|
||
Arguments:
|
||
|
||
PotentialNetwork - Pointer to the network structure to be verified.
|
||
|
||
Return Value:
|
||
|
||
NULL - No such network exists
|
||
|
||
A pointer to the network found. The found network should be dereferenced
|
||
using BrDereferenceNetwork.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
PLIST_ENTRY NetEntry;
|
||
|
||
EnterCriticalSection(&NetworkCritSect);
|
||
|
||
for (NetEntry = ServicedNetworks.Flink ;
|
||
NetEntry != &ServicedNetworks;
|
||
NetEntry = NetEntry->Flink ) {
|
||
PNETWORK Network = CONTAINING_RECORD(NetEntry, NETWORK, NextNet);
|
||
|
||
if ( PotentialNetwork == Network ) {
|
||
|
||
Network->ReferenceCount ++;
|
||
BrPrint(( BR_LOCKS,
|
||
"%ws: %ws: reference network: %ld\n",
|
||
Network->DomainInfo->DomUnicodeDomainName,
|
||
Network->NetworkName.Buffer,
|
||
Network->ReferenceCount ));
|
||
LeaveCriticalSection(&NetworkCritSect);
|
||
|
||
return Network;
|
||
}
|
||
|
||
}
|
||
|
||
LeaveCriticalSection(&NetworkCritSect);
|
||
|
||
return NULL;
|
||
}
|
||
|
||
|
||
VOID
|
||
BrDereferenceNetwork(
|
||
IN PNETWORK Network
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine decrements the reference to a network. If the network reference
|
||
count goes to 0, remove the network.
|
||
|
||
On entry, the global NetworkCritSect crit sect may not be locked
|
||
|
||
Arguments:
|
||
|
||
Network - The network to dereference
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
ULONG ReferenceCount;
|
||
|
||
EnterCriticalSection(&NetworkCritSect);
|
||
ReferenceCount = -- Network->ReferenceCount;
|
||
LeaveCriticalSection(&NetworkCritSect);
|
||
BrPrint(( BR_LOCKS,
|
||
"%ws: %ws: Dereference network: %ld\n",
|
||
Network->DomainInfo->DomUnicodeDomainName,
|
||
Network->NetworkName.Buffer,
|
||
ReferenceCount ));
|
||
|
||
if ( ReferenceCount != 0 ) {
|
||
return;
|
||
}
|
||
|
||
//
|
||
// The alternate network still has a pointer to this network,
|
||
// ditch it.
|
||
//
|
||
|
||
if ( Network->AlternateNetwork != NULL ) {
|
||
Network->AlternateNetwork->AlternateNetwork = NULL;
|
||
}
|
||
|
||
|
||
//
|
||
// Tell everyone that this net is going away.
|
||
//
|
||
|
||
BrShutdownBrowserForNet( Network, NULL );
|
||
|
||
|
||
//
|
||
// If this service did the bind, do the unbind.
|
||
//
|
||
// True for IPX and for emulated domains.
|
||
//
|
||
|
||
if (Network->Flags & NETWORK_BOUND) {
|
||
NET_API_STATUS NetStatus;
|
||
|
||
NetStatus = BrUnbindFromTransport( Network->NetworkName.Buffer,
|
||
Network->DomainInfo->DomUnicodeDomainName );
|
||
|
||
if (NetStatus != NERR_Success) {
|
||
BrPrint(( BR_CRITICAL,
|
||
"%ws: %ws: Unable to unbind from IPX transport\n",
|
||
Network->DomainInfo->DomUnicodeDomainName,
|
||
Network->NetworkName.Buffer ));
|
||
}
|
||
|
||
}
|
||
|
||
UninitializeInterimServerList(&Network->BrowseTable);
|
||
|
||
UninitializeInterimServerList(&Network->DomainList);
|
||
|
||
if (Network->BackupServerList != NULL) {
|
||
MIDL_user_free(Network->BackupServerList);
|
||
}
|
||
|
||
if (Network->BackupDomainList != NULL) {
|
||
MIDL_user_free(Network->BackupDomainList);
|
||
}
|
||
|
||
if (Network->NetworkName.Buffer != NULL) {
|
||
MIDL_user_free(Network->NetworkName.Buffer);
|
||
}
|
||
|
||
RtlDeleteResource(&Network->Lock);
|
||
|
||
|
||
BrDestroyResponseCache(Network);
|
||
|
||
DeleteCriticalSection(&Network->ResponseCacheLock);
|
||
|
||
BrDereferenceDomain( Network->DomainInfo );
|
||
|
||
MIDL_user_free(Network);
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
NET_API_STATUS
|
||
BrDeleteNetwork(
|
||
IN PNETWORK Network,
|
||
IN PVOID Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine prevents any new references to the network. It then removes
|
||
the global reference to the Network allowing it to be deleted.
|
||
|
||
Finally, it sleeps until the only reference left is the one held by the caller.
|
||
This ensures the Network will be deleted when the caller Dereferences the
|
||
network.
|
||
|
||
Arguments:
|
||
|
||
Network - The network to remove
|
||
The caller must have a reference to the Network.
|
||
|
||
Context - not used.
|
||
|
||
Return Value:
|
||
|
||
NERR_Success - always
|
||
|
||
--*/
|
||
{
|
||
BrPrint(( BR_NETWORK,
|
||
"%ws: %ws: Delete network\n",
|
||
Network->DomainInfo->DomUnicodeDomainName,
|
||
Network->NetworkName.Buffer ));
|
||
//
|
||
// Remove this network from the list to prevent any new references.
|
||
//
|
||
|
||
EnterCriticalSection(&NetworkCritSect);
|
||
RemoveEntryList(&Network->NextNet);
|
||
NumberOfServicedNetworks -= 1;
|
||
LeaveCriticalSection(&NetworkCritSect);
|
||
|
||
//
|
||
// Prevent new references by the timer routines
|
||
//
|
||
|
||
BrDestroyTimer(&Network->MasterBrowserAnnouncementTimer);
|
||
|
||
BrDestroyTimer(&Network->MasterBrowserTimer);
|
||
|
||
BrDestroyTimer(&Network->BackupBrowserTimer);
|
||
|
||
BrDestroyTimer(&Network->UpdateAnnouncementTimer);
|
||
|
||
//
|
||
// Decrement the global reference due to being is 'ServicedNetworks'
|
||
//
|
||
|
||
BrDereferenceNetwork( Network );
|
||
|
||
|
||
//
|
||
// Loop until the caller has the last reference.
|
||
//
|
||
|
||
EnterCriticalSection(&NetworkCritSect);
|
||
while ( Network->ReferenceCount != 1 ) {
|
||
LeaveCriticalSection(&NetworkCritSect);
|
||
Sleep(1000);
|
||
EnterCriticalSection(&NetworkCritSect);
|
||
}
|
||
LeaveCriticalSection(&NetworkCritSect);
|
||
|
||
UNREFERENCED_PARAMETER(Context);
|
||
|
||
return NERR_Success;
|
||
|
||
}
|
||
|
||
|
||
PNETWORK
|
||
BrFindNetwork(
|
||
PDOMAIN_INFO DomainInfo,
|
||
PUNICODE_STRING TransportName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will look up a network given a name.
|
||
|
||
Arguments:
|
||
|
||
DomainInfo - Specifies the domain this network is specific to
|
||
|
||
TransportName - The name of the transport to look up.
|
||
|
||
Return Value:
|
||
|
||
NULL - No such network exists
|
||
|
||
A pointer to the network found. The found network should be dereferenced
|
||
using BrDereferenceNetwork.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
PLIST_ENTRY NetEntry;
|
||
|
||
EnterCriticalSection(&NetworkCritSect);
|
||
|
||
for (NetEntry = ServicedNetworks.Flink ;
|
||
NetEntry != &ServicedNetworks;
|
||
NetEntry = NetEntry->Flink ) {
|
||
PNETWORK Network = CONTAINING_RECORD(NetEntry, NETWORK, NextNet);
|
||
|
||
if ( Network->DomainInfo == DomainInfo &&
|
||
RtlEqualUnicodeString(&Network->NetworkName, TransportName, TRUE)) {
|
||
|
||
Network->ReferenceCount ++;
|
||
BrPrint(( BR_LOCKS,
|
||
"%ws: %ws: find network: %ld\n",
|
||
Network->DomainInfo->DomUnicodeDomainName,
|
||
Network->NetworkName.Buffer,
|
||
Network->ReferenceCount ));
|
||
LeaveCriticalSection(&NetworkCritSect);
|
||
|
||
return Network;
|
||
}
|
||
|
||
}
|
||
|
||
LeaveCriticalSection(&NetworkCritSect);
|
||
|
||
return NULL;
|
||
}
|
||
|
||
|
||
PNETWORK
|
||
BrFindWannishMasterBrowserNetwork(
|
||
PDOMAIN_INFO DomainInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will look up a network that is running IP and is
|
||
a master browser.
|
||
|
||
Arguments:
|
||
|
||
DomainInfo - Specifies the domain this network is specific to
|
||
|
||
Return Value:
|
||
|
||
NULL - No such network exists
|
||
|
||
A pointer to the network found. The found network should be dereferenced
|
||
using BrDereferenceNetwork.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
PLIST_ENTRY NetEntry;
|
||
|
||
EnterCriticalSection(&NetworkCritSect);
|
||
|
||
for (NetEntry = ServicedNetworks.Flink ;
|
||
NetEntry != &ServicedNetworks;
|
||
NetEntry = NetEntry->Flink ) {
|
||
PNETWORK Network = CONTAINING_RECORD(NetEntry, NETWORK, NextNet);
|
||
|
||
//
|
||
// Find a network that is:
|
||
// for this domain, and
|
||
// is wannish, and
|
||
// is a master browser.
|
||
//
|
||
if ( Network->DomainInfo == DomainInfo &&
|
||
(Network->Flags & NETWORK_WANNISH) != 0 &&
|
||
(Network->Role & ROLE_MASTER) != 0 ) {
|
||
|
||
Network->ReferenceCount ++;
|
||
BrPrint(( BR_LOCKS,
|
||
"%ws: %ws: find wannish master network: %ld\n",
|
||
Network->DomainInfo->DomUnicodeDomainName,
|
||
Network->NetworkName.Buffer,
|
||
Network->ReferenceCount ));
|
||
LeaveCriticalSection(&NetworkCritSect);
|
||
|
||
return Network;
|
||
}
|
||
|
||
}
|
||
|
||
LeaveCriticalSection(&NetworkCritSect);
|
||
|
||
return NULL;
|
||
}
|
||
|
||
NET_API_STATUS
|
||
BrEnumerateNetworks(
|
||
PNET_ENUM_CALLBACK Callback,
|
||
PVOID Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine enumerates all the networks and calls back the specified
|
||
callback routine with the specified context.
|
||
|
||
Arguments:
|
||
|
||
Callback - The callback routine to call.
|
||
Context - Context for the routine.
|
||
|
||
Return Value:
|
||
|
||
Status of operation (mostly status of allocations).
|
||
|
||
--*/
|
||
{
|
||
NET_API_STATUS NetStatus = NERR_Success;
|
||
PLIST_ENTRY NetEntry;
|
||
PNETWORK Network;
|
||
PNETWORK NetworkToDereference = NULL;
|
||
|
||
EnterCriticalSection(&NetworkCritSect);
|
||
|
||
|
||
for (NetEntry = ServicedNetworks.Flink ;
|
||
NetEntry != &ServicedNetworks;
|
||
NetEntry = NetEntry->Flink ) {
|
||
|
||
//
|
||
// Reference the next network in the list
|
||
//
|
||
|
||
Network = CONTAINING_RECORD(NetEntry, NETWORK, NextNet);
|
||
Network->ReferenceCount ++;
|
||
BrPrint(( BR_LOCKS,
|
||
"%ws: %ws: enumerate network: %ld\n",
|
||
Network->DomainInfo->DomUnicodeDomainName,
|
||
Network->NetworkName.Buffer,
|
||
Network->ReferenceCount ));
|
||
|
||
LeaveCriticalSection(&NetworkCritSect);
|
||
|
||
//
|
||
// Dereference any network previously referenced.
|
||
//
|
||
if ( NetworkToDereference != NULL) {
|
||
BrDereferenceNetwork( NetworkToDereference );
|
||
NetworkToDereference = NULL;
|
||
}
|
||
|
||
|
||
//
|
||
// Call into the callback routine with this network.
|
||
//
|
||
|
||
NetStatus = (Callback)(Network, Context);
|
||
|
||
EnterCriticalSection(&NetworkCritSect);
|
||
|
||
NetworkToDereference = Network;
|
||
|
||
if (NetStatus != NERR_Success) {
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
LeaveCriticalSection(&NetworkCritSect);
|
||
|
||
//
|
||
// Dereference the last network
|
||
//
|
||
if ( NetworkToDereference != NULL) {
|
||
BrDereferenceNetwork( NetworkToDereference );
|
||
}
|
||
|
||
return NetStatus;
|
||
|
||
}
|
||
|
||
NET_API_STATUS
|
||
BrEnumerateNetworksForDomain(
|
||
PDOMAIN_INFO DomainInfo OPTIONAL,
|
||
PNET_ENUM_CALLBACK Callback,
|
||
PVOID Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine enumerates all the networks for a specified domain
|
||
and calls back the specified callback routine with the specified context.
|
||
|
||
Arguments:
|
||
|
||
DomainInfo - Specifies the Domain to limit the enumeration to.
|
||
NULL implies the primary domain.
|
||
|
||
Callback - The callback routine to call.
|
||
|
||
Context - Context for the routine.
|
||
|
||
Return Value:
|
||
|
||
Status of operation (mostly status of allocations).
|
||
|
||
--*/
|
||
{
|
||
|
||
NTSTATUS NetStatus = NERR_Success;
|
||
PLIST_ENTRY NetEntry;
|
||
PNETWORK Network;
|
||
PNETWORK NetworkToDereference = NULL;
|
||
|
||
//
|
||
// Default to the primary domain.
|
||
//
|
||
if ( DomainInfo == NULL && !IsListEmpty( &ServicedDomains ) ) {
|
||
DomainInfo = CONTAINING_RECORD(ServicedDomains.Flink, DOMAIN_INFO, Next);
|
||
}
|
||
|
||
EnterCriticalSection(&NetworkCritSect);
|
||
|
||
|
||
for (NetEntry = ServicedNetworks.Flink ;
|
||
NetEntry != &ServicedNetworks;
|
||
NetEntry = NetEntry->Flink ) {
|
||
|
||
|
||
//
|
||
// If the entry isn't for the specified domain,
|
||
// skip it.
|
||
//
|
||
Network = CONTAINING_RECORD(NetEntry, NETWORK, NextNet);
|
||
if ( Network->DomainInfo != DomainInfo ) {
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Reference the next network in the list
|
||
//
|
||
Network->ReferenceCount ++;
|
||
BrPrint(( BR_LOCKS,
|
||
"%ws: %ws: enumerate network for domain: %ld\n",
|
||
Network->DomainInfo->DomUnicodeDomainName,
|
||
Network->NetworkName.Buffer,
|
||
Network->ReferenceCount ));
|
||
|
||
LeaveCriticalSection(&NetworkCritSect);
|
||
|
||
//
|
||
// Dereference any network previously referenced.
|
||
//
|
||
if ( NetworkToDereference != NULL) {
|
||
BrDereferenceNetwork( NetworkToDereference );
|
||
NetworkToDereference = NULL;
|
||
}
|
||
|
||
|
||
//
|
||
// Call into the callback routine with this network.
|
||
//
|
||
|
||
NetStatus = (Callback)(Network, Context);
|
||
|
||
EnterCriticalSection(&NetworkCritSect);
|
||
|
||
NetworkToDereference = Network;
|
||
|
||
if (NetStatus != NERR_Success) {
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
LeaveCriticalSection(&NetworkCritSect);
|
||
|
||
//
|
||
// Dereference the last network
|
||
//
|
||
if ( NetworkToDereference != NULL) {
|
||
BrDereferenceNetwork( NetworkToDereference );
|
||
}
|
||
|
||
return NERR_Success;
|
||
|
||
}
|
||
|
||
#if DBG
|
||
|
||
BOOL
|
||
BrLockNetwork(
|
||
IN PNETWORK Network,
|
||
IN PCHAR FileName,
|
||
IN ULONG LineNumber
|
||
)
|
||
{
|
||
PCHAR File;
|
||
|
||
File = strrchr(FileName, '\\');
|
||
|
||
if (File == NULL) {
|
||
File = FileName;
|
||
}
|
||
|
||
BrPrint(( BR_LOCKS,
|
||
"%ws: %ws: Acquiring network lock %s:%d\n",
|
||
Network->DomainInfo->DomUnicodeDomainName,
|
||
Network->NetworkName.Buffer,
|
||
File,
|
||
LineNumber ));
|
||
|
||
if (!RtlAcquireResourceExclusive(&(Network)->Lock, TRUE)) {
|
||
BrPrint(( BR_CRITICAL,
|
||
"%ws: %ws: Failed to acquire network %s:%d\n",
|
||
Network->DomainInfo->DomUnicodeDomainName,
|
||
Network->NetworkName.Buffer,
|
||
File, LineNumber ));
|
||
return FALSE;
|
||
|
||
} else {
|
||
|
||
InterlockedIncrement( &Network->LockCount );
|
||
|
||
BrPrint(( BR_LOCKS,
|
||
"%ws: %ws: network lock %s:%d acquired\n",
|
||
Network->DomainInfo->DomUnicodeDomainName,
|
||
Network->NetworkName.Buffer,
|
||
File, LineNumber ));
|
||
}
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
BOOL
|
||
BrLockNetworkShared(
|
||
IN PNETWORK Network,
|
||
IN PCHAR FileName,
|
||
IN ULONG LineNumber
|
||
)
|
||
{
|
||
PCHAR File;
|
||
|
||
File = strrchr(FileName, '\\');
|
||
|
||
if (File == NULL) {
|
||
File = FileName;
|
||
}
|
||
|
||
BrPrint(( BR_LOCKS,
|
||
"%ws: %ws: Acquiring network lock %s:%d\n",
|
||
Network->DomainInfo->DomUnicodeDomainName,
|
||
Network->NetworkName.Buffer,
|
||
File, LineNumber ));
|
||
|
||
if (!RtlAcquireResourceShared(&(Network)->Lock, TRUE)) {
|
||
BrPrint(( BR_CRITICAL,
|
||
"%ws: %ws: failed to acquire network lock %s:%d\n",
|
||
Network->DomainInfo->DomUnicodeDomainName,
|
||
Network->NetworkName.Buffer,
|
||
File, LineNumber ));
|
||
|
||
return FALSE;
|
||
|
||
} else {
|
||
|
||
// Use InterlockedIncrement since we only have a shared lock on the
|
||
// resource.
|
||
InterlockedIncrement( &Network->LockCount );
|
||
|
||
BrPrint(( BR_LOCKS,
|
||
"%ws: %ws: Network lock %s:%d acquired\n",
|
||
Network->DomainInfo->DomUnicodeDomainName,
|
||
Network->NetworkName.Buffer,
|
||
File, LineNumber ));
|
||
}
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
VOID
|
||
BrUnlockNetwork(
|
||
IN PNETWORK Network,
|
||
IN PCHAR FileName,
|
||
IN ULONG LineNumber
|
||
)
|
||
{
|
||
PCHAR File;
|
||
LONG ReturnValue;
|
||
|
||
File = strrchr(FileName, '\\');
|
||
|
||
if (File == NULL) {
|
||
File = FileName;
|
||
}
|
||
|
||
|
||
BrPrint(( BR_LOCKS,
|
||
"%ws: %ws: Releasing network lock %s:%d\n",
|
||
Network->DomainInfo->DomUnicodeDomainName,
|
||
Network->NetworkName.Buffer,
|
||
File, LineNumber ));
|
||
|
||
//
|
||
// Decrement the lock count.
|
||
//
|
||
|
||
ReturnValue = InterlockedDecrement( &Network->LockCount );
|
||
|
||
if ( ReturnValue < 0) {
|
||
BrPrint(( BR_CRITICAL,
|
||
"%ws: %ws: Over released network lock %s:%d\n",
|
||
Network->DomainInfo->DomUnicodeDomainName,
|
||
Network->NetworkName.Buffer,
|
||
File, LineNumber ));
|
||
}
|
||
|
||
RtlReleaseResource(&(Network)->Lock);
|
||
|
||
return;
|
||
}
|
||
#endif
|
||
|
||
|
||
|
||
#if DBG
|
||
VOID
|
||
BrDumpNetworks(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will dump the contents of each of the browser network
|
||
structures.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
BrEnumerateNetworks(BrDumpNetworksWorker, NULL);
|
||
}
|
||
|
||
|
||
NET_API_STATUS
|
||
BrDumpNetworksWorker(
|
||
IN PNETWORK Network,
|
||
IN PVOID Context
|
||
)
|
||
{
|
||
if (!LOCK_NETWORK(Network)) {
|
||
return NERR_InternalError;
|
||
}
|
||
|
||
BrPrint(( BR_CRITICAL,
|
||
"%ws: %ws: Network at %lx\n",
|
||
Network->DomainInfo->DomUnicodeDomainName,
|
||
Network->NetworkName.Buffer,
|
||
Network ));
|
||
BrPrint(( BR_CRITICAL, " Reference Count: %lx\n", Network->ReferenceCount));
|
||
BrPrint(( BR_CRITICAL, " Flags: %lx\n", Network->Flags));
|
||
BrPrint(( BR_CRITICAL, " Role: %lx\n", Network->Role));
|
||
BrPrint(( BR_CRITICAL, " Master Browser Name: %ws\n", Network->UncMasterBrowserName ));
|
||
|
||
UNLOCK_NETWORK(Network);
|
||
|
||
return(NERR_Success);
|
||
}
|
||
#endif
|