Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1885 lines
49 KiB

/*++
Copyright (c) 1989, 1990, 1991 Microsoft Corporation
Module Name:
addrobj.c
Abstract:
This module contains code which implements the ADDRESS_FILE object.
Routines are provided to create, destroy, reference, and dereference,
transport address objects. All stack equivalents(sockets, listeners)
are also opened here.
BUGBUG:
Should creation of address/connection objects increment ref counts
on device objects (currently they are not referenced). It is not
being done with the assumption that NT will call NtClose for all
existing handles before the Unload routine is called.
Author:
Nikhil Kamkolkar (nikhilk) July 1, 1992
Environment:
Kernel mode
Revision History:
--*/
#include "atalknt.h"
#include "addrobj.h"
//
// NOTE: All worker routines *must* be passed valid connection/address
// objects
//
VOID
AtalkAllocateAddress(
IN PATALK_DEVICE_CONTEXT Context,
OUT PADDRESS_FILE *Address
)
/*++
Routine Description:
This routine allocates storage for a transport Address. Some
minimal initialization is done.
Arguments:
Context - Currently unused, later statistics/freelists etc.
Address - Pointer to a place where this routine will
return a pointer to a transport Address structure. Returns
NULL if the storage cannot be allocated.
Return Value:
None.
--*/
{
PADDRESS_FILE address;
address = (PADDRESS_FILE)AtalkCallocNonPagedMemory(sizeof(ADDRESS_FILE),
sizeof(char));
if (address != NULL) {
//
// Initialize
//
address->Type = ATALK_ADDRESS_SIGNATURE;
address->Size = sizeof(ADDRESS_FILE);
} else {
//
// BUGBUG: LOG ERROR
//
}
*Address = address;
return;
}
VOID
AtalkDeallocateAddress(
IN PATALK_DEVICE_CONTEXT Context,
IN PADDRESS_FILE Address
)
/*++
Routine Description:
Deallocates the address structure
Arguments:
Context - Currently unused, later statistics/freelists etc.
Address - Pointer to a address structure
Return Value:
None.
--*/
{
DBGPRINT(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkDeallocateAddress - Deallocating %lx\n", Address));
AtalkFreeNonPagedMemory(Address);
return;
} /* AtalkDeallocateAddress */
VOID
AtalkRefAddress(
IN PADDRESS_FILE Address,
IN REFERENCE_SET ReferenceSet
)
/*++
Routine Description:
This routine increments the reference count on a transport address.
If the ReferenceSet is PRIMARY_REFSET, the primary reference count
is incremented, else the secondary reference count is incremented.
Arguments:
Address - Pointer to a transport address object.
ReferenceSet- Reference type to be incremented (PRIMARY_REFSET or
SECONDARY_REFSET).
Return Value:
none.
--*/
{
ULONG count;
if (ReferenceSet == PRIMARY_REFSET) {
count = NdisInterlockedAddUlong (
(PULONG)&Address->PrimaryReferenceCount,
(ULONG)1,
&AtalkGlobalRefLock);
} else {
//
// Secondary ref set
//
count = NdisInterlockedAddUlong (
(PULONG)&Address->SecondaryReferenceCount,
(ULONG)1,
&AtalkGlobalRefLock);
}
ASSERT (count >= 0);
return;
} /* AtalkReferenceAddress */
VOID
AtalkDerefAddress(
IN PADDRESS_FILE Address,
IN REFERENCE_SET ReferenceSet
)
/*++
Routine Description:
This routine dereferences a transport address by decrementing the
reference count contained in the structure. If, after being
decremented, both the primary and the secondary reference count are zero,
then this routine calls AtalkDestroyAddress to remove it from the system.
Arguments:
Address - Pointer to a transport address object.
ReferenceSet- Reference type to be decremented (PRIMARY_REFSET or
SECONDARY_REFSET).
Return Value:
none.
--*/
{
BOOLEAN cleanup = FALSE;
ACQUIRE_SPIN_LOCK(&AtalkGlobalRefLock);
if (ReferenceSet == PRIMARY_REFSET) {
Address->PrimaryReferenceCount--;
} else {
Address->SecondaryReferenceCount--;
}
if ((Address->PrimaryReferenceCount == 0) &&
(Address->SecondaryReferenceCount == 0)) {
cleanup = TRUE;
}
RELEASE_SPIN_LOCK(&AtalkGlobalRefLock);
if (cleanup) {
//
// Time to destroy the address
//
AtalkDestroyAddress (Address);
}
return;
} /* AtalkDereferenceAddress */
NTSTATUS
AtalkCreateAddress(
IN PTA_APPLETALK_ADDRESS AppletalkAddress,
OUT PADDRESS_FILE *Address,
IN UCHAR ProtocolType,
IN UCHAR SocketType,
IN PATALK_DEVICE_CONTEXT Context
)
/*++
Routine Description:
This routine creates a transport address. This includes opening
the socket (DDP/ATP).
Arguments:
Context - Pointer to the device context (which is really just
the device object with its extension) to be associated
with the address.
AppletalkAddress - Socket address to open and associate with address object.
The network/node values are ignored.
Address - Pointer to a place where this routine will return a pointer
to a transport address structure.
Return Value:
NTSTATUS - status of operation.
--*/
{
NTSTATUS status;
PADDRESS_FILE address;
PORTABLE_ERROR errorCode;
UCHAR socket;
AtalkAllocateAddress (Context, &address);
if (address == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Initialize all of the static data for this address.
//
#if DBG
{
UINT Counter;
for (Counter = 0; Counter < NUMBER_OF_AREFS; Counter++) {
address->RefTypes[Counter] = 0;
}
}
#endif
//
// This reference is removed by CloseAddress
//
AtalkReferenceAddress("CreationAddr", address, AREF_CREATION, PRIMARY_REFSET);
address->ProtocolType = ProtocolType;
address->SocketType = SocketType;
address->Flags = ADDRESS_FLAGS_OPEN;
address->DeviceContext = Context;
address->OwningDevice = Context->DeviceType;
NdisAllocateSpinLock(&address->AddressLock);
InitializeListHead(&address->ConnectionLinkage);
InitializeListHead(&address->RequestLinkage);
//
// Now create the socket depending on the devicetype
// Only two socket types are possible: DDP for ADSP/DDP devices
// ATP for ASP/PAP/ATP devices
//
socket = AppletalkAddress->Address[0].Address[0].Socket;
switch (address->OwningDevice) {
case ATALK_DEVICE_DDP :
case ATALK_DEVICE_ADSP :
//
// For all of these devices open a ddp socket
//
DBGPRINT(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkCreateAddress - DDP Socket %lx\n", (INT)socket));
errorCode = OpenSocketOnNode(
&address->SocketRefNum,
DEFAULT_PORT,
NULL, // Desired node
(INT)socket, // Socket to open
NULL, // Handler
(ULONG)0, // UserData
FALSE, // Is handler an event handler for datagrams?
NULL, // Datagram buffers
0, // Buffer size
NULL); // Actual address
break;
case ATALK_DEVICE_ATP :
case ATALK_DEVICE_ASP :
case ATALK_DEVICE_PAP :
//
// For all these devices open an ATP socket
//
DBGPRINT(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkCreateAddress - Socket ATP %lx\n", (INT)socket));
//
// We open an ATP socket- executes synchronously
//
errorCode = AtpOpenSocketOnNode(
&address->SocketRefNum,
DEFAULT_PORT,
NULL, // Extended Appletalk node number
(INT)socket, // Socket to open
NULL, // Datagram buffers
0); // Size of buffers
status = ConvertToNTStatus(errorCode, SYNC_REQUEST);
break;
default:
KeBugCheck(0);
}
status = ConvertToNTStatus(errorCode, SYNC_REQUEST);
if (NT_SUCCESS(status)) {
//
// Initialize the request handlers.
//
address->RegisteredConnectionHandler = FALSE;
address->ConnectionHandler = TdiDefaultConnectHandler;
address->ConnectionHandlerContext = NULL;
address->RegisteredDisconnectHandler = FALSE;
address->DisconnectHandler = TdiDefaultDisconnectHandler;
address->DisconnectHandlerContext = NULL;
address->RegisteredReceiveHandler = FALSE;
address->ReceiveHandler = TdiDefaultReceiveHandler;
address->ReceiveHandlerContext = NULL;
address->RegisteredReceiveDatagramHandler = FALSE;
address->ReceiveDatagramHandler = TdiDefaultRcvDatagramHandler;
address->ReceiveDatagramHandlerContext = NULL;
address->RegisteredExpeditedDataHandler = FALSE;
address->ExpeditedDataHandler = TdiDefaultRcvExpeditedHandler;
address->ExpeditedDataHandlerContext = NULL;
address->RegisteredErrorHandler = FALSE;
address->ErrorHandler = TdiDefaultErrorHandler;
address->ErrorHandlerContext = NULL;
} else {
//
// Cleanup work done so far
//
DBGPRINT(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_ERROR,
("ERROR: AtalkCreateAddress - %lx\n", status));
AtalkDeallocateAddress(Context, address);
address = NULL;
}
*Address = address; // return the address.
return status;
} /* AtalkCreateAddress */
NTSTATUS
AtalkCreateListener(
IN PADDRESS_FILE Address
)
/*++
Routine Description:
Opens a listener using the socket of the address object.
NOTE: We hold the address spinlock while the listener is
created, to avoid the race-conditions of connects
being posted on the COs at the same time.
Arguments:
Address - pointer to a ADDRESS_FILE object
Return Value:
NTSTATUS - status of operation.
--*/
{
NTSTATUS status;
PORTABLE_ERROR errorCode;
ACQUIRE_SPIN_LOCK(&Address->AddressLock);
do {
if (Address->Flags & ADDRESS_FLAGS_LISTENER) {
//
// Listener already created
//
status = STATUS_SUCCESS;
break;
}
if (Address->Flags & ADDRESS_FLAGS_CONNECT) {
//
// Only connects allowed on this address object!
//
DBGPRINT(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_ERROR,
("ERROR: AtalkCreateListener - ConnectsOnly %lx\n", Address));
status = STATUS_OBJECT_TYPE_MISMATCH;
break;
}
if (Address->Flags & ADDRESS_FLAGS_CLOSING) {
DBGPRINT(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_ERROR,
("ERROR: AtalkCreateListener - Address CLOSING %lx\n", Address));
status = STATUS_FILE_CLOSED;
break;
}
//
// Depending on the provider type open the listener- HOLD SpinLock
//
switch (Address->OwningDevice) {
case ATALK_DEVICE_DDP :
case ATALK_DEVICE_ATP :
//
// BUGBUG: Change this to
// errorCode = ATrequestNotSupported;
//
status = STATUS_NOT_SUPPORTED;
break;
case ATALK_DEVICE_ADSP :
errorCode = AdspCreateConnectionListener(
DEFAULT_PORT,
NULL, // Desired node
Address->SocketRefNum,
0, // Desired socket
&Address->ListenerRefNum,
NULL, // Return socket handle
NULL, // Connection event handler
0); // Context for handler
break;
case ATALK_DEVICE_ASP :
errorCode = AspCreateSessionListenerOnNode(
DEFAULT_PORT,
Address->SocketRefNum,
0, // Desired socket
&Address->ListenerRefNum, // Return listner ref num
NULL); // Opened socket
break;
case ATALK_DEVICE_PAP :
errorCode = PapCreateServiceListenerOnNode(
DEFAULT_PORT,
Address->SocketRefNum,
0, // Desired socket
NULL, // NBP Object
NULL, // Type
NULL, // Zone
(SHORT)8, // BUGBUG: Get from options
// PAP Server quantum
NULL, // Return opened socket
&Address->ListenerRefNum,
NULL, // Completion routines
(ULONG)0, // Completion context
NULL, // connection event handler
(ULONG)0); // context for above
break;
default:
KeBugCheck(0);
}
status = ConvertToNTStatus(errorCode, SYNC_REQUEST);
if (status == STATUS_SUCCESS) {
Address->Flags |= ADDRESS_FLAGS_LISTENER;
}
break;
} while (FALSE);
RELEASE_SPIN_LOCK(&Address->AddressLock);
return status;
} /* AtalkCreateListener */
NTSTATUS
AtalkVerifyAddressObject (
IN PADDRESS_FILE Address
)
/*++
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.
Arguments:
Address - potential pointer to a ADDRESS_FILE object
Return Value:
STATUS_SUCCESS if all is well;
STATUS_INVALID_ADDRESS otherwise
--*/
{
NTSTATUS status = STATUS_SUCCESS;
//
// try to verify the address file signature.
// Note that the only time we return an error for state is
// if the address is closing.
//
try {
if ((Address->Size == sizeof (ADDRESS_FILE)) &&
(Address->Type == ATALK_ADDRESS_SIGNATURE)) {
ACQUIRE_SPIN_LOCK (&Address->AddressLock);
if ((Address->Flags & ADDRESS_FLAGS_CLOSING) == 0) {
AtalkReferenceAddress ("VerAddr", Address, AREF_VERIFY,
SECONDARY_REFSET);
} else {
DBGPRINT(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_ERROR,
("ERROR: AtalkVerifyAddress - Addr %lx closing\n", Address));
status = STATUS_INVALID_ADDRESS;
}
RELEASE_SPIN_LOCK (&Address->AddressLock);
} else {
DBGPRINT(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_ERROR,
("ERROR: AtalkVerifyAddress - Address %lx bad sign\n", Address));
DBGBRK(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_ERROR);
status = STATUS_INVALID_ADDRESS;
}
} except(EXCEPTION_EXECUTE_HANDLER) {
//
// BUGBUG: Could spinlock be held at this point?
//
DBGPRINT(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_ERROR,
("ERROR: AtalkVerifyAddress - Addr %lx exception\n", Address));
status = GetExceptionCode();
}
return status;
}
NTSTATUS
AtalkDestroyAddress(
IN PADDRESS_FILE Address
)
/*++
Routine Description:
This routine destroys a transport address.
This routine is only called by AtalkDerefAddress. 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.
--*/
{
PIRP closeIrp;
DBGPRINT(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkDestroyAddress - %lx\n", Address));
if ((Address->Flags & ADDRESS_FLAGS_CLOSING) == 0) {
DBGPRINT(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_IMPOSSIBLE,
("IMPOSSIBLE: AtalkDestroyAddress - no close flag %lx\n", Address->Flags));
DBGBRK(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_IMPOSSIBLE);
return(STATUS_FILE_CLOSED);
}
//
// BUGBUG: Deal with security in Create
// SeDeassignSecurity (&Address->SecurityDescriptor);
//
//
// Now we can deallocate the transport address object.
// Get the irp out before deallocating it
//
closeIrp = Address->CloseIrp;
Address->CloseIrp = (PIRP)NULL;
//
// Complete the close irp
//
if (closeIrp != (PIRP)NULL) {
//
// Set the status in the iostatus block
//
closeIrp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(closeIrp, IO_NETWORK_INCREMENT );
} else {
DBGPRINT(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_IMPOSSIBLE,
("IMPOSSIBLE: AtalkDestroyAddress - Address %x No CloseIrp\n", Address));
DBGBRK(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_IMPOSSIBLE);
}
AtalkDeallocateAddress (Address->DeviceContext, Address);
return STATUS_SUCCESS;
} /* AtalkDestroyAddress */
NTSTATUS
AtalkStopAddress(
IN PADDRESS_FILE Address
)
/*++
Routine Description:
This routine is called to terminate all activity on an AddressFile and
destroy the object.
IMPORTANT: This can only be called from AtalkCloseAddress. Also,
unlike the connection objects, once the STOPPING flag is
set, it cannot the reset. Its a one-way-road to extinction.
Arguments:
Address - pointer to the address to be stopped
Return Value:
STATUS_SUCCESS if all is well,
STATUS_INVALID_HANDLE if the Irp does not point to a real address.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PORTABLE_ERROR errorCode = ATnoError;
PLIST_ENTRY p;
PCONNECTION_FILE connection;
ACQUIRE_SPIN_LOCK (&Address->AddressLock);
//
// now remove all of the connections owned by this address
//
p=Address->ConnectionLinkage.Flink;
while (p != &Address->ConnectionLinkage) {
connection = CONTAINING_RECORD (p, CONNECTION_FILE, Linkage);
DBGPRINT(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkStopAddress - Connection being removed: %lx\n", connection));
//
// Reference the connection so it doesn't go away before we have a
// chance to deal with it- hold the address lock so we don't allow
// any disassociates to happen while we mess around with the linkage
// pointers.
//
// These references are also important to complete the STOPPING phase
// in the deref code
//
AtalkReferenceConnection("AddressClosing", connection,
CREF_STOP_ADDRESS, SECONDARY_REFSET);
RELEASE_SPIN_LOCK(&Address->AddressLock);
//
// Stop the connection (this might also disassociate it)
// Since this could execute asynchronously, we will *loop*
// until the disassociate happens...
//
// BUGBUG: Find a better way!
// Although those who do this ought to pay!
//
AtalkStopConnection(connection);
//
// Now dereference it, the previous operation could have turned
// out to be a NULL operation as the CO might already have been closing.
//
AtalkDereferenceConnection("AddressClosingDone", connection,
CREF_STOP_ADDRESS, SECONDARY_REFSET);
//
// Get the next connection off the address list. Note we have to start
// over as the disassociates are screwing around with the pointers here.
//
ACQUIRE_SPIN_LOCK(&Address->AddressLock);
p = Address->ConnectionLinkage.Flink;
}
RELEASE_SPIN_LOCK (&Address->AddressLock);
//
// At this point, depending on the address type, close the
// listener/socket that was created for this provider type
//
// This is the only way we can get any posted requests to complete
//
do {
switch (Address->OwningDevice) {
case ATALK_DEVICE_ADSP :
if (Address->Flags & ADDRESS_FLAGS_LISTENER) {
//
// Close the ADSP listener and break out
//
DBGPRINT(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkCloseAddress - ADSP Listener %lx closed %lx\n",
Address->ListenerRefNum, errorCode));
errorCode = AdspDeleteConnectionListener(Address->ListenerRefNum);
status = ConvertToNTStatus(errorCode, SYNC_REQUEST);
}
break;
case ATALK_DEVICE_DDP :
//
// No listener for DDP
//
break;
case ATALK_DEVICE_ASP :
if (Address->Flags & ADDRESS_FLAGS_LISTENER) {
//
// Close the ASP listener and break out
//
DBGPRINT(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkCloseAddress - ASP lis deleted%lx\n",
Address->ListenerRefNum));
errorCode = AspDeleteSessionListener(Address->ListenerRefNum);
status = ConvertToNTStatus(errorCode, SYNC_REQUEST);
}
break;
case ATALK_DEVICE_PAP :
if (Address->Flags & ADDRESS_FLAGS_LISTENER) {
//
// Close the PAP listener and break out
//
DBGPRINT(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkCloseAddress - PAP Listener being deleted %lx\n",
Address->ListenerRefNum));
errorCode = PapDeleteServiceListener(Address->ListenerRefNum);
status = ConvertToNTStatus(errorCode, SYNC_REQUEST);
}
break;
case ATALK_DEVICE_ATP :
//
// No listener for DDP
//
break;
default:
//
// Should never be here...
//
KeBugCheck(0);
}
ASSERT(status == STATUS_SUCCESS);
if (status != STATUS_SUCCESS) {
break;
} else {
Address->Flags &= ~ADDRESS_FLAGS_LISTENER;
}
//
// Now close the socket
//
switch (Address->OwningDevice) {
case ATALK_DEVICE_ADSP :
case ATALK_DEVICE_DDP :
//
// Close the ddp socket
//
errorCode = CloseSocketOnNode(Address->SocketRefNum);
status = ConvertToNTStatus(errorCode, SYNC_REQUEST);
DBGPRINT(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkCloseAddress - ddp socket %lx\n", Address->SocketRefNum));
break;
case ATALK_DEVICE_ASP :
case ATALK_DEVICE_PAP :
case ATALK_DEVICE_ATP :
//
// For all these devices close the ATP socket
//
errorCode = AtpCloseSocketOnNode(Address->SocketRefNum);
status = ConvertToNTStatus(errorCode, SYNC_REQUEST);
DBGPRINT(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkCloseAddress - atp socket %lx\n", Address->SocketRefNum));
break;
default:
KeBugCheck(0);
}
ASSERT(status == STATUS_SUCCESS);
if (status != STATUS_SUCCESS) {
break;
}
} while (FALSE);
return(status);
} /* AtalkStopAddress */
NTSTATUS
AtalkCleanupAddress(
IN OUT PIO_STATUS_BLOCK IoStatus,
IN PADDRESS_FILE Address,
IN PIRP Irp,
IN PATALK_DEVICE_CONTEXT Context
)
/*++
Routine Description:
This routine calls stop address when the cleanup irp
is received.
Arguments:
IoStatus - The io status block for the request (pointer to the one in the irp)
Address - The address object's fscontext
Irp - The close irp
Context - The device context for the device the object belongs to
Return Value:
status of StopAddress
--*/
{
return (AtalkStopAddress(Address));
}
NTSTATUS
AtalkCloseAddress(
IN OUT PIO_STATUS_BLOCK IoStatus,
IN PADDRESS_FILE Address,
IN PIRP Irp,
IN PATALK_DEVICE_CONTEXT Context
)
/*++
Routine Description:
This is called when a close irp is received. It removes the
creation reference.
Arguments:
IoStatus - The io status block for the request (pointer to the one in the irp)
Address - The address object's fscontext
Irp - The close irp
Context - The device context for the device the object belongs to
Return Value:
STATUS_SUCCESS if all is well,
STATUS_INVALID_HANDLE if the Irp does not point to a real address.
--*/
{
NTSTATUS status;
DBGPRINT(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_INFOCLASS0,
("INFO0: AtalkCloseAddress - Closing address %lx\n", Address));
ACQUIRE_SPIN_LOCK (&Address->AddressLock);
//
// If we're already stopping this address, then don't try to do it again.
//
if (Address->Flags & ADDRESS_FLAGS_CLOSING) {
RELEASE_SPIN_LOCK (&Address->AddressLock);
DBGPRINT(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_SEVERE,
("SEVERE: AtalkCloseAddress %lx already closing\n", Address));
DBGBRK(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_SEVERE);
IoStatus->Status = STATUS_SUCCESS;
status = STATUS_SUCCESS;
} else {
Address->Flags |= ADDRESS_FLAGS_CLOSING;
Address->CloseIrp = Irp;
RELEASE_SPIN_LOCK(&Address->AddressLock);
//
// Do this before the dereference as that could potentially
// complete the irp right away
//
IoStatus->Status = STATUS_PENDING;
AtalkDereferenceAddress("Stopping", Address, AREF_CREATION, PRIMARY_REFSET);
status = STATUS_PENDING;
}
return status;
} /* AtalkCloseAddress */
//
// TDI Requests on address objects
//
NTSTATUS
AtalkAddrQueryAddress(
PADDRESS_FILE Address,
PTDI_ADDRESS_INFO AddressInfo
)
{
NTSTATUS status = STATUS_SUCCESS;
PORTABLE_ERROR errorCode;
PORTABLE_ADDRESS portableAddress;
PTA_APPLETALK_ADDRESS atAddress;
ACQUIRE_SPIN_LOCK(&Address->AddressLock);
if ((Address->Flags & ADDRESS_FLAGS_CLOSING) != 0) {
status = STATUS_INVALID_ADDRESS;
}
RELEASE_SPIN_LOCK(&Address->AddressLock);
if (NT_SUCCESS(status)) {
errorCode = MapSocketToAddress(
Address->SocketRefNum,
&portableAddress);
status = ConvertToNTStatus(errorCode, SYNC_REQUEST);
if (NT_SUCCESS(status)) {
//
// Set the address
//
atAddress = (PTA_APPLETALK_ADDRESS)&AddressInfo->Address;
atAddress->TAAddressCount = 1;
atAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_APPLETALK);
atAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_APPLETALK;
atAddress->Address[0].Address[0].Network = portableAddress.networkNumber;
atAddress->Address[0].Address[0].Node = portableAddress.nodeNumber;
atAddress->Address[0].Address[0].Socket = portableAddress.socketNumber;
}
}
return(status);
}
NTSTATUS
AtalkAddrSetEventHandler(
IN OUT PADDRESS_FILE Address,
IN PATALK_TDI_REQUEST Request
)
{
NTSTATUS status = STATUS_SUCCESS;
PORTABLE_ERROR errorCode;
PTDI_REQUEST_KERNEL_SET_EVENT parameters;
ACQUIRE_SPIN_LOCK(&Address->AddressLock);
if ((Address->Flags & ADDRESS_FLAGS_CLOSING) != 0) {
status = STATUS_INVALID_ADDRESS;
}
//
// BUGBUG: Set with portable stack also. NOTE: If a close object comes in
// while the portable code is making an indication, then it must
// defer the close until the indication returns. Then it must make
// no more indications and should then call the close completion.
//
if (NT_SUCCESS(status)) {
parameters = (PTDI_REQUEST_KERNEL_SET_EVENT)Request->Parameters;
switch (parameters->EventType) {
case TDI_EVENT_RECEIVE_DATAGRAM:
if (Request->OwningDevice != ATALK_DEVICE_DDP) {
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
if (parameters->EventHandler == NULL) {
Address->ReceiveDatagramHandler =
(PTDI_IND_RECEIVE_DATAGRAM)TdiDefaultRcvDatagramHandler;
Address->ReceiveDatagramHandlerContext = NULL;
Address->RegisteredReceiveDatagramHandler = FALSE;
} else {
Address->ReceiveDatagramHandler =
(PTDI_IND_RECEIVE_DATAGRAM)parameters->EventHandler;
Address->ReceiveDatagramHandlerContext = parameters->EventContext;
Address->RegisteredReceiveDatagramHandler = TRUE;
}
//
// Now set the handler with the portable stack
//
errorCode = NewHandlerForSocket(
Address->SocketRefNum,
&NTDdpReceiveDatagramEventHandler,
(ULONG)Address,
TRUE); // Event handler?
status = ConvertToNTStatus(errorCode, SYNC_REQUEST);
break;
case TDI_EVENT_ERROR:
if ((Request->OwningDevice != ATALK_DEVICE_DDP) &&
(Request->OwningDevice != ATALK_DEVICE_ADSP)) {
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
if (parameters->EventHandler == NULL) {
Address->ErrorHandler =
(PTDI_IND_ERROR)TdiDefaultErrorHandler;
Address->ErrorHandlerContext = NULL;
Address->RegisteredErrorHandler = FALSE;
} else {
Address->ErrorHandler =
(PTDI_IND_ERROR)parameters->EventHandler;
Address->ErrorHandlerContext = parameters->EventContext;
Address->RegisteredErrorHandler = TRUE;
}
//
// Set the handler with the portable stack
//
break;
case TDI_EVENT_CONNECT:
if ((Request->OwningDevice != ATALK_DEVICE_ADSP) &&
(Request->OwningDevice != ATALK_DEVICE_PAP)) {
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
if (parameters->EventHandler == NULL) {
Address->ConnectionHandler =
(PTDI_IND_CONNECT)TdiDefaultConnectHandler;
Address->ConnectionHandlerContext = NULL;
Address->RegisteredConnectionHandler = FALSE;
} else {
Address->ConnectionHandler =
(PTDI_IND_CONNECT)parameters->EventHandler;
Address->ConnectionHandlerContext = parameters->EventContext;
Address->RegisteredConnectionHandler = TRUE;
}
//
// Set handler with portable stack - only valid for listener/neutral.
// Create listener if not already created. This acquires the lock - so
// release it.
//
RELEASE_SPIN_LOCK(&Address->AddressLock);
status = AtalkCreateListener(
Address);
ACQUIRE_SPIN_LOCK(&Address->AddressLock);
if (NT_SUCCESS(status)) {
if (Request->OwningDevice == ATALK_DEVICE_ADSP) {
errorCode = AdspSetConnectionEventHandler(
Address->ListenerRefNum,
&NTAdspConnectionEventHandler,
(ULONG)Address);
} else {
//
// Setting one handler will automatically set both the portable
// handlers, and at the glue code level it is the default handler
// that will be called, if the client did not actually set the
// other handler also.
//
errorCode = PapSetConnectionEventHandler(
Address->ListenerRefNum,
&NTPapConnectionEventHandler,
(ULONG)Address);
}
status = ConvertToNTStatus(errorCode, SYNC_REQUEST);
}
break;
case TDI_EVENT_RECEIVE:
if (Request->OwningDevice != ATALK_DEVICE_ADSP) {
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
if (parameters->EventHandler == NULL) {
Address->ReceiveHandler =
(PTDI_IND_RECEIVE)TdiDefaultReceiveHandler;
Address->ReceiveHandlerContext = NULL;
Address->RegisteredReceiveHandler = FALSE;
} else {
Address->ReceiveHandler =
(PTDI_IND_RECEIVE)parameters->EventHandler;
Address->ReceiveHandlerContext = parameters->EventContext;
Address->RegisteredReceiveHandler = TRUE;
}
//
// BUGBUG:
// Walk list of all the associated connection objects, settting handler
// on each if they are in active state with the portable stack.
//
// For now, just set them when accepting/opening a connection
//
break;
case TDI_EVENT_RECEIVE_EXPEDITED:
if (Request->OwningDevice != ATALK_DEVICE_ADSP) {
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
if (parameters->EventHandler == NULL) {
Address->ExpeditedDataHandler =
(PTDI_IND_RECEIVE_EXPEDITED)TdiDefaultRcvExpeditedHandler;
Address->ExpeditedDataHandlerContext = NULL;
Address->RegisteredExpeditedDataHandler = FALSE;
} else {
Address->ExpeditedDataHandler =
(PTDI_IND_RECEIVE_EXPEDITED)parameters->EventHandler;
Address->ExpeditedDataHandlerContext = parameters->EventContext;
Address->RegisteredExpeditedDataHandler = TRUE;
}
//
// BUGBUG:
// Walk list of all the associated connection objects, settting handler
// on each if they are in active state with the portable stack.
//
// For now, just set them when accepting/opening a connection
//
break;
case TDI_EVENT_DISCONNECT:
if ((Request->OwningDevice != ATALK_DEVICE_ADSP) &&
(Request->OwningDevice != ATALK_DEVICE_PAP)) {
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
if (parameters->EventHandler == NULL) {
Address->DisconnectHandler =
(PTDI_IND_DISCONNECT)TdiDefaultDisconnectHandler;
Address->DisconnectHandlerContext = NULL;
Address->RegisteredDisconnectHandler = FALSE;
} else {
Address->DisconnectHandler =
(PTDI_IND_DISCONNECT)parameters->EventHandler;
Address->DisconnectHandlerContext = parameters->EventContext;
Address->RegisteredDisconnectHandler = TRUE;
}
//
// Walk list of all the associated connection objects, settting handler
// on each if they are in active state with the portable stack.
//
// For now, just set them when accepting/opening a connection
//
break;
case TDI_EVENT_SEND_POSSIBLE :
//
// BUGBUG: Implement in the portable stack
//
if ((Request->OwningDevice != ATALK_DEVICE_ADSP) &&
(Request->OwningDevice != ATALK_DEVICE_PAP)) {
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
if (parameters->EventHandler == NULL) {
Address->SendPossibleHandler =
(PTDI_IND_SEND_POSSIBLE)TdiDefaultSendPossibleHandler;
Address->SendPossibleHandlerContext = NULL;
Address->RegisteredSendPossibleHandler = FALSE;
} else {
Address->SendPossibleHandler =
(PTDI_IND_SEND_POSSIBLE)parameters->EventHandler;
Address->SendPossibleHandlerContext = parameters->EventContext;
Address->RegisteredSendPossibleHandler = TRUE;
}
break;
default:
status = STATUS_INVALID_PARAMETER;
} /* switch */
}
RELEASE_SPIN_LOCK(&Address->AddressLock);
#if DBG
return(STATUS_SUCCESS);
#else
return(status);
#endif
}
NTSTATUS
AtalkAddrReceiveDatagram(
PADDRESS_FILE Address,
PATALK_TDI_REQUEST Request
)
/*++
Routine Description:
This routine is called to receive a datagram on an address object
Arguments:
Address - The address object's fscontext
Request - the receive dg request block
Return Value:
status of receive.
--*/
{
NTSTATUS status;
PORTABLE_ERROR errorCode;
ULONG recvLength;
PTDI_REQUEST_KERNEL_RECEIVEDG parameters;
#if TDI_SPEC_ISSUE_RESOLVED
PORTABLE_ADDRESS portableAddress;
PTA_APPLETALK_ADDRESS remoteAddress;
#endif
ACQUIRE_SPIN_LOCK(&Address->AddressLock);
if (Address->Flags & CONNECTION_FLAGS_CLOSING) {
RELEASE_SPIN_LOCK(&Address->AddressLock);
DBGPRINT(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_ERROR,
("ERROR: AtalkAddrReceiveDatagram - flags: %lx \n", Address->Flags));
return(STATUS_INVALID_ADDRESS);
}
//
// Queue the request into the address list
//
InsertTailList(&Address->RequestLinkage, &Request->Linkage);
RELEASE_SPIN_LOCK(&Address->AddressLock);
parameters = (PTDI_REQUEST_KERNEL_RECEIVEDG)Request->Parameters;
//
// Get the length of the send mdl
//
AtalkGetMdlChainLength(Request->ReceiveDatagram.MdlAddress, &recvLength);
errorCode = DdpRead(
Address->SocketRefNum,
(PVOID)Request->ReceiveDatagram.MdlAddress,
recvLength,
AtalkAddrReceiveDatagramComplete,
(ULONG)Request);
status = ConvertToNTStatus(errorCode, ASYNC_REQUEST);
if (status != STATUS_PENDING) {
//
// An error occurred, dequeue the request...
//
ACQUIRE_SPIN_LOCK(&Address->AddressLock);
RemoveEntryList(&Request->Linkage);
RELEASE_SPIN_LOCK(&Address->AddressLock);
InitializeListHead(&Request->Linkage);
}
return(status);
}
NTSTATUS
AtalkAddrSendDatagram(
PADDRESS_FILE Address,
PATALK_TDI_REQUEST Request
)
/*++
Routine Description:
This routine is called to send a datagram on a specified address
Arguments:
Address - The address object's fscontext
Request - the send dg request block
Return Value:
status of Send
--*/
{
NTSTATUS status;
PORTABLE_ERROR errorCode;
PTDI_REQUEST_KERNEL_SENDDG parameters;
PTA_APPLETALK_ADDRESS remoteAddress;
PORTABLE_ADDRESS portableAddress;
ACQUIRE_SPIN_LOCK(&Address->AddressLock);
if (Address->Flags & CONNECTION_FLAGS_CLOSING) {
RELEASE_SPIN_LOCK(&Address->AddressLock);
DBGPRINT(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_ERROR,
("ERROR: AtalkAddrSendDatagram - flags %lx \n", Address->Flags));
return(STATUS_INVALID_ADDRESS);
}
//
// Queue the request into the address list
//
InsertTailList(&Address->RequestLinkage, &Request->Linkage);
RELEASE_SPIN_LOCK(&Address->AddressLock);
parameters = (PTDI_REQUEST_KERNEL_SENDDG)Request->Parameters;
remoteAddress =
(PTA_APPLETALK_ADDRESS)parameters->SendDatagramInformation->RemoteAddress;
DBGPRINT(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkAddrSendDatagram - Net %x Node %x Socket %x\n",
remoteAddress->Address[0].Address[0].Network,
remoteAddress->Address[0].Address[0].Node,
remoteAddress->Address[0].Address[0].Socket));
if ((remoteAddress->Address[0].AddressType != TDI_ADDRESS_TYPE_APPLETALK) ||
(remoteAddress->Address[0].AddressLength != sizeof(TDI_ADDRESS_APPLETALK))) {
DBGPRINT(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_ERROR,
("ERROR: AtalkAddrSendDatagram - Type %x\n Len %d\n",
remoteAddress->Address[0].AddressType,
remoteAddress->Address[0].AddressLength));
status = STATUS_INVALID_ADDRESS;
} else {
LONG sendLength;
portableAddress.networkNumber = remoteAddress->Address[0].Address[0].Network;
portableAddress.nodeNumber = remoteAddress->Address[0].Address[0].Node;
portableAddress.socketNumber = remoteAddress->Address[0].Address[0].Socket;
//
// Get the length of the send mdl
//
AtalkGetMdlChainLength(Request->SendDatagram.MdlAddress, &sendLength);
//
// Set the information field to indicate bytes sent it all
// BUGBUG: this belongs in the comopletion routine
//
Request->IoStatus->Information = sendLength;
errorCode = DdpWrite(
Address->SocketRefNum,
portableAddress,
DEFAULT_PROTOCOLTYPE, // BUGBUG - get from options
(PVOID)Request->SendDatagram.MdlAddress,
sendLength,
AtalkAddrSendDatagramComplete,
(ULONG)Request);
status = ConvertToNTStatus(errorCode, ASYNC_REQUEST);
if (status != STATUS_PENDING) {
//
// An error occurred, dequeue the request...
//
ACQUIRE_SPIN_LOCK(&Address->AddressLock);
RemoveEntryList(&Request->Linkage);
RELEASE_SPIN_LOCK(&Address->AddressLock);
InitializeListHead(&Request->Linkage);
}
}
return(status);
}
VOID
AtalkAddrSendDatagramComplete(
PORTABLE_ERROR Error,
ULONG UserData,
PVOID BufferDescriptor
)
/*++
Routine Description:
Completion routine for the send datagram routine.
Arguments:
BUGBUG: Change the arguments to include an error code and no buffer
descriptor
Return Value:
None
--*/
{
NTSTATUS status;
PATALK_TDI_REQUEST request;
PADDRESS_FILE address;
#if !TDI_SPEC_ISSUE_RESOLVED
#endif
//
// Dequeue from list and complete the request
//
status = ConvertToNTStatus(Error, SYNC_REQUEST);
DBGPRINT(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkAddrSendDatagram - Send complete nt %lx req! %lx\n",
status, request));
request = (PATALK_TDI_REQUEST)UserData;
address = (PADDRESS_FILE)request->FileObject->FsContext;
if (NT_SUCCESS(status)) {
//
// Copy information into the return information structure
// OK to have the spinlock released at this point.
//
#ifdef TDI_SPEC_ISSUE_RESOLVED
//
// Set some return values in the listen parameters structure
// if STATUS was success
//
// BUGBUG: TDI SPEC IS BROKEN ON THIS!
// BUG #8123
//
#endif
}
//
// Dequeue the request from the address object
//
ACQUIRE_SPIN_LOCK(&address->AddressLock);
RemoveEntryList(&request->Linkage);
InitializeListHead(&request->Linkage);
RELEASE_SPIN_LOCK(&address->AddressLock);
//
// Complete the request
//
AtalkCompleteTdiRequest(request, status);
return;
}
LONG
AtalkAddrReceiveDatagramComplete(
PORTABLE_ERROR Error,
ULONG UserData,
INT Port,
PORTABLE_ADDRESS Source,
INT DestinationSocket,
INT ProtocolType,
PVOID Datagram,
INT DatagramLength,
PORTABLE_ADDRESS ActualDestination
)
/*++
Routine Description:
Completion routine for receive datagram.
Arguments:
Error - portable error corresponding to this receive
UserData - our Request structure
Port - port on which the receive was posted
Source - source of the datagram received
DestinationSocket - the destination socket of the datagram
ProtocolType - protocol type of the datagram
Datagram - the datagram mdl
DatagramLength - the number of bytes written into the mdl
ActualDestination - the actual destination address of the datagram
Return Value:
None
--*/
{
NTSTATUS status;
PATALK_TDI_REQUEST request;
PADDRESS_FILE address;
PTDI_REQUEST_KERNEL_RECEIVEDG parameters;
PTDI_CONNECTION_INFORMATION returnInfo;
PTA_APPLETALK_ADDRESS remoteAddress;
//
// Dequeue from list and complete the request
//
status = ConvertToNTStatus(Error, SYNC_REQUEST);
DBGPRINT(ATALK_DEBUG_ADDROBJ, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkAddrReceiveDatagramComplete - status %lx nt %lx req %lx\n",
Error, status, request));
request = (PATALK_TDI_REQUEST)UserData;
address = (PADDRESS_FILE)request->FileObject->FsContext;
if (NT_SUCCESS(status)) {
//
// Copy information into the return information structure
// OK to have the spinlock released at this point.
//
//
// Set some return values in the parameters structure
// if STATUS was success
//
// BUGBUG: TDI SPEC IS BROKEN ON THIS!
// BUG #8123
//
parameters = (PTDI_REQUEST_KERNEL_RECEIVEDG)request->Parameters;
ASSERT(parameters != NULL);
if (parameters != NULL) {
parameters->ReceiveLength = (ULONG)DatagramLength;
returnInfo =
(PTDI_CONNECTION_INFORMATION)parameters->ReturnDatagramInformation;
ASSERT(returnInfo != NULL);
if (returnInfo != NULL) {
if (returnInfo->RemoteAddressLength >=
sizeof(TA_APPLETALK_ADDRESS)) {
//
// Fill in the remote address
//
remoteAddress =
(PTA_APPLETALK_ADDRESS)returnInfo->RemoteAddress;
ASSERT(remoteAddress != NULL);
if (remoteAddress != NULL) {
remoteAddress->TAAddressCount = 1;
remoteAddress->Address[0].AddressType =
TDI_ADDRESS_TYPE_APPLETALK;
remoteAddress->Address[0].AddressLength =
sizeof(TDI_ADDRESS_APPLETALK);
remoteAddress->Address[0].Address[0].Network =
Source.networkNumber;
remoteAddress->Address[0].Address[0].Node =
Source.nodeNumber;
remoteAddress->Address[0].Address[0].Socket =
Source.socketNumber;
DBGPRINT(ATALK_DEBUG_CONNOBJ, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkAddrRecvDgComp - Net %x Node %x Socket %x\n",
remoteAddress->Address[0].Address[0].Network,
remoteAddress->Address[0].Address[0].Node,
remoteAddress->Address[0].Address[0].Socket));
DBGPRINT(ATALK_DEBUG_CONNOBJ, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkAddrRecvDgComp - Cnt: %x\n",
remoteAddress->TAAddressCount));
DBGPRINT(ATALK_DEBUG_CONNOBJ, DEBUG_LEVEL_INFOCLASS1,
("INFO1: AtalkAddrRecvDgComp - Type %x\n Length %d\n",
remoteAddress->Address[0].AddressType,
remoteAddress->Address[0].AddressLength));
}
}
}
}
request->IoRequestIrp->IoStatus.Information = (ULONG)DatagramLength;
}
//
// Dequeue the request from the address object
//
ACQUIRE_SPIN_LOCK(&address->AddressLock);
RemoveEntryList(&request->Linkage);
InitializeListHead(&request->Linkage);
RELEASE_SPIN_LOCK(&address->AddressLock);
//
// Complete the request
//
AtalkCompleteTdiRequest(request, status);
return (LONG)DatagramLength;
}