2396 lines
63 KiB
C
2396 lines
63 KiB
C
/*++
|
||
|
||
Copyright (c) 1989-1993 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
address.c
|
||
|
||
Abstract:
|
||
|
||
This module contains code which implements the ADDRESS object.
|
||
Routines are provided to create, destroy, reference, and dereference,
|
||
transport address objects.
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
|
||
|
||
//
|
||
// Map all generic accesses to the same one.
|
||
//
|
||
|
||
static GENERIC_MAPPING AddressGenericMapping =
|
||
{ READ_CONTROL, READ_CONTROL, READ_CONTROL, READ_CONTROL };
|
||
|
||
|
||
|
||
TDI_ADDRESS_NETBIOS *
|
||
NbiParseTdiAddress(
|
||
IN TRANSPORT_ADDRESS UNALIGNED *TransportAddress,
|
||
IN ULONG MaxBufferLength,
|
||
IN BOOLEAN BroadcastAddressOk
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine scans a TRANSPORT_ADDRESS, looking for an address
|
||
of type TDI_ADDRESS_TYPE_NETBIOS.
|
||
|
||
Arguments:
|
||
|
||
Transport - The generic TDI address.
|
||
|
||
BroadcastAddressOk - TRUE if we should return the broadcast
|
||
address if found. If so, a value of (PVOID)-1 indicates
|
||
the broadcast address.
|
||
|
||
Return Value:
|
||
|
||
A pointer to the Netbios address, or NULL if none is found,
|
||
or (PVOID)-1 if the broadcast address is found.
|
||
|
||
--*/
|
||
|
||
{
|
||
TA_ADDRESS * addressName;
|
||
INT i;
|
||
ULONG LastBufferLength;
|
||
|
||
//
|
||
// At least 1 Netbios address should be present
|
||
//
|
||
if (MaxBufferLength < sizeof(TA_NETBIOS_ADDRESS))
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
addressName = &TransportAddress->Address[0];
|
||
//
|
||
// The name can be passed with multiple entries; we'll take and use only
|
||
// the Netbios one.
|
||
//
|
||
LastBufferLength = FIELD_OFFSET(TRANSPORT_ADDRESS,Address); // Just before Address[0]
|
||
for (i=0;i<TransportAddress->TAAddressCount;i++)
|
||
{
|
||
if (addressName->AddressType == TDI_ADDRESS_TYPE_NETBIOS)
|
||
{
|
||
if ((addressName->AddressLength == 0) && BroadcastAddressOk)
|
||
{
|
||
return (PVOID)-1;
|
||
}
|
||
else if (addressName->AddressLength == sizeof(TDI_ADDRESS_NETBIOS))
|
||
{
|
||
return ((TDI_ADDRESS_NETBIOS *)(addressName->Address));
|
||
}
|
||
}
|
||
|
||
//
|
||
// Update LastBufferLength + check for space for at least one
|
||
// Netbios address beyond this
|
||
//
|
||
LastBufferLength += FIELD_OFFSET(TA_ADDRESS,Address) + addressName->AddressLength;
|
||
if (MaxBufferLength < (LastBufferLength +
|
||
(sizeof(TA_NETBIOS_ADDRESS)-FIELD_OFFSET(TRANSPORT_ADDRESS,Address))))
|
||
{
|
||
NbiPrint0 ("NbiParseTdiAddress: No valid Netbios address to register!\n");
|
||
return (NULL);
|
||
}
|
||
|
||
addressName = (TA_ADDRESS *)(addressName->Address + addressName->AddressLength);
|
||
}
|
||
|
||
return NULL;
|
||
} /* NbiParseTdiAddress */
|
||
|
||
|
||
BOOLEAN
|
||
NbiValidateTdiAddress(
|
||
IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
|
||
IN ULONG TransportAddressLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine scans a TRANSPORT_ADDRESS, verifying that the
|
||
components of the address do not extend past the specified
|
||
length.
|
||
|
||
Arguments:
|
||
|
||
TransportAddress - The generic TDI address.
|
||
|
||
TransportAddressLength - The specific length of TransportAddress.
|
||
|
||
Return Value:
|
||
|
||
TRUE if the address is valid, FALSE otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
PUCHAR AddressEnd = ((PUCHAR)TransportAddress) + TransportAddressLength;
|
||
TA_ADDRESS * addressName;
|
||
INT i;
|
||
|
||
if (TransportAddressLength < sizeof(TransportAddress->TAAddressCount)) {
|
||
NbiPrint0 ("NbfValidateTdiAddress: runt address\n");
|
||
return FALSE;
|
||
}
|
||
|
||
addressName = &TransportAddress->Address[0];
|
||
|
||
for (i=0;i<TransportAddress->TAAddressCount;i++) {
|
||
if (addressName->Address > AddressEnd) {
|
||
NbiPrint0 ("NbiValidateTdiAddress: address too short\n");
|
||
return FALSE;
|
||
}
|
||
addressName = (TA_ADDRESS *)(addressName->Address +
|
||
addressName->AddressLength);
|
||
}
|
||
|
||
if ((PUCHAR)addressName > AddressEnd) {
|
||
NbiPrint0 ("NbiValidateTdiAddress: address too short\n");
|
||
return FALSE;
|
||
}
|
||
return TRUE;
|
||
|
||
} /* NbiValidateTdiAddress */
|
||
|
||
|
||
NTSTATUS
|
||
NbiOpenAddress(
|
||
IN PDEVICE Device,
|
||
IN PREQUEST Request
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine opens a file that points to an existing address object, or, if
|
||
the object doesn't exist, creates it (note that creation of the address
|
||
object includes registering the address, and may take many seconds to
|
||
complete, depending upon system configuration).
|
||
|
||
If the address already exists, and it has an ACL associated with it, the
|
||
ACL is checked for access rights before allowing creation of the address.
|
||
|
||
Arguments:
|
||
|
||
Device - pointer to the device describing the Netbios transport.
|
||
|
||
Request - a pointer to the request used for the creation of the address.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - status of operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
PADDRESS Address;
|
||
PADDRESS_FILE AddressFile;
|
||
PFILE_FULL_EA_INFORMATION ea;
|
||
TRANSPORT_ADDRESS UNALIGNED *name;
|
||
TDI_ADDRESS_NETBIOS * NetbiosAddress;
|
||
ULONG DesiredShareAccess;
|
||
CTELockHandle LockHandle;
|
||
PACCESS_STATE AccessState;
|
||
ACCESS_MASK GrantedAccess;
|
||
BOOLEAN AccessAllowed;
|
||
BOOLEAN found = FALSE;
|
||
ULONG AddressLength = 0;
|
||
#ifdef ISN_NT
|
||
PIRP Irp = (PIRP)Request;
|
||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
#endif
|
||
#if 0
|
||
TA_NETBIOS_ADDRESS FakeAddress;
|
||
#endif
|
||
|
||
|
||
//
|
||
// The network name is in the EA, passed in the request.
|
||
//
|
||
|
||
ea = OPEN_REQUEST_EA_INFORMATION(Request);
|
||
if (ea == NULL) {
|
||
NbiPrint1("OpenAddress: REQUEST %lx has no EA\n", Request);
|
||
return STATUS_INVALID_ADDRESS_COMPONENT;
|
||
}
|
||
|
||
//
|
||
// this may be a valid name; parse the name from the EA and use it if OK.
|
||
//
|
||
|
||
name = (PTRANSPORT_ADDRESS)&ea->EaName[ea->EaNameLength+1];
|
||
AddressLength = (ULONG) ea->EaValueLength;
|
||
#if 0
|
||
TdiBuildNetbiosAddress(
|
||
"ADAMBA67 ",
|
||
FALSE,
|
||
&FakeAddress);
|
||
name = (PTRANSPORT_ADDRESS)&FakeAddress;
|
||
#endif
|
||
|
||
//
|
||
// The name can be passed with multiple entries; we'll take and use only
|
||
// the first one of type Netbios. This call returns (PVOID)-1 if the
|
||
// address is the broadcast address.
|
||
//
|
||
|
||
NetbiosAddress = NbiParseTdiAddress (name, AddressLength, TRUE);
|
||
|
||
if (NetbiosAddress == NULL) {
|
||
NbiPrint1("OpenAddress: REQUEST %lx has no Netbios Address\n", Request);
|
||
return STATUS_INVALID_ADDRESS_COMPONENT;
|
||
}
|
||
|
||
//
|
||
// get an address file structure to represent this address.
|
||
//
|
||
|
||
AddressFile = NbiCreateAddressFile (Device);
|
||
|
||
if (AddressFile == (PADDRESS_FILE)NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
//
|
||
// See if this address is already established. This call automatically
|
||
// increments the reference count on the address so that it won't disappear
|
||
// from underneath us after this call but before we have a chance to use it.
|
||
//
|
||
// To ensure that we don't create two address objects for the
|
||
// same address, we hold the device context addressResource until
|
||
// we have found the address or created a new one.
|
||
//
|
||
|
||
KeEnterCriticalRegion();
|
||
ExAcquireResourceExclusiveLite (&Device->AddressResource, TRUE);
|
||
|
||
Address = NbiFindAddress(Device, (NetbiosAddress == (PVOID)-1 ) ? (PVOID)-1:NetbiosAddress->NetbiosName);
|
||
if (Address == NULL) {
|
||
|
||
//
|
||
// This address doesn't exist. Create it.
|
||
// This initializes the address with a ref
|
||
// of type ADDRESS_FILE, so if we fail here
|
||
// we need to remove that.
|
||
//
|
||
if (NT_SUCCESS (status = NbiCreateAddress (Request, AddressFile, IrpSp, Device, NetbiosAddress, &Address))) {
|
||
|
||
ExReleaseResourceLite (&Device->AddressResource);
|
||
KeLeaveCriticalRegion();
|
||
|
||
ASSERT (Address);
|
||
if (status == STATUS_PENDING) {
|
||
NbiStartRegistration (Address);
|
||
}
|
||
|
||
NbiDereferenceAddress (Address, AREF_ADDRESS_FILE); // We had 1 extra ref in NbiCreateAddress
|
||
} else {
|
||
|
||
ExReleaseResourceLite (&Device->AddressResource);
|
||
KeLeaveCriticalRegion();
|
||
|
||
//
|
||
// If the address could not be created, and is not in the
|
||
// process of being created, then we can't open up an address.
|
||
// Since we can't use the AddressLock to deref, we just destroy
|
||
// the address file.
|
||
//
|
||
|
||
NbiDestroyAddressFile (AddressFile);
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
} else {
|
||
|
||
NB_DEBUG2 (ADDRESS, ("Add to address %lx\n", Address));
|
||
|
||
//
|
||
// Set this now in case we have to deref.
|
||
//
|
||
|
||
AddressFile->AddressLock = &Address->Lock;
|
||
|
||
//
|
||
// Make sure the types do not conflict.
|
||
//
|
||
|
||
if ((NetbiosAddress != (PVOID)-1) &&
|
||
(NetbiosAddress->NetbiosNameType != Address->NetbiosAddress.NetbiosNameType)) {
|
||
|
||
NB_DEBUG (ADDRESS, ("Address types conflict %lx\n", Address));
|
||
ExReleaseResourceLite (&Device->AddressResource);
|
||
KeLeaveCriticalRegion();
|
||
NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
|
||
status = STATUS_DUPLICATE_NAME;
|
||
|
||
} else {
|
||
|
||
//
|
||
// The address already exists. Check the ACL and see if we
|
||
// can access it. If so, simply use this address as our address.
|
||
//
|
||
|
||
AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
|
||
|
||
AccessAllowed = SeAccessCheck(
|
||
Address->SecurityDescriptor,
|
||
&AccessState->SubjectSecurityContext,
|
||
FALSE, // tokens locked
|
||
IrpSp->Parameters.Create.SecurityContext->DesiredAccess,
|
||
(ACCESS_MASK)0, // previously granted
|
||
NULL, // privileges
|
||
&AddressGenericMapping,
|
||
(KPROCESSOR_MODE)((IrpSp->Flags&SL_FORCE_ACCESS_CHECK) ? UserMode : Irp->RequestorMode),
|
||
&GrantedAccess,
|
||
&status);
|
||
|
||
if (!AccessAllowed) {
|
||
|
||
NB_DEBUG (ADDRESS, ("Address access not allowed %lx\n", Address));
|
||
ExReleaseResourceLite (&Device->AddressResource);
|
||
KeLeaveCriticalRegion();
|
||
NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
|
||
|
||
} else {
|
||
|
||
//
|
||
// Now check that we can obtain the desired share
|
||
// access. We use read access to control all access.
|
||
//
|
||
|
||
DesiredShareAccess = (ULONG)
|
||
(((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
|
||
(IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
|
||
FILE_SHARE_READ : 0);
|
||
|
||
status = IoCheckShareAccess(
|
||
FILE_READ_DATA,
|
||
DesiredShareAccess,
|
||
IrpSp->FileObject,
|
||
&Address->u.ShareAccess,
|
||
TRUE);
|
||
|
||
|
||
if (!NT_SUCCESS (status)) {
|
||
|
||
NB_DEBUG (ADDRESS, ("Address share access wrong %lx\n", Address));
|
||
ExReleaseResourceLite (&Device->AddressResource);
|
||
KeLeaveCriticalRegion();
|
||
NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
|
||
|
||
} else {
|
||
|
||
ExReleaseResourceLite (&Device->AddressResource);
|
||
KeLeaveCriticalRegion();
|
||
|
||
NB_GET_LOCK (&Address->Lock, &LockHandle);
|
||
|
||
//
|
||
// Insert the address file on the address
|
||
// list; we will pend this open if the address
|
||
// is still registering. If the address has
|
||
// already failed as duplicate, then we
|
||
// fail the open.
|
||
//
|
||
|
||
if (Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) {
|
||
|
||
NB_DEBUG (ADDRESS, ("Address duplicated %lx\n", Address));
|
||
NB_FREE_LOCK (&Address->Lock, LockHandle);
|
||
|
||
NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
|
||
status = STATUS_DUPLICATE_NAME;
|
||
|
||
} else {
|
||
|
||
InsertTailList (
|
||
&Address->AddressFileDatabase,
|
||
&AddressFile->Linkage);
|
||
|
||
//
|
||
// Start registration unless it is registered or
|
||
// it is the broadcast address.
|
||
//
|
||
|
||
if ((Address->State == ADDRESS_STATE_REGISTERING) &&
|
||
(NetbiosAddress != (PVOID)-1)) {
|
||
|
||
AddressFile->OpenRequest = Request;
|
||
AddressFile->State = ADDRESSFILE_STATE_OPENING;
|
||
status = STATUS_PENDING;
|
||
|
||
} else {
|
||
|
||
AddressFile->OpenRequest = NULL;
|
||
AddressFile->State = ADDRESSFILE_STATE_OPEN;
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
|
||
AddressFile->Address = Address;
|
||
#ifdef ISN_NT
|
||
AddressFile->FileObject = IrpSp->FileObject;
|
||
#endif
|
||
|
||
NbiReferenceAddress (Address, AREF_ADDRESS_FILE);
|
||
|
||
REQUEST_OPEN_CONTEXT(Request) = (PVOID)AddressFile;
|
||
REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
|
||
|
||
NB_FREE_LOCK (&Address->Lock, LockHandle);
|
||
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Remove the reference from NbiLookupAddress.
|
||
//
|
||
|
||
NbiDereferenceAddress (Address, AREF_LOOKUP);
|
||
}
|
||
|
||
return status;
|
||
|
||
} /* NbiOpenAddress */
|
||
|
||
|
||
VOID
|
||
NbiStartRegistration(
|
||
IN PADDRESS Address
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine starts the registration process for a netbios name
|
||
by sending out the first add name packet and starting the timer
|
||
so that NbiRegistrationTimeout is called after the correct timeout.
|
||
|
||
Arguments:
|
||
|
||
Address - The address which is to be registered.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - status of operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
NB_DEBUG2 (ADDRESS, ("StartRegistration of %lx\n", Address));
|
||
|
||
//
|
||
// First send out an add name packet.
|
||
//
|
||
|
||
NbiSendNameFrame(
|
||
Address,
|
||
(UCHAR)(Address->NameTypeFlag | NB_NAME_USED),
|
||
NB_CMD_ADD_NAME,
|
||
NULL,
|
||
NULL);
|
||
|
||
Address->RegistrationCount = 0;
|
||
|
||
//
|
||
// Now start the timer.
|
||
//
|
||
|
||
NbiReferenceAddress (Address, AREF_TIMER);
|
||
|
||
CTEInitTimer (&Address->RegistrationTimer);
|
||
CTEStartTimer(
|
||
&Address->RegistrationTimer,
|
||
Address->Device->BroadcastTimeout,
|
||
NbiRegistrationTimeout,
|
||
(PVOID)Address);
|
||
|
||
} /* NbiStartRegistration */
|
||
|
||
|
||
VOID
|
||
NbiRegistrationTimeout(
|
||
IN CTEEvent * Event,
|
||
IN PVOID Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called when the address registration
|
||
timer expires. It sends another add name if needed, or
|
||
checks the result if the correct number have been sent.
|
||
|
||
Arguments:
|
||
|
||
Event - The event used to queue the timer.
|
||
|
||
Context - The context, which is the address pointer.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PADDRESS Address = (PADDRESS)Context;
|
||
CTELockHandle LockHandle;
|
||
PADDRESS_FILE AddressFile, ReferencedAddressFile;
|
||
PLIST_ENTRY p;
|
||
|
||
++Address->RegistrationCount;
|
||
|
||
if ((Address->RegistrationCount < Address->Device->BroadcastCount) &&
|
||
((Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) == 0)) {
|
||
|
||
NB_DEBUG2 (ADDRESS, ("Send add name %d for %lx\n", Address->RegistrationCount+1, Address));
|
||
|
||
NbiSendNameFrame(
|
||
Address,
|
||
(UCHAR)(Address->NameTypeFlag | NB_NAME_USED),
|
||
NB_CMD_ADD_NAME,
|
||
NULL,
|
||
NULL);
|
||
|
||
CTEStartTimer(
|
||
&Address->RegistrationTimer,
|
||
Address->Device->BroadcastTimeout,
|
||
NbiRegistrationTimeout,
|
||
(PVOID)Address);
|
||
|
||
} else {
|
||
|
||
//
|
||
// The correct number of frames have been sent, see what
|
||
// happened.
|
||
//
|
||
|
||
NB_DEBUG2 (ADDRESS, ("Done with add names for %lx\n", Address));
|
||
|
||
ReferencedAddressFile = NULL;
|
||
|
||
NB_GET_LOCK (&Address->Lock, &LockHandle);
|
||
|
||
for (p = Address->AddressFileDatabase.Flink;
|
||
p != &Address->AddressFileDatabase;
|
||
p = p->Flink) {
|
||
|
||
AddressFile = CONTAINING_RECORD (p, ADDRESS_FILE, Linkage);
|
||
CTEAssert (AddressFile->State == ADDRESSFILE_STATE_OPENING);
|
||
CTEAssert (AddressFile->OpenRequest != NULL);
|
||
|
||
NbiReferenceAddressFileLock (AddressFile, AFREF_TIMEOUT);
|
||
|
||
NB_FREE_LOCK (&Address->Lock, LockHandle);
|
||
|
||
if (ReferencedAddressFile) {
|
||
NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_TIMEOUT);
|
||
}
|
||
|
||
//
|
||
// Now see what to do with this address file.
|
||
//
|
||
|
||
REQUEST_INFORMATION(AddressFile->OpenRequest) = 0;
|
||
|
||
if (Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) {
|
||
|
||
NB_DEBUG (ADDRESS, ("Open of address file %lx failed, duplicate\n", AddressFile));
|
||
REQUEST_STATUS(AddressFile->OpenRequest) = STATUS_DUPLICATE_NAME;
|
||
NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
|
||
|
||
} else {
|
||
|
||
NB_DEBUG2 (ADDRESS, ("Complete open of address file %lx\n", AddressFile));
|
||
REQUEST_STATUS(AddressFile->OpenRequest) = STATUS_SUCCESS;
|
||
AddressFile->State = ADDRESSFILE_STATE_OPEN;
|
||
|
||
}
|
||
|
||
NbiCompleteRequest (AddressFile->OpenRequest);
|
||
NbiFreeRequest (Address->Device, AddressFile->OpenRequest);
|
||
|
||
NB_GET_LOCK (&Address->Lock, &LockHandle);
|
||
|
||
ReferencedAddressFile = AddressFile;
|
||
|
||
}
|
||
|
||
//
|
||
// Set the Address Flag here since in the loop above, we are constantly
|
||
// releasing and reacquiring the lock -- hence we could have a new
|
||
// client added to this address, but there there would be no OpenRequest
|
||
// value since he would think that the registration process had already completed.
|
||
//
|
||
if ((Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) == 0) {
|
||
Address->State = ADDRESS_STATE_OPEN;
|
||
} else {
|
||
Address->State = ADDRESS_STATE_STOPPING;
|
||
}
|
||
|
||
NB_FREE_LOCK (&Address->Lock, LockHandle);
|
||
|
||
if (ReferencedAddressFile) {
|
||
NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_TIMEOUT);
|
||
}
|
||
|
||
NbiDereferenceAddress (Address, AREF_TIMER);
|
||
|
||
}
|
||
|
||
} /* NbiRegistrationTimeout */
|
||
|
||
|
||
VOID
|
||
NbiProcessFindName(
|
||
IN PIPX_LOCAL_TARGET RemoteAddress,
|
||
IN ULONG MacOptions,
|
||
IN PUCHAR PacketBuffer,
|
||
IN UINT PacketSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine handles NB_CMD_FIND_NAME frames.
|
||
|
||
Arguments:
|
||
|
||
RemoteAddress - The local target this packet was received from.
|
||
|
||
MacOptions - The MAC options for the underlying NDIS binding.
|
||
|
||
LookaheadBuffer - The packet data, starting at the IPX
|
||
header.
|
||
|
||
PacketSize - The total length of the packet, starting at the
|
||
IPX header.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PADDRESS Address;
|
||
NB_CONNECTIONLESS UNALIGNED * NbConnectionless =
|
||
(NB_CONNECTIONLESS UNALIGNED *)PacketBuffer;
|
||
PDEVICE Device = NbiDevice;
|
||
|
||
if (PacketSize != sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME)) {
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Quick check for any names starting with this character.
|
||
//
|
||
|
||
if (Device->AddressCounts[NbConnectionless->NameFrame.Name[0]] == 0) {
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Always respond to broadcast requests.
|
||
//
|
||
#if defined(_PNP_POWER)
|
||
if (RtlEqualMemory (NetbiosBroadcastName, NbConnectionless->NameFrame.Name, 16)) {
|
||
|
||
NbiSendNameFrame(
|
||
NULL,
|
||
NB_NAME_DUPLICATED, // this is what Novell machines use
|
||
NB_CMD_NAME_RECOGNIZED,
|
||
RemoteAddress,
|
||
NbConnectionless);
|
||
|
||
} else if (Address = NbiFindAddress(Device, (PUCHAR)NbConnectionless->NameFrame.Name)) {
|
||
|
||
NbiSendNameFrame(
|
||
Address,
|
||
(UCHAR)(Address->NameTypeFlag | NB_NAME_USED | NB_NAME_REGISTERED),
|
||
NB_CMD_NAME_RECOGNIZED,
|
||
RemoteAddress,
|
||
NbConnectionless);
|
||
|
||
NbiDereferenceAddress (Address, AREF_FIND);
|
||
|
||
} else if ( NbiFindAdapterAddress( NbConnectionless->NameFrame.Name, LOCK_NOT_ACQUIRED ) ) {
|
||
|
||
NbiSendNameFrame(
|
||
NULL,
|
||
(UCHAR)(NB_NAME_UNIQUE | NB_NAME_USED | NB_NAME_REGISTERED),
|
||
NB_CMD_NAME_RECOGNIZED,
|
||
RemoteAddress,
|
||
NbConnectionless);
|
||
}
|
||
#else
|
||
if (RtlEqualMemory (NetbiosBroadcastName, NbConnectionless->NameFrame.Name, 16)) {
|
||
|
||
NbiSendNameFrame(
|
||
NULL,
|
||
NB_NAME_DUPLICATED, // this is what Novell machines use
|
||
NB_CMD_NAME_RECOGNIZED,
|
||
RemoteAddress,
|
||
(PTDI_ADDRESS_IPX)(NbConnectionless->IpxHeader.SourceNetwork));
|
||
|
||
} else if (Address = NbiFindAddress(Device, (PUCHAR)NbConnectionless->NameFrame.Name)) {
|
||
|
||
NbiSendNameFrame(
|
||
Address,
|
||
(UCHAR)(Address->NameTypeFlag | NB_NAME_USED | NB_NAME_REGISTERED),
|
||
NB_CMD_NAME_RECOGNIZED,
|
||
RemoteAddress,
|
||
(PTDI_ADDRESS_IPX)(NbConnectionless->IpxHeader.SourceNetwork));
|
||
|
||
NbiDereferenceAddress (Address, AREF_FIND);
|
||
|
||
}
|
||
#endif _PNP_POWER
|
||
} /* NbiProcessFindName */
|
||
|
||
|
||
VOID
|
||
NbiProcessAddName(
|
||
IN PIPX_LOCAL_TARGET RemoteAddress,
|
||
IN ULONG MacOptions,
|
||
IN PUCHAR PacketBuffer,
|
||
IN UINT PacketSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine handles NB_CMD_ADD_NAME frames.
|
||
|
||
Arguments:
|
||
|
||
RemoteAddress - The local target this packet was received from.
|
||
|
||
MacOptions - The MAC options for the underlying NDIS binding.
|
||
|
||
LookaheadBuffer - The packet data, starting at the IPX
|
||
header.
|
||
|
||
PacketSize - The total length of the packet, starting at the
|
||
IPX header.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PADDRESS Address;
|
||
NB_CONNECTIONLESS UNALIGNED * NbConnectionless =
|
||
(NB_CONNECTIONLESS UNALIGNED *)PacketBuffer;
|
||
PDEVICE Device = NbiDevice;
|
||
CTELockHandle LockHandle;
|
||
BOOLEAN LocalFrame;
|
||
|
||
|
||
if (PacketSize != sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME)) {
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Ignore any frame that came from us, except for the purpose
|
||
// of updating the cache.
|
||
//
|
||
|
||
if ((Device->Bind.QueryHandler)(
|
||
IPX_QUERY_IS_ADDRESS_LOCAL,
|
||
#if defined(_PNP_POWER)
|
||
&RemoteAddress->NicHandle,
|
||
#else
|
||
RemoteAddress->NicId,
|
||
#endif _PNP_POWER
|
||
NbConnectionless->IpxHeader.SourceNetwork,
|
||
sizeof(TDI_ADDRESS_IPX),
|
||
NULL) == STATUS_SUCCESS) {
|
||
|
||
LocalFrame = TRUE;
|
||
|
||
} else {
|
||
|
||
LocalFrame = FALSE;
|
||
|
||
}
|
||
|
||
if (!LocalFrame) {
|
||
|
||
if ((Device->AddressCounts[NbConnectionless->NameFrame.Name[0]] != 0) &&
|
||
(Address = NbiFindAddress(Device, (PUCHAR)NbConnectionless->NameFrame.Name))) {
|
||
|
||
if (NB_NODE_BROADCAST(NbConnectionless->IpxHeader.DestinationNode)) {
|
||
|
||
//
|
||
// If this frame is an add name (identified because it is a
|
||
// broadcast frame) then respond if we have it registered
|
||
// unique, or we have it group and someone is trying to add
|
||
// it unique.
|
||
//
|
||
|
||
if ((Address->NetbiosAddress.NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_UNIQUE) ||
|
||
((Address->NetbiosAddress.NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_GROUP) &&
|
||
((NbConnectionless->NameFrame.NameTypeFlag & NB_NAME_GROUP) == 0))) {
|
||
|
||
//
|
||
// According to GeorgeJ's doc, on a name in use we just
|
||
// echo back the name type flags from the request.
|
||
//
|
||
|
||
NbiSendNameFrame(
|
||
Address,
|
||
NbConnectionless->NameFrame.NameTypeFlag,
|
||
NB_CMD_NAME_IN_USE,
|
||
RemoteAddress,
|
||
#if defined(_PNP_POWER)
|
||
NbConnectionless);
|
||
#else
|
||
(PTDI_ADDRESS_IPX)(NbConnectionless->IpxHeader.SourceNetwork));
|
||
#endif _PNP_POWER
|
||
}
|
||
|
||
} else if ((*(UNALIGNED ULONG *)NbConnectionless->IpxHeader.DestinationNetwork ==
|
||
*(UNALIGNED ULONG *)Device->Bind.Network) &&
|
||
NB_NODE_EQUAL(NbConnectionless->IpxHeader.DestinationNode, Device->Bind.Node)) {
|
||
|
||
//
|
||
// If this is an add name response (which will be sent
|
||
// directly to us) then we need to mark the address
|
||
// as such.
|
||
//
|
||
|
||
NB_GET_LOCK (&Address->Lock, &LockHandle);
|
||
Address->Flags |= ADDRESS_FLAGS_DUPLICATE_NAME;
|
||
NB_FREE_LOCK (&Address->Lock, LockHandle);
|
||
}
|
||
|
||
NbiDereferenceAddress (Address, AREF_FIND);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// Pass this frame over to the netbios cache management
|
||
// routines to check if they need to update their cache.
|
||
//
|
||
|
||
CacheUpdateFromAddName (RemoteAddress, NbConnectionless, LocalFrame);
|
||
|
||
} /* NbiProcessAddName */
|
||
|
||
NTSTATUS
|
||
SetAddressSecurityInfo(
|
||
IN PADDRESS Address,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
)
|
||
{
|
||
ULONG DesiredShareAccess;
|
||
PACCESS_STATE AccessState;
|
||
NTSTATUS status;
|
||
|
||
//
|
||
// Initialize the shared access now. We use read access
|
||
// to control all access.
|
||
//
|
||
DesiredShareAccess = (ULONG) (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
|
||
(IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
|
||
FILE_SHARE_READ : 0);
|
||
|
||
IoSetShareAccess(FILE_READ_DATA, DesiredShareAccess, IrpSp->FileObject, &Address->u.ShareAccess);
|
||
|
||
//
|
||
// Assign the security descriptor (need to do this with
|
||
// the spinlock released because the descriptor is not
|
||
// mapped).
|
||
//
|
||
AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
|
||
status = SeAssignSecurity(
|
||
NULL, // parent descriptor
|
||
AccessState->SecurityDescriptor,
|
||
&Address->SecurityDescriptor,
|
||
FALSE, // is directory
|
||
&AccessState->SubjectSecurityContext,
|
||
&AddressGenericMapping,
|
||
NonPagedPool);
|
||
|
||
if (!NT_SUCCESS (status)) {
|
||
IoRemoveShareAccess (IrpSp->FileObject, &Address->u.ShareAccess);
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
NbiCreateAddress(
|
||
IN PREQUEST Request,
|
||
IN PADDRESS_FILE AddressFile,
|
||
IN PIO_STACK_LOCATION IrpSp,
|
||
IN PDEVICE Device,
|
||
IN TDI_ADDRESS_NETBIOS *NetbiosAddress,
|
||
OUT PADDRESS *pAddress
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine creates a transport address and associates it with
|
||
the specified transport device context. The reference count in the
|
||
address is initialized to 2, and the reference count of the
|
||
device context is incremented.
|
||
|
||
Arguments:
|
||
|
||
Device - Pointer to the device context (which is really just
|
||
the device object with its extension) to be associated with the
|
||
address.
|
||
|
||
NetbiosAddress - The name to assign to this address, or -1 if it
|
||
is the broadcast address.
|
||
|
||
Return Value:
|
||
|
||
The newly created address, or NULL if none can be allocated.
|
||
|
||
--*/
|
||
|
||
{
|
||
PADDRESS Address;
|
||
CTELockHandle LockHandle;
|
||
NTSTATUS status;
|
||
|
||
//
|
||
// if the adapter isn't ready, we can't do any of this; get out
|
||
//
|
||
if (Device->State != DEVICE_STATE_OPEN) {
|
||
return STATUS_DEVICE_NOT_READY;
|
||
}
|
||
|
||
if (!(Address = (PADDRESS)NbiAllocateMemory (sizeof(ADDRESS), MEMORY_ADDRESS, "Address"))) {
|
||
NB_DEBUG (ADDRESS, ("Create address %.16s failed\n",
|
||
(NetbiosAddress == (PVOID)-1) ? "<broadcast>" : NetbiosAddress->NetbiosName));
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
NB_DEBUG2 (ADDRESS, ("Create address %lx (%.16s)\n", Address,
|
||
(NetbiosAddress == (PVOID)-1) ? "<broadcast>" : NetbiosAddress->NetbiosName));
|
||
RtlZeroMemory (Address, sizeof(ADDRESS));
|
||
|
||
if (!NT_SUCCESS (status = SetAddressSecurityInfo(Address, IrpSp))) {
|
||
//
|
||
// Error, return status.
|
||
//
|
||
NbiFreeMemory (Address, sizeof(ADDRESS), MEMORY_ADDRESS, "Address");
|
||
return status;
|
||
}
|
||
|
||
Address->Type = NB_ADDRESS_SIGNATURE;
|
||
Address->Size = sizeof (ADDRESS);
|
||
Address->State = ADDRESS_STATE_REGISTERING;
|
||
Address->Flags = 0;
|
||
|
||
Address->Device = Device;
|
||
Address->DeviceLock = &Device->Lock;
|
||
CTEInitLock (&Address->Lock.Lock);
|
||
|
||
InitializeListHead (&Address->AddressFileDatabase);
|
||
|
||
Address->ReferenceCount = 2; // Initialize it to 2 -- it will be Deref'ed by the caller
|
||
#if DBG
|
||
Address->RefTypes[AREF_ADDRESS_FILE] = 1;
|
||
#endif
|
||
|
||
if (NetbiosAddress == (PVOID)-1) {
|
||
Address->NetbiosAddress.Broadcast = TRUE;
|
||
} else {
|
||
Address->NetbiosAddress.Broadcast = FALSE;
|
||
Address->NetbiosAddress.NetbiosNameType = NetbiosAddress->NetbiosNameType;
|
||
RtlCopyMemory (Address->NetbiosAddress.NetbiosName, NetbiosAddress->NetbiosName, 16);
|
||
++Device->AddressCounts[NetbiosAddress->NetbiosName[0]];
|
||
}
|
||
|
||
if (Address->NetbiosAddress.NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_UNIQUE) {
|
||
Address->NameTypeFlag = NB_NAME_UNIQUE;
|
||
} else {
|
||
Address->NameTypeFlag = NB_NAME_GROUP;
|
||
}
|
||
|
||
//
|
||
// Set this now in case we have to deref.
|
||
//
|
||
AddressFile->AddressLock = &Address->Lock;
|
||
|
||
REQUEST_OPEN_CONTEXT(Request) = (PVOID)AddressFile;
|
||
REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
|
||
AddressFile->FileObject = IrpSp->FileObject;
|
||
AddressFile->Address = Address;
|
||
|
||
NB_INSERT_TAIL_LIST (&Address->AddressFileDatabase, &AddressFile->Linkage, &Address->Lock);
|
||
|
||
if (NetbiosAddress == (PVOID)-1) {
|
||
AddressFile->OpenRequest = NULL;
|
||
AddressFile->State = ADDRESSFILE_STATE_OPEN;
|
||
status = STATUS_SUCCESS;
|
||
} else {
|
||
AddressFile->OpenRequest = Request;
|
||
AddressFile->State = ADDRESSFILE_STATE_OPENING;
|
||
status = STATUS_PENDING;
|
||
}
|
||
|
||
//
|
||
// Now link this address into the specified device context's
|
||
// address database. To do this, we need to acquire the spin lock
|
||
// on the device context.
|
||
//
|
||
NB_GET_LOCK (&Device->Lock, &LockHandle);
|
||
|
||
InsertTailList (&Device->AddressDatabase, &Address->Linkage);
|
||
++Device->AddressCount;
|
||
|
||
NB_FREE_LOCK (&Device->Lock, LockHandle);
|
||
|
||
NbiReferenceDevice (Device, DREF_ADDRESS);
|
||
|
||
*pAddress = Address;
|
||
return status;
|
||
} /* NbiCreateAddress */
|
||
|
||
|
||
NTSTATUS
|
||
NbiVerifyAddressFile (
|
||
#if defined(_PNP_POWER)
|
||
IN PADDRESS_FILE AddressFile,
|
||
IN BOOLEAN ConflictIsOk
|
||
#else
|
||
IN PADDRESS_FILE AddressFile
|
||
#endif _PNP_POWER
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to verify that the pointer given us in a file
|
||
object is in fact a valid address file object. We also verify that the
|
||
address object pointed to by it is a valid address object, and reference
|
||
it to keep it from disappearing while we use it.
|
||
|
||
Arguments:
|
||
|
||
AddressFile - potential pointer to a ADDRESS_FILE object
|
||
|
||
ConflictIsOk - TRUE if we should succeed the verify even if the
|
||
corresponding address is in CONFLICT. ( For Close and
|
||
cleanup we return STATUS_SUCCESS even if we are in conflict
|
||
so that the addressfile can be destroyed)
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if all is well; STATUS_INVALID_ADDRESS otherwise
|
||
|
||
--*/
|
||
|
||
{
|
||
CTELockHandle LockHandle;
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
PADDRESS Address;
|
||
BOOLEAN LockHeld = FALSE;
|
||
|
||
//
|
||
// try to verify the address file signature. If the signature is valid,
|
||
// verify the address pointed to by it and get the address spinlock.
|
||
// check the address's state, and increment the reference count if it's
|
||
// ok to use it. Note that the only time we return an error for state is
|
||
// if the address is closing.
|
||
//
|
||
|
||
try {
|
||
|
||
if ((AddressFile->Size == sizeof (ADDRESS_FILE)) &&
|
||
(AddressFile->Type == NB_ADDRESSFILE_SIGNATURE) ) {
|
||
// (AddressFile->State != ADDRESSFILE_STATE_CLOSING) ) {
|
||
|
||
Address = AddressFile->Address;
|
||
|
||
if ((Address->Size == sizeof (ADDRESS)) &&
|
||
(Address->Type == NB_ADDRESS_SIGNATURE) ) {
|
||
|
||
NB_GET_LOCK (&Address->Lock, &LockHandle);
|
||
|
||
LockHeld = TRUE;
|
||
|
||
#if defined(_PNP_POWER)
|
||
if (Address->State != ADDRESS_STATE_STOPPING &&
|
||
( ConflictIsOk || ( !(Address->Flags & ADDRESS_FLAGS_CONFLICT) )) ) {
|
||
#else
|
||
if (Address->State != ADDRESS_STATE_STOPPING) {
|
||
#endif _PNP_POWER
|
||
|
||
NbiReferenceAddressFileLock (AddressFile, AFREF_VERIFY);
|
||
|
||
} else {
|
||
|
||
NbiPrint1("NbiVerifyAddressFile: A %lx closing\n", Address);
|
||
status = STATUS_INVALID_ADDRESS;
|
||
}
|
||
|
||
NB_FREE_LOCK (&Address->Lock, LockHandle);
|
||
|
||
} else {
|
||
|
||
NbiPrint1("NbiVerifyAddressFile: A %lx bad signature\n", Address);
|
||
status = STATUS_INVALID_ADDRESS;
|
||
}
|
||
|
||
} else {
|
||
|
||
NbiPrint1("NbiVerifyAddressFile: AF %lx bad signature\n", AddressFile);
|
||
status = STATUS_INVALID_ADDRESS;
|
||
}
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
||
NbiPrint1("NbiVerifyAddressFile: AF %lx exception\n", Address);
|
||
if (LockHeld) {
|
||
NB_FREE_LOCK (&Address->Lock, LockHandle);
|
||
}
|
||
return GetExceptionCode();
|
||
}
|
||
|
||
return status;
|
||
|
||
} /* NbiVerifyAddressFile */
|
||
|
||
|
||
VOID
|
||
NbiDestroyAddress(
|
||
IN PVOID Parameter
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine destroys a transport address and removes all references
|
||
made by it to other objects in the transport. The address structure
|
||
is returned to nonpaged system pool. It is assumed
|
||
that the caller has already removed all addressfile structures associated
|
||
with this address.
|
||
|
||
It is called from a worker thread queue by NbiDerefAddress when
|
||
the reference count goes to 0.
|
||
|
||
This thread is only queued by NbiDerefAddress. The reason for
|
||
this is that there may be multiple streams of execution which are
|
||
simultaneously referencing the same address object, and it should
|
||
not be deleted out from under an interested stream of execution.
|
||
|
||
Arguments:
|
||
|
||
Address - Pointer to a transport address structure to be destroyed.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - status of operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
PADDRESS Address = (PADDRESS)Parameter;
|
||
PDEVICE Device = Address->Device;
|
||
CTELockHandle LockHandle;
|
||
|
||
NB_DEBUG2 (ADDRESS, ("Destroy address %lx <%.16s>\n", Address,
|
||
Address->NetbiosAddress.Broadcast ? "<broadcast>" : Address->NetbiosAddress.NetbiosName));
|
||
|
||
SeDeassignSecurity (&Address->SecurityDescriptor);
|
||
|
||
//
|
||
// Delink this address from its associated device context's address
|
||
// database. To do this we must spin lock on the device context object,
|
||
// not on the address.
|
||
//
|
||
|
||
NB_GET_LOCK (&Device->Lock, &LockHandle);
|
||
|
||
if (!Address->NetbiosAddress.Broadcast) {
|
||
--Device->AddressCounts[Address->NetbiosAddress.NetbiosName[0]];
|
||
}
|
||
--Device->AddressCount;
|
||
RemoveEntryList (&Address->Linkage);
|
||
NB_FREE_LOCK (&Device->Lock, LockHandle);
|
||
|
||
NbiFreeMemory (Address, sizeof(ADDRESS), MEMORY_ADDRESS, "Address");
|
||
|
||
NbiDereferenceDevice (Device, DREF_ADDRESS);
|
||
|
||
} /* NbiDestroyAddress */
|
||
|
||
|
||
#if DBG
|
||
VOID
|
||
NbiRefAddress(
|
||
IN PADDRESS Address
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine increments the reference count on a transport address.
|
||
|
||
Arguments:
|
||
|
||
Address - Pointer to a transport address object.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
CTEAssert (Address->ReferenceCount > 0); // not perfect, but...
|
||
|
||
InterlockedIncrement( &Address->ReferenceCount );
|
||
} /* NbiRefAddress */
|
||
|
||
|
||
VOID
|
||
NbiRefAddressLock(
|
||
IN PADDRESS Address
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine increments the reference count on a transport address
|
||
when the device lock is already held.
|
||
|
||
Arguments:
|
||
|
||
Address - Pointer to a transport address object.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
CTEAssert (Address->ReferenceCount > 0); // not perfect, but...
|
||
|
||
InterlockedIncrement( &Address->ReferenceCount );
|
||
|
||
} /* NbiRefAddressLock */
|
||
#endif
|
||
|
||
|
||
VOID
|
||
NbiDerefAddress(
|
||
IN PADDRESS Address
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine dereferences a transport address by decrementing the
|
||
reference count contained in the structure. If, after being
|
||
decremented, the reference count is zero, then this routine calls
|
||
NbiDestroyAddress to remove it from the system.
|
||
|
||
Arguments:
|
||
|
||
Address - Pointer to a transport address object.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG newvalue;
|
||
|
||
newvalue = InterlockedDecrement( &Address->ReferenceCount );
|
||
//
|
||
// If we have deleted all references to this address, then we can
|
||
// destroy the object. It is okay to have already released the spin
|
||
// lock at this point because there is no possible way that another
|
||
// stream of execution has access to the address any longer.
|
||
//
|
||
|
||
CTEAssert ((LONG)newvalue >= 0);
|
||
|
||
if (newvalue == 0) {
|
||
|
||
#if ISN_NT
|
||
ExInitializeWorkItem(
|
||
&Address->u.DestroyAddressQueueItem,
|
||
NbiDestroyAddress,
|
||
(PVOID)Address);
|
||
ExQueueWorkItem(&Address->u.DestroyAddressQueueItem, DelayedWorkQueue);
|
||
#else
|
||
NbiDestroyAddress(Address);
|
||
#endif
|
||
|
||
}
|
||
|
||
} /* NbiDerefAddress */
|
||
|
||
|
||
PADDRESS_FILE
|
||
NbiCreateAddressFile(
|
||
IN PDEVICE Device
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine creates an address file from the pool of ther
|
||
specified device context. The reference count in the
|
||
address is automatically set to 1.
|
||
|
||
Arguments:
|
||
|
||
Device - Pointer to the device context (which is really just
|
||
the device object with its extension) to be associated with the
|
||
address.
|
||
|
||
Return Value:
|
||
|
||
The allocate address file or NULL.
|
||
|
||
--*/
|
||
|
||
{
|
||
CTELockHandle LockHandle;
|
||
PADDRESS_FILE AddressFile;
|
||
UINT i;
|
||
|
||
NB_GET_LOCK (&Device->Lock, &LockHandle);
|
||
|
||
AddressFile = (PADDRESS_FILE)NbiAllocateMemory (sizeof(ADDRESS_FILE), MEMORY_ADDRESS, "AddressFile");
|
||
if (AddressFile == NULL) {
|
||
NB_DEBUG (ADDRESS, ("Create address file failed\n"));
|
||
NB_FREE_LOCK (&Device->Lock, LockHandle);
|
||
return NULL;
|
||
}
|
||
|
||
NB_DEBUG2 (ADDRESS, ("Create address file %lx\n", AddressFile));
|
||
|
||
RtlZeroMemory (AddressFile, sizeof(ADDRESS_FILE));
|
||
|
||
AddressFile->Type = NB_ADDRESSFILE_SIGNATURE;
|
||
AddressFile->Size = sizeof (ADDRESS_FILE);
|
||
|
||
InitializeListHead (&AddressFile->ReceiveDatagramQueue);
|
||
InitializeListHead (&AddressFile->ConnectionDatabase);
|
||
|
||
NB_FREE_LOCK (&Device->Lock, LockHandle);
|
||
|
||
AddressFile->Address = NULL;
|
||
#ifdef ISN_NT
|
||
AddressFile->FileObject = NULL;
|
||
#endif
|
||
AddressFile->Device = Device;
|
||
AddressFile->State = ADDRESSFILE_STATE_OPENING;
|
||
AddressFile->ReferenceCount = 1;
|
||
#if DBG
|
||
AddressFile->RefTypes[AFREF_CREATE] = 1;
|
||
#endif
|
||
AddressFile->CloseRequest = (PREQUEST)NULL;
|
||
|
||
//
|
||
// Initialize the request handlers.
|
||
//
|
||
|
||
for (i = 0; i < 6; i++) {
|
||
AddressFile->RegisteredHandler[i] = FALSE;
|
||
AddressFile->HandlerContexts[i] = NULL;
|
||
AddressFile->Handlers[i] = TdiDefaultHandlers[i];
|
||
}
|
||
|
||
CTEAssert (AddressFile->ConnectionHandler == TdiDefaultConnectHandler);
|
||
CTEAssert (AddressFile->DisconnectHandler == TdiDefaultDisconnectHandler);
|
||
CTEAssert (AddressFile->ErrorHandler == TdiDefaultErrorHandler);
|
||
CTEAssert (AddressFile->ReceiveHandler == TdiDefaultReceiveHandler);
|
||
CTEAssert (AddressFile->ReceiveDatagramHandler == TdiDefaultRcvDatagramHandler);
|
||
CTEAssert (AddressFile->ExpeditedDataHandler == TdiDefaultRcvExpeditedHandler);
|
||
|
||
return AddressFile;
|
||
|
||
} /* NbiCreateAddressFile */
|
||
|
||
|
||
NTSTATUS
|
||
NbiDestroyAddressFile(
|
||
IN PADDRESS_FILE AddressFile
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine destroys an address file and removes all references
|
||
made by it to other objects in the transport.
|
||
|
||
This routine is only called by NbiDereferenceAddressFile. The reason
|
||
for this is that there may be multiple streams of execution which are
|
||
simultaneously referencing the same address file object, and it should
|
||
not be deleted out from under an interested stream of execution.
|
||
|
||
Arguments:
|
||
|
||
AddressFile Pointer to a transport address file structure to be destroyed.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - status of operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
CTELockHandle LockHandle, LockHandle1;
|
||
PADDRESS Address;
|
||
PDEVICE Device;
|
||
PREQUEST CloseRequest;
|
||
BOOLEAN StopAddress;
|
||
|
||
NB_DEBUG2 (ADDRESS, ("Destroy address file %lx\n", AddressFile));
|
||
|
||
Address = AddressFile->Address;
|
||
Device = AddressFile->Device;
|
||
|
||
if (Address) {
|
||
|
||
//
|
||
// This addressfile was associated with an address.
|
||
//
|
||
|
||
NB_GET_LOCK (&Address->Lock, &LockHandle);
|
||
|
||
//
|
||
// remove this addressfile from the address list and disassociate it from
|
||
// the file handle.
|
||
//
|
||
|
||
RemoveEntryList (&AddressFile->Linkage);
|
||
InitializeListHead (&AddressFile->Linkage);
|
||
|
||
if (Address->AddressFileDatabase.Flink == &Address->AddressFileDatabase) {
|
||
|
||
//
|
||
// This is the last open of this address, it will close
|
||
// due to normal dereferencing but we have to set the
|
||
// CLOSING flag too to stop further references.
|
||
//
|
||
|
||
NB_GET_LOCK (&Device->Lock, &LockHandle1);
|
||
Address->State = ADDRESS_STATE_STOPPING;
|
||
NB_FREE_LOCK (&Device->Lock, LockHandle1);
|
||
|
||
StopAddress = TRUE;
|
||
|
||
} else {
|
||
|
||
StopAddress = FALSE;
|
||
}
|
||
|
||
AddressFile->Address = NULL;
|
||
|
||
#ifdef ISN_NT
|
||
AddressFile->FileObject->FsContext = NULL;
|
||
AddressFile->FileObject->FsContext2 = NULL;
|
||
#endif
|
||
|
||
NB_FREE_LOCK (&Address->Lock, LockHandle);
|
||
|
||
//
|
||
// We will already have been removed from the ShareAccess
|
||
// of the owning address.
|
||
//
|
||
|
||
if (StopAddress && (!Address->NetbiosAddress.Broadcast)) {
|
||
|
||
NbiSendNameFrame(
|
||
Address,
|
||
(UCHAR)(Address->NameTypeFlag |
|
||
NB_NAME_USED | NB_NAME_REGISTERED | NB_NAME_DEREGISTERED),
|
||
NB_CMD_DELETE_NAME,
|
||
NULL,
|
||
NULL);
|
||
}
|
||
|
||
//
|
||
// Now dereference the owning address.
|
||
//
|
||
|
||
NbiDereferenceAddress (Address, AREF_ADDRESS_FILE);
|
||
|
||
}
|
||
|
||
//
|
||
// Save this for later completion.
|
||
//
|
||
|
||
CloseRequest = AddressFile->CloseRequest;
|
||
|
||
//
|
||
// return the addressFile to the pool of address files
|
||
//
|
||
|
||
NbiFreeMemory (AddressFile, sizeof(ADDRESS_FILE), MEMORY_ADDRESS, "AddressFile");
|
||
|
||
if (CloseRequest != (PREQUEST)NULL) {
|
||
REQUEST_INFORMATION(CloseRequest) = 0;
|
||
REQUEST_STATUS(CloseRequest) = STATUS_SUCCESS;
|
||
NbiCompleteRequest (CloseRequest);
|
||
NbiFreeRequest (Device, CloseRequest);
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
} /* NbiDestroyAddressFile */
|
||
|
||
|
||
#if DBG
|
||
VOID
|
||
NbiRefAddressFile(
|
||
IN PADDRESS_FILE AddressFile
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine increments the reference count on an address file.
|
||
|
||
Arguments:
|
||
|
||
AddressFile - Pointer to a transport address file object.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but...
|
||
|
||
|
||
InterlockedIncrement( &AddressFile->ReferenceCount );
|
||
} /* NbiRefAddressFile */
|
||
|
||
|
||
VOID
|
||
NbiRefAddressFileLock(
|
||
IN PADDRESS_FILE AddressFile
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine increments the reference count on an address file.
|
||
IT IS CALLED WITH THE ADDRESS LOCK HELD.
|
||
|
||
Arguments:
|
||
|
||
AddressFile - Pointer to a transport address file object.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but...
|
||
|
||
|
||
InterlockedIncrement( &AddressFile->ReferenceCount );
|
||
|
||
} /* NbiRefAddressFileLock */
|
||
|
||
#endif
|
||
|
||
|
||
VOID
|
||
NbiDerefAddressFile(
|
||
IN PADDRESS_FILE AddressFile
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine dereferences an address file by decrementing the
|
||
reference count contained in the structure. If, after being
|
||
decremented, the reference count is zero, then this routine calls
|
||
NbiDestroyAddressFile to remove it from the system.
|
||
|
||
Arguments:
|
||
|
||
AddressFile - Pointer to a transport address file object.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG newvalue;
|
||
|
||
newvalue = InterlockedDecrement( &AddressFile->ReferenceCount );
|
||
|
||
//
|
||
// If we have deleted all references to this address file, then we can
|
||
// destroy the object. It is okay to have already released the spin
|
||
// lock at this point because there is no possible way that another
|
||
// stream of execution has access to the address any longer.
|
||
//
|
||
|
||
CTEAssert ((LONG)newvalue >= 0);
|
||
|
||
if (newvalue == 0) {
|
||
NbiDestroyAddressFile (AddressFile);
|
||
}
|
||
|
||
} /* NbiDerefAddressFile */
|
||
|
||
#if !defined(_PNP_POWER)
|
||
|
||
PADDRESS
|
||
NbiLookupAddress(
|
||
IN PDEVICE Device,
|
||
IN TDI_ADDRESS_NETBIOS UNALIGNED * NetbiosAddress
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine scans the transport addresses defined for the given
|
||
device context and compares them with the specified NETWORK
|
||
NAME values. If an exact match is found, then a pointer to the
|
||
ADDRESS object is returned, and as a side effect, the reference
|
||
count to the address object is incremented. If the address is not
|
||
found, then NULL is returned.
|
||
|
||
NOTE: This routine must be called with the Device
|
||
spinlock held.
|
||
|
||
Arguments:
|
||
|
||
Device - Pointer to the device object and its extension.
|
||
|
||
NetbiosAddress - The name to look up, or -1 if the broadcast
|
||
address is being searched for.
|
||
|
||
Return Value:
|
||
|
||
Pointer to the ADDRESS object found, or NULL if not found.
|
||
|
||
--*/
|
||
|
||
{
|
||
PADDRESS Address;
|
||
PLIST_ENTRY p;
|
||
|
||
p = Device->AddressDatabase.Flink;
|
||
|
||
for (p = Device->AddressDatabase.Flink;
|
||
p != &Device->AddressDatabase;
|
||
p = p->Flink) {
|
||
|
||
Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
|
||
|
||
if (Address->State == ADDRESS_STATE_STOPPING) {
|
||
continue;
|
||
}
|
||
|
||
if (Address->NetbiosAddress.Broadcast) {
|
||
|
||
//
|
||
// This address is the broadcast one, so no match
|
||
// unless we are looking for that.
|
||
//
|
||
|
||
if (NetbiosAddress != (PVOID)-1) {
|
||
continue;
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// This address is not the broadcast, so if we are
|
||
// looking for that then no match, else compare the
|
||
// two names.
|
||
//
|
||
|
||
if (NetbiosAddress == (PVOID)-1) {
|
||
continue;
|
||
}
|
||
|
||
if (!RtlEqualMemory(
|
||
Address->NetbiosAddress.NetbiosName,
|
||
NetbiosAddress->NetbiosName,
|
||
16)) {
|
||
continue;
|
||
}
|
||
}
|
||
|
||
//
|
||
// We found the match. Bump the reference count on the address, and
|
||
// return a pointer to the address object for the caller to use.
|
||
//
|
||
|
||
NbiReferenceAddressLock (Address, AREF_LOOKUP);
|
||
return Address;
|
||
|
||
} /* for */
|
||
|
||
//
|
||
// The specified address was not found.
|
||
//
|
||
|
||
return NULL;
|
||
|
||
} /* NbiLookupAddress */
|
||
#endif !_PNP_POWER
|
||
|
||
|
||
PADDRESS
|
||
NbiFindAddress(
|
||
IN PDEVICE Device,
|
||
IN PUCHAR NetbiosName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine scans the transport addresses defined for the given
|
||
device context and compares them with the specified NetbiosName
|
||
values. If a match is found, the address is referenced and the
|
||
pointer is returned.
|
||
|
||
We ignore any addresses which are either STOPPING or are under
|
||
CONFLICT state.
|
||
|
||
A name in CONFLICT is dead for all practical purposes
|
||
except Close. This routine is called by various name service,
|
||
datagram and session sevice routines. We hide any names in CONFLICT
|
||
from these routines.
|
||
|
||
This routine is also called by NbiTdiOpenAddress().
|
||
A name could have been marked in CONFLICT ages ago(but is not closed
|
||
yet). We must allow another open of the same name as that might
|
||
succeed now.
|
||
|
||
Arguments:
|
||
|
||
Device - Pointer to the device object and its extension.
|
||
|
||
NetbiosName - The name to look up, or -1 for the broadcast name.
|
||
|
||
Return Value:
|
||
|
||
Pointer to the ADDRESS object found, or NULL if not found.
|
||
|
||
--*/
|
||
|
||
{
|
||
PADDRESS Address;
|
||
PLIST_ENTRY p;
|
||
CTELockHandle LockHandle;
|
||
|
||
|
||
NB_GET_LOCK (&Device->Lock, &LockHandle);
|
||
|
||
p = Device->AddressDatabase.Flink;
|
||
|
||
for (p = Device->AddressDatabase.Flink;
|
||
p != &Device->AddressDatabase;
|
||
p = p->Flink) {
|
||
|
||
Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
|
||
|
||
#if defined(_PNP_POWER)
|
||
if ( ( Address->State == ADDRESS_STATE_STOPPING ) ||
|
||
( Address->Flags & ADDRESS_FLAGS_CONFLICT ) ) {
|
||
#else
|
||
if (Address->State == ADDRESS_STATE_STOPPING) {
|
||
#endif _PNP_POWER
|
||
continue;
|
||
}
|
||
|
||
if (Address->NetbiosAddress.Broadcast) {
|
||
|
||
//
|
||
// This address is the broadcast one, so no match
|
||
// unless we are looking for that.
|
||
//
|
||
|
||
if (NetbiosName != (PVOID)-1) {
|
||
continue;
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// This address is not the broadcast, so if we are
|
||
// looking for that then no match, else compare the
|
||
// two names.
|
||
//
|
||
|
||
if ((NetbiosName == (PVOID)-1) ||
|
||
(!RtlEqualMemory(
|
||
Address->NetbiosAddress.NetbiosName,
|
||
NetbiosName,
|
||
16))) {
|
||
continue;
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// We found the match. Bump the reference count on the address, and
|
||
// return a pointer to the address object for the caller to use.
|
||
//
|
||
|
||
NbiReferenceAddressLock (Address, AREF_FIND);
|
||
NB_FREE_LOCK (&Device->Lock, LockHandle);
|
||
return Address;
|
||
|
||
} /* for */
|
||
|
||
//
|
||
// The specified address was not found.
|
||
//
|
||
|
||
NB_FREE_LOCK (&Device->Lock, LockHandle);
|
||
return NULL;
|
||
|
||
} /* NbiFindAddress */
|
||
|
||
|
||
NTSTATUS
|
||
NbiStopAddressFile(
|
||
IN PADDRESS_FILE AddressFile,
|
||
IN PADDRESS Address
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to terminate all activity on an AddressFile and
|
||
destroy the object. We remove every connection and datagram associated
|
||
with this addressfile from the address database and terminate their
|
||
activity. Then, if there are no other outstanding addressfiles open on
|
||
this address, the address will go away.
|
||
|
||
Arguments:
|
||
|
||
AddressFile - pointer to the addressFile to be stopped
|
||
|
||
Address - the owning address for this addressFile (we do not depend upon
|
||
the pointer in the addressFile because we want this routine to be safe)
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the request
|
||
is not for a real address.
|
||
|
||
--*/
|
||
|
||
{
|
||
PLIST_ENTRY p;
|
||
PCONNECTION Connection;
|
||
PREQUEST Request;
|
||
PDEVICE Device = Address->Device;
|
||
CTELockHandle LockHandle1, LockHandle2;
|
||
LIST_ENTRY SendDatagramList;
|
||
PNB_SEND_RESERVED Reserved;
|
||
PREQUEST DatagramRequest;
|
||
NB_DEFINE_LOCK_HANDLE (LockHandle3)
|
||
CTELockHandle CancelLH;
|
||
NB_DEFINE_SYNC_CONTEXT (SyncContext)
|
||
LIST_ENTRY DatagramQ;
|
||
|
||
|
||
|
||
NB_GET_LOCK (&Address->Lock, &LockHandle1);
|
||
|
||
if (AddressFile->State == ADDRESSFILE_STATE_CLOSING) {
|
||
NB_FREE_LOCK (&Address->Lock, LockHandle1);
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
//
|
||
// This prevents anybody else from being put on the
|
||
// ConnectionDatabase.
|
||
//
|
||
|
||
AddressFile->State = ADDRESSFILE_STATE_CLOSING;
|
||
|
||
while (!IsListEmpty (&AddressFile->ConnectionDatabase)) {
|
||
|
||
p = RemoveHeadList (&AddressFile->ConnectionDatabase);
|
||
Connection = CONTAINING_RECORD (p, CONNECTION, AddressFileLinkage);
|
||
|
||
CTEAssert (Connection->AddressFile == AddressFile);
|
||
Connection->AddressFileLinked = FALSE;
|
||
|
||
NB_GET_LOCK (&Device->Lock, &LockHandle2);
|
||
|
||
if (Connection->ReferenceCount == 0) {
|
||
|
||
//
|
||
// The refcount is already 0, so we can just
|
||
// NULL out this field to complete the disassociate.
|
||
//
|
||
|
||
Connection->AddressFile = NULL;
|
||
NB_FREE_LOCK (&Device->Lock, LockHandle2);
|
||
NB_FREE_LOCK (&Address->Lock, LockHandle1);
|
||
|
||
NbiDereferenceAddressFile (AddressFile, AFREF_CONNECTION);
|
||
|
||
} else {
|
||
|
||
//
|
||
// Mark this so we know to disassociate when the
|
||
// count goes to 0, but that there is no specific
|
||
// request pending on it. We also stop the connection
|
||
// to shut it down.
|
||
//
|
||
|
||
Connection->DisassociatePending = (PVOID)-1;
|
||
NbiReferenceConnectionLock (Connection, CREF_DISASSOC);
|
||
|
||
NB_FREE_LOCK (&Device->Lock, LockHandle2);
|
||
NB_FREE_LOCK (&Address->Lock, LockHandle1);
|
||
|
||
NB_BEGIN_SYNC (&SyncContext);
|
||
NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle3);
|
||
|
||
//
|
||
// This call frees the connection lock.
|
||
//
|
||
|
||
NbiStopConnection(
|
||
Connection,
|
||
STATUS_INVALID_ADDRESS
|
||
NB_LOCK_HANDLE_ARG (LockHandle3));
|
||
|
||
NB_END_SYNC (&SyncContext);
|
||
|
||
NbiDereferenceConnection (Connection, CREF_DISASSOC);
|
||
|
||
}
|
||
|
||
NB_GET_LOCK (&Address->Lock, &LockHandle1);
|
||
}
|
||
|
||
NB_FREE_LOCK (&Address->Lock, LockHandle1);
|
||
|
||
|
||
//
|
||
// Abort all pending send datagrams.
|
||
//
|
||
|
||
InitializeListHead (&SendDatagramList);
|
||
|
||
NB_GET_LOCK (&Device->Lock, &LockHandle2);
|
||
|
||
p = Device->WaitingDatagrams.Flink;
|
||
|
||
while (p != &Device->WaitingDatagrams) {
|
||
|
||
Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
|
||
|
||
p = p->Flink;
|
||
|
||
if (Reserved->u.SR_DG.AddressFile == AddressFile) {
|
||
|
||
RemoveEntryList (&Reserved->WaitLinkage);
|
||
InsertTailList (&SendDatagramList, &Reserved->WaitLinkage);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
NB_FREE_LOCK (&Device->Lock, LockHandle2);
|
||
|
||
for (p = SendDatagramList.Flink; p != &SendDatagramList; ) {
|
||
|
||
Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
|
||
p = p->Flink;
|
||
|
||
DatagramRequest = Reserved->u.SR_DG.DatagramRequest;
|
||
|
||
NB_DEBUG2 (DATAGRAM, ("Aborting datagram %lx on %lx\n", DatagramRequest, AddressFile));
|
||
|
||
REQUEST_STATUS(DatagramRequest) = STATUS_SUCCESS;
|
||
|
||
NbiCompleteRequest(DatagramRequest);
|
||
NbiFreeRequest (Device, DatagramRequest);
|
||
|
||
NbiDereferenceAddressFile (AddressFile, AFREF_SEND_DGRAM);
|
||
|
||
ExInterlockedPushEntrySList(
|
||
&Device->SendPacketList,
|
||
&Reserved->PoolLinkage,
|
||
&NbiGlobalPoolInterlock);
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// Abort all pending receive datagrams.
|
||
//
|
||
|
||
InitializeListHead( &DatagramQ );
|
||
|
||
NB_GET_CANCEL_LOCK(&CancelLH);
|
||
NB_GET_LOCK (&Address->Lock, &LockHandle1);
|
||
|
||
while (!IsListEmpty(&AddressFile->ReceiveDatagramQueue)) {
|
||
|
||
p = RemoveHeadList (&AddressFile->ReceiveDatagramQueue);
|
||
Request = LIST_ENTRY_TO_REQUEST (p);
|
||
|
||
// Insert it on a private Q, so it can be completed later.
|
||
InsertTailList( &DatagramQ, p);
|
||
|
||
REQUEST_INFORMATION(Request) = 0;
|
||
REQUEST_STATUS(Request) = STATUS_NETWORK_NAME_DELETED;
|
||
|
||
IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
|
||
|
||
|
||
|
||
NbiDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM);
|
||
|
||
}
|
||
|
||
NB_FREE_LOCK (&Address->Lock, LockHandle1);
|
||
NB_FREE_CANCEL_LOCK(CancelLH);
|
||
|
||
for( p = DatagramQ.Flink; p != &DatagramQ; ) {
|
||
Request = LIST_ENTRY_TO_REQUEST ( p );
|
||
|
||
p = p->Flink;
|
||
|
||
NbiCompleteRequest (Request);
|
||
NbiFreeRequest (Device, Request);
|
||
|
||
}
|
||
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
} /* NbiStopAddressFile */
|
||
|
||
|
||
NTSTATUS
|
||
NbiCloseAddressFile(
|
||
IN PDEVICE Device,
|
||
IN PREQUEST Request
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to close the addressfile pointed to by a file
|
||
object. If there is any activity to be run down, we will run it down
|
||
before we terminate the addressfile. We remove every connection and
|
||
datagram associated with this addressfile from the address database
|
||
and terminate their activity. Then, if there are no other outstanding
|
||
addressfiles open on this address, the address will go away.
|
||
|
||
Arguments:
|
||
|
||
Request - the close request.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the
|
||
request does not point to a real address.
|
||
|
||
--*/
|
||
|
||
{
|
||
PADDRESS Address;
|
||
PADDRESS_FILE AddressFile;
|
||
|
||
AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
|
||
AddressFile->CloseRequest = Request;
|
||
|
||
//
|
||
// We assume that addressFile has already been verified
|
||
// at this point.
|
||
//
|
||
|
||
Address = AddressFile->Address;
|
||
CTEAssert (Address);
|
||
|
||
//
|
||
// Remove us from the access info for this address.
|
||
//
|
||
|
||
KeEnterCriticalRegion();
|
||
ExAcquireResourceExclusiveLite (&Device->AddressResource, TRUE);
|
||
#ifdef ISN_NT
|
||
IoRemoveShareAccess (AddressFile->FileObject, &Address->u.ShareAccess);
|
||
#endif
|
||
ExReleaseResourceLite (&Device->AddressResource);
|
||
KeLeaveCriticalRegion();
|
||
|
||
NbiStopAddressFile (AddressFile, Address);
|
||
NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
|
||
|
||
return STATUS_PENDING;
|
||
|
||
} /* NbiCloseAddressFile */
|
||
|
||
#if defined(_PNP_POWER)
|
||
|
||
|
||
PADAPTER_ADDRESS
|
||
NbiCreateAdapterAddress(
|
||
IN PCHAR AdapterMacAddress
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine creates an adapter address sttuctures which stores
|
||
the netbios name of an adapter. the netbios name has 12 0's
|
||
followed by the mac address of the adapter.
|
||
|
||
Arguments:
|
||
|
||
Device - Pointer to the device context (which is really just
|
||
the device object with its extension) to be associated with the
|
||
address.
|
||
|
||
AdapterMacAddress - pointer to the adapter mac address given to us
|
||
by IPX.
|
||
|
||
Return Value:
|
||
|
||
The newly created address, or NULL if none can be allocated.
|
||
THIS ROUTINE MUST BE CALLED WITH THE DEVICE LOCK HELD.
|
||
|
||
--*/
|
||
|
||
{
|
||
PADAPTER_ADDRESS AdapterAddress;
|
||
CTELockHandle LockHandle;
|
||
PDEVICE Device = NbiDevice;
|
||
|
||
AdapterAddress = (PADAPTER_ADDRESS)NbiAllocateMemory (sizeof(ADAPTER_ADDRESS), MEMORY_ADAPTER_ADDRESS, "Adapter Address");
|
||
if (AdapterAddress == NULL) {
|
||
CTEAssert (AdapterMacAddress);
|
||
NB_DEBUG (ADDRESS, ("Create Adapter Address <%2.2x><%2.2x><%2.2x><%2.2x><%2.2x><%2.2x> failed\n",
|
||
(UCHAR) AdapterMacAddress[0],
|
||
(UCHAR) AdapterMacAddress[1],
|
||
(UCHAR) AdapterMacAddress[2],
|
||
(UCHAR) AdapterMacAddress[3],
|
||
(UCHAR) AdapterMacAddress[4],
|
||
(UCHAR) AdapterMacAddress[5]
|
||
));
|
||
return NULL;
|
||
}
|
||
|
||
AdapterAddress->Type = NB_ADAPTER_ADDRESS_SIGNATURE;
|
||
AdapterAddress->Size = sizeof (ADDRESS);
|
||
|
||
RtlZeroMemory(AdapterAddress->NetbiosName, 10);
|
||
RtlCopyMemory(&AdapterAddress->NetbiosName[10], AdapterMacAddress, 6);
|
||
|
||
|
||
InsertTailList (&Device->AdapterAddressDatabase, &AdapterAddress->Linkage);
|
||
++Device->AddressCounts[AdapterAddress->NetbiosName[0]];
|
||
|
||
return AdapterAddress;
|
||
|
||
} /* NbiCreateAdapterAddress */
|
||
|
||
|
||
NTSTATUS
|
||
NbiDestroyAdapterAddress(
|
||
IN PADAPTER_ADDRESS AdapterAddress OPTIONAL,
|
||
IN PCHAR AdapterMacAddress OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine destroys the adapter address structure and removes it
|
||
from the list.
|
||
|
||
Arguments:
|
||
|
||
AdapterAddress - Pointer to an adapter address structure to be destroyed
|
||
NULL if AdapterMacAddress is given.
|
||
|
||
AdapterMacAddress - Mac Address of the adapter which just got deleted. so find
|
||
the corresponding adapter address structure and remove it.
|
||
NULL if AdapterAddress is supplied.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS or STATUS_UNSUCCESSFUL if address not found.
|
||
|
||
THIS ROUTINE ASSUMES THE THE DEVICE IS LOCK IS HELD BY THE CALLER
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE Device = NbiDevice;
|
||
CTELockHandle LockHandle;
|
||
UCHAR NetbiosName[NB_NETBIOS_NAME_SIZE];
|
||
|
||
|
||
//
|
||
|
||
CTEAssert( AdapterAddress || AdapterMacAddress );
|
||
if ( !AdapterAddress ) {
|
||
RtlZeroMemory( NetbiosName, 10);
|
||
RtlCopyMemory( &NetbiosName[10], AdapterMacAddress, 6 );
|
||
|
||
AdapterAddress = NbiFindAdapterAddress( NetbiosName, LOCK_ACQUIRED );
|
||
|
||
if ( !AdapterAddress ) {
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
}
|
||
|
||
NB_DEBUG2 (ADDRESS, ("Destroy Adapter address %lx <%.16s>\n", AdapterAddress,AdapterAddress->NetbiosName));
|
||
RemoveEntryList (&AdapterAddress->Linkage);
|
||
++Device->AddressCounts[AdapterAddress->NetbiosName[0]];
|
||
|
||
NbiFreeMemory (AdapterAddress, sizeof(ADAPTER_ADDRESS), MEMORY_ADAPTER_ADDRESS, "AdapterAddress");
|
||
|
||
return STATUS_SUCCESS;
|
||
} /* NbiDestroyAdapterAddress */
|
||
|
||
|
||
PADAPTER_ADDRESS
|
||
NbiFindAdapterAddress(
|
||
IN PCHAR NetbiosName,
|
||
IN BOOLEAN LockHeld
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine finds an adapter address ( netbios name ) for the given
|
||
AdapterMacAddress and returns a pointer to it. Note that no reference
|
||
is done on this address, so if this routine is called without the device
|
||
lock, the caller must not use this pointer directly.
|
||
|
||
Arguments:
|
||
|
||
NetbiosName - NetbiosName to be found.
|
||
|
||
LockHeld - is device lock already held or not.
|
||
|
||
Return Value:
|
||
|
||
Pointer to the adapter address if found, NULL otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PLIST_ENTRY p;
|
||
CTELockHandle LockHandle;
|
||
PADAPTER_ADDRESS AdapterAddress;
|
||
PDEVICE Device = NbiDevice;
|
||
|
||
|
||
if ( !LockHeld ) {
|
||
NB_GET_LOCK( &Device->Lock, &LockHandle );
|
||
}
|
||
for ( p = Device->AdapterAddressDatabase.Flink;
|
||
p != &Device->AdapterAddressDatabase;
|
||
p = p->Flink ) {
|
||
|
||
AdapterAddress = CONTAINING_RECORD( p, ADAPTER_ADDRESS, Linkage );
|
||
if ( RtlEqualMemory(
|
||
NetbiosName,
|
||
AdapterAddress->NetbiosName,
|
||
NB_NETBIOS_NAME_SIZE ) ) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
if ( !LockHeld ) {
|
||
NB_FREE_LOCK( &Device->Lock, LockHandle );
|
||
}
|
||
|
||
if ( p == &Device->AdapterAddressDatabase ) {
|
||
return NULL;
|
||
} else {
|
||
return AdapterAddress;
|
||
}
|
||
|
||
} /* NbiFindAdapterAddress */
|
||
|
||
#endif _PNP_POWER
|