|
|
/*
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); }
|