windows-nt/Source/XPSP1/NT/net/sfm/afp/server/tcptdi.c
2020-09-26 16:20:57 +08:00

1318 lines
36 KiB
C

/*
Copyright (c) 1998 Microsoft Corporation
Module Name:
tcptdi.c
Abstract:
This module contains the interfaces to the TCP/IP stack via TDI
Author:
Shirish Koti
Revision History:
22 Jan 1998 Initial Version
--*/
#define FILENUM FILE_TCPTDI
#include <afp.h>
/*** DsiOpenTdiAddress
*
* This routine creates a TDI address for the AFP port on the given adapter
*
* Parm IN: pTcpAdptr - adapter object
*
* Parm OUT: pRetFileHandle - file handle to the address object
* ppRetFileObj - pointer to file object pointer
*
* Returns: status of operation
*
*/
NTSTATUS
DsiOpenTdiAddress(
IN PTCPADPTR pTcpAdptr,
OUT PHANDLE pRetFileHandle,
OUT PFILE_OBJECT *ppRetFileObj
)
{
OBJECT_ATTRIBUTES AddressAttributes;
IO_STATUS_BLOCK IoStatusBlock;
PFILE_FULL_EA_INFORMATION EaBuffer;
NTSTATUS status;
UNICODE_STRING ucDeviceName;
PTRANSPORT_ADDRESS pTransAddressEa;
PTRANSPORT_ADDRESS pTransAddr;
TDI_ADDRESS_IP TdiIpAddr;
HANDLE FileHandle;
PFILE_OBJECT pFileObject;
PDEVICE_OBJECT pDeviceObject;
PEPROCESS CurrentProcess;
BOOLEAN fAttachAttempted;
ASSERT(KeGetCurrentIrql() != DISPATCH_LEVEL);
ASSERT(pTcpAdptr->adp_Signature == DSI_ADAPTER_SIGNATURE);
*pRetFileHandle = INVALID_HANDLE_VALUE;
// copy device name into the unicode string
ucDeviceName.MaximumLength = (wcslen(AFP_TCP_BINDNAME) + 1)*sizeof(WCHAR);
ucDeviceName.Length = 0;
ucDeviceName.Buffer = (PWSTR)AfpAllocZeroedNonPagedMemory(
ucDeviceName.MaximumLength);
if (ucDeviceName.Buffer == NULL)
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiOpenTdiAddress: malloc for ucDeviceName Failed\n"));
return(STATUS_INSUFFICIENT_RESOURCES);
}
status = RtlAppendUnicodeToString(&ucDeviceName, AFP_TCP_BINDNAME);
if (!NT_SUCCESS(status))
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiOpenTdiAddress: RtlAppend... failed %lx\n",status));
AfpFreeMemory(ucDeviceName.Buffer);
return(status);
}
EaBuffer = (PFILE_FULL_EA_INFORMATION)AfpAllocZeroedNonPagedMemory(
sizeof(FILE_FULL_EA_INFORMATION) - 1 +
TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
sizeof(TRANSPORT_ADDRESS) +
sizeof(TDI_ADDRESS_IP));
if (EaBuffer == NULL)
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiOpenTdiAddress: malloc for Eabuffer failed!\n"));
AfpFreeMemory(ucDeviceName.Buffer);
return(STATUS_INSUFFICIENT_RESOURCES);
}
EaBuffer->NextEntryOffset = 0;
EaBuffer->Flags = 0;
EaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
EaBuffer->EaValueLength = sizeof(TRANSPORT_ADDRESS) -1
+ sizeof(TDI_ADDRESS_IP);
// put "TransportAddress" into the name
RtlMoveMemory(EaBuffer->EaName,
TdiTransportAddress,
EaBuffer->EaNameLength + 1);
// fill in the IP address and Port number
//
pTransAddressEa = (TRANSPORT_ADDRESS *)&EaBuffer->EaName[EaBuffer->EaNameLength+1];
// allocate Memory for the transport address
//
pTransAddr = (PTRANSPORT_ADDRESS)AfpAllocZeroedNonPagedMemory(
sizeof(TDI_ADDRESS_IP)+sizeof(TRANSPORT_ADDRESS));
if (pTransAddr == NULL)
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiOpenTdiAddress: malloc for pTransAddr failed!\n"));
AfpFreeMemory(ucDeviceName.Buffer);
AfpFreeMemory(EaBuffer);
return(STATUS_INSUFFICIENT_RESOURCES);
}
pTransAddr->TAAddressCount = 1;
pTransAddr->Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
pTransAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
TdiIpAddr.sin_port = htons(AFP_TCP_PORT); // put in network order
TdiIpAddr.in_addr = 0; // inaddr_any
// zero fill the last component of the IP address
//
RtlFillMemory((PVOID)&TdiIpAddr.sin_zero,
sizeof(TdiIpAddr.sin_zero),
0);
// copy the ip address to the end of the structure
//
RtlMoveMemory(pTransAddr->Address[0].Address,
(CONST PVOID)&TdiIpAddr,
sizeof(TdiIpAddr));
// copy the ip address to the end of the name in the EA structure
//
RtlMoveMemory((PVOID)pTransAddressEa,
(CONST PVOID)pTransAddr,
sizeof(TDI_ADDRESS_IP) + sizeof(TRANSPORT_ADDRESS)-1);
InitializeObjectAttributes(
&AddressAttributes,
&ucDeviceName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
CurrentProcess = IoGetCurrentProcess();
AFPAttachProcess(CurrentProcess);
fAttachAttempted = TRUE;
status = ZwCreateFile(
&FileHandle,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
&AddressAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN_IF,
0,
(PVOID)EaBuffer,
sizeof(FILE_FULL_EA_INFORMATION) - 1 +
EaBuffer->EaNameLength + 1 +
EaBuffer->EaValueLength);
// don't need these no more..
AfpFreeMemory((PVOID)pTransAddr);
AfpFreeMemory((PVOID)EaBuffer);
AfpFreeMemory(ucDeviceName.Buffer);
if (NT_SUCCESS(status))
{
// if the ZwCreate passed set the status to the IoStatus
status = IoStatusBlock.Status;
if (!NT_SUCCESS(status))
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiOpenTdiAddress: ZwCreateFile failed, iostatus=%lx\n",status));
AFPDetachProcess(CurrentProcess);
return(status);
}
// dereference the file object to keep the device ptr around to avoid
// this dereference at run time
//
status = ObReferenceObjectByHandle(
FileHandle,
(ULONG)0,
0,
KernelMode,
(PVOID *)&pFileObject,
NULL);
if (NT_SUCCESS(status))
{
AFPDetachProcess(CurrentProcess);
fAttachAttempted = FALSE;
pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
status = DsiSetEventHandler(
pDeviceObject,
pFileObject,
TDI_EVENT_ERROR,
(PVOID)DsiTdiErrorHandler,
(PVOID)pTcpAdptr);
if (NT_SUCCESS(status))
{
status = DsiSetEventHandler(
pDeviceObject,
pFileObject,
TDI_EVENT_RECEIVE,
(PVOID)DsiTdiReceiveHandler,
(PVOID)pTcpAdptr);
if (NT_SUCCESS(status))
{
status = DsiSetEventHandler(
pDeviceObject,
pFileObject,
TDI_EVENT_DISCONNECT,
(PVOID)DsiTdiDisconnectHandler,
(PVOID)pTcpAdptr);
if (NT_SUCCESS(status))
{
status = DsiSetEventHandler(
pDeviceObject,
pFileObject,
TDI_EVENT_CONNECT,
(PVOID)DsiTdiConnectHandler,
(PVOID)pTcpAdptr);
if (NT_SUCCESS(status))
{
// all worked well: done here
*pRetFileHandle = FileHandle;
*ppRetFileObj = pFileObject;
return(status);
}
else
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiOpenTdiAddress: Set.. DsiTdiConnectHandler failed %lx\n",
status));
}
}
else
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiOpenTdiAddress: Set.. DsiTdiDisconnectHandler failed %lx\n",
status));
}
}
else
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiOpenTdiAddress: Set.. DsiTdiReciveHandler failed %lx\n",
status));
}
//
// ERROR Case
//
ObDereferenceObject(pFileObject);
ZwClose(FileHandle);
return(status);
}
else
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiOpenTdiAddress: Set.. DsiTdiErrorHandler failed %lx\n",
status));
}
}
else
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiOpenTdiAddress: ObReferenceObjectByHandle failed %lx\n",status));
ZwClose(FileHandle);
}
}
else
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiOpenTdiAddress: ZwCreateFile failed %lx\n",status));
}
if (fAttachAttempted)
{
AFPDetachProcess(CurrentProcess);
}
return(status);
}
/*** DsiOpenTdiConnection
*
* This routine creates a TDI Conection for the given connection object
*
* Parm IN: pTcpConn - connection object
*
* Returns: status of operation
*
*/
NTSTATUS
DsiOpenTdiConnection(
IN PTCPCONN pTcpConn
)
{
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
PFILE_FULL_EA_INFORMATION EaBuffer;
UNICODE_STRING RelativeDeviceName = {0,0,NULL};
PMDL pMdl;
PEPROCESS CurrentProcess;
BOOLEAN fAttachAttempted;
ASSERT(KeGetCurrentIrql() != DISPATCH_LEVEL);
ASSERT(VALID_TCPCONN(pTcpConn));
ASSERT(pTcpConn->con_pTcpAdptr->adp_Signature == DSI_ADAPTER_SIGNATURE);
InitializeObjectAttributes (
&ObjectAttributes,
&RelativeDeviceName,
0,
pTcpConn->con_pTcpAdptr->adp_FileHandle,
NULL);
// Allocate memory for the address info to be passed to the transport
EaBuffer = (PFILE_FULL_EA_INFORMATION)AfpAllocZeroedNonPagedMemory (
sizeof(FILE_FULL_EA_INFORMATION) - 1 +
TDI_CONNECTION_CONTEXT_LENGTH + 1 +
sizeof(CONNECTION_CONTEXT));
if (!EaBuffer)
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiOpenTdiConnection: alloc for EaBuffer failed\n"));
return(STATUS_INSUFFICIENT_RESOURCES);
}
EaBuffer->NextEntryOffset = 0;
EaBuffer->Flags = 0;
EaBuffer->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
EaBuffer->EaValueLength = sizeof (CONNECTION_CONTEXT);
// copy ConnectionContext to EaName
RtlMoveMemory( EaBuffer->EaName, TdiConnectionContext, EaBuffer->EaNameLength + 1 );
// put out context into the EaBuffer
RtlMoveMemory (
(PVOID)&EaBuffer->EaName[EaBuffer->EaNameLength + 1],
(CONST PVOID)&pTcpConn,
sizeof (CONNECTION_CONTEXT));
CurrentProcess = IoGetCurrentProcess();
AFPAttachProcess(CurrentProcess);;
fAttachAttempted = TRUE;
Status = ZwCreateFile (
&pTcpConn->con_FileHandle,
GENERIC_READ | GENERIC_WRITE,
&ObjectAttributes, // object attributes.
&IoStatusBlock, // returned status information.
NULL, // block size (unused).
FILE_ATTRIBUTE_NORMAL, // file attributes.
0,
FILE_CREATE,
0, // create options.
(PVOID)EaBuffer, // EA buffer.
sizeof(FILE_FULL_EA_INFORMATION) - 1 +
TDI_CONNECTION_CONTEXT_LENGTH + 1 +
sizeof(CONNECTION_CONTEXT));
AfpFreeMemory((PVOID)EaBuffer);
if (NT_SUCCESS(Status))
{
// if the ZwCreate passed set the status to the IoStatus
//
Status = IoStatusBlock.Status;
if (NT_SUCCESS(Status))
{
// dereference file handle, now that we are at task time
Status = ObReferenceObjectByHandle(
pTcpConn->con_FileHandle,
0L,
NULL,
KernelMode,
(PVOID *)&pTcpConn->con_pFileObject,
NULL);
if (NT_SUCCESS(Status))
{
AFPDetachProcess(CurrentProcess);
return(Status);
}
else
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiOpenTdiConnection: ObReference.. failed %lx\n",Status));
ZwClose(pTcpConn->con_FileHandle);
}
}
else
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiOpenTdiConnection: ZwCreateFile IoStatus failed %lx\n",Status));
}
}
else
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiOpenTdiConnection: ZwCreateFile failed %lx\n",Status));
}
if (fAttachAttempted)
{
AFPDetachProcess(CurrentProcess);
}
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiOpenTdiConnection: taking error path, returning %lx\n",Status));
return Status;
}
/*** DsiAssociateTdiConnection
*
* This routine associates a TDI connection with the address object for AFP port
*
* Parm IN: pTcpConn - connection object
*
* Returns: status of operation
*
*/
NTSTATUS
DsiAssociateTdiConnection(
IN PTCPCONN pTcpConn
)
{
NTSTATUS status;
PIRP pIrp;
PDEVICE_OBJECT pDeviceObject;
ASSERT(VALID_TCPCONN(pTcpConn));
ASSERT(pTcpConn->con_pTcpAdptr->adp_Signature == DSI_ADAPTER_SIGNATURE);
pDeviceObject = IoGetRelatedDeviceObject(pTcpConn->con_pFileObject);
if ((pIrp = AfpAllocIrp(pDeviceObject->StackSize)) == NULL)
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiAssociateTdiConnection: alloc for pIrp failed\n"));
return(STATUS_INSUFFICIENT_RESOURCES);
}
TdiBuildAssociateAddress(
pIrp,
pDeviceObject,
pTcpConn->con_pFileObject,
DsiTdiCompletionRoutine,
NULL,
pTcpConn->con_pTcpAdptr->adp_FileHandle);
status = DsiTdiSynchronousIrp(pIrp, pDeviceObject);
if (status != STATUS_SUCCESS)
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiAssociateTdiConnection: ..TdiSynch.. failed %lx\n",status));
}
AfpFreeIrp(pIrp);
return(status);
}
/*** DsiSetEventHandler
*
* This routine sends an irp down to the tcp stack to set a specified event handler
*
* Parm IN: pDeviceObject - TCP's device object
* pFileObject - file object corresponding to the address object
* EventType - TDI_EVENT_CONNECT, TDI_EVENT_RECEIVE etc.
* EventHandler - the handler for this event
* Context - our adapter object
*
* Returns: status of operation
*
*/
NTSTATUS
DsiSetEventHandler(
IN PDEVICE_OBJECT pDeviceObject,
IN PFILE_OBJECT pFileObject,
IN ULONG EventType,
IN PVOID EventHandler,
IN PVOID Context
)
{
PIRP pIrp;
NTSTATUS status;
if ((pIrp = AfpAllocIrp(pDeviceObject->StackSize)) == NULL)
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiSetEventHandler: alloc for pIrp failed\n"));
return(STATUS_INSUFFICIENT_RESOURCES);
}
TdiBuildSetEventHandler(pIrp,
pDeviceObject,
pFileObject,
NULL,
NULL,
EventType,
EventHandler,
Context);
status = DsiTdiSynchronousIrp(pIrp, pDeviceObject);
if (status != STATUS_SUCCESS)
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiSetEventHandler: ..TdiSynch.. failed %lx\n",status));
}
AfpFreeIrp(pIrp);
return(status);
}
/*** DsiTdiSynchronousIrp
*
* This routine sends an irp down to the tcp stack, and blocks until the irp
* is completed
*
* Parm IN: pIrp - the irp that needs to be sent down
* pDeviceObject - TCP's device object
*
* Returns: status of operation
*
*/
NTSTATUS
DsiTdiSynchronousIrp(
IN PIRP pIrp,
PDEVICE_OBJECT pDeviceObject
)
{
NTSTATUS status;
KEVENT Event;
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
IoSetCompletionRoutine(pIrp,
(PIO_COMPLETION_ROUTINE)DsiTdiCompletionRoutine,
(PVOID)&Event,
TRUE,
TRUE,
TRUE);
status = IoCallDriver(pDeviceObject, pIrp);
if (!NT_SUCCESS(status))
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiTdiSynchronousIrp: IoCallDriver failed %lx\n",status));
}
if (status == STATUS_PENDING)
{
status = KeWaitForSingleObject((PVOID)&Event,
Executive,
KernelMode,
FALSE,
NULL);
if (!NT_SUCCESS(status))
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiTdiSynchronousIrp: KeWaitFor... failed %lx\n",status));
return(status);
}
status = pIrp->IoStatus.Status;
}
return(status);
}
/*** DsiTdiCompletionRoutine
*
* This routine gets called when the irp sent in DsiTdiSynchronousIrp is
* completed
*
* Parm IN: pDeviceObject - TCP's device object
* pIrp - the irp that got completed
* Context - our adapter object
*
* Returns: status of operation
*
*/
NTSTATUS
DsiTdiCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
KeSetEvent((PKEVENT )Context, 0, FALSE);
return(STATUS_MORE_PROCESSING_REQUIRED);
}
/*** DsiTdiSend
*
* This routine is the send routine for all DSI sends out to TCP
*
* Parm IN: pTcpConn - the connection object
* pMdl - mdl containing the buffer
* DataLen - how many bytes to send
* pCompletionRoutine - whom to call when send completes
* pContext - context for the completion routine
*
* Returns: status of operation
*
*/
NTSTATUS
DsiTdiSend(
IN PTCPCONN pTcpConn,
IN PMDL pMdl,
IN DWORD DataLen,
IN PVOID pCompletionRoutine,
IN PVOID pContext
)
{
PDEVICE_OBJECT pDeviceObject;
PIRP pIrp;
NTSTATUS status;
// make sure beginning of the packet looks like the DSI header
#if DBG
PBYTE pPacket;
pPacket = MmGetSystemAddressForMdlSafe(
pMdl,
NormalPagePriority);
if (pPacket != NULL)
ASSERT(*(DWORD *)&pPacket[DSI_OFFSET_DATALEN] == ntohl(DataLen-DSI_HEADER_SIZE));
#endif
pDeviceObject = IoGetRelatedDeviceObject(pTcpConn->con_pFileObject);
if ((pIrp = AfpAllocIrp(pDeviceObject->StackSize)) == NULL)
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiTdiSend: AllocIrp failed\n"));
return(STATUS_INSUFFICIENT_RESOURCES);
}
pIrp->CancelRoutine = NULL;
TdiBuildSend(
pIrp,
pDeviceObject,
pTcpConn->con_pFileObject,
pCompletionRoutine,
pContext,
pMdl,
0,
DataLen);
status = IoCallDriver(pDeviceObject,pIrp);
if (!NT_SUCCESS(status))
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiTdiSend: IoCallDriver failed %lx\n",status));
}
return(STATUS_PENDING);
}
/*** DsiIpAddressCameIn
*
* This routine gets called when ipaddress becomes available on an adapter
*
* Parm IN: Address - TA_ADDRESS
* Context1 -
* Context2 -
*
* Returns: none
*
*/
VOID
DsiIpAddressCameIn(
IN PTA_ADDRESS Address,
IN PUNICODE_STRING DeviceName,
IN PTDI_PNP_CONTEXT Context2
)
{
IPADDRESS IpAddress;
PUNICODE_STRING pBindDeviceName;
NTSTATUS status=STATUS_SUCCESS;
KIRQL OldIrql;
BOOLEAN fCreateAdapter=FALSE;
BOOLEAN fClosing=FALSE;
pBindDeviceName = DeviceName;
// if this is not an ipaddress, we don't care: just return
if (Address->AddressType != TDI_ADDRESS_TYPE_IP)
{
return;
}
IpAddress = ntohl(((PTDI_ADDRESS_IP)&Address->Address[0])->in_addr);
if (IpAddress == 0)
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_WARN,
("AfpTdiIpAddressCameIn: ipaddress is 0 on %ws!\n",
(pBindDeviceName)->Buffer));
return;
}
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_WARN,
("AfpTdiIpAddressCameIn: %d.%d.%d.%d on %ws\n",
(IpAddress>>24)&0xFF,(IpAddress>>16)&0xFF,(IpAddress>>8)&0xFF,
IpAddress&0xFF,(pBindDeviceName)->Buffer));
if ((AfpServerState == AFP_STATE_STOP_PENDING) ||
(AfpServerState == AFP_STATE_SHUTTINGDOWN) ||
(AfpServerState == AFP_STATE_STOPPED))
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("AfpTdiIpAddressCameIn: server shutting down, returning\n"));
return;
}
//
// do we already have the DSI-tdi interface initialized (i.e. DsiTcpAdapter
// is non-null)? If we already saw an ipaddr come in earlier, this would be
// initialized. if not, we must initialize now
//
ACQUIRE_SPIN_LOCK(&DsiAddressLock, &OldIrql);
if (DsiTcpAdapter == NULL)
{
fCreateAdapter = TRUE;
}
RELEASE_SPIN_LOCK(&DsiAddressLock, OldIrql);
// add this ipaddress to our list
DsiAddIpaddressToList(IpAddress);
if (fCreateAdapter)
{
DsiCreateAdapter();
}
// ipaddress came in: update the status buffer
DsiScheduleWorkerEvent(DsiUpdateAfpStatus, NULL);
}
/*** DsiIpAddressWentAway
*
* This routine gets called when ipaddress goes away on an adapter
*
* Parm IN: Address - TA_ADDRESS
* Context1 -
* Context2 -
*
* Returns: none
*
*/
VOID
DsiIpAddressWentAway(
IN PTA_ADDRESS Address,
IN PUNICODE_STRING DeviceName,
IN PTDI_PNP_CONTEXT Context2
)
{
PUNICODE_STRING pBindDeviceName;
IPADDRESS IpAddress;
KIRQL OldIrql;
BOOLEAN fDestroyIt=FALSE;
BOOLEAN fIpAddrRemoved=TRUE;
BOOLEAN fMustDeref=FALSE;
pBindDeviceName = DeviceName;
if (Address->AddressType != TDI_ADDRESS_TYPE_IP)
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_WARN,
("AfpTdiIpAddressWentAway: unknown AddrType %d on %ws, ignoring!\n",
Address->AddressType,(pBindDeviceName)->Buffer));
return;
}
IpAddress = ntohl(((PTDI_ADDRESS_IP)&Address->Address[0])->in_addr);
if (IpAddress == 0)
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_WARN,
("AfpTdiIpAddressWentAway: ipaddress is 0 on %ws!\n",
(pBindDeviceName)->Buffer));
return;
}
DsiRemoveIpaddressFromList(IpAddress);
//
// if the global adapter exists, see if we need to destroy it because the
// last ipaddress went away
//
ACQUIRE_SPIN_LOCK(&DsiAddressLock, &OldIrql);
if (DsiTcpAdapter != NULL)
{
fDestroyIt = IsListEmpty(&DsiIpAddrList)? TRUE : FALSE;
}
RELEASE_SPIN_LOCK(&DsiAddressLock, OldIrql);
// ipaddress went away: update the status buffer
DsiScheduleWorkerEvent(DsiUpdateAfpStatus, NULL);
if (fDestroyIt)
{
DsiDestroyAdapter();
}
}
/*** DsiTdiConnectHandler
*
* This routine
*
* Parm IN: EventContext - pTcpAdptr that we passed when we set tdi handlers
* MacIpAddrLen - length of the address of the Mac (4 bytes!)
* pMacIpAddr - ipaddr of the Mac that's attempting to connect
* DsiDataLength - length of DSI data, if any, in this connect request
* pDsiData - pointer to DSI data, if any
* OptionsLength - unused
* pOptions - unused
*
* Parm OUT: pOurConnContext - connection context, pTcpConn for this connection
* ppOurAcceptIrp - irp, if accpeting this connection
*
* Returns: status of operation
*
*/
NTSTATUS
DsiTdiConnectHandler(
IN PVOID EventContext,
IN int MacIpAddrLen,
IN PVOID pSrcAddress,
IN int DsiDataLength,
IN PVOID pDsiData,
IN int OptionsLength,
IN PVOID pOptions,
OUT CONNECTION_CONTEXT *pOurConnContext,
OUT PIRP *ppOurAcceptIrp
)
{
NTSTATUS status=STATUS_SUCCESS;
PTCPADPTR pTcpAdptr;
PTCPCONN pTcpConn;
PDEVICE_OBJECT pDeviceObject;
IPADDRESS MacIpAddr;
PTRANSPORT_ADDRESS pXportAddr;
PIRP pIrp;
pTcpAdptr = (PTCPADPTR)EventContext;
*pOurConnContext = NULL;
*ppOurAcceptIrp = NULL;
ASSERT(pTcpAdptr->adp_Signature == DSI_ADAPTER_SIGNATURE);
pDeviceObject = IoGetRelatedDeviceObject(pTcpAdptr->adp_pFileObject);
if ((pIrp = AfpAllocIrp(pDeviceObject->StackSize)) == NULL)
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiTdiConnectHandler: AllocIrp failed\n"));
return(STATUS_DATA_NOT_ACCEPTED);
}
pXportAddr = (PTRANSPORT_ADDRESS)pSrcAddress;
MacIpAddr = ((PTDI_ADDRESS_IP)&pXportAddr->Address[0].Address[0])->in_addr;
//
// see if DSI wants to accept this connection
//
status = DsiAcceptConnection(pTcpAdptr, ntohl(MacIpAddr), &pTcpConn);
if (!NT_SUCCESS(status))
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiTdiConnectHandler: DsiAccep.. failed %lx\n",status));
AfpFreeIrp(pIrp);
return(status);
}
TdiBuildAccept(pIrp,
IoGetRelatedDeviceObject(pTcpConn->con_pFileObject),
pTcpConn->con_pFileObject,
DsiAcceptConnectionCompletion,
pTcpConn,
NULL,
NULL);
pIrp->MdlAddress = NULL;
*pOurConnContext = (CONNECTION_CONTEXT)pTcpConn;
*ppOurAcceptIrp = pIrp;
// do what IoSubSystem would have done, if we had called IoCallDriver
IoSetNextIrpStackLocation(pIrp);
return(STATUS_MORE_PROCESSING_REQUIRED);
}
/*** DsiTdiReceiveHandler
*
* This routine
*
* Parm IN: EventContext - pTcpAdptr that we passed when we set tdi handlers
* ConnectionContext - our context, pTcpConn for this connection
* RcvFlags - more info about how the data was received
* BytesIndicated - number of bytes tcp is indicating
* BytesAvailable - number of bytes that came in (tcp has with it)
* pDsiData - the data that came in
*
* Parm OUT: pBytesAccepted - how many bytes did we accept
* ppIrp - irp, if for tcp to copy data in (if needed)
*
* Returns: status of operation
*
*/
NTSTATUS
DsiTdiReceiveHandler(
IN PVOID EventContext,
IN PVOID ConnectionContext,
IN USHORT RcvFlags,
IN ULONG BytesIndicated,
IN ULONG BytesAvailable,
OUT PULONG pBytesAccepted,
IN PVOID pDsiData,
OUT PIRP *ppIrp
)
{
NTSTATUS status;
PTCPCONN pTcpConn;
PBYTE pBuffer;
PIRP pIrp;
pTcpConn = (PTCPCONN)ConnectionContext;
*ppIrp = NULL;
*pBytesAccepted = 0;
ASSERT(VALID_TCPCONN(pTcpConn));
status = DsiProcessData(pTcpConn,
BytesIndicated,
BytesAvailable,
(PBYTE)pDsiData,
pBytesAccepted,
ppIrp);
return(status);
}
/*** DsiTdiDisconnectHandler
*
* This routine
*
* Parm IN: EventContext - pTcpAdptr that we passed when we set tdi handlers
* ConnectionContext - our context, pTcpConn for this connection
* DisconnectDataLength -
* pDisconnectData -
*
*
*
* Returns: status of operation
*
*/
NTSTATUS
DsiTdiDisconnectHandler(
IN PVOID EventContext,
IN PVOID ConnectionContext,
IN ULONG DisconnectDataLength,
IN PVOID pDisconnectData,
IN ULONG DisconnectInformationLength,
IN PVOID pDisconnectInformation,
IN ULONG DisconnectIndicators
)
{
PTCPCONN pTcpConn;
KIRQL OldIrql;
BOOLEAN fMustAbort=FALSE;
BOOLEAN fWeInitiatedAbort=FALSE;
pTcpConn = (PTCPCONN)ConnectionContext;
ASSERT(VALID_TCPCONN(pTcpConn));
//
// if the connection went away non-gracefully (i.e. TCP got a reset), and
// if we have not already given an irp down to tcp to disconnect, then
// complete the disconnect here
//
if ((UCHAR)DisconnectIndicators == TDI_DISCONNECT_ABORT)
{
ACQUIRE_SPIN_LOCK(&pTcpConn->con_SpinLock, &OldIrql);
fWeInitiatedAbort =
(pTcpConn->con_State & TCPCONN_STATE_ABORTIVE_DISCONNECT)? TRUE : FALSE;
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("ABORT from %s on %lx\n",fWeInitiatedAbort?"Local":"Remote",pTcpConn));
if (pTcpConn->con_State & TCPCONN_STATE_NOTIFY_TCP)
{
fMustAbort = TRUE;
pTcpConn->con_State &= ~TCPCONN_STATE_NOTIFY_TCP;
pTcpConn->con_State |= TCPCONN_STATE_CLOSING;
}
RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
if (fMustAbort)
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_WARN,
("DsiTdiDisconnectHandler: abortive disconnect on %lx\n",pTcpConn));
DsiAbortConnection(pTcpConn);
DsiTcpDisconnectCompletion(NULL, NULL, pTcpConn);
// TCP is telling us it got cient's RST: remove the TCP CLIENT-FIN refcount
DsiDereferenceConnection(pTcpConn);
DBGREFCOUNT(("DsiTdiDisconnectHandler: CLIENT-FIN dec %lx (%d %d,%d)\n",
pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
}
//
// if we had initiated a graceful close, remove that TCP CLIENT-FIN refcount:
// (if we had initiated an abortive close, we already took care of it)
//
else if (!fWeInitiatedAbort)
{
DsiDereferenceConnection(pTcpConn);
}
else
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiTdiDisconnectHandler: abortive disc,race condition on %lx\n",
pTcpConn));
}
}
else if ((UCHAR)DisconnectIndicators == TDI_DISCONNECT_RELEASE)
{
//
// since we got a graceful disconnect from the remote client, we had
// better received the DSI Close already. If not, the client is on
// drugs, so just reset the connection!
//
ACQUIRE_SPIN_LOCK(&pTcpConn->con_SpinLock, &OldIrql);
if ((pTcpConn->con_State & TCPCONN_STATE_AFP_ATTACHED) &&
(!(pTcpConn->con_State & TCPCONN_STATE_RCVD_REMOTE_CLOSE)))
{
fMustAbort = TRUE;
}
RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
if (fMustAbort)
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_WARN,
("DsiTdiDisconnectHandler: ungraceful FIN, killing %lx\n",pTcpConn));
DsiAbortConnection(pTcpConn);
}
else
{
//
// by this time, we shouldn't have to do this, but just in case we
// have an ill-behaved client (calling this routine many times is ok)
//
DsiTerminateConnection(pTcpConn);
// TCP is telling us it got cient's FIN: remove the TCP CLIENT-FIN refcount
DsiDereferenceConnection(pTcpConn);
DBGREFCOUNT(("DsiTdiDisconnectHandler: CLIENT-FIN dec %lx (%d %d,%d)\n",
pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
}
}
else
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiTdiDisconnectHandler: flag=%d, ignored on %lx\n",
DisconnectIndicators,pTcpConn));
ASSERT(0);
}
return(STATUS_SUCCESS);
}
/*** DsiTdiErrorHandler
*
* This routine
*
* Parm IN: EventContext - pTcpAdptr that we passed when we set tdi handlers
* status - what went wrong?
*
* Returns: status of operation
*
*/
NTSTATUS
DsiTdiErrorHandler(
IN PVOID EventContext,
IN NTSTATUS Status
)
{
DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
("DsiTdiErrorHandler: entered, with Status=%lx\n",Status));
ASSERT(0);
return(STATUS_DATA_NOT_ACCEPTED);
}
/*** DsiCloseTdiAddress
*
* This routine closes the address object with TCP
*
* Parm IN: pTcpAdptr - our adapter object
*
* Returns: status of operation
*
*/
NTSTATUS
DsiCloseTdiAddress(
IN PTCPADPTR pTcpAdptr
)
{
PEPROCESS CurrentProcess;
ASSERT(KeGetCurrentIrql() != DISPATCH_LEVEL);
ASSERT(pTcpAdptr->adp_Signature == DSI_ADAPTER_SIGNATURE);
CurrentProcess = IoGetCurrentProcess();
AFPAttachProcess(CurrentProcess);;
if (pTcpAdptr->adp_pFileObject)
{
ObDereferenceObject((PVOID *)pTcpAdptr->adp_pFileObject);
pTcpAdptr->adp_pFileObject = NULL;
}
if (pTcpAdptr->adp_FileHandle != INVALID_HANDLE_VALUE)
{
ZwClose(pTcpAdptr->adp_FileHandle);
pTcpAdptr->adp_FileHandle = INVALID_HANDLE_VALUE;
}
AFPDetachProcess(CurrentProcess);
return(STATUS_SUCCESS);
}
/*** DsiCloseTdiConnection
*
* This routine closes the connection object with TCP
*
* Parm IN: pTcpConn - our connection context
*
* Returns: status of operation
*
*/
NTSTATUS
DsiCloseTdiConnection(
IN PTCPCONN pTcpConn
)
{
PEPROCESS CurrentProcess;
ASSERT(KeGetCurrentIrql() != DISPATCH_LEVEL);
ASSERT(pTcpConn->con_Signature == DSI_CONN_SIGNATURE);
ASSERT(pTcpConn->con_pTcpAdptr->adp_Signature == DSI_ADAPTER_SIGNATURE);
CurrentProcess = IoGetCurrentProcess();
AFPAttachProcess(CurrentProcess);;
if (pTcpConn->con_pFileObject)
{
ObDereferenceObject((PVOID *)pTcpConn->con_pFileObject);
pTcpConn->con_pFileObject = NULL;
}
if (pTcpConn->con_FileHandle != INVALID_HANDLE_VALUE)
{
ZwClose(pTcpConn->con_FileHandle);
pTcpConn->con_FileHandle = INVALID_HANDLE_VALUE;
}
AFPDetachProcess(CurrentProcess);
return(STATUS_SUCCESS);
}