/*++ 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: Sanjay Anand (SanjayAn) - 22-Sept-1995 BackFill optimization changes added under #if BACK_FILL Sanjay Anand (SanjayAn) 3-Oct-1995 Changes to support transfer of buffer ownership to transports - tagged [CH] --*/ #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_IPX UNALIGNED * IpxParseTdiAddress( IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress ) /*++ Routine Description: This routine scans a TRANSPORT_ADDRESS, looking for an address of type TDI_ADDRESS_TYPE_IPX. Arguments: Transport - The generic TDI address. Return Value: A pointer to the IPX address, or NULL if none is found. --*/ { TA_ADDRESS UNALIGNED * addressName; INT i; addressName = &TransportAddress->Address[0]; // // The name can be passed with multiple entries; we'll take and use only // the IPX one. // for (i=0;iTAAddressCount;i++) { if (addressName->AddressType == TDI_ADDRESS_TYPE_IPX) { if (addressName->AddressLength >= sizeof(TDI_ADDRESS_IPX)) { return ((TDI_ADDRESS_IPX UNALIGNED *)(addressName->Address)); } } addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address + addressName->AddressLength); } return NULL; } /* IpxParseTdiAddress */ BOOLEAN IpxValidateTdiAddress( 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 UNALIGNED * addressName; INT i; if (TransportAddressLength < sizeof(TransportAddress->TAAddressCount)) { IpxPrint0 ("IpxValidateTdiAddress: runt address\n"); return FALSE; } addressName = &TransportAddress->Address[0]; for (i=0;iTAAddressCount;i++) { if (addressName->Address > AddressEnd) { IpxPrint0 ("IpxValidateTdiAddress: address too short\n"); return FALSE; } addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address + addressName->AddressLength); } if ((PUCHAR)addressName > AddressEnd) { IpxPrint0 ("IpxValidateTdiAddress: address too short\n"); return FALSE; } return TRUE; } /* IpxValidateTdiAddress */ #if DBG VOID IpxBuildTdiAddress( IN PVOID AddressBuffer, IN ULONG Network, IN UCHAR Node[6], IN USHORT Socket ) /*++ Routine Description: This routine fills in a TRANSPORT_ADDRESS in the specified buffer, given the socket, network and node. Arguments: AddressBuffer - The buffer that will hold the address. Network - The network number. Node - The node address. Socket - The socket. Return Value: None. --*/ { TA_IPX_ADDRESS UNALIGNED * IpxAddress; IpxAddress = (TA_IPX_ADDRESS UNALIGNED *)AddressBuffer; IpxAddress->TAAddressCount = 1; IpxAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IPX); IpxAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX; IpxAddress->Address[0].Address[0].NetworkAddress = Network; IpxAddress->Address[0].Address[0].Socket = Socket; RtlCopyMemory(IpxAddress->Address[0].Address[0].NodeAddress, Node, 6); } /* IpxBuildTdiAddress */ #endif NTSTATUS IpxOpenAddress( 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 IPX 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; TA_ADDRESS UNALIGNED *AddressName; USHORT Socket; ULONG DesiredShareAccess; CTELockHandle LockHandle; PACCESS_STATE AccessState; ACCESS_MASK GrantedAccess; BOOLEAN AccessAllowed; int i; BOOLEAN found = FALSE; #ifdef ISN_NT PIRP Irp = (PIRP)Request; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); #endif // // If we are a dedicated router, we cannot let addresses // be opened. // if (Device->DedicatedRouter) { return STATUS_NOT_SUPPORTED; } // // The network name is in the EA, passed in the request. // ea = OPEN_REQUEST_EA_INFORMATION(Request); if (ea == NULL) { IpxPrint1("OpenAddress: REQUEST %lx has no EA\n", Request); return STATUS_NONEXISTENT_EA_ENTRY; } // // 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]; AddressName = (PTA_ADDRESS)&name->Address[0]; // // The name can be passed with multiple entries; we'll take and use only // the first one of type IPX. // for (i=0;iTAAddressCount;i++) { if (AddressName->AddressType == TDI_ADDRESS_TYPE_IPX) { if (AddressName->AddressLength >= sizeof(TDI_ADDRESS_IPX)) { Socket = ((TDI_ADDRESS_IPX UNALIGNED *)&AddressName->Address[0])->Socket; found = TRUE; } break; } else { AddressName = (PTA_ADDRESS)(AddressName->Address + AddressName->AddressLength); } } if (!found) { IPX_DEBUG (ADDRESS, ("OpenAddress, request %lx has no IPX Address\n", Request)); return STATUS_NONEXISTENT_EA_ENTRY; } if (Socket == 0) { Socket = IpxAssignSocket (Device); if (Socket == 0) { IPX_DEBUG (ADDRESS, ("OpenAddress, no unique socket found\n")); return STATUS_INSUFFICIENT_RESOURCES; } else { IPX_DEBUG (ADDRESS, ("OpenAddress, assigned socket %lx\n", REORDER_USHORT(Socket))); } } else { IPX_DEBUG (ADDRESS, ("OpenAddress, socket %lx\n", REORDER_USHORT(Socket))); } // // get an address file structure to represent this address. // AddressFile = IpxCreateAddressFile (Device); if (AddressFile == (PADDRESS_FILE)NULL) { return status; } // // We mark this socket specially. // if (Socket == SAP_SOCKET) { AddressFile->IsSapSocket = TRUE; AddressFile->SpecialReceiveProcessing = TRUE; } // // 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. // ExAcquireResourceExclusive (&Device->AddressResource, TRUE); CTEGetLock (&Device->Lock, &LockHandle); Address = IpxLookupAddress (Device, Socket); if (Address == NULL) { CTEFreeLock (&Device->Lock, LockHandle); // // This address doesn't exist. Create it. // registering it. // Address = IpxCreateAddress ( Device, Socket); if (Address != (PADDRESS)NULL) { // // Set this now in case we have to deref. // AddressFile->AddressLock = &Address->Lock; #ifdef ISN_NT // // 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)) { // // Error, return status. // IoRemoveShareAccess (IrpSp->FileObject, &Address->u.ShareAccess); ExReleaseResource (&Device->AddressResource); IpxDereferenceAddress (Address, AREF_ADDRESS_FILE); IpxDereferenceAddressFile (AddressFile, AFREF_CREATE); return status; } #endif ExReleaseResource (&Device->AddressResource); // // if the adapter isn't ready, we can't do any of this; get out // if (Device->State == DEVICE_STATE_STOPPING) { IpxDereferenceAddress (Address, AREF_ADDRESS_FILE); IpxDereferenceAddressFile (AddressFile, AFREF_CREATE); status = STATUS_DEVICE_NOT_READY; } else { REQUEST_OPEN_CONTEXT(Request) = (PVOID)AddressFile; REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE; #ifdef ISN_NT AddressFile->FileObject = IrpSp->FileObject; #endif AddressFile->Request = Request; AddressFile->Address = Address; CTEGetLock (&Address->Lock, &LockHandle); InsertTailList (&Address->AddressFileDatabase, &AddressFile->Linkage); CTEFreeLock (&Address->Lock, LockHandle); AddressFile->Request = NULL; AddressFile->State = ADDRESSFILE_STATE_OPEN; status = STATUS_SUCCESS; } } else { ExReleaseResource (&Device->AddressResource); // // 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. // IpxDestroyAddressFile (AddressFile); } } else { CTEFreeLock (&Device->Lock, LockHandle); IPX_DEBUG (ADDRESS, ("Add to address %lx\n", Address)); // // Set this now in case we have to deref. // AddressFile->AddressLock = &Address->Lock; // // The address already exists. Check the ACL and see if we // can access it. If so, simply use this address as our address. // #ifdef ISN_NT 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, Irp->RequestorMode, &GrantedAccess, &status); #else // ISN_NT AccessAllowed = TRUE; #endif // ISN_NT if (!AccessAllowed) { ExReleaseResource (&Device->AddressResource); IpxDereferenceAddressFile (AddressFile, AFREF_CREATE); } else { #ifdef ISN_NT // // 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); #else // ISN_NT status = STATUS_SUCCESS; #endif // ISN_NT if (!NT_SUCCESS (status)) { ExReleaseResource (&Device->AddressResource); IpxDereferenceAddressFile (AddressFile, AFREF_CREATE); } else { ExReleaseResource (&Device->AddressResource); CTEGetLock (&Address->Lock, &LockHandle); InsertTailList ( &Address->AddressFileDatabase, &AddressFile->Linkage); AddressFile->Request = NULL; AddressFile->Address = Address; #ifdef ISN_NT AddressFile->FileObject = IrpSp->FileObject; #endif AddressFile->State = ADDRESSFILE_STATE_OPEN; IpxReferenceAddress (Address, AREF_ADDRESS_FILE); REQUEST_OPEN_CONTEXT(Request) = (PVOID)AddressFile; REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE; CTEFreeLock (&Address->Lock, LockHandle); status = STATUS_SUCCESS; } } // // Remove the reference from IpxLookupAddress. // IpxDereferenceAddress (Address, AREF_LOOKUP); } return status; } /* IpxOpenAddress */ USHORT IpxAssignSocket( IN PDEVICE Device ) /*++ Routine Description: This routine assigns a socket that is unique within a range of SocketUniqueness. Arguments: Device - Pointer to the device context. Return Value: The assigned socket number, or 0 if a unique one cannot be found. --*/ { USHORT InitialSocket, CurrentSocket, AddressSocket; ULONG CurrentHash; BOOLEAN Conflict; PLIST_ENTRY p; PADDRESS Address; CTELockHandle LockHandle; // // Loop through all possible sockets, starting at // Device->CurrentSocket, looking for a suitable one. // Device->CurrentSocket rotates through the possible // sockets to improve the chances of finding one // quickly. // CTEGetLock (&Device->Lock, &LockHandle); InitialSocket = Device->CurrentSocket; Device->CurrentSocket = (USHORT)(Device->CurrentSocket + Device->SocketUniqueness); if ((USHORT)(Device->CurrentSocket+Device->SocketUniqueness) > Device->SocketEnd) { Device->CurrentSocket = Device->SocketStart; } CurrentSocket = InitialSocket; do { // // Scan all addresses; if we find one with a socket // that conflicts with this one, we can't use it. // // NOTE: Device->Lock is acquired here. // Conflict = FALSE; for (CurrentHash = 0; CurrentHash < IPX_ADDRESS_HASH_COUNT; CurrentHash++) { for (p = Device->AddressDatabases[CurrentHash].Flink; p != &Device->AddressDatabases[CurrentHash]; p = p->Flink) { Address = CONTAINING_RECORD (p, ADDRESS, Linkage); AddressSocket = REORDER_USHORT(Address->Socket); if ((AddressSocket + Device->SocketUniqueness > CurrentSocket) && (AddressSocket < CurrentSocket + Device->SocketUniqueness)) { Conflict = TRUE; break; } } // // If we've found a conflict, no need to check the other // queues. // if (Conflict) { break; } } CTEFreeLock (&Device->Lock, LockHandle); // // We intentionally free the lock here so that we // never spend too much time with it held. // if (!Conflict) { // // We went through the address list without // finding a conflict; use this socket. // return REORDER_USHORT(CurrentSocket); } CurrentSocket = (USHORT)(CurrentSocket + Device->SocketUniqueness); if ((USHORT)(CurrentSocket+Device->SocketUniqueness) > Device->SocketEnd) { CurrentSocket = Device->SocketStart; } CTEGetLock (&Device->Lock, &LockHandle); } while (CurrentSocket != InitialSocket); CTEFreeLock (&Device->Lock, LockHandle); // // Could not find one to assign. // return (USHORT)0; } /* IpxAssignSocket */ PADDRESS IpxCreateAddress( IN PDEVICE Device, IN USHORT Socket ) /*++ Routine Description: This routine creates a transport address and associates it with the specified transport device context. The reference count in the address is automatically set to 1, and the reference count of the device context is incremented. NOTE: This routine must be called with the Device spinlock held. Arguments: Device - Pointer to the device context (which is really just the device object with its extension) to be associated with the address. Socket - The socket to assign to this address. Return Value: The newly created address, or NULL if none can be allocated. --*/ { PADDRESS Address; PIPX_SEND_RESERVED SendReserved; PIPX_RECEIVE_RESERVED ReceiveReserved; NDIS_STATUS Status; IPX_DEFINE_LOCK_HANDLE (LockHandle) Address = (PADDRESS)IpxAllocateMemory (sizeof(ADDRESS), MEMORY_ADDRESS, "Address"); if (Address == NULL) { IPX_DEBUG (ADDRESS, ("Create address %lx failed\n", REORDER_USHORT(Socket))); return NULL; } IPX_DEBUG (ADDRESS, ("Create address %lx (%lx)\n", Address, REORDER_USHORT(Socket))); RtlZeroMemory (Address, sizeof(ADDRESS)); #ifndef IPX_OWN_PACKETS IpxAllocateSingleSendPacket(Device, &Address->SendPacket, &Status); if (Status != NDIS_STATUS_SUCCESS) { goto Fail1; } #endif if (IpxInitializeSendPacket (Device, &Address->SendPacket, Address->SendPacketHeader) != STATUS_SUCCESS) { #ifndef IPX_OWN_PACKETS Fail1: #endif Address->SendPacketInUse = TRUE; } else { SendReserved = SEND_RESERVED(&Address->SendPacket); SendReserved->Address = Address; SendReserved->OwnedByAddress = TRUE; Address->SendPacketInUse = FALSE; #ifdef IPX_TRACK_POOL SendReserved->Pool = NULL; #endif } #if BACK_FILL { PIPX_SEND_RESERVED BackFillReserved; #ifndef IPX_OWN_PACKETS IpxAllocateSingleSendPacket(Device, &Address->BackFillPacket, &Status); if (Status != NDIS_STATUS_SUCCESS) { goto Fail2; } #endif if (IpxInitializeBackFillPacket (Device, &Address->BackFillPacket, NULL) != STATUS_SUCCESS) { #ifndef IPX_OWN_PACKETS Fail2: #endif Address->BackFillPacketInUse = TRUE; } else { BackFillReserved = SEND_RESERVED(&Address->BackFillPacket); BackFillReserved->Address = Address; Address->BackFillPacketInUse = FALSE; BackFillReserved->OwnedByAddress = TRUE; #ifdef IPX_TRACK_POOL BackFillReserved->Pool = NULL; #endif } } #endif #ifndef IPX_OWN_PACKETS IpxAllocateSingleReceivePacket(Device, &Address->ReceivePacket, &Status); if (Status != NDIS_STATUS_SUCCESS) { goto Fail3; } #endif if (IpxInitializeReceivePacket (Device, &Address->ReceivePacket) != STATUS_SUCCESS) { #ifndef IPX_OWN_PACKETS Fail3: #endif Address->ReceivePacketInUse = TRUE; } else { ReceiveReserved = RECEIVE_RESERVED(&Address->ReceivePacket); ReceiveReserved->Address = Address; ReceiveReserved->OwnedByAddress = TRUE; Address->ReceivePacketInUse = FALSE; #ifdef IPX_TRACK_POOL ReceiveReserved->Pool = NULL; #endif } Address->Type = IPX_ADDRESS_SIGNATURE; Address->Size = sizeof (ADDRESS); Address->Device = Device; Address->DeviceLock = &Device->Lock; CTEInitLock (&Address->Lock); InitializeListHead (&Address->AddressFileDatabase); Address->ReferenceCount = 1; #if DBG Address->RefTypes[AREF_ADDRESS_FILE] = 1; #endif Address->Socket = Socket; Address->SendSourceSocket = Socket; // // Save our local address for building datagrams quickly. // RtlCopyMemory (&Address->LocalAddress, &Device->SourceAddress, FIELD_OFFSET(TDI_ADDRESS_IPX,Socket)); Address->LocalAddress.Socket = Socket; // // 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. // IPX_GET_LOCK (&Device->Lock, &LockHandle); InsertTailList (&Device->AddressDatabases[IPX_HASH_SOCKET(Socket)], &Address->Linkage); IPX_FREE_LOCK (&Device->Lock, LockHandle); IpxReferenceDevice (Device, DREF_ADDRESS); return Address; } /* IpxCreateAddress */ NTSTATUS IpxVerifyAddressFile( IN PADDRESS_FILE AddressFile ) /*++ 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 Return Value: STATUS_SUCCESS if all is well; STATUS_INVALID_ADDRESS otherwise --*/ { CTELockHandle LockHandle; NTSTATUS status = STATUS_SUCCESS; PADDRESS Address; // // 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 == IPX_ADDRESSFILE_SIGNATURE) ) { // (AddressFile->State != ADDRESSFILE_STATE_CLOSING) ) { Address = AddressFile->Address; if ((Address->Size == sizeof (ADDRESS)) && (Address->Type == IPX_ADDRESS_SIGNATURE) ) { CTEGetLock (&Address->Lock, &LockHandle); if (!Address->Stopping) { IpxReferenceAddressFileLock (AddressFile, AFREF_VERIFY); } else { IpxPrint1("IpxVerifyAddressFile: A %lx closing\n", Address); status = STATUS_INVALID_ADDRESS; } CTEFreeLock (&Address->Lock, LockHandle); } else { IpxPrint1("IpxVerifyAddressFile: A %lx bad signature\n", Address); status = STATUS_INVALID_ADDRESS; } } else { IpxPrint1("IpxVerifyAddressFile: AF %lx bad signature\n", AddressFile); status = STATUS_INVALID_ADDRESS; } } except(EXCEPTION_EXECUTE_HANDLER) { IpxPrint1("IpxVerifyAddressFile: AF %lx exception\n", Address); return GetExceptionCode(); } return status; } /* IpxVerifyAddressFile */ VOID IpxDestroyAddress( 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 IpxDerefAddress when the reference count goes to 0. This thread is only queued by IpxDerefAddress. 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; IPX_DEBUG (ADDRESS, ("Destroy address %lx (%lx)\n", Address, REORDER_USHORT(Address->Socket))); 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. // CTEGetLock (&Device->Lock, &LockHandle); RemoveEntryList (&Address->Linkage); CTEFreeLock (&Device->Lock, LockHandle); if (!Address->SendPacketInUse) { IpxDeinitializeSendPacket (Device, &Address->SendPacket); #ifndef IPX_OWN_PACKETS IpxFreeSingleSendPacket (Device, Address->SendPacket); #endif } if (!Address->ReceivePacketInUse) { IpxDeinitializeReceivePacket (Device, &Address->ReceivePacket); #ifndef IPX_OWN_PACKETS IpxFreeSingleReceivePacket (Device, Address->ReceivePacket); #endif } #if BACK_FILL if (!Address->BackFillPacketInUse) { IpxDeinitializeBackFillPacket (Device, &Address->BackFillPacket); #ifndef IPX_OWN_PACKETS IpxFreeSingleSendPacket (Device, Address->BackFillPacket); #endif } #endif IpxFreeMemory (Address, sizeof(ADDRESS), MEMORY_ADDRESS, "Address"); IpxDereferenceDevice (Device, DREF_ADDRESS); } /* IpxDestroyAddress */ #if DBG VOID IpxRefAddress( 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... (VOID)InterlockedIncrement(&Address->ReferenceCount); } /* IpxRefAddress */ VOID IpxRefAddressLock( 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... // ++Address->ReferenceCount; (VOID)InterlockedIncrement(&Address->ReferenceCount); } /* IpxRefAddressLock */ #endif VOID IpxDerefAddress( 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 IpxDestroyAddress to remove it from the system. Arguments: Address - Pointer to a transport address object. Return Value: none. --*/ { ULONG oldvalue; oldvalue = IPX_ADD_ULONG ( &Address->ReferenceCount, (ULONG)-1, Address->DeviceLock); // // 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 (oldvalue != 0); if (oldvalue == 1) { #if ISN_NT ExInitializeWorkItem( &Address->u.DestroyAddressQueueItem, IpxDestroyAddress, (PVOID)Address); ExQueueWorkItem(&Address->u.DestroyAddressQueueItem, DelayedWorkQueue); #else IpxDestroyAddress(Address); #endif } } /* IpxDerefAddress */ VOID IpxDerefAddressSync( 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 IpxDestroyAddress to remove it from the system. This routine can only be called when we are synchronized (inside an IPX_SYNC_START/ IPX_SYNC_END pair, with a lock held, or in an indication). Arguments: Address - Pointer to a transport address object. Return Value: none. --*/ { ULONG oldvalue; oldvalue = IPX_ADD_ULONG ( &Address->ReferenceCount, (ULONG)-1, Address->DeviceLock); // // 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 (oldvalue != 0); if (oldvalue == 1) { #if ISN_NT ExInitializeWorkItem( &Address->u.DestroyAddressQueueItem, IpxDestroyAddress, (PVOID)Address); ExQueueWorkItem(&Address->u.DestroyAddressQueueItem, DelayedWorkQueue); #else IpxDestroyAddress(Address); #endif } } /* IpxDerefAddressSync */ PADDRESS_FILE IpxCreateAddressFile( 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; CTEGetLock (&Device->Lock, &LockHandle); AddressFile = (PADDRESS_FILE)IpxAllocateMemory (sizeof(ADDRESS_FILE), MEMORY_ADDRESS, "AddressFile"); if (AddressFile == NULL) { IPX_DEBUG (ADDRESS, ("Create address file failed\n")); CTEFreeLock (&Device->Lock, LockHandle); return NULL; } IPX_DEBUG (ADDRESS, ("Create address file %lx\n", AddressFile)); RtlZeroMemory (AddressFile, sizeof(ADDRESS_FILE)); AddressFile->Type = IPX_ADDRESSFILE_SIGNATURE; AddressFile->Size = sizeof (ADDRESS_FILE); InitializeListHead (&AddressFile->ReceiveDatagramQueue); CTEFreeLock (&Device->Lock, LockHandle); #if 0 AddressFile->SpecialReceiveProcessing = FALSE; AddressFile->ExtendedAddressing = FALSE; AddressFile->ReceiveIpxHeader = FALSE; AddressFile->FilterOnPacketType = FALSE; AddressFile->DefaultPacketType = 0; AddressFile->Address = NULL; #ifdef ISN_NT AddressFile->FileObject = NULL; #endif #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. // AddressFile->RegisteredReceiveDatagramHandler = FALSE; AddressFile->ReceiveDatagramHandler = TdiDefaultRcvDatagramHandler; AddressFile->ReceiveDatagramHandlerContext = NULL; // // [CH] Added these handlers for chained buffer receives // AddressFile->RegisteredChainedReceiveDatagramHandler = FALSE; AddressFile->ChainedReceiveDatagramHandler = TdiDefaultChainedRcvDatagramHandler; AddressFile->ChainedReceiveDatagramHandlerContext = NULL; AddressFile->RegisteredErrorHandler = FALSE; AddressFile->ErrorHandler = TdiDefaultErrorHandler; AddressFile->ErrorHandlerContext = NULL; return AddressFile; } /* IpxCreateAddressFile */ NTSTATUS IpxDestroyAddressFile( 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 IpxDereferenceAddressFile. 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; IPX_DEBUG (ADDRESS, ("Destroy address file %lx\n", AddressFile)); Address = AddressFile->Address; Device = AddressFile->Device; if (Address) { // // This addressfile was associated with an address. // CTEGetLock (&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. // CTEGetLock (&Device->Lock, &LockHandle1); Address->Stopping = TRUE; if (Device->LastAddress == Address) { Device->LastAddress = NULL; } CTEFreeLock (&Device->Lock, LockHandle1); } AddressFile->Address = NULL; #ifdef ISN_NT AddressFile->FileObject->FsContext = NULL; AddressFile->FileObject->FsContext2 = NULL; #endif CTEFreeLock (&Address->Lock, LockHandle); // // We will already have been removed from the ShareAccess // of the owning address. // // // Now dereference the owning address. // IpxDereferenceAddress (Address, AREF_ADDRESS_FILE); } // // Save this for later completion. // CloseRequest = AddressFile->CloseRequest; // // return the addressFile to the pool of address files // IpxFreeMemory (AddressFile, sizeof(ADDRESS_FILE), MEMORY_ADDRESS, "AddressFile"); if (CloseRequest != (PREQUEST)NULL) { REQUEST_INFORMATION(CloseRequest) = 0; REQUEST_STATUS(CloseRequest) = STATUS_SUCCESS; IpxCompleteRequest (CloseRequest); IpxFreeRequest (Device, CloseRequest); } return STATUS_SUCCESS; } /* IpxDestroyAddressFile */ #if DBG VOID IpxRefAddressFile( 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... (VOID)IPX_ADD_ULONG ( &AddressFile->ReferenceCount, 1, AddressFile->AddressLock); } /* IpxRefAddressFile */ VOID IpxRefAddressFileLock( 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... //++AddressFile->ReferenceCount; (VOID)InterlockedIncrement(&AddressFile->ReferenceCount); } /* IpxRefAddressFileLock */ VOID IpxRefAddressFileSync( 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... (VOID)IPX_ADD_ULONG ( &AddressFile->ReferenceCount, 1, AddressFile->AddressLock); } /* IpxRefAddressFileSync */ VOID IpxDerefAddressFile( 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 IpxDestroyAddressFile to remove it from the system. Arguments: AddressFile - Pointer to a transport address file object. Return Value: none. --*/ { ULONG oldvalue; oldvalue = IPX_ADD_ULONG ( &AddressFile->ReferenceCount, (ULONG)-1, AddressFile->AddressLock); // // 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 (oldvalue > 0); if (oldvalue == 1) { IpxDestroyAddressFile (AddressFile); } } /* IpxDerefAddressFile */ VOID IpxDerefAddressFileSync( 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 IpxDestroyAddressFile to remove it from the system. This routine can only be called when we are synchronized (inside an IPX_SYNC_START/ IPX_SYNC_END pair, with a lock held, or in an indication). Arguments: AddressFile - Pointer to a transport address file object. Return Value: none. --*/ { ULONG oldvalue; oldvalue = IPX_ADD_ULONG ( &AddressFile->ReferenceCount, (ULONG)-1, AddressFile->AddressLock); // // 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 (oldvalue > 0); if (oldvalue == 1) { IpxDestroyAddressFile (AddressFile); } } /* IpxDerefAddressFileSync */ #endif PADDRESS IpxLookupAddress( IN PDEVICE Device, IN USHORT Socket ) /*++ 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. Socket - The socket to look up. Return Value: Pointer to the ADDRESS object found, or NULL if not found. --*/ { PADDRESS Address; PLIST_ENTRY p; ULONG Hash = IPX_HASH_SOCKET (Socket); p = Device->AddressDatabases[Hash].Flink; for (p = Device->AddressDatabases[Hash].Flink; p != &Device->AddressDatabases[Hash]; p = p->Flink) { Address = CONTAINING_RECORD (p, ADDRESS, Linkage); if (Address->Stopping) { continue; } if (Address->Socket == Socket) { // // We found the match. Bump the reference count on the address, and // return a pointer to the address object for the caller to use. // IpxReferenceAddressLock (Address, AREF_LOOKUP); return Address; } } // // The specified address was not found. // return NULL; } /* IpxLookupAddress */ NTSTATUS IpxStopAddressFile( IN PADDRESS_FILE AddressFile ) /*++ 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 Return Value: STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the request is not for a real address. --*/ { CTELockHandle LockHandle; PREQUEST Request; PADDRESS Address = AddressFile->Address; PLIST_ENTRY p; KIRQL irql; IoAcquireCancelSpinLock( &irql ); CTEGetLock (&Address->Lock, &LockHandle); if (AddressFile->State == ADDRESSFILE_STATE_CLOSING) { CTEFreeLock (&Address->Lock, LockHandle); IoReleaseCancelSpinLock( irql ); return STATUS_SUCCESS; } AddressFile->State = ADDRESSFILE_STATE_CLOSING; while (!(IsListEmpty(&AddressFile->ReceiveDatagramQueue))) { p = RemoveHeadList (&AddressFile->ReceiveDatagramQueue); Request = LIST_ENTRY_TO_REQUEST (p); REQUEST_INFORMATION(Request) = 0; REQUEST_STATUS(Request) = STATUS_NETWORK_NAME_DELETED; IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL); CTEFreeLock(&Address->Lock, LockHandle); IoReleaseCancelSpinLock( irql ); IpxCompleteRequest (Request); IpxFreeRequest (Device, Request); IpxDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM); IoAcquireCancelSpinLock( &irql ); CTEGetLock(&Address->Lock, &LockHandle); } CTEFreeLock(&Address->Lock, LockHandle); IoReleaseCancelSpinLock( irql ); } /* IpxStopAddressFile */ NTSTATUS IpxCloseAddressFile( 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; CTELockHandle LockHandle; 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. // ExAcquireResourceExclusive (&Device->AddressResource, TRUE); #ifdef ISN_NT IoRemoveShareAccess (AddressFile->FileObject, &Address->u.ShareAccess); #endif ExReleaseResource (&Device->AddressResource); // // If this address file had broadcasts enabled, turn it off. // CTEGetLock (&Device->Lock, &LockHandle); if (AddressFile->EnableBroadcast) { AddressFile->EnableBroadcast = FALSE; IpxRemoveBroadcast (Device); } CTEFreeLock (&Device->Lock, LockHandle); IpxStopAddressFile (AddressFile); IpxDereferenceAddressFile (AddressFile, AFREF_CREATE); return STATUS_PENDING; } /* IpxCloseAddressFile */