windows-nt/Source/XPSP1/NT/net/irda/irtdicl/irtdicl.c

2128 lines
55 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
irtdicl.c
Abstract:
Library of routines that abstracts the tdi client interface to
the IrDA stack. Used by rasirda.sys
Author:
mbert 9-97
--*/
/*
TDI Client Libary TDI Client Driver
-----------------------------------------------------------
Peer initated connection
<---------- IrdaOpenEndpoint(
in ClEndpointContext,
in ListenAddress
out EndpointContext)
IrdaIncomingConnection( ---------->
in ClEndpointContext
in ConnectContext
out ClConnContext)
Locally initiated connection
<---------- IrdaDiscoverDevices(
out DeviceList)
<---------- IrdaOpenConnection(
in DestinationAddress,
in ClConnContext,
out ConnectionContext)
Peer initiated disconnect
IrdaConnectionClosed( ----------->
in ClConnContext)
<----------- IrdaCloseConnection(
in ConnectionContext)
Locally initiated disconnect
<---------- IrdaCloseConnection(
in ConnectionContext)
If the driver closes all connections on an endpoint by calling
IrdaCloseEndpoint() then it will receive an IrdaConnectionClosed()
for all connections on the endpoint. The driver must then call
IrdaCloseConnection() to free its reference to the connection
object maintained in the library.
Sending Data
<----------- IrdaSend(
in ConnectionContext,
in pMdl,
in SendContext)
IrdaSendComplete( ----------->
in ClConnContext,
in SendContext,
in Status)
Receiving Data
------------> IrdaReceiveIndication(
in ClConnContext,
in ReceiveBuffer)
IrdaReceiveComplete( <------------
in ConnectionContext,
in ReceiveBuffer)
*/
#define UNICODE
#include <ntosp.h>
#include <cxport.h>
#include <zwapi.h>
#include <tdikrnl.h>
#define UINT ULONG //tmp
#include <af_irda.h>
#include <dbgmsg.h>
#include <refcnt.h>
#include <irdatdi.h>
#include <irtdicl.h>
#include <irtdiclp.h>
#include <irioctl.h>
#include <irmem.h>
#define LOCKIT() CTEGetLock(&ClientLock, &hLock)
#define UNLOCKIT() CTEFreeLock(&ClientLock, hLock)
CTELockHandle hLock;
CTELock ClientLock;
LIST_ENTRY SrvEndpList;
CTEEvent CreateConnEvent;
//CTEEvent DataReadyEvent;
CTEEvent RestartRecvEvent;
PKPROCESS IrclSystemProcess;
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, IrdaClientInitialize)
#endif
//------------------------------------------------------------------
// public funtions
//
NTSTATUS
IrdaClientInitialize()
{
CTEInitLock(&ClientLock);
CTEInitEvent(&CreateConnEvent, IrdaCreateConnCallback);
// CTEInitEvent(&DataReadyEvent, IrdaDataReadyCallback);
CTEInitEvent(&RestartRecvEvent, IrdaRestartRecvCallback);
InitializeListHead(&SrvEndpList);
// so we can open and use handles in the context of this driver
IrclSystemProcess = (PKPROCESS)IoGetCurrentProcess();
return STATUS_SUCCESS;
}
VOID
IrdaClientShutdown()
{
PIRENDPOINT pEndp;
LOCKIT();
while (!IsListEmpty(&SrvEndpList))
{
pEndp = (PIRENDPOINT) RemoveHeadList(&SrvEndpList);
UNLOCKIT();
if (IrdaCloseEndpointInternal(pEndp, TRUE) != STATUS_SUCCESS)
{
ASSERT(0);
}
LOCKIT();
}
UNLOCKIT();
}
VOID
CloseAddressesCallback()
{
IrdaCloseAddresses();
}
VOID
SetCloseAddressesCallback()
{
NTSTATUS Status;
PIRP pIrp;
PIO_STACK_LOCATION pIrpSp;
UNICODE_STRING DeviceName;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK Iosb;
HANDLE DevHandle = NULL;
PFILE_OBJECT pFileObject = NULL;
PDEVICE_OBJECT pDeviceObject;
RtlInitUnicodeString(&DeviceName, IRDA_DEVICE_NAME);
InitializeObjectAttributes(&ObjectAttributes, &DeviceName,
OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = ZwCreateFile(&DevHandle,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
&ObjectAttributes,
&Iosb, // returned status information.
0, // block size (unused).
0, // file attributes.
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_CREATE, // create disposition.
0, // create options.
NULL,
0);
if (Status != STATUS_SUCCESS)
{
DEBUGMSG(DBG_ERROR, ("IRTDI: Failed to open control channel\n"));
goto EXIT;
}
Status = ObReferenceObjectByHandle(
DevHandle,
0L, // DesiredAccess
NULL,
KernelMode,
(PVOID *)&pFileObject,
NULL);
if (Status != STATUS_SUCCESS)
{
DEBUGMSG(DBG_ERROR, ("IRTDI: ObReferenceObjectByHandle failed\n"));
goto EXIT;
}
pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
pIrp = TdiBuildInternalDeviceControlIrp(
TDI_SET_INFORMATION,
pDeviceObject,
pFileObject,
NULL,
&Iosb);
if (pIrp == NULL)
{
goto EXIT;
}
IoSetCompletionRoutine(pIrp, NULL, NULL, FALSE, FALSE, FALSE);
pIrpSp = IoGetNextIrpStackLocation(pIrp);
if (pIrpSp == NULL)
{
goto EXIT;
}
pIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
pIrpSp->MinorFunction = TDI_SET_INFORMATION;
pIrpSp->DeviceObject = pDeviceObject;
pIrpSp->FileObject = pFileObject;
pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer = (PVOID) CloseAddressesCallback;
Status = IoCallDriver(pDeviceObject, pIrp);
EXIT:
if (pFileObject)
{
ObDereferenceObject(pFileObject);
}
if (DevHandle)
{
ZwClose(DevHandle);
}
}
NTSTATUS
IrdaOpenEndpoint(
IN PVOID ClEndpContext,
IN PTDI_ADDRESS_IRDA pRequestedIrdaAddr,
OUT PVOID *pEndpContext)
{
NTSTATUS Status;
PIRENDPOINT pEndp;
int i, ConnCnt;
PIRCONN pConn;
TDI_ADDRESS_IRDA IrdaAddr;
PTDI_ADDRESS_IRDA pIrdaAddr;
BOOLEAN Detach = FALSE;
*pEndpContext = NULL;
//
// Create an address object
//
IRDA_ALLOC_MEM(pEndp, sizeof(IRENDPOINT), MT_TDICL_ENDP);
if (pEndp == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
CTEMemSet(pEndp, 0, sizeof(IRENDPOINT));
*pEndpContext = pEndp;
pEndp->Sig = ENDPSIG;
pEndp->ClEndpContext = ClEndpContext;
InitializeListHead(&pEndp->ConnList);
CTEInitEvent(&pEndp->DeleteEndpEvent, DeleteEndpCallback);
ReferenceInit(&pEndp->RefCnt, pEndp, IrdaDeleteEndpoint);
REFADD(&pEndp->RefCnt, ' TS1');
LOCKIT();
InsertTailList(&SrvEndpList, &pEndp->Linkage);
UNLOCKIT();
//
// A client endpoint will have a null RequestedIrdaAddr
//
if (pRequestedIrdaAddr == NULL)
{
IrdaAddr.irdaServiceName[0] = 0; // tells irda.sys addrObj is a client
ConnCnt = 1;
pIrdaAddr = &IrdaAddr;
pEndp->Flags = EPF_CLIENT;
}
else
{
// out for now bug 326750
//SetCloseAddressesCallback();
pIrdaAddr = pRequestedIrdaAddr;
ConnCnt = LISTEN_BACKLOG;
pEndp->Flags = EPF_SERVER;
}
Status = IrdaCreateAddress(pIrdaAddr, &pEndp->AddrHandle);
DEBUGMSG(DBG_LIB_OBJ, ("IRTDI: CreateAddress ep:%X, status %X\n",
pEndp, Status));
if (Status != STATUS_SUCCESS)
{
goto error;
}
pEndp->pFileObject = NULL;
KeAttachProcess(IrclSystemProcess);
Status = ObReferenceObjectByHandle(
pEndp->AddrHandle,
0L, // DesiredAccess
NULL,
KernelMode,
(PVOID *)&pEndp->pFileObject,
NULL);
KeDetachProcess();
if (Status != STATUS_SUCCESS)
{
DEBUGMSG(DBG_ERROR, ("IRTDI: ObRefObjectByHandle failed %X\n",
Status));
goto error;
}
pEndp->pDeviceObject = IoGetRelatedDeviceObject(
pEndp->pFileObject);
//
// Register disconnect and receive handlers with irda.sys
//
Status = IrdaSetEventHandler(
pEndp->pFileObject,
TDI_EVENT_DISCONNECT,
IrdaDisconnectEventHandler,
pEndp);
if (Status != STATUS_SUCCESS)
{
DEBUGMSG(DBG_ERROR, ("IRTDI: SetEventHandler failed %X\n", Status));
goto error;
}
Status = IrdaSetEventHandler(
pEndp->pFileObject,
TDI_EVENT_RECEIVE,
IrdaReceiveEventHandler,
pEndp);
if (Status != STATUS_SUCCESS)
{
DEBUGMSG(DBG_ERROR, ("IRTDI: SetEventHandler failed %X\n", Status));
goto error;
}
//
// Create BACKLOG worth of connection objects and
// associate them with the address object
//
for (i = 0; i < ConnCnt; i++)
{
REFADD(&pEndp->RefCnt, 'NNOC');
IrdaCreateConnCallback(NULL, pEndp);
}
if (pEndp->Flags & EPF_SERVER)
{
Status = IrdaSetEventHandler(
pEndp->pFileObject,
TDI_EVENT_CONNECT,
IrdaConnectEventHandler,
pEndp);
if (Status != STATUS_SUCCESS)
{
DEBUGMSG(DBG_ERROR, ("IRTDI: SetEventHandler failed %X\n", Status));
goto error;
}
}
goto done;
error:
IrdaCloseEndpointInternal(pEndp, TRUE);
*pEndpContext = NULL;
done:
DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: IrdaOpenEndpoint %X, returning %X\n",
*pEndpContext, Status));
return Status;
}
NTSTATUS
IrdaCloseEndpoint(
PVOID pEndpContext)
{
return IrdaCloseEndpointInternal(pEndpContext, FALSE);
}
NTSTATUS
IrdaCloseEndpointInternal(
PVOID pEndpContext,
BOOLEAN InternalRequest)
{
PIRENDPOINT pEndp = (PIRENDPOINT) pEndpContext;
PIRCONN pConn, pConnNext;
DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: IrdaCloseEndpoint %X\n",
pEndp));
GOODENDP(pEndp);
if (!InternalRequest)
{
pEndp->Flags |= EPF_COMPLETE_CLOSE;
}
if (pEndp->pFileObject)
{
IrdaSetEventHandler(pEndp->pFileObject,
TDI_EVENT_CONNECT,
NULL, pEndp);
}
LOCKIT();
for (pConn = (PIRCONN) pEndp->ConnList.Flink;
pConn != (PIRCONN) &pEndp->ConnList;
pConn = pConnNext)
{
GOODCONN(pConn);
pConnNext = (PIRCONN) pConn->Linkage.Flink;
// IrdaCloseConnInternal wants lock held
// when calling and will release it before
// returning
IrdaCloseConnInternal(pConn);
LOCKIT();
}
UNLOCKIT();
REFDEL(&pEndp->RefCnt, ' TS1');
return STATUS_SUCCESS;
}
NTSTATUS
IrdaDiscoverDevices(
PDEVICELIST pDevList,
PULONG pDevListLen)
{
NTSTATUS Status;
IO_STATUS_BLOCK Iosb;
HANDLE ControlHandle;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING DeviceName;
RtlInitUnicodeString(&DeviceName, IRDA_DEVICE_NAME);
InitializeObjectAttributes(&ObjectAttributes, &DeviceName,
OBJ_CASE_INSENSITIVE, NULL, NULL);
KeAttachProcess(IrclSystemProcess);
Status = ZwCreateFile(
&ControlHandle,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
&ObjectAttributes,
&Iosb, // returned status information.
0, // block size (unused).
0, // file attributes.
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_CREATE, // create disposition.
0, // create options.
NULL,
0
);
Status = ZwDeviceIoControlFile(
ControlHandle,
NULL, // EventHandle
NULL, // APC Routine
NULL, // APC Context
&Iosb,
IOCTL_IRDA_GET_INFO_ENUM_DEV,
pDevList,
*pDevListLen,
pDevList, // OutputBuffer
*pDevListLen // OutputBufferLength
);
if (Status == STATUS_PENDING )
{
Status = ZwWaitForSingleObject(ControlHandle, TRUE, NULL);
ASSERT(NT_SUCCESS(Status) );
Status = Iosb.Status;
}
ZwClose(ControlHandle);
KeDetachProcess();
return Status;
}
VOID
SetIrCommMode(
PIRENDPOINT pEndp)
{
NTSTATUS Status;
IO_STATUS_BLOCK Iosb;
int Options = OPT_9WIRE_MODE;
KeAttachProcess(IrclSystemProcess);
Status = ZwDeviceIoControlFile(
pEndp->AddrHandle,
NULL, // EventHandle
NULL, // APC Routine
NULL, // APC Context
&Iosb,
IOCTL_IRDA_SET_OPTIONS,
&Options,
sizeof(int),
NULL, // OutputBuffer
0 // OutputBufferLength
);
KeDetachProcess();
DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: setting IrComm mode, Status %x\n",
Status));
}
NTSTATUS
IrdaOpenConnection(
PTDI_ADDRESS_IRDA pConnIrdaAddr,
PVOID ClConnContext,
PVOID *pConnectContext,
BOOLEAN IrCommMode)
{
NTSTATUS Status;
PIRP pIrp;
PIRENDPOINT pEndp;
PIRCONN pConn;
KEVENT Event;
IO_STATUS_BLOCK Iosb;
TDI_CONNECTION_INFORMATION ConnInfo;
UCHAR AddrBuf[sizeof(TRANSPORT_ADDRESS) +
sizeof(TDI_ADDRESS_IRDA)];
PTRANSPORT_ADDRESS pTranAddr = (PTRANSPORT_ADDRESS) AddrBuf;
PTDI_ADDRESS_IRDA pIrdaAddr = (PTDI_ADDRESS_IRDA) pTranAddr->Address[0].Address;
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
*pConnectContext = NULL;
if ((Status = IrdaOpenEndpoint(NULL, NULL, (PVOID *) &pEndp)) != STATUS_SUCCESS)
{
return Status;
}
if (IrCommMode)
{
SetIrCommMode(pEndp);
}
pConn = (PIRCONN) pEndp->ConnList.Flink;
pConn->State = CONN_ST_OPEN;
REFADD(&pConn->RefCnt, 'NEPO');
pConn->ClConnContext = NULL;
*pConnectContext = NULL;
AllocRecvData(pConn);
pIrp = TdiBuildInternalDeviceControlIrp(
TDI_CONNECT,
pConn->pDeviceObject,
pConn->pFileObject,
&Event,
&Iosb);
if (pIrp == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
pTranAddr->TAAddressCount = 1;
RtlCopyMemory(pIrdaAddr, pConnIrdaAddr, sizeof(TDI_ADDRESS_IRDA));
ConnInfo.UserDataLength = 0;
ConnInfo.UserData = NULL;
ConnInfo.OptionsLength = 0;
ConnInfo.Options = NULL;
ConnInfo.RemoteAddressLength = sizeof(AddrBuf);
ConnInfo.RemoteAddress = pTranAddr;
TdiBuildConnect(
pIrp,
pConn->pDeviceObject,
pConn->pFileObject,
NULL, // CompRoutine
NULL, // Context
NULL, // Timeout
&ConnInfo,
NULL); // ReturnConnectionInfo
Status = IoCallDriver(pConn->pDeviceObject, pIrp);
//
// If necessary, wait for the I/O to complete.
//
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject((PVOID)&Event, UserRequest, KernelMode,
FALSE, NULL);
}
//
// If the request was successfully queued, get the final I/O status.
//
if (NT_SUCCESS(Status))
{
Status = Iosb.Status;
}
if (Status == STATUS_SUCCESS)
{
DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: IrdaOpenConnection pConn:%X\n",
*pConnectContext));
pConn->ClConnContext = ClConnContext;
*pConnectContext = pConn;
}
else
{
DEBUGMSG(DBG_ERROR, ("IRTDI: TDI_CONNECT failed %X\n", Status));
pConn->State = CONN_ST_CLOSED;
REFDEL(&pConn->RefCnt, 'NEPO');
REFDEL(&pConn->RefCnt, ' TS1');
}
return Status;
}
VOID
IrdaCloseConnection(
PVOID ConnectContext)
{
PIRCONN pConn = (PIRCONN) ConnectContext;
GOODCONN(pConn);
LOCKIT();
if (pConn->State == CONN_ST_OPEN)
{
// IrdaCloseConnInternal will release the lock
IrdaCloseConnInternal(pConn);
}
else
{
DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: IrdaCloseConnection pConn:%X, not open\n",
pConn));
UNLOCKIT();
}
REFDEL(&pConn->RefCnt, 'NEPO');
}
VOID
IrdaSend(
PVOID ConnectionContext,
PMDL pMdl,
PVOID SendContext)
{
PIRCONN pConn = (PIRCONN) ConnectionContext;
PIRP pIrp;
ULONG SendLength = 0;
PMDL pMdl2 = pMdl;
NTSTATUS Status;
GOODCONN(pConn);
if (pConn->State != CONN_ST_OPEN)
{
Status = STATUS_ADDRESS_CLOSED;
}
else if ((pIrp = IoAllocateIrp((CCHAR)(pConn->pDeviceObject->StackSize),
FALSE)) == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
}
else
{
LOCKIT();
REFADD(&pConn->RefCnt, 'DNES');
UNLOCKIT();
pIrp->MdlAddress = pMdl;
pIrp->Flags = 0;
pIrp->RequestorMode = KernelMode;
pIrp->PendingReturned = FALSE;
pIrp->UserIosb = NULL;
pIrp->UserEvent = NULL;
pIrp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
pIrp->AssociatedIrp.SystemBuffer = NULL;
pIrp->UserBuffer = NULL;
pIrp->Tail.Overlay.Thread = PsGetCurrentThread();
pIrp->Tail.Overlay.OriginalFileObject = pConn->pFileObject;
pIrp->Tail.Overlay.AuxiliaryBuffer = (PCHAR) pConn;
while (pMdl2 != NULL)
{
SendLength += MmGetMdlByteCount(pMdl2);
pMdl2 = pMdl2->Next;
}
TdiBuildSend(
pIrp,
pConn->pDeviceObject,
pConn->pFileObject,
IrdaCompleteSendIrp,
SendContext,
pMdl,
0, // send flags
SendLength);
IoCallDriver(pConn->pDeviceObject, pIrp);
return;
}
IrdaSendComplete(pConn->ClConnContext, SendContext, Status);
}
VOID
IrdaReceiveComplete(
PVOID ConnectionContext,
PIRDA_RECVBUF pRecvBuf)
{
PIRCONN pConn = ConnectionContext;
GOODCONN(pConn);
LOCKIT();
InsertTailList(&pConn->RecvBufFreeList, &pRecvBuf->Linkage);
// Were there any previous receive indications from the
// stack that we couldn't take because RecvBufFreeList was
// empty?
if (!IsListEmpty(&pConn->RecvIndList) && pConn->State == CONN_ST_OPEN)
{
REFADD(&pConn->RefCnt, '3VCR');
if (CTEScheduleEvent(&RestartRecvEvent, pConn) == FALSE)
{
REFDEL(&pConn->RefCnt, '3VCR');
ASSERT(0);
}
}
UNLOCKIT();
REFDEL(&pConn->RefCnt, '2VCR');
}
//------------------------------------------------------------------
// callback handlers reqistered with irda.sys
//
NTSTATUS
IrdaDisconnectEventHandler(
IN PVOID TdiEventContext,
IN CONNECTION_CONTEXT ConnectionContext,
IN int DisconnectDataLength,
IN PVOID DisconnectData,
IN int DisconnectInformationLength,
IN PVOID DisconnectInformation,
IN ULONG DisconnectFlags
)
{
PIRCONN pConn = (PIRCONN) ConnectionContext;
GOODCONN(pConn);
LOCKIT();
if (pConn->State != CONN_ST_OPEN)
{
UNLOCKIT();
DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: DisconnectEvent, pConn:%X not open\n",
pConn));
return STATUS_SUCCESS;
}
pConn->State = CONN_ST_CLOSED;
UNLOCKIT();
DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: DisconnectEvent for pConn:%X\n",
pConn));
IrdaConnectionClosed(pConn->ClConnContext);
REFDEL(&pConn->RefCnt, ' TS1');
return STATUS_SUCCESS;
}
NTSTATUS
IrdaReceiveEventHandler (
IN PVOID TdiEventContext,
IN CONNECTION_CONTEXT ConnectionContext,
IN ULONG ReceiveFlags,
IN ULONG BytesIndicated,
IN ULONG BytesAvailable,
OUT ULONG *BytesTaken,
IN PVOID Tsdu,
OUT PIRP *IoRequestPacket
)
{
PIRCONN pConn = (PIRCONN) ConnectionContext;
PRECEIVEIND pRecvInd;
ULONG FinalSeg = ReceiveFlags & TDI_RECEIVE_ENTIRE_MESSAGE;
NTSTATUS Status;
PIRDA_RECVBUF pCompleteBuf = NULL;
BOOLEAN LastBuf = FALSE;
GOODCONN(pConn);
ASSERT(BytesIndicated <= IRDA_MAX_DATA_SIZE);
ASSERT(BytesIndicated == BytesAvailable);
LOCKIT();
if (pConn->pAssemBuf == NULL) // Currently not reassembling a message
{
// Assemble receive indication into pAssemBuf
pConn->pAssemBuf = (PIRDA_RECVBUF) RemoveHeadList(&pConn->RecvBufFreeList);
if (pConn->pAssemBuf == (PIRDA_RECVBUF) &pConn->RecvBufFreeList) // empty list?
{
// We don't have any receive buffers so Irda will have to buffer
// the data until we get a receive buffer.
pConn->pAssemBuf = NULL;
*BytesTaken = 0;
}
else
{
// start assembing into the beginning of the buffer
pConn->pAssemBuf->BufLen = 0;
if (IsListEmpty(&pConn->RecvBufFreeList))
{
LastBuf = TRUE;
}
}
}
if (pConn->pAssemBuf)
{
ASSERT(BytesIndicated + pConn->pAssemBuf->BufLen <= IRDA_MAX_DATA_SIZE);
RtlCopyMemory(pConn->pAssemBuf->Buf + pConn->pAssemBuf->BufLen,
Tsdu, BytesIndicated);
pConn->pAssemBuf->BufLen += BytesIndicated;
*BytesTaken = BytesIndicated;
}
if (*BytesTaken == 0)
{
PRECEIVEIND pRecvInd = (PRECEIVEIND) RemoveHeadList(&pConn->RecvIndFreeList);
ASSERT(pRecvInd);
DbgPrint("flowed, buf %d\n", BytesIndicated);
// When IrDA has indicated data that we can't take, we store
// the # bytes, whether its the last segment, and the connection
// in a RECEIVEIND entry. Later we can use the info to retrieve
// the buffered data when we are ready for more.
if (pRecvInd)
{
pRecvInd->BytesIndicated = BytesIndicated;
pRecvInd->FinalSeg = ReceiveFlags & TDI_RECEIVE_ENTIRE_MESSAGE;
pRecvInd->pConn = pConn;
InsertTailList(&pConn->RecvIndList, &pRecvInd->Linkage);
}
else
{
// This should never happen. We have a TTP credits worth of
// RECEIVEIND entries so the peer should stop sending before
// we run out
ASSERT(0); // tear down
}
Status = STATUS_DATA_NOT_ACCEPTED;
}
else
{
if (FinalSeg)
{
// Done assembling the packet. Indicate it up on a worker
// thread.
pCompleteBuf = pConn->pAssemBuf;
pConn->pAssemBuf = NULL;
REFADD(&pConn->RefCnt, '2VCR');
/* OLD
InsertTailList(&pConn->RecvBufList,
&pConn->pAssemBuf->Linkage);
pConn->pAssemBuf = NULL;
REFADD(&pConn->RefCnt, '1VCR');
if (CTEScheduleEvent(&DataReadyEvent, pConn) == FALSE)
{
REFDEL(&pConn->RefCnt, '1VCR');
ASSERT(0);
}
*/
}
Status = STATUS_SUCCESS;
}
UNLOCKIT();
if (pCompleteBuf)
{
IrdaReceiveIndication(pConn->ClConnContext, pCompleteBuf, LastBuf);
}
return Status;
}
NTSTATUS
IrdaConnectEventHandler (
IN PVOID TdiEventContext,
IN int RemoteAddressLength,
IN PVOID RemoteAddress,
IN int UserDataLength,
IN PVOID UserData,
IN int OptionsLength,
IN PVOID Options,
OUT CONNECTION_CONTEXT *ConnectionContext,
OUT PIRP *AcceptIrp
)
{
PIRENDPOINT pEndp = TdiEventContext;
PIRCONN pConn = NULL;
PIRP pIrp;
GOODENDP(pEndp);
//
// Find an idle connection
//
LOCKIT();
for (pConn = (PIRCONN) pEndp->ConnList.Flink;
pConn != (PIRCONN) &pEndp->ConnList;
pConn = (PIRCONN) pConn->Linkage.Flink)
{
if (pConn->State == CONN_ST_CREATED)
break;
}
if (pConn == NULL || pConn == (PIRCONN) &pEndp->ConnList)
{
// no available connection
UNLOCKIT();
DEBUGMSG(DBG_ERROR, ("IRTDI: ConnectEvent refused\n"));
return STATUS_CONNECTION_REFUSED;
}
REFADD(&pConn->RefCnt, 'NEPO');
pConn->State = CONN_ST_OPEN;
UNLOCKIT();
pIrp = IoAllocateIrp((CCHAR)(pConn->pDeviceObject->StackSize), FALSE);
if ( pIrp == NULL )
{
pConn->State = CONN_ST_CREATED;
REFDEL(&pConn->RefCnt, 'NEPO');
return STATUS_INSUFFICIENT_RESOURCES;
}
AllocRecvData(pConn);
DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: ConnectEvent, pConn:%X open\n",
pConn));
// Jeez, irps are ugly spuds..
pIrp->MdlAddress = NULL;
pIrp->Flags = 0;
pIrp->RequestorMode = KernelMode;
pIrp->PendingReturned = FALSE;
pIrp->UserIosb = NULL;
pIrp->UserEvent = NULL;
pIrp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
pIrp->AssociatedIrp.SystemBuffer = NULL;
pIrp->UserBuffer = NULL;
pIrp->Tail.Overlay.Thread = PsGetCurrentThread();
pIrp->Tail.Overlay.OriginalFileObject = pConn->pFileObject;
pIrp->Tail.Overlay.AuxiliaryBuffer = NULL;
TdiBuildAccept(
pIrp,
pConn->pDeviceObject,
pConn->pFileObject,
IrdaCompleteAcceptIrp,
pConn,
NULL, // request connection information
NULL // return connection information
);
IoSetNextIrpStackLocation(pIrp);
//
// Set the return IRP so the transport processes this accept IRP.
//
*AcceptIrp = pIrp;
//
// Set up the connection context as a pointer to the connection block
// we're going to use for this connect request. This allows the
// TDI provider to which connection object to use.
//
*ConnectionContext = (CONNECTION_CONTEXT) pConn;
REFADD(&pConn->RefCnt, 'TPCA');
return STATUS_MORE_PROCESSING_REQUIRED;
}
//------------------------------------------------------------------
// irp completion routines
//
NTSTATUS
IrdaCompleteAcceptIrp (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PIRCONN pConn = Context;
PIRENDPOINT pEndp;
GOODCONN(pConn);
pEndp = pConn->pEndp;
GOODENDP(pEndp);
if (!NT_SUCCESS(Irp->IoStatus.Status))
{
LOCKIT();
pConn->State = CONN_ST_CREATED;
UNLOCKIT();
REFDEL(&pConn->RefCnt, 'NEPO');
}
else
{
if (IrdaIncomingConnection(pEndp->ClEndpContext, pConn,
&pConn->ClConnContext) != STATUS_SUCCESS)
{
DEBUGMSG(DBG_CONNECT, ("IRTDI: IrdaIncomingConnection failed in accept for pConn:%X\n",
pConn));
IrdaCloseConnection(pConn);
}
// Create new connection object. We're at DPC so this
// must be done on a worker thread.
REFADD(&pEndp->RefCnt, 'NNOC');
if (CTEScheduleEvent(&CreateConnEvent, pEndp) == FALSE)
{
REFDEL(&pEndp->RefCnt, 'NNOC');
ASSERT(0);
}
}
//
// Free the IRP now since it is no longer needed.
//
IoFreeIrp(Irp);
//
// Return STATUS_MORE_PROCESSING_REQUIRED so that IoCompleteRequest
// will stop working on the IRP.
// mbert: What?
REFDEL(&pConn->RefCnt, 'TPCA');
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
IrdaCompleteDisconnectIrp (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context)
{
PIRCONN pConn = Context;
GOODCONN(pConn);
IoFreeIrp(Irp);
DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: DisconnectIrp complete for pConn:%X\n",
pConn));
REFDEL(&pConn->RefCnt, ' TS1');
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
IrdaCompleteSendIrp (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context)
{
PIRCONN pConn = (PIRCONN) Irp->Tail.Overlay.AuxiliaryBuffer;
GOODCONN(pConn);
IrdaSendComplete(pConn->ClConnContext, Context, STATUS_SUCCESS);
IoFreeIrp(Irp);
REFDEL(&pConn->RefCnt, 'DNES');
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
IrdaCompleteReceiveIrp (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context)
{
PRECEIVEIND pRecvInd = (PRECEIVEIND) Context;
PIRCONN pConn = pRecvInd->pConn;
PIRDA_RECVBUF pCompleteBuf = NULL;
GOODCONN(pConn);
ASSERT(Irp->IoStatus.Information == pRecvInd->BytesIndicated);
LOCKIT();
if (pRecvInd->FinalSeg)
{
pCompleteBuf = pConn->pAssemBuf;
pConn->pAssemBuf = NULL;
REFADD(&pConn->RefCnt, '2VCR');
/*
InsertTailList(&pConn->RecvBufList,
&pConn->pAssemBuf->Linkage);
pConn->pAssemBuf = NULL;
REFADD(&pConn->RefCnt, '1VCR');
if (CTEScheduleEvent(&DataReadyEvent, pConn) == FALSE)
{
REFDEL(&pConn->RefCnt, '1VCR');
ASSERT(0);
}
*/
}
IoFreeMdl(pRecvInd->pMdl);
InsertTailList(&pConn->RecvIndFreeList, &pRecvInd->Linkage);
if (!IsListEmpty(&pConn->RecvIndList) && pConn->State == CONN_ST_OPEN)
{
REFADD(&pConn->RefCnt, '3VCR');
if (CTEScheduleEvent(&RestartRecvEvent, pConn) == FALSE)
{
REFDEL(&pConn->RefCnt, '3VCR');
ASSERT(0);
}
}
UNLOCKIT();
if (pCompleteBuf)
{
IrdaReceiveIndication(pConn->ClConnContext, pCompleteBuf, TRUE);
}
IoFreeIrp(Irp);
REFDEL(&pConn->RefCnt, '4VCR');
return STATUS_MORE_PROCESSING_REQUIRED;
}
//------------------------------------------------------------------
//
// THIS FUNCTION IS CALLED WITH THE LOCK HELD AND RELEASES
// THE LOCK BEFORE RETURNING.
VOID
IrdaCloseConnInternal(
PVOID ConnectContext)
{
PIRCONN pConn = (PIRCONN) ConnectContext;
PIRP pIrp;
GOODCONN(pConn);
switch (pConn->State)
{
case CONN_ST_CREATED:
DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: IrdaCloseConnInternal, pConn:%X created\n",
pConn));
UNLOCKIT();
REFDEL(&pConn->RefCnt, ' TS1');
break;
case CONN_ST_CLOSED:
DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: IrdaCloseConnInternal, pConn:%X closed\n",
pConn));
UNLOCKIT();
break;
case CONN_ST_OPEN:
pConn->State = CONN_ST_CLOSED;
UNLOCKIT();
DEBUGMSG(DBG_LIB_CONNECT, ("IRTDI: build disconnect irp for pConn:%X\n",
pConn));
//
// Build a disconnect Irp to pass to the TDI provider.
//
pIrp = IoAllocateIrp((CCHAR)(pConn->pDeviceObject->StackSize), FALSE);
if (pIrp == NULL )
{
ASSERT(0);
return;
}
//
// Initialize the IRP. Love them irps.
//
pIrp->MdlAddress = NULL;
pIrp->Flags = 0;
pIrp->RequestorMode = KernelMode;
pIrp->PendingReturned = FALSE;
pIrp->UserIosb = NULL;
pIrp->UserEvent = NULL;
pIrp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
pIrp->AssociatedIrp.SystemBuffer = NULL;
pIrp->UserBuffer = NULL;
pIrp->Tail.Overlay.Thread = PsGetCurrentThread();
pIrp->Tail.Overlay.OriginalFileObject = pConn->pFileObject;
pIrp->Tail.Overlay.AuxiliaryBuffer = NULL;
TdiBuildDisconnect(
pIrp,
pConn->pDeviceObject,
pConn->pFileObject,
IrdaCompleteDisconnectIrp,
pConn,
NULL,
TDI_DISCONNECT_RELEASE,
NULL,
NULL);
if (IoCallDriver(pConn->pDeviceObject, pIrp) != STATUS_SUCCESS)
{
ASSERT(0);
}
break;
default:
DEBUGMSG(DBG_ERROR, ("IRTDI: bad conn state %d\n", pConn->State));
UNLOCKIT();
}
}
NTSTATUS
IrdaDisassociateAddress(
PIRCONN pConn)
{
NTSTATUS Status;
IO_STATUS_BLOCK Iosb;
PIRP pIrp;
KEVENT Event;
KeAttachProcess(IrclSystemProcess);
KeInitializeEvent( &Event, SynchronizationEvent, FALSE );
pIrp = TdiBuildInternalDeviceControlIrp(
TDI_DISASSOCIATE_ADDRESS,
pConn->pDeviceObject,
pConn->pFileObject,
&Event,
&Iosb);
if (pIrp == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
TdiBuildDisassociateAddress(
pIrp,
pConn->pDeviceObject,
pConn->pFileObject,
NULL,
NULL);
Status = IoCallDriver(pConn->pDeviceObject, pIrp);
if (Status == STATUS_PENDING)
{
Status = KeWaitForSingleObject((PVOID) &Event, Executive, KernelMode, FALSE, NULL);
ASSERT(Status == STATUS_SUCCESS);
}
else
{
ASSERT(NT_ERROR(Status) || KeReadStateEvent(&Event));
}
if (NT_SUCCESS(Status))
{
Status = Iosb.Status;
}
KeDetachProcess();
return Status;
}
NTSTATUS
IrdaCreateAddress(
IN PTDI_ADDRESS_IRDA pRequestedIrdaAddr,
OUT PHANDLE pAddrHandle)
{
NTSTATUS Status;
UNICODE_STRING DeviceName;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK Iosb;
UCHAR EaBuf[sizeof(FILE_FULL_EA_INFORMATION)-1 +
TDI_TRANSPORT_ADDRESS_LENGTH+1 +
sizeof(TRANSPORT_ADDRESS) +
sizeof(TDI_ADDRESS_IRDA)];
PFILE_FULL_EA_INFORMATION pEa = (PFILE_FULL_EA_INFORMATION) EaBuf;
ULONG EaBufLen = sizeof(EaBuf);
PTRANSPORT_ADDRESS pTranAddr = (PTRANSPORT_ADDRESS)
&(pEa->EaName[TDI_TRANSPORT_ADDRESS_LENGTH + 1]);
PTDI_ADDRESS_IRDA pIrdaAddr = (PTDI_ADDRESS_IRDA)
pTranAddr->Address[0].Address;
TRANSPORT_ADDRESS TempTransportAddress;
pEa->NextEntryOffset = 0;
pEa->Flags = 0;
pEa->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
RtlCopyMemory(pEa->EaName,
TdiTransportAddress,
pEa->EaNameLength + 1);
pEa->EaValueLength = sizeof(TRANSPORT_ADDRESS) + sizeof(TDI_ADDRESS_IRDA);
//
// fill these in so we can do this in an aligned manner
//
TempTransportAddress.TAAddressCount = 1;
TempTransportAddress.Address[0].AddressLength = sizeof(TDI_ADDRESS_IRDA);
TempTransportAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_IRDA;
RtlCopyMemory(pTranAddr,&TempTransportAddress,sizeof(TempTransportAddress));
RtlCopyMemory(pIrdaAddr,
pRequestedIrdaAddr,
sizeof(TDI_ADDRESS_IRDA));
RtlInitUnicodeString(&DeviceName, IRDA_DEVICE_NAME);
InitializeObjectAttributes(&ObjectAttributes, &DeviceName,
OBJ_CASE_INSENSITIVE, NULL, NULL);
KeAttachProcess(IrclSystemProcess);
Status = ZwCreateFile(pAddrHandle,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
&ObjectAttributes,
&Iosb, // returned status information.
0, // block size (unused).
0, // file attributes.
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_CREATE, // create disposition.
0, // create options.
pEa,
EaBufLen);
KeDetachProcess();
return Status;
}
NTSTATUS
IrdaCreateConnection(
OUT PHANDLE pConnHandle,
IN PVOID ClientContext)
{
NTSTATUS Status;
UNICODE_STRING DeviceName;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK Iosb;
UCHAR EaBuf[sizeof(FILE_FULL_EA_INFORMATION)-1 +
TDI_CONNECTION_CONTEXT_LENGTH + 1 +
sizeof(CONNECTION_CONTEXT)];
PFILE_FULL_EA_INFORMATION pEa = (PFILE_FULL_EA_INFORMATION) EaBuf;
ULONG EaBufLen = sizeof(EaBuf);
CONNECTION_CONTEXT UNALIGNED *ctx;
pEa->NextEntryOffset = 0;
pEa->Flags = 0;
pEa->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
pEa->EaValueLength = sizeof(CONNECTION_CONTEXT);
RtlMoveMemory(pEa->EaName, TdiConnectionContext, pEa->EaNameLength + 1);
ctx = (CONNECTION_CONTEXT UNALIGNED *)&pEa->EaName[pEa->EaNameLength + 1];
*ctx = (CONNECTION_CONTEXT) ClientContext;
RtlInitUnicodeString(&DeviceName, IRDA_DEVICE_NAME);
InitializeObjectAttributes(&ObjectAttributes, &DeviceName,
OBJ_CASE_INSENSITIVE, NULL, NULL);
KeAttachProcess(IrclSystemProcess);
ASSERT((PKPROCESS)IoGetCurrentProcess() == IrclSystemProcess);
Status = ZwCreateFile(pConnHandle,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
&ObjectAttributes,
&Iosb, // returned status information.
0, // block size (unused).
0, // file attributes.
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_CREATE, // create disposition.
0, // create options.
pEa,
EaBufLen);
KeDetachProcess();
return Status;
}
NTSTATUS
IrdaAssociateAddress(
PIRCONN pConn,
HANDLE AddressHandle)
{
PIRP pIrp;
KEVENT Event;
IO_STATUS_BLOCK Iosb;
NTSTATUS Status;
KeAttachProcess(IrclSystemProcess);
KeInitializeEvent( &Event, SynchronizationEvent, FALSE );
pIrp = TdiBuildInternalDeviceControlIrp(
TDI_ASSOCIATE_ADDRESS,
pConn->pDeviceObject,
pConn->pFileObject,
&Event,
&Iosb);
if (pIrp == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
TdiBuildAssociateAddress(
pIrp,
pConn->pDeviceObject,
pConn->pFileObject,
NULL,
NULL,
AddressHandle);
Status = IoCallDriver(pConn->pDeviceObject, pIrp);
if (Status == STATUS_PENDING)
{
Status = KeWaitForSingleObject((PVOID) &Event, Executive, KernelMode, FALSE, NULL);
ASSERT(Status == STATUS_SUCCESS);
}
else
{
ASSERT(NT_ERROR(Status) || KeReadStateEvent(&Event));
}
if (NT_SUCCESS(Status))
{
Status = Iosb.Status;
}
KeDetachProcess();
return Status;
}
VOID
IrdaCreateConnCallback(
struct CTEEvent *Event,
PVOID Arg)
{
PIRENDPOINT pEndp = Arg;
PIRCONN pConn;
NTSTATUS Status;
BOOLEAN Detach = FALSE;
GOODENDP(pEndp);
/*
// Open handles in the context of our driver
if ((PKPROCESS)IoGetCurrentProcess() != IrclSystemProcess)
{
Detach = TRUE;
KeAttachProcess(IrclSystemProcess);
}
*/
IRDA_ALLOC_MEM(pConn, sizeof(IRCONN), MT_TDICL_CONN);
if (pConn == NULL)
{
goto error1;
}
CTEMemSet(pConn, 0, sizeof(IRCONN));
pConn->State = CONN_ST_CREATED;
pConn->Sig = CONNSIG;
InitializeListHead(&pConn->RecvBufFreeList);
InitializeListHead(&pConn->RecvIndList);
InitializeListHead(&pConn->RecvIndFreeList);
CTEInitEvent(&pConn->DeleteConnEvent, DeleteConnCallback);
ReferenceInit(&pConn->RefCnt, pConn, IrdaDeleteConnection);
REFADD(&pConn->RefCnt, ' TS1');
Status = IrdaCreateConnection(&pConn->ConnHandle, pConn);
DEBUGMSG(DBG_LIB_OBJ, ("IRTDI: CreateConnection conn:%X, status %X\n",
pConn, Status));
if (Status != STATUS_SUCCESS)
{
goto error2;
}
KeAttachProcess(IrclSystemProcess);
Status = ObReferenceObjectByHandle(
pConn->ConnHandle,
0L, // DesiredAccess
NULL,
KernelMode,
(PVOID *)&pConn->pFileObject,
NULL);
KeDetachProcess();
if (Status != STATUS_SUCCESS)
{
goto error2;
}
pConn->pDeviceObject = IoGetRelatedDeviceObject(pConn->pFileObject);
Status = IrdaAssociateAddress(pConn, pEndp->AddrHandle);
if (Status == STATUS_SUCCESS)
{
pConn->pEndp = pEndp;
LOCKIT();
InsertTailList(&pEndp->ConnList, &pConn->Linkage);
UNLOCKIT();
goto done;
}
error2:
REFDEL(&pConn->RefCnt, ' TS1');
error1:
REFDEL(&pEndp->RefCnt, 'NNOC');
done:
/*
if (Detach)
KeDetachProcess();
*/
return;
}
/*
VOID
IrdaDataReadyCallback(
struct CTEEvent *Event,
PVOID Arg)
{
PIRCONN pConn = Arg;
PIRDA_RECVBUF pRecvBuf;
GOODCONN(pConn);
LOCKIT();
if (pConn->State == CONN_ST_OPEN)
{
while (!IsListEmpty(&pConn->RecvBufList))
{
pRecvBuf = (PIRDA_RECVBUF) RemoveHeadList(&pConn->RecvBufList);
UNLOCKIT();
REFADD(&pConn->RefCnt, '2VCR');
IrdaReceiveIndication(pConn->ClConnContext, pRecvBuf);
LOCKIT();
}
}
UNLOCKIT();
REFDEL(&pConn->RefCnt, '1VCR');
}
*/
VOID
IrdaRestartRecvCallback(
struct CTEEvent *Event,
PVOID Arg)
{
PIRCONN pConn = Arg;
PRECEIVEIND pRecvInd;
PIRP pIrp;
NTSTATUS Status;
GOODCONN(pConn);
LOCKIT();
pRecvInd = (PRECEIVEIND) RemoveHeadList(&pConn->RecvIndList);
if (pRecvInd == (PRECEIVEIND) &pConn->RecvIndList)
{
// empty list
goto done;
}
if (pConn->pAssemBuf == NULL)
{
pConn->pAssemBuf = (PIRDA_RECVBUF) RemoveHeadList(&pConn->RecvBufFreeList);
if (pConn->pAssemBuf == (PIRDA_RECVBUF) &pConn->RecvBufFreeList)
{
InsertHeadList(&pConn->RecvIndList, &pRecvInd->Linkage);
pRecvInd = NULL;
goto error;
}
ASSERT(pConn->pAssemBuf != (PIRDA_RECVBUF) &pConn->RecvBufFreeList);
pConn->pAssemBuf->BufLen = 0;
}
ASSERT(pRecvInd->BytesIndicated + pConn->pAssemBuf->BufLen <= IRDA_MAX_DATA_SIZE);
pRecvInd->pMdl = IoAllocateMdl(
pConn->pAssemBuf->Buf + pConn->pAssemBuf->BufLen,
pRecvInd->BytesIndicated,
FALSE, FALSE, NULL);
if (pRecvInd->pMdl == NULL)
{
goto error;
}
pConn->pAssemBuf->BufLen += pRecvInd->BytesIndicated;
MmBuildMdlForNonPagedPool(pRecvInd->pMdl);
pIrp = IoAllocateIrp((CCHAR)(pConn->pDeviceObject->StackSize), FALSE);
if (pIrp)
{
pIrp->Flags = 0;
pIrp->RequestorMode = KernelMode;
pIrp->PendingReturned = FALSE;
pIrp->UserIosb = NULL;
pIrp->UserEvent = NULL;
pIrp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
pIrp->AssociatedIrp.SystemBuffer = NULL;
pIrp->UserBuffer = NULL;
pIrp->Tail.Overlay.Thread = PsGetCurrentThread();
pIrp->Tail.Overlay.OriginalFileObject = pConn->pFileObject;
pIrp->Tail.Overlay.AuxiliaryBuffer = NULL;
TdiBuildReceive(
pIrp,
pConn->pDeviceObject,
pConn->pFileObject,
IrdaCompleteReceiveIrp,
pRecvInd,
pRecvInd->pMdl,
pRecvInd->FinalSeg,
pRecvInd->BytesIndicated);
REFADD(&pConn->RefCnt, '4VCR');
UNLOCKIT();
Status = IoCallDriver(pConn->pDeviceObject, pIrp);
ASSERT(Status == STATUS_SUCCESS);
if (Status != STATUS_SUCCESS)
{
REFDEL(&pConn->RefCnt, '4VCR');
}
REFDEL(&pConn->RefCnt, '3VCR');
return;
}
error:
if (pRecvInd)
{
InsertHeadList(&pConn->RecvIndFreeList, &pRecvInd->Linkage);
}
ASSERT(0); // tear down
done:
UNLOCKIT();
REFDEL(&pConn->RefCnt, '3VCR');
}
VOID
AllocRecvData(
PIRCONN pConn)
{
PIRDA_RECVBUF pRecvBuf;
PRECEIVEIND pRecvInd;
ULONG i;
ASSERT(IsListEmpty(&pConn->RecvBufFreeList));
for (i = 0; i < IRTDI_RECV_BUF_CNT; i++)
{
IRDA_ALLOC_MEM(pRecvBuf, sizeof(IRDA_RECVBUF), MT_TDICL_RXBUF);
if (!pRecvBuf)
break;
LOCKIT();
InsertTailList(&pConn->RecvBufFreeList, &pRecvBuf->Linkage);
UNLOCKIT();
}
for (i = 0; i < TTP_RECV_CREDITS; i++)
{
IRDA_ALLOC_MEM(pRecvInd, sizeof(RECEIVEIND), MT_TDICL_RXIND);
if (!pRecvInd)
break;
LOCKIT();
InsertTailList(&pConn->RecvIndFreeList, &pRecvInd->Linkage);
UNLOCKIT();
}
}
ULONG
IrdaGetConnectionSpeed(
PVOID ConnectionContext)
{
NTSTATUS Status;
IO_STATUS_BLOCK Iosb;
HANDLE ControlHandle;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING DeviceName;
IRLINK_STATUS LinkStatus;
CTEMemSet(&LinkStatus, 0, sizeof(LinkStatus));
RtlInitUnicodeString(&DeviceName, IRDA_DEVICE_NAME);
InitializeObjectAttributes(&ObjectAttributes, &DeviceName,
OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = ZwCreateFile(
&ControlHandle,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
&ObjectAttributes,
&Iosb, // returned status information.
0, // block size (unused).
0, // file attributes.
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_CREATE, // create disposition.
0, // create options.
NULL,
0
);
Status = ZwDeviceIoControlFile(
ControlHandle,
NULL, // EventHandle
NULL, // APC Routine
NULL, // APC Context
&Iosb,
IOCTL_IRDA_LINK_STATUS_NB,
NULL,
0,
&LinkStatus, // OutputBuffer
sizeof(LinkStatus) // OutputBufferLength
);
if (Status != STATUS_SUCCESS)
{
DEBUGMSG(DBG_ERROR, ("IRTDI: Ioctl LINK_STATUS failed %X\n", Status));
}
ZwClose(ControlHandle);
return LinkStatus.ConnectSpeed;
}
VOID
IrdaDeleteConnection(PIRCONN pConn)
{
CTEScheduleEvent(&pConn->DeleteConnEvent, pConn);
}
VOID
DeleteConnCallback(
struct CTEEvent *Event,
PVOID Arg)
{
PIRCONN pConn = Arg;
PIRENDPOINT pEndp;
PIRDA_RECVBUF pRecvBuf;
PRECEIVEIND pRecvInd;
BOOLEAN Detach = FALSE;
GOODCONN(pConn);
pConn->Sig = 0xDAED0CCC;
DEBUGMSG(DBG_LIB_OBJ, ("IRTDI: DeleteConnection conn:%X\n", pConn));
pEndp = pConn->pEndp;
#if DBG
if (pEndp)
GOODENDP(pEndp);
#endif
/*
if ((PKPROCESS)IoGetCurrentProcess() != IrclSystemProcess)
{
Detach = TRUE;
KeAttachProcess(IrclSystemProcess);
}
*/
LOCKIT();
while (!IsListEmpty(&pConn->RecvBufFreeList))
{
pRecvBuf = (PIRDA_RECVBUF) RemoveHeadList(&pConn->RecvBufFreeList);
IRDA_FREE_MEM(pRecvBuf);
}
/*
while (!IsListEmpty(&pConn->RecvBufList))
{
pRecvBuf = (PIRDA_RECVBUF) RemoveHeadList(&pConn->RecvBufList);
IRDA_FREE_MEM(pRecvBuf);
}
*/
if (pConn->pAssemBuf)
{
IRDA_FREE_MEM(pConn->pAssemBuf);
pConn->pAssemBuf = NULL;
}
while (!IsListEmpty(&pConn->RecvIndFreeList))
{
pRecvInd = (PRECEIVEIND) RemoveHeadList(&pConn->RecvIndFreeList);
IRDA_FREE_MEM(pRecvInd);
}
while (!IsListEmpty(&pConn->RecvIndList))
{
pRecvInd = (PRECEIVEIND) RemoveHeadList(&pConn->RecvIndList);
IRDA_FREE_MEM(pRecvInd);
}
// remove association from address object if it exists
if (pEndp)
{
RemoveEntryList(&pConn->Linkage);
UNLOCKIT();
// if it was a client endpoint, delete the endpoint
if (pEndp->Flags & EPF_CLIENT)
{
REFDEL(&pEndp->RefCnt, ' TS1');
}
IrdaDisassociateAddress(pConn);
REFDEL(&pEndp->RefCnt, 'NNOC');
}
else
{
UNLOCKIT();
}
if (pConn->ConnHandle)
{
ZwClose(pConn->ConnHandle);
}
if (pConn->pFileObject)
{
ObDereferenceObject(pConn->pFileObject);
}
if (pConn->ClConnContext)
{
// Free the reference in the client
IrdaCloseConnectionComplete(pConn->ClConnContext);
}
DEBUGMSG(DBG_LIB_OBJ, ("IRTDI: conn:%X deleted\n", pConn));
IRDA_FREE_MEM(pConn);
}
VOID
IrdaDeleteEndpoint(PIRENDPOINT pEndp)
{
CTEScheduleEvent(&pEndp->DeleteEndpEvent, pEndp);
}
VOID
DeleteEndpCallback(
struct CTEEvent *Event,
PVOID Arg)
{
PIRENDPOINT pEndp = Arg;
PVOID ClEndpContext;
BOOLEAN Detach = FALSE;
GOODENDP(pEndp);
pEndp->Sig = 0xDAED0EEE;
ClEndpContext = pEndp->Flags & EPF_COMPLETE_CLOSE ?
pEndp->ClEndpContext : NULL;
DEBUGMSG(DBG_LIB_OBJ, ("IRTDI: DeleteEndpoint ep:%X\n", pEndp));
LOCKIT();
/*
if ((PKPROCESS)IoGetCurrentProcess() != IrclSystemProcess)
{
Detach = TRUE;
KeAttachProcess(IrclSystemProcess);
}
*/
RemoveEntryList(&pEndp->Linkage);
UNLOCKIT();
if (pEndp->pFileObject)
ObDereferenceObject(pEndp->pFileObject);
ASSERT(IsListEmpty(&pEndp->ConnList));
if (pEndp->AddrHandle)
ZwClose(pEndp->AddrHandle);
DEBUGMSG(DBG_LIB_OBJ, ("IRTDI: ep:%X deleted \n", pEndp));
IRDA_FREE_MEM(pEndp);
if (ClEndpContext )
{
IrdaCloseEndpointComplete(ClEndpContext);
}
/*
if (Detach)
KeDetachProcess();
*/
}