Windows-Server-2003/net/irda/sys/irda.c

5191 lines
146 KiB
C

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
irda.c
Abstract:
TDI interface portion of irda.sys
Author:
mbert 9-97
--*/
#define UNICODE
#include <irda.h>
#include <tdi.h>
#include <tdikrnl.h>
#include <tdistat.h>
#include <tdiinfo.h>
#include <irioctl.h>
#include <irlap.h>
#include <irlmp.h>
#include <irdap.h>
#undef offsetof
#include "irda.tmh"
static LARGE_INTEGER Magic10000 = {0xe219652c, 0xd1b71758};
#if 0
#if DBG
int DbgSettings =
DBG_TDI |
// DBG_NDIS |
// DBG_TDI_IRP |
DBG_IRLMP |
// DBG_IRLMP_CONN |
// DBG_IRLMP_IAS |
// DBG_IRLMP_CRED |
// DBG_IRLAPLOG |
DBG_IRLAP |
// DBG_TXFRAME |
// DBG_RXFRAME |
// DBG_DISCOVERY |
DBG_ERROR |
DBG_WARN |
1;
int DbgOutput = /*DBG_OUTPUT_DEBUGGER |*/ DBG_OUTPUT_BUFFER;
#endif
#endif
PDRIVER_OBJECT pIrDADriverObject;
PDEVICE_OBJECT pIrDADeviceObject;
PVOID IrdaMsgPool;
PVOID RecvBufPool;
PIRDA_ADDR_OBJ AddrObjList;
LIST_ENTRY DscvIrpList;
LIST_ENTRY IasIrpList;
LIST_ENTRY ConnIrpList;
LIST_ENTRY StatusIrpList;
LIST_ENTRY IasAttribList;
CTEEvent PendingIasEvent;
IRLINK_STATUS LinkStatus;
BOOLEAN LinkStatusUpdated;
LONG ConnectionCount;
BOOLEAN ConnectionInterrupted;
CTELock IrdaLock;
char IasBuf[sizeof(IAS_QUERY) + IAS_MAX_OCTET_STRING];
IAS_QUERY *pvIasQuery = (IAS_QUERY *) IasBuf;
PIRP pIasIrp;
LIST_ENTRY LazyDscvIrpList;
IRDA_TIMER LazyDscvTimer;
BOOLEAN LazyDscvTimerRunning;
UINT LazyDscvInterval;
UINT LazyDscvMacAddrs;
UINT RandSeed;
int gNextLsapSel;
VOID (*CloseRasIrdaAddresses)();
NTSTATUS
DriverEntry(
PDRIVER_OBJECT pDriverObject,
PUNICODE_STRING pRegistryPath);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#endif
PIRP
GetIrpOnConnIrpList(PIRDA_CONN_OBJ pConn);
NTSTATUS
DriverEntry(
PDRIVER_OBJECT pDriverObject,
PUNICODE_STRING pRegistryPath)
{
NTSTATUS Status;
UNICODE_STRING DeviceName;
UNICODE_STRING ProtocolName;
int i;
LARGE_INTEGER li;
WPP_INIT_TRACING(pDriverObject,pRegistryPath);
#if 0
DbgMsgInit();
#endif
DEBUGMSG(DBG_TDI, ("IRDA: DriverEntry(), %ws.\n",
pRegistryPath->Buffer));
pIrDADriverObject = pDriverObject;
RtlInitUnicodeString(&DeviceName, IRDA_DEVICE_NAME);
RtlInitUnicodeString(&ProtocolName, IRDA_NAME);
Status = IoCreateDevice(
pDriverObject, // DriverObject
0, // DeviceExtensionSize
&DeviceName, // DeviceName
FILE_DEVICE_NETWORK, // DeviceType
FILE_DEVICE_SECURE_OPEN,// DeviceCharacteristics
FALSE, // Exclusive?
&pIrDADeviceObject); // DeviceObject pointer returned
if (! NT_SUCCESS(Status))
{
/* wmz
CTELogEvent(
pDriverObject,
EVENT_IRDA_CREATE_DEVICE_FAILED,
1,
1,
&DeviceName.Buffer,
0,
NULL);
*/
DEBUGMSG(DBG_ERROR, ("IRDA: IoCreateDevice() failed, 0x%1x.\n",
Status));
return Status;
}
// Initialize the driver object.
pDriverObject->DriverUnload = DriverUnload;
pDriverObject->FastIoDispatch = NULL;
for (i=0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
{
pDriverObject->MajorFunction[i] = IrDADispatch;
}
// Internal Device Controls are hot paths for kernel-mode clients.
pDriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
IrDADispatchInternalDeviceControl;
// Intialize the device objects.
pIrDADeviceObject->Flags |= DO_DIRECT_IO;
CTEInitLock(&IrdaLock);
CTEInitEvent(&PendingIasEvent, PendingIasRequestCallback);
InitializeListHead(&DscvIrpList);
InitializeListHead(&IasIrpList);
InitializeListHead(&ConnIrpList);
InitializeListHead(&LazyDscvIrpList);
InitializeListHead(&StatusIrpList);
InitializeListHead(&IasAttribList);
pIasIrp = NULL;
gNextLsapSel = IRDA_MIN_LSAP_SEL;
if ((IrdaMsgPool = CreateIrdaBufPool(IRDA_MSG_DATA_SIZE_INTERNAL,
MT_IMSG_POOL)) == NULL)
{
IoDeleteDevice(pIrDADeviceObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
if ((RecvBufPool = CreateIrdaBufPool(sizeof(IRDA_RECV_BUF),
MT_RXBUF_POOL)) == NULL)
{
DeleteIrdaBufPool(IrdaMsgPool);
IoDeleteDevice(pIrDADeviceObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
if ((Status = IrdaInitialize(&ProtocolName, pRegistryPath,
&LazyDscvInterval)) != STATUS_SUCCESS)
{
DEBUGMSG(DBG_ERROR, ("IRDA: IrdaInitialize() failed.\n"));
IoDeleteDevice(pIrDADeviceObject);
DeleteIrdaBufPool(IrdaMsgPool);
DeleteIrdaBufPool(RecvBufPool);
return Status;
}
if (LazyDscvInterval == 0)
LazyDscvInterval = DEFAULT_LAZY_DSCV_INTERVAL;
#if DBG
LazyDscvTimer.pName = "LazyDscv";
#endif
IrdaTimerInitialize(&LazyDscvTimer,
LazyDscvTimerExp,
LazyDscvInterval*1000,
NULL, NULL);
KeQuerySystemTime(&li);
RandSeed = li.LowPart;
return STATUS_SUCCESS;
}
VOID
DriverUnload(
PDRIVER_OBJECT pDriverObject)
{
DEBUGMSG(DBG_TDI, ("IRDA: DriverUnload\n"));
IrdaTimerStop(&LazyDscvTimer);
IrdaShutdown();
DeleteIrdaBufPool(IrdaMsgPool);
DeleteIrdaBufPool(RecvBufPool);
IoDeleteDevice(pIrDADeviceObject);
WPP_CLEANUP(pDriverObject);
}
NTSTATUS
IrDADispatch(
PDEVICE_OBJECT pDeviceObject,
PIRP pIrp)
{
NTSTATUS Status;
PIO_STACK_LOCATION pIrpSp;
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
/*
DEBUGMSG(DBG_TDI_IRP, ("IRDA: IrDADispatch(), Irp:%X %s.\n",
pIrp,
IrpMJTxt(pIrpSp)));
*/
CTEAssert(pIrpSp->MajorFunction != IRP_MJ_INTERNAL_DEVICE_CONTROL);
switch (pIrpSp->MajorFunction)
{
case IRP_MJ_CREATE:
Status = IrDACreate(pDeviceObject, pIrp, pIrpSp);
break;
case IRP_MJ_CLEANUP:
Status = IrDACleanup(pDeviceObject, pIrp, pIrpSp);
break;
case IRP_MJ_CLOSE:
Status = IrDAClose(pIrp, pIrpSp);
break;
case IRP_MJ_DEVICE_CONTROL:
Status = TdiMapUserRequest(pDeviceObject, pIrp, pIrpSp);
if (Status == STATUS_SUCCESS)
{
/*
IrDA will not support TdiMapUserRequest as it is not safe.
return IrDADispatchInternalDeviceControl(pDeviceObject, pIrp);
*/
Status = STATUS_INVALID_DEVICE_REQUEST;
ASSERT(0);
}
else
{
return IrDADispatchDeviceControl(pIrp, IoGetCurrentIrpStackLocation(pIrp));
}
case IRP_MJ_QUERY_SECURITY:
case IRP_MJ_WRITE:
case IRP_MJ_READ:
default:
DEBUGMSG(DBG_ERROR, ("IRDA: Irp:0x%p, Unsupported %s.\n",
pIrp,
IrpMJTxt(pIrpSp)));
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
CTEAssert(Status != TDI_PENDING);
DEBUGMSG(DBG_TDI_IRP,
("IRDA: Completing Irp:%p, Status %x.\n",
pIrp,
Status));
pIrp->IoStatus.Status = Status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
return Status;
}
NTSTATUS
IrDACreate(
PDEVICE_OBJECT pDeviceObject,
PIRP pIrp,
PIO_STACK_LOCATION pIrpSp)
{
NTSTATUS Status;
FILE_FULL_EA_INFORMATION *pEAs;
FILE_FULL_EA_INFORMATION UNALIGNED *pEA;
pEAs = (PFILE_FULL_EA_INFORMATION) pIrp->AssociatedIrp.SystemBuffer;
// Open a control channel
if (pEAs == NULL)
{
pIrpSp->FileObject->FsContext = (PVOID) 1; // no context here
pIrpSp->FileObject->FsContext2 = (PVOID) TDI_CONTROL_CHANNEL_FILE;
DEBUGMSG(DBG_TDI, ("IRDA: IrdaCreate() new control channel (fo:%p)\n",
pIrpSp->FileObject));
return STATUS_SUCCESS;
}
// Address Object open?
pEA = FindEA(pEAs,TdiTransportAddress,TDI_TRANSPORT_ADDRESS_LENGTH);
if (pEA != NULL)
{
PIRDA_ADDR_OBJ pAddr;
Status = TdiOpenAddress(&pAddr, (TRANSPORT_ADDRESS UNALIGNED *)
&(pEA->EaName[pEA->EaNameLength + 1]),
pEA->EaValueLength);
CTEAssert(Status != TDI_PENDING);
if (NT_SUCCESS(Status))
{
pIrpSp->FileObject->FsContext = pAddr;
pIrpSp->FileObject->FsContext2 = (PVOID) TDI_TRANSPORT_ADDRESS_FILE;
DEBUGMSG(DBG_TDI,
("IRDA: IrdaCreate() new AddrObj:%p (fo:%p)\n",
pAddr, pIrpSp->FileObject));
}
else
{
DEBUGMSG(DBG_ERROR,
("IRDA: TdiOpenAddress() failed, 0x%1x.\n", Status));
if (Status == STATUS_ADDRESS_ALREADY_EXISTS)
{
Status = STATUS_SHARING_VIOLATION;
}
}
return Status;
}
// Connection Object open?
pEA = FindEA(
pEAs,
TdiConnectionContext,
TDI_CONNECTION_CONTEXT_LENGTH);
if (pEA != NULL)
{
PIRDA_CONN_OBJ pConn;
Status = TdiOpenConnection(&pConn,
*((CONNECTION_CONTEXT UNALIGNED *)
&(pEA->EaName[pEA->EaNameLength + 1])),
pEA->EaValueLength);
CTEAssert(Status != TDI_PENDING);
if (NT_SUCCESS(Status))
{
pIrpSp->FileObject->FsContext = pConn;
pIrpSp->FileObject->FsContext2 = (PVOID) TDI_CONNECTION_FILE;
DEBUGMSG(DBG_TDI,
("IRDA: IrdaCreate() new ConnObj:%p (fo:%p)\n",
pConn, pIrpSp->FileObject));
}
else
{
DEBUGMSG(DBG_ERROR,
("IRDA: TdiOpenConnection() failed, 0x%1x.\n", Status));
}
return Status;
}
DEBUGMSG(DBG_ERROR, ("IRDA: Unsupported EA.\n"));
Status = STATUS_INVALID_EA_NAME;
return Status;
}
FILE_FULL_EA_INFORMATION UNALIGNED *
FindEA(
PFILE_FULL_EA_INFORMATION pStartEA,
CHAR *pTargetName,
USHORT TargetNameLength)
{
FILE_FULL_EA_INFORMATION UNALIGNED *pCurrentEA;
BOOLEAN Found;
USHORT i;
do
{
Found = TRUE;
pCurrentEA = pStartEA;
(PCHAR) pStartEA += pCurrentEA->NextEntryOffset;
if (pCurrentEA->EaNameLength != TargetNameLength)
{
continue;
}
for (i=0; i < pCurrentEA->EaNameLength; i++)
{
if (pCurrentEA->EaName[i] == pTargetName[i])
{
continue;
}
Found = FALSE;
break;
}
if (Found)
{
return pCurrentEA;
}
} while (pCurrentEA->NextEntryOffset != 0);
return NULL;
}
VOID
CancelCtrlChannelIrpsOnList(
PLIST_ENTRY pIrpList,
PFILE_OBJECT pFileObject)
{
PIRP pIrp;
PLIST_ENTRY pListEntry, pListEntryNext;
PIO_STACK_LOCATION pIrpSp;
for (pListEntry = LazyDscvIrpList.Flink;
pListEntry != &LazyDscvIrpList;
pListEntry = pListEntryNext)
{
pListEntryNext = pListEntry->Flink;
pIrp = CONTAINING_RECORD(pListEntry, IRP, Tail.Overlay.ListEntry);
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
if (pIrpSp->FileObject == pFileObject)
{
RemoveEntryList(pListEntry);
if (IoSetCancelRoutine(pIrp, NULL) == NULL)
{
// Cancel routine is going to run. Indicate to the
// cancel routine that the Irp has already been removed
// from the list by setting Flink to NULL
pIrp->Tail.Overlay.ListEntry.Flink = NULL;
}
else
{
DEBUGMSG(DBG_TDI_IRP, ("IRDA: cancelled irp %p\n", pIrp));
pIrp->IoStatus.Status = STATUS_CANCELLED;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
}
}
}
}
NTSTATUS
IrDACleanup(
PDEVICE_OBJECT pDeviceObject,
PIRP pIrp,
PIO_STACK_LOCATION pIrpSp)
{
NTSTATUS Status;
KIRQL OldIrql;
switch((UINT_PTR)pIrpSp->FileObject->FsContext2)
{
case TDI_TRANSPORT_ADDRESS_FILE:
DEBUGMSG(DBG_TDI_IRP, ("IRDA: Cleanup AddrObj:%p\n",
pIrpSp->FileObject->FsContext));
break;
case TDI_CONNECTION_FILE:
DEBUGMSG(DBG_TDI_IRP, ("IRDA: Cleanup ConnObj:%p\n",
pIrpSp->FileObject->FsContext));
break;
case TDI_CONTROL_CHANNEL_FILE:
{
CTELockHandle hLock;
DEBUGMSG(DBG_TDI_IRP, ("IRDA: Cleanup control channel (fo:%p)\n",
pIrpSp->FileObject));
CTEGetLock(&IrdaLock, &hLock);
// Cleanup any Irps that may have been placed on
// a list by this control channel
CancelCtrlChannelIrpsOnList(&LazyDscvIrpList, pIrpSp->FileObject);
CancelCtrlChannelIrpsOnList(&DscvIrpList, pIrpSp->FileObject);
CancelCtrlChannelIrpsOnList(&StatusIrpList, pIrpSp->FileObject);
CTEFreeLock(&IrdaLock, hLock);
break;
}
}
// Search for IAS entries that have been added on this
// control channel and delete them
{
PIRDA_IAS_ATTRIB pIasAttrib, pIasAttribNext;
CTELockHandle hLock;
IRDA_MSG IMsg;
CTEGetLock(&IrdaLock, &hLock);
for (pIasAttrib = (PIRDA_IAS_ATTRIB) IasAttribList.Flink;
pIasAttrib != (PIRDA_IAS_ATTRIB) &IasAttribList;
pIasAttrib = pIasAttribNext)
{
pIasAttribNext = (PIRDA_IAS_ATTRIB) pIasAttrib->Linkage.Flink;
DEBUGMSG(DBG_TDI_IRP, ("IRDA IAS cleanup compare fs-%p fs-%p\n",
pIasAttrib->pFileObject, pIrpSp->FileObject));
if (pIasAttrib->pFileObject == pIrpSp->FileObject)
{
IMsg.Prim = IRLMP_DELATTRIBUTE_REQ;
IMsg.IRDA_MSG_AttribHandle = pIasAttrib->AttribHandle;
RemoveEntryList(&pIasAttrib->Linkage);
CTEFreeLock(&IrdaLock, hLock);
IrlmpDown(NULL, &IMsg);
CTEGetLock(&IrdaLock, &hLock);
IRDA_FREE_MEM(pIasAttrib);
}
}
CTEFreeLock(&IrdaLock, hLock);
}
return STATUS_SUCCESS;
}
NTSTATUS
IrDAClose(
PIRP pIrp,
PIO_STACK_LOCATION pIrpSp)
{
NTSTATUS Status;
KIRQL OldIrql;
switch((UINT_PTR) pIrpSp->FileObject->FsContext2)
{
case TDI_TRANSPORT_ADDRESS_FILE:
TdiCloseAddress((PIRDA_ADDR_OBJ) pIrpSp->FileObject->FsContext);
break;
case TDI_CONNECTION_FILE:
TdiCloseConnection((PIRDA_CONN_OBJ) pIrpSp->FileObject->FsContext);
break;
case TDI_CONTROL_CHANNEL_FILE:
DEBUGMSG(DBG_TDI, ("IRDA: Close control channel (fo:%p)\n",
pIrpSp->FileObject));
break;
}
return STATUS_SUCCESS;
}
NTSTATUS
IrDADispatchInternalDeviceControl(
PDEVICE_OBJECT pDeviceObject,
PIRP pIrp)
{
NTSTATUS Status;
PIO_STACK_LOCATION pIrpSp;
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
DEBUGMSG(DBG_TDI_IRP,
("IRDA: IrDADispatch(), Irp:0x%p %s %s FileObj:0x%p %s:0x%p.\n",
pIrp,
IrpMJTxt(pIrpSp),
IrpTdiTxt(pIrpSp),
pIrpSp->FileObject,
IrpTdiObjTypeTxt(pIrpSp),
pIrpSp->FileObject->FsContext));
if (((UINT_PTR) pIrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE)
{
switch (pIrpSp->MinorFunction)
{
case TDI_ASSOCIATE_ADDRESS:
return TdiAssociateAddress(pIrp, pIrpSp);
case TDI_DISASSOCIATE_ADDRESS:
return TdiDisassociateAddress(pIrp, pIrpSp);
case TDI_CONNECT:
return TdiConnect(pIrp, pIrpSp);
case TDI_DISCONNECT:
return TdiDisconnect(pIrp, pIrpSp, NULL);
case TDI_SEND:
return TdiSend(pIrp, pIrpSp);
case TDI_RECEIVE:
return TdiReceive(pIrp, pIrpSp);
case TDI_QUERY_INFORMATION:
case TDI_SET_INFORMATION:
break;
default:
DEBUGMSG(DBG_ERROR, ("IRDA: minor function %X not supportedon\n",
pIrpSp->MinorFunction));
CTEAssert(FALSE);
Status = STATUS_NOT_IMPLEMENTED;
pIrp->IoStatus.Status = Status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
return Status;
}
}
else if (((UINT_PTR) pIrpSp->FileObject->FsContext2) ==
TDI_TRANSPORT_ADDRESS_FILE)
{
if (pIrpSp->MinorFunction == TDI_SET_EVENT_HANDLER)
{
PTDI_REQUEST_KERNEL_SET_EVENT pTdiParmsSetEvent;
pTdiParmsSetEvent = (PTDI_REQUEST_KERNEL_SET_EVENT)
&(pIrpSp->Parameters);
Status = TdiSetEvent(
(PIRDA_ADDR_OBJ) pIrpSp->FileObject->FsContext,
pTdiParmsSetEvent->EventType,
pTdiParmsSetEvent->EventHandler,
pTdiParmsSetEvent->EventContext);
CTEAssert(Status != TDI_PENDING);
DEBUGMSG(DBG_TDI_IRP,
("IRDA: Completing Irp:0x%p %s %s FileObj:0x%p %s:0x%p, Status 0x%lx.\n",
pIrp,
IrpMJTxt(pIrpSp),
IrpTdiTxt(pIrpSp),
pIrpSp->FileObject,
IrpTdiObjTypeTxt(pIrpSp),
pIrpSp->FileObject->FsContext,
Status));
pIrp->IoStatus.Status = Status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
return Status;
}
}
CTEAssert(
(((UINT_PTR)pIrpSp->FileObject->FsContext2)
== TDI_TRANSPORT_ADDRESS_FILE) ||
(((UINT_PTR)pIrpSp->FileObject->FsContext2)
== TDI_CONNECTION_FILE) ||
(((UINT_PTR)pIrpSp->FileObject->FsContext2)
== TDI_CONTROL_CHANNEL_FILE));
switch(pIrpSp->MinorFunction)
{
case TDI_QUERY_INFORMATION:
return TdiQueryInformation(pIrp, pIrpSp);
case TDI_SET_INFORMATION:
return TdiSetInformation(pIrp, pIrpSp);
case TDI_ACTION:
Status = STATUS_NOT_IMPLEMENTED;
break;
default:
Status = STATUS_INVALID_DEVICE_REQUEST;
}
CTEAssert(Status != TDI_PENDING);
DEBUGMSG(DBG_TDI_IRP,
("IRDA: Completing Irp:0x%p %s %s FileObj:0x%p %s:0x%p, Status 0x%lx.\n",
pIrp,
IrpMJTxt(pIrpSp),
IrpTdiTxt(pIrpSp),
pIrpSp->FileObject,
IrpTdiObjTypeTxt(pIrpSp),
pIrpSp->FileObject->FsContext,
Status));
pIrp->IoStatus.Status = Status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
return Status;
}
BOOLEAN
ValidConnectObject(
PIRDA_CONN_OBJ pConnCheck)
{
CTELockHandle hLock;
PIRDA_ADDR_OBJ pAddr;
PIRDA_CONN_OBJ pConn;
BOOLEAN Valid = FALSE;
CTEGetLock(&IrdaLock, &hLock);
for (pAddr = AddrObjList; pAddr != NULL; pAddr = pAddr->pNext)
{
for (pConn = pAddr->ConnObjList; pConn != NULL; pConn = pConn->pNext)
{
if (pConn == pConnCheck)
{
Valid = TRUE;
break;
}
}
}
CTEFreeLock(&IrdaLock, hLock);
return Valid;
}
BOOLEAN
ValidAddrObject(
PIRDA_ADDR_OBJ pAddrCheck)
{
CTELockHandle hLock;
PIRDA_ADDR_OBJ pAddr;
BOOLEAN Valid = FALSE;
CTEGetLock(&IrdaLock, &hLock);
for (pAddr = AddrObjList; pAddr != NULL; pAddr = pAddr->pNext)
{
if (pAddr == pAddrCheck)
{
Valid = TRUE;
break;
}
}
CTEFreeLock(&IrdaLock, hLock);
return Valid;
}
NTSTATUS
IrDADispatchDeviceControl(
PIRP pIrp,
PIO_STACK_LOCATION pIrpSp)
{
NTSTATUS Status;
CTELockHandle hLock;
#if DBG
if (pIrpSp->Parameters.DeviceIoControl.IoControlCode != IOCTL_IRDA_GET_DBG_MSGS)
DEBUGMSG(DBG_TDI_IRP,
("IRDA: IrDADispatchDeviceControl(), Irp:%p %s FileObj:%p %s:%p IoControlCode %X.\n",
pIrp,
IrpTdiTxt(pIrpSp),
pIrpSp->FileObject,
IrpTdiObjTypeTxt(pIrpSp),
pIrpSp->FileObject->FsContext,
pIrpSp->Parameters.DeviceIoControl.IoControlCode));
#endif
pIrp->IoStatus.Information = 0;
switch(pIrpSp->Parameters.DeviceIoControl.IoControlCode)
{
IRDA_MSG IMsg;
case IOCTL_IRDA_GET_INFO_ENUM_DEV:
PendIrp(
&DscvIrpList,
pIrp,
NULL,
FALSE
);
Status=STATUS_PENDING;
#if DBG
pIrp=NULL;
#endif
IMsg.Prim = IRLMP_DISCOVERY_REQ;
IMsg.IRDA_MSG_SenseMedia = TRUE;
IrlmpDown(NULL, &IMsg);
break;
case IOCTL_IRDA_LAZY_DISCOVERY:
{
CTEGetLock(&IrdaLock, &hLock);
PendIrp(
&LazyDscvIrpList,
pIrp,
NULL,
TRUE
);
Status=STATUS_PENDING;
#if DBG
pIrp=NULL;
#endif
if (LazyDscvTimerRunning == FALSE) {
LazyDscvTimerRunning = TRUE;
IrdaTimerStart(&LazyDscvTimer);
}
CTEFreeLock(&IrdaLock, hLock);
break;
}
case IOCTL_IRDA_FLUSH_DISCOVERY_CACHE:
{
IMsg.Prim = IRLMP_FLUSHDSCV_REQ;
IrlmpDown(NULL, &IMsg);
LazyDscvMacAddrs = 0;
Status = STATUS_SUCCESS;
// also reset LinkStatusUpated flag so that irmon will get
// latest status if it was restarted
LinkStatusUpdated = TRUE;
break;
}
case IOCTL_IRDA_SET_OPTIONS:
{
PIRDA_ADDR_OBJ pAddr = pIrpSp->FileObject->FsContext;
int *pOptions;
DEBUGMSG(DBG_TDI, ("IRDA: IOCTL_IRDA_SET_OPTIONS\n"));
if (!ValidAddrObject(pAddr))
{
Status = STATUS_INVALID_HANDLE;
break;
}
CTEAssert(IS_VALID_ADDR(pAddr));
if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(int))
{
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
pOptions = pIrp->AssociatedIrp.SystemBuffer;
if (*pOptions & OPT_IRLPT_MODE)
{
DEBUGMSG(DBG_TDI, ("IRDA: AddrObj:%p use IrLPT mode\n", pAddr));
pAddr->UseIrlptMode = IRLPT_MODE1;
}
if (*pOptions & OPT_9WIRE_MODE)
{
DEBUGMSG(DBG_TDI, ("IRDA: AddrObj:%p use 9-wire mode\n", pAddr));
pAddr->Use9WireMode = TRUE;
}
Status = STATUS_SUCCESS;
break;
}
case IOCTL_IRDA_GET_SEND_PDU_LEN:
{
PIRDA_CONN_OBJ pConn = pIrpSp->FileObject->FsContext;
// protect ourselves from malicious hackers by verifying
// this is a valid connObject
if (!ValidConnectObject(pConn))
{
Status = STATUS_INVALID_HANDLE;
break;
}
CTEAssert(IS_VALID_CONN(pConn));
if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(UINT))
{
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
*(UINT *) pIrp->AssociatedIrp.SystemBuffer = pConn->SendMaxPDU;
DEBUGMSG(DBG_TDI, ("IRDA: GET_SEND_PDU_LEN Conn:%p, Len %d\n",
pConn, *(UINT *) pIrp->AssociatedIrp.SystemBuffer));
pIrp->IoStatus.Information = sizeof(UINT);
Status = STATUS_SUCCESS;
break;
}
case IOCTL_IRDA_QUERY_IAS:
Status = InitiateIasQuery(pIrp, pIrpSp, NULL);
if (Status == STATUS_PENDING)
{
return STATUS_PENDING;
}
break;
case IOCTL_IRDA_SET_IAS:
{
PVOID AttribHandle;
PIRDA_IAS_ATTRIB pIasAttrib;
if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(IAS_SET) ||
pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PVOID))
{
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
IMsg.Prim = IRLMP_ADDATTRIBUTE_REQ;
IMsg.IRDA_MSG_pIasSet = (IAS_SET *) pIrp->AssociatedIrp.SystemBuffer;
IMsg.IRDA_MSG_pAttribHandle = &AttribHandle;
IrlmpDown(NULL, &IMsg);
Status = STATUS_INSUFFICIENT_RESOURCES;
if (AttribHandle)
{
IRDA_ALLOC_MEM(pIasAttrib, sizeof(IRDA_IAS_ATTRIB), MT_TDI_IAS);
if (!pIasAttrib)
{
IMsg.Prim = IRLMP_DELATTRIBUTE_REQ;
IMsg.IRDA_MSG_AttribHandle = AttribHandle;
IrlmpDown(NULL, &IMsg);
}
else
{
pIasAttrib->pFileObject = pIrpSp->FileObject;
pIasAttrib->AttribHandle = AttribHandle;
CTEGetLock(&IrdaLock, &hLock);
InsertTailList(&IasAttribList, &pIasAttrib->Linkage);
CTEFreeLock(&IrdaLock, hLock);
pIrp->IoStatus.Information = sizeof(PVOID);
*(PVOID *) pIrp->AssociatedIrp.SystemBuffer = AttribHandle;
Status = STATUS_SUCCESS;
DEBUGMSG(DBG_TDI, ("IRDA: IAS entry added, fo:%p ah:%p\n",
pIrpSp->FileObject, AttribHandle));
}
}
break;
}
case IOCTL_IRDA_DEL_IAS_ATTRIB:
{
PVOID *pAttribHandle = (PVOID *) pIrp->AssociatedIrp.SystemBuffer;
if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(PVOID))
{
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
IMsg.Prim = IRLMP_DELATTRIBUTE_REQ;
IMsg.IRDA_MSG_AttribHandle = *pAttribHandle;
IrlmpDown(NULL, &IMsg);
pIrp->IoStatus.Information = 0;
Status = STATUS_SUCCESS;
break;
}
case IOCTL_IRDA_LINK_STATUS_NB:
{
PIRLINK_STATUS pLinkStatus = (PIRLINK_STATUS) pIrp->AssociatedIrp.SystemBuffer;
if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(IRLINK_STATUS))
{
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
CTEGetLock(&IrdaLock, &hLock);
CTEMemCopy(pLinkStatus, &LinkStatus, sizeof(IRLINK_STATUS));
CTEFreeLock(&IrdaLock, hLock);
pIrp->IoStatus.Information = sizeof(IRLINK_STATUS);
Status = STATUS_SUCCESS;
break;
}
case IOCTL_IRDA_LINK_STATUS:
{
PIRLINK_STATUS pLinkStatus = (PIRLINK_STATUS) pIrp->AssociatedIrp.SystemBuffer;
if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(IRLINK_STATUS))
{
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
CTEGetLock(&IrdaLock, &hLock);
if (LinkStatusUpdated)
{
LinkStatusUpdated = FALSE;
CTEMemCopy(pLinkStatus, &LinkStatus, sizeof(IRLINK_STATUS));
pIrp->IoStatus.Information = sizeof(IRLINK_STATUS);
Status = STATUS_SUCCESS;
}
else
{
PendIrp(&StatusIrpList, pIrp, NULL, TRUE);
Status = STATUS_PENDING;
}
CTEFreeLock(&IrdaLock, hLock);
break;
}
#if 0 //DBG
case IOCTL_IRDA_GET_DBG_MSGS:
Status = DbgMsgIrp(pIrp, pIrpSp);
break;
case IOCTL_IRDA_GET_DBG_SETTINGS:
{
UINT *Settings = pIrp->AssociatedIrp.SystemBuffer;
if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(UINT)*2)
{
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
Settings[0] = DbgSettings;
Settings[1] = DbgOutput;
pIrp->IoStatus.Information = sizeof(UINT)*2;
Status = STATUS_SUCCESS;
break;
}
case IOCTL_IRDA_SET_DBG_SETTINGS:
{
UINT *Settings = pIrp->AssociatedIrp.SystemBuffer;
if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(UINT)*2)
{
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
DbgSettings = Settings[0];
DbgOutput = Settings[1];
pIrp->IoStatus.Information = 0;
Status = STATUS_SUCCESS;
break;
}
#endif
default:
Status = STATUS_NOT_IMPLEMENTED;
break;
}
if (Status != STATUS_PENDING)
{
pIrp->IoStatus.Status = Status;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
}
return Status;
}
NTSTATUS
TdiQueryInformation(
PIRP pIrp,
PIO_STACK_LOCATION pIrpSp)
{
NTSTATUS Status = STATUS_SUCCESS;
PIRDA_CONN_OBJ pConn;
PIRDA_ADDR_OBJ pAddr;
CTELockHandle hLock;
int InfoSize = 0;
int BytesCopied;
int DataLen = GetMdlChainByteCount(pIrp->MdlAddress);
PTDI_REQUEST_KERNEL_QUERY_INFORMATION pTdiParmsQueryInfo;
//
// This is large enough for TDI_QUERY_ADDRESS_INFO because
// of the inclusion of TDI_PROVIDER_STATISTICS.
//
union
{
TDI_CONNECTION_INFO ConnInfo;
TDI_ADDRESS_INFO AddrInfo;
TDI_PROVIDER_INFO ProviderInfo;
TDI_PROVIDER_STATISTICS ProviderStats;
} InfoBuf;
pTdiParmsQueryInfo = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)
&(pIrpSp->Parameters);
switch(pTdiParmsQueryInfo->QueryType)
{
case TDI_QUERY_PROVIDER_INFO:
InfoSize = sizeof(TDI_PROVIDER_INFO);
InfoBuf.ProviderInfo.Version = 0x0100;
InfoBuf.ProviderInfo.MaxSendSize = 2048;//IRDA_MAX_DATA_SIZE;
InfoBuf.ProviderInfo.MaxConnectionUserData = 0;
InfoBuf.ProviderInfo.MaxDatagramSize = 0;
InfoBuf.ProviderInfo.ServiceFlags =
TDI_SERVICE_CONNECTION_MODE |
TDI_SERVICE_FORCE_ACCESS_CHECK/* |
TDI_SERVICE_ORDERLY_RELEASE*/;
InfoBuf.ProviderInfo.MinimumLookaheadData = 0;
InfoBuf.ProviderInfo.MaximumLookaheadData = 0;
InfoBuf.ProviderInfo.NumberOfResources = 0;
InfoBuf.ProviderInfo.StartTime.LowPart =
CTESystemUpTime();
InfoBuf.ProviderInfo.StartTime.HighPart = 0;
break;
case TDI_QUERY_ADDRESS_INFO:
//
// typedef struct _TA_ADDRESS
// {
// USHORT AddressLength;
// USHORT AddressType;
// UCHAR Address[1];
// } TA_ADDRESS, *PTA_ADDRESS;
//
// typedef struct _TRANSPORT_ADDRESS
// {
// LONG TAAddressCount;
// TA_ADDRESS Address[1];
// } TRANSPORT_ADDRESS, *PTRANSPORT_ADDRESS;
//
// typedef struct _TDI_ADDRESS_IRDA
// {
// UCHAR irdaDeviceID[4];
// CHAR irdaServiceName[26];
// } TDI_ADDRESS_IRDA, *PTDI_ADDRESS_IRDA;
//
// IrDA assumes one TA_ADDRESS containing a TDI_ADDRESS_IRDA.
//
// typedef struct _TDI_ADDRESS_INFO
// {
// ULONG ActivityCount;
// TRANSPORT_ADDRESS Address;
// } TDI_ADDRESS_INFO, *PTDI_ADDRESS_INFO;
InfoSize =
offsetof(TDI_ADDRESS_INFO, Address.Address[0].Address[0]) +
sizeof(TDI_ADDRESS_IRDA);
InfoBuf.AddrInfo.ActivityCount = 1; // What is this?
InfoBuf.AddrInfo.Address.TAAddressCount = 1;
InfoBuf.AddrInfo.Address.Address[0].AddressLength =
sizeof(TDI_ADDRESS_IRDA);
InfoBuf.AddrInfo.Address.Address[0].AddressType =
TDI_ADDRESS_TYPE_IRDA;
if ((UINT_PTR) pIrpSp->FileObject->FsContext2 == TDI_CONNECTION_FILE)
{
// Extract the local address from the Connection
pConn = (PIRDA_CONN_OBJ) pIrpSp->FileObject->FsContext;
CTEAssert(IS_VALID_CONN(pConn));
GET_CONN_LOCK(pConn, &hLock);
CTEMemCopy(
&InfoBuf.AddrInfo.Address.Address[0].Address[0],
&pConn->LocalAddr,
sizeof(TDI_ADDRESS_IRDA));
FREE_CONN_LOCK(pConn, hLock);
DEBUGMSG(DBG_TDI,
("IRDA: TdiQueryInformation(), From ConnObj:%p, %d %02X%02X%02X%02X \"%s\".\n",
pConn,
InfoBuf.AddrInfo.Address.Address[0].AddressType,
InfoBuf.AddrInfo.Address.Address[0].Address[0],
InfoBuf.AddrInfo.Address.Address[0].Address[1],
InfoBuf.AddrInfo.Address.Address[0].Address[2],
InfoBuf.AddrInfo.Address.Address[0].Address[3],
(char *) &InfoBuf.AddrInfo.Address.Address[0].Address[4]));
}
else // Extract the local address from the Address Object
{
pAddr = (PIRDA_ADDR_OBJ) pIrpSp->FileObject->FsContext;
CTEAssert(IS_VALID_ADDR(pAddr));
GET_ADDR_LOCK(pAddr, &hLock);
CTEMemCopy(
&InfoBuf.AddrInfo.Address.Address[0].Address[0],
&pAddr->LocalAddr,
sizeof(TDI_ADDRESS_IRDA));
FREE_ADDR_LOCK(pAddr, hLock);
DEBUGMSG(DBG_TDI,
("IRDA: TdiQueryInformation(), From AddrObj:%p, %d %02X%02X%02X%02X \"%s\".\n",
pAddr,
InfoBuf.AddrInfo.Address.Address[0].AddressType,
InfoBuf.AddrInfo.Address.Address[0].Address[0],
InfoBuf.AddrInfo.Address.Address[0].Address[1],
InfoBuf.AddrInfo.Address.Address[0].Address[2],
InfoBuf.AddrInfo.Address.Address[0].Address[3],
(char *) &InfoBuf.AddrInfo.Address.Address[0].Address[4]));
}
break;
case TDI_QUERY_CONNECTION_INFO:
CTEAssert(FALSE);
break;
case TDI_QUERY_PROVIDER_STATISTICS:
CTEAssert(FALSE);
/*
InfoSize = sizeof(TDI_PROVIDER_STATISTICS);
CTEMemSet(&InfoBuf.ProviderStats, 0, sizeof(TDI_PROVIDER_STATISTICS));
InfoBuf.ProviderStats.Version = 0x100;
*/
break;
case TDI_QUERY_BROADCAST_ADDRESS:
default:
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
BytesCopied=0;
if (Status == STATUS_SUCCESS)
{
if (DataLen < InfoSize)
{
DEBUGMSG(DBG_ERROR, ("IRDA: Buffer overflow in TdiQueryInformation\n"));
Status = STATUS_BUFFER_OVERFLOW;
}
else
{
//
// could fail to get the system address for the mdl
//
Status=TdiCopyBufferToMdl(&InfoBuf, 0, InfoSize, pIrp->MdlAddress, 0, &BytesCopied);
}
}
pIrp->IoStatus.Status = Status;
pIrp->IoStatus.Information = BytesCopied;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
return Status;
}
NTSTATUS
TdiSetInformation(
PIRP pIrp,
PIO_STACK_LOCATION pIrpSp)
{
DEBUGMSG(DBG_TDI, ("IRDA: TdiSetInformation()\n"));
//(PVOID) CloseRasIrdaAddresses = pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
pIrp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
TdiSetEvent(
PIRDA_ADDR_OBJ pAddr,
int Type,
PVOID pHandler,
PVOID pContext)
{
TDI_STATUS Status;
CTELockHandle hLock;
DEBUGMSG(DBG_TDI, ("IRDA: TdiSetEvent(), %s for AddrObj:%p, Handler:%p, Context:%p \n",
TdiEventTxt(Type), pAddr, pHandler, pContext));
CTEAssert(IS_VALID_ADDR(pAddr));
Status = STATUS_SUCCESS;
GET_ADDR_LOCK(pAddr, &hLock);
switch (Type)
{
case TDI_EVENT_CONNECT:
pAddr->pEventConnect = pHandler;
pAddr->pEventConnectContext = pContext;
break;
case TDI_EVENT_DISCONNECT:
pAddr->pEventDisconnect = pHandler;
pAddr->pEventDisconnectContext = pContext;
break;
case TDI_EVENT_RECEIVE:
pAddr->pEventReceive = pHandler;
pAddr->pEventReceiveContext = pContext;
break;
case TDI_EVENT_ERROR:
break;
case TDI_EVENT_RECEIVE_DATAGRAM:
case TDI_EVENT_RECEIVE_EXPEDITED:
default:
Status = STATUS_INVALID_PARAMETER;//TDI_BAD_EVENT_TYPE;
break;
}
FREE_ADDR_LOCK(pAddr, hLock);
return Status;
}
int
GetLsapSelServiceName(CHAR *ServiceName)
{
int LsapSel = 0;
int i;
CHAR *Digits;
// Is the service name of the form "LSAP-SELxxx"?
// If yes then return xxx if it is a number else -1.
// If not "LSAP-SELxxx" return 0.
if (RtlCompareMemory(LSAPSEL_TXT, ServiceName, LSAPSEL_TXTLEN)
== LSAPSEL_TXTLEN)
{
Digits = ServiceName + LSAPSEL_TXTLEN;
for (i = 0; i< 3; i++)
{
if (Digits[i] == 0)
break;
if (Digits[i] < '0' || Digits[i] > '9')
{
LsapSel = -1;
break;
}
LsapSel = (LsapSel*10) + (Digits[i] - '0');
}
if (Digits[i] != 0) // LSAP-SELxxx should be null terminated
{
LsapSel = -1;
}
}
if (LsapSel > 127) {
//
// lsapsel's are only 7 bits
//
LsapSel=-1;
}
return LsapSel;
}
NTSTATUS
TdiOpenAddress(
PIRDA_ADDR_OBJ *ppNewAddrObj,
TRANSPORT_ADDRESS UNALIGNED *pAddrList,
USHORT AddrListLen)
{
TDI_STATUS Status = TDI_SUCCESS;
PIRDA_ADDR_OBJ pAddr;
CTELockHandle hLock;
int NewLsapSel;
int i;
PTDI_ADDRESS_IRDA pIrdaAddr = (PTDI_ADDRESS_IRDA) pAddrList->Address[0].Address;
BOOLEAN AddIasServiceName = TRUE;
//
// typedef struct _TA_ADDRESS
// {
// USHORT AddressLength;
// USHORT AddressType;
// UCHAR Address[1];
// } TA_ADDRESS, *PTA_ADDRESS;
//
// typedef struct _TRANSPORT_ADDRESS
// {
// LONG TAAddressCount;
// TA_ADDRESS Address[1];
// } TRANSPORT_ADDRESS, *PTRANSPORT_ADDRESS;
//
// typedef struct _TDI_ADDRESS_IRDA
// {
// UCHAR irdaDeviceID[4];
// CHAR irdaServiceName[26];
// } TDI_ADDRESS_IRDA, *PTDI_ADDRESS_IRDA;
//
// IrDA assumes one TA_ADDRESS containing a TDI_ADDRESS_IRDA.
//
// typedef struct _TDI_ADDRESS_INFO
// {
// ULONG ActivityCount;
// TRANSPORT_ADDRESS Address;
// } TDI_ADDRESS_INFO, *PTDI_ADDRESS_INFO;
//
if (AddrListLen < sizeof(TRANSPORT_ADDRESS) + sizeof(TDI_ADDRESS_IRDA) - 1)
{
return STATUS_EA_LIST_INCONSISTENT;
}
DEBUGMSG(DBG_TDI,
("IRDA: TdiOpenAddress(), Type:%d Addr:%02X%02X%02X%02X \"%s\".\n",
pAddrList->Address[0].AddressType,
pAddrList->Address[0].Address[0],
pAddrList->Address[0].Address[1],
pAddrList->Address[0].Address[2],
pAddrList->Address[0].Address[3],
(char *) &pAddrList->Address[0].Address[4]));
if (pAddrList->TAAddressCount != 1 ||
pAddrList->Address[0].AddressLength != sizeof(TDI_ADDRESS_IRDA) ||
pAddrList->Address[0].AddressType != TDI_ADDRESS_TYPE_IRDA)
{
DEBUGMSG(DBG_ERROR, ("IRDA: TdiOpenAddress(), Bad Address. Count=%d, AddrLen:%d!=%d Type:%d!=%d\n",
pAddrList->TAAddressCount, pAddrList->Address[0].AddressLength,
sizeof(TDI_ADDRESS_IRDA), pAddrList->Address[0].AddressType,
TDI_ADDRESS_TYPE_IRDA));
return STATUS_INVALID_ADDRESS_COMPONENT; //TDI_BAD_ADDR;
}
CTEGetLock(&IrdaLock, &hLock);
// Service name supplied. Ensure that an address object with the same
// name does not exist
if (pIrdaAddr->irdaServiceName[0] != 0)
{
for (pAddr = AddrObjList; pAddr != NULL; pAddr = pAddr->pNext)
{
if (MyStrEqual(pIrdaAddr->irdaServiceName,
pAddr->LocalAddr.irdaServiceName,
sizeof(pIrdaAddr->irdaServiceName)))
{
DEBUGMSG(DBG_ERROR, ("IRDA: TdiOpenAddress(), Duplicate irdaServiceName.\n"));
Status = STATUS_ADDRESS_ALREADY_EXISTS;//TDI_ADDR_IN_USE;
CTEFreeLock(&IrdaLock, hLock);
goto done;
}
}
}
NewLsapSel = GetLsapSelServiceName(pIrdaAddr->irdaServiceName);
if (NewLsapSel == -1)
{
// Service name was of the form "LSAP-SELxxx" but xxx was invalid
Status = STATUS_INVALID_ADDRESS_COMPONENT;
CTEFreeLock(&IrdaLock, hLock);
goto done;
}
if (NewLsapSel)
{
// Service name was of the form "LSAP-SELxxx"
// NewLsapSel = xxx
AddIasServiceName = FALSE;
}
else if ((NewLsapSel = GetUnusedLsapSel()) == -1)
{
DEBUGMSG(DBG_ERROR, ("IRDA: TdiOpenAddress(), No LSAP-SELs.\n"));
Status = STATUS_TOO_MANY_ADDRESSES;//TDI_NO_FREE_ADDR;
CTEFreeLock(&IrdaLock, hLock);
goto done;
}
IRDA_ALLOC_MEM(pAddr, sizeof(IRDA_ADDR_OBJ), MT_TDI_ADDROBJ);
if (pAddr == NULL)
{
DEBUGMSG(DBG_ERROR, ("IRDA: AllocMem(IRDA_ADDR_OBJ) failed.\n"));
Status = STATUS_INSUFFICIENT_RESOURCES;//TDI_NO_RESOURCES;
CTEFreeLock(&IrdaLock, hLock);
goto done;
}
CTEMemSet(pAddr, 0, sizeof(IRDA_ADDR_OBJ));
CTEInitLock(&pAddr->Lock);
pAddr->ConnObjList = NULL;
pAddr->pEventConnect = NULL;
pAddr->pEventConnectContext = NULL;
pAddr->pEventDisconnect = NULL;
pAddr->pEventDisconnectContext = NULL;
pAddr->pEventReceive = NULL;
pAddr->pEventReceiveContext = NULL;
pAddr->LocalLsapSel = NewLsapSel;
pAddr->UseIrlptMode = 0;
pAddr->Use9WireMode = FALSE;
pAddr->pNext = AddrObjList;
AddrObjList = pAddr;
#if DBG
pAddr->Sig = ADDR_OBJ_SIG;
#endif
CTEFreeLock(&IrdaLock, hLock);
// A server
if (pIrdaAddr->irdaServiceName[0] != 0)
{
IRDA_MSG IMsg;
IAS_SET IasSet;
RtlCopyMemory(&pAddr->LocalAddr,
pIrdaAddr, sizeof(TDI_ADDRESS_IRDA));
pAddr->IsServer = TRUE;
// register LSAP-SEL
IMsg.Prim = IRLMP_REGISTERLSAP_REQ;
IMsg.IRDA_MSG_LocalLsapSel = NewLsapSel;
IMsg.IRDA_MSG_UseTtp = TRUE;
IrlmpDown(NULL, &IMsg);
// and IAS LsapSel attribute
if (AddIasServiceName)
{
i = 0;
while (pAddr->LocalAddr.irdaServiceName[i] && i < 60)
{
IasSet.irdaClassName[i] = pAddr->LocalAddr.irdaServiceName[i];
i++;
}
IasSet.irdaClassName[i] = 0;
i = 0;
while (IasAttribName_TTPLsapSel[i])
{
IasSet.irdaAttribName[i] = IasAttribName_TTPLsapSel[i];
i++;
}
IasSet.irdaAttribName[i] = 0;
IasSet.irdaAttribType = IAS_ATTRIB_INT;
IasSet.irdaAttribute.irdaAttribInt = NewLsapSel;
IMsg.Prim = IRLMP_ADDATTRIBUTE_REQ;
IMsg.IRDA_MSG_pIasSet = &IasSet;
IMsg.IRDA_MSG_pAttribHandle = &pAddr->IasAttribHandle;
IrlmpDown(NULL, &IMsg);
}
}
// A client
else
{
pAddr->IsServer = FALSE;
SetLsapSelAddr(NewLsapSel, pAddr->LocalAddr.irdaServiceName);
}
*ppNewAddrObj = pAddr;
DEBUGMSG(DBG_TDI,
("IRDA: TdiOpenAddress(), Assigned local LSAP-SEL %d, Service:\"%s\".\n",
pAddr->LocalLsapSel, pAddr->LocalAddr.irdaServiceName));
done:
return Status;
}
NTSTATUS
TdiOpenConnection(
PIRDA_CONN_OBJ *ppNewConnObj,
PVOID pContext,
USHORT ContextLen)
{
PIRDA_CONN_OBJ pNewConnObj;
*ppNewConnObj=NULL;
if (ContextLen < sizeof(CONNECTION_CONTEXT))
{
return STATUS_EA_LIST_INCONSISTENT;
}
IRDA_ALLOC_MEM(pNewConnObj, sizeof(IRDA_CONN_OBJ), MT_TDI_CONNOBJ);
if (pNewConnObj == NULL)
{
DEBUGMSG(DBG_ERROR, ("IRDA: AllocMem(IRDA_CONN_OBJ) failed.\n"));
return STATUS_INSUFFICIENT_RESOURCES;//TDI_NO_RESOURCES;
}
CTEMemSet(pNewConnObj, 0, sizeof(IRDA_CONN_OBJ));
CTEInitLock(&pNewConnObj->Lock);
pNewConnObj->ClientContext = pContext;
pNewConnObj->ConnState = IRDA_CONN_CREATED;
InitializeListHead(&pNewConnObj->RecvBufList);
InitializeListHead(&pNewConnObj->RecvIrpList);
InitializeListHead(&pNewConnObj->SendIrpList);
InitializeListHead(&pNewConnObj->SendIrpPassiveList);
IrdaTimerInitialize(&pNewConnObj->RetryConnTimer,
RetryConnTimerExp,
BUSY_LINK_CONN_RETRY_WAIT,
pNewConnObj, NULL);
ReferenceInit(&pNewConnObj->RefCnt, pNewConnObj, FreeConnObject);
REFADD(&pNewConnObj->RefCnt, ' TS1');
CTEInitEvent(&pNewConnObj->SendEvent, TdiSendAtPassiveCallback);
#if DBG
pNewConnObj->Sig = CONN_OBJ_SIG;
pNewConnObj->RetryConnTimer.pName = "RetryConn";
#endif
*ppNewConnObj = pNewConnObj;
return STATUS_SUCCESS;
}
NTSTATUS
TdiCloseAddress(PIRDA_ADDR_OBJ pAddr)
{
PIRDA_ADDR_OBJ pPrevAddrObj;
CTELockHandle hLock;
DEBUGMSG(DBG_TDI, ("IRDA: TdiCloseAddress() AddrObj:%p\n",
pAddr));
CTEAssert(IS_VALID_ADDR(pAddr));
CTEAssert(pAddr->ConnObjList == NULL);
CTEGetLock(&IrdaLock, &hLock);
// if pAddr is first in the list, remove it from the list
if (AddrObjList == pAddr)
AddrObjList = pAddr->pNext;
else
{
// find the previous IRDA_ADDR_OBJ
pPrevAddrObj = AddrObjList;
while (pPrevAddrObj->pNext != pAddr)
pPrevAddrObj = pPrevAddrObj->pNext;
// remove pAddr from the list
pPrevAddrObj->pNext = pAddr->pNext;
}
CTEFreeLock(&IrdaLock, hLock);
if (pAddr->IsServer)
{
IRDA_MSG IMsg;
IMsg.Prim = IRLMP_DEREGISTERLSAP_REQ;
IMsg.IRDA_MSG_LocalLsapSel = pAddr->LocalLsapSel;
IrlmpDown(NULL, &IMsg);
IMsg.Prim = IRLMP_DELATTRIBUTE_REQ;
IMsg.IRDA_MSG_AttribHandle = pAddr->IasAttribHandle;
IrlmpDown(NULL, &IMsg);
}
#if DBG
pAddr->Sig = ' DAB';
#endif
IRDA_FREE_MEM(pAddr);
return STATUS_SUCCESS;
}
VOID
ConnectionStatusChange(
PIRDA_CONN_OBJ pConn,
IRDA_CONNECTION_STATUS ConnStatus)
{
PLIST_ENTRY pListEntry;
PIRP pIrp;
CTELockHandle hLock;
if (ConnStatus == CONNECTION_UP)
{
IRDA_MSG IMsg;
if (!ConnectionCount)
{
return;
}
ConnectionInterrupted = FALSE;
if (pConn)
{
// Query Irlap for the connected speed and
// the MAC address of the peer so Irmon
// can display the name of the connected device
IMsg.Prim = IRLAP_STATUS_REQ;
IMsg.IRDA_MSG_pLinkStatus = &LinkStatus;
IrlmpDown(pConn->IrlmpContext, &IMsg);
}
}
CTEGetLock(&IrdaLock, &hLock);
LinkStatusUpdated = TRUE;
switch (ConnStatus)
{
case CONNECTION_UP:
LinkStatus.Flags = LF_CONNECTED;
break;
case CONNECTION_DOWN:
LinkStatus.Flags = 0;
break;
case CONNECTION_INTERRUPTED:
if (ConnectionInterrupted || !ConnectionCount)
{
CTEFreeLock(&IrdaLock, hLock);
return;
}
LinkStatus.Flags = LF_INTERRUPTED;
ConnectionInterrupted = TRUE;
break;
}
while (!IsListEmpty(&StatusIrpList)) {
pListEntry = RemoveHeadList(&StatusIrpList);
pIrp = CONTAINING_RECORD(pListEntry, IRP, Tail.Overlay.ListEntry);
if (IoSetCancelRoutine(pIrp, NULL) == NULL) {
// Cancel routine is going to run. Mark Irp so cancel
// routine won't attempt to remove it from the list
pIrp->Tail.Overlay.ListEntry.Flink = NULL;
} else {
CTEMemCopy(pIrp->AssociatedIrp.SystemBuffer,
&LinkStatus, sizeof(IRLINK_STATUS));
CTEFreeLock(&IrdaLock, hLock);
pIrp->IoStatus.Information = sizeof(IRLINK_STATUS);
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
CTEGetLock(&IrdaLock, &hLock);
LinkStatusUpdated = FALSE;
}
}
CTEFreeLock(&IrdaLock, hLock);
return;
}
VOID
ConnectionUp(
PIRDA_CONN_OBJ pConn,
BOOLEAN ConnectionUp)
{
if (ConnectionUp)
{
if (pConn->ConnectionUp)
{
return;
}
pConn->ConnectionUp = TRUE;
CTEInterlockedIncrementLong(&ConnectionCount);
if (ConnectionCount == 1)
{
ConnectionStatusChange(pConn, CONNECTION_UP);
}
}
else
{
if (!pConn->ConnectionUp)
{
return;
}
pConn->ConnectionUp = FALSE;
ASSERT(ConnectionCount);
CTEInterlockedDecrementLong(&ConnectionCount);
if (ConnectionCount == 0)
{
ConnectionStatusChange(pConn, CONNECTION_DOWN);
}
}
}
VOID
IrdaDisconnectIrlmp(PIRDA_CONN_OBJ pConn)
{
IRDA_MSG IMsg;
if (pConn->IrlmpContext)
{
IMsg.Prim = IRLMP_DISCONNECT_REQ;
IMsg.IRDA_MSG_pDiscData = NULL;
IMsg.IRDA_MSG_DiscDataLen = 0;
IMsg.IRDA_MSG_pDiscContext = pConn;
IrlmpDown(pConn->IrlmpContext, &IMsg);
DEBUGMSG(DBG_TDI, ("IRDA: IrdaDisconnectIrlmp co:%p\n", pConn));
}
else
{
DEBUGMSG(DBG_TDI, ("IRDA: IrdaDisconnectIrlmp co %p, IrlmpContext == NULL\n",
pConn));
}
}
VOID
FreeConnObject(PIRDA_CONN_OBJ pConn)
{
IRDA_FREE_MEM(pConn);
}
NTSTATUS
TdiCloseConnection(PIRDA_CONN_OBJ pConn)
{
PIRDA_ADDR_OBJ pAddr=NULL;
CTELockHandle hLock;
DEBUGMSG(DBG_TDI, ("IRDA: TdiCloseConnecion() ConnObj:%p\n",
pConn));
CTEAssert(IS_VALID_CONN(pConn));
if (pConn->ConnState != IRDA_CONN_CREATED)
{
TdiDisconnect(NULL, NULL, pConn);
}
GET_CONN_LOCK(pConn, &hLock);
pAddr=pConn->pAddr;
pConn->pAddr=NULL;
if (pAddr != NULL) {
PIRDA_CONN_OBJ pPrevConnObj;
CTELockHandle hAddrLock;
GET_ADDR_LOCK(pAddr, &hAddrLock);
//
// if pConn is first in the list, remove it from the list
//
if (pAddr->ConnObjList == pConn) {
pAddr->ConnObjList = pConn->pNext;
} else {
//
// find the previous IRDA_CONN_OBJ
//
pPrevConnObj = pAddr->ConnObjList;
while ((pPrevConnObj != NULL) && (pPrevConnObj->pNext != pConn)) {
pPrevConnObj = pPrevConnObj->pNext;
}
//
// since the connection has a pointer to the address object,
// the connection should really be in the address objects connection list.
//
ASSERT(pPrevConnObj != NULL);
//
// remove pConn from the list
//
if (pPrevConnObj != NULL) {
pPrevConnObj->pNext = pConn->pNext;
}
}
DumpObjects();
FREE_ADDR_LOCK(pAddr, hAddrLock);
//
// done with this address object
//
ObDereferenceObject(pConn->AddressFileObject);
}
FREE_CONN_LOCK(pConn, hLock);
if (pConn->IrlmpContext)
{
IRDA_MSG IMsg;
IMsg.Prim = IRLMP_CLOSELSAP_REQ;
IrlmpDown(pConn->IrlmpContext, &IMsg);
}
#if DBG
pConn->Sig = ' DAB';
#endif
CTEAssert(IsListEmpty(&pConn->RecvBufList));
CTEAssert(IsListEmpty(&pConn->SendIrpList));
REFDEL(&pConn->RefCnt, ' TS1');
return STATUS_SUCCESS;
}
NTSTATUS
TdiAssociateAddress(
PIRP pIrp,
PIO_STACK_LOCATION pIrpSp)
{
NTSTATUS Status;
PTDI_REQUEST_KERNEL_ASSOCIATE pTdiParmsAssoc;
PFILE_OBJECT AddressFileObject;
CTEAssert(((UINT_PTR) pIrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
pTdiParmsAssoc = (PTDI_REQUEST_KERNEL_ASSOCIATE) &(pIrpSp->Parameters);
Status = ObReferenceObjectByHandle(
pTdiParmsAssoc->AddressHandle,
0,
*IoFileObjectType,
pIrp->RequestorMode,
&AddressFileObject,
NULL);
if (!NT_SUCCESS(Status))
{
DEBUGMSG(DBG_ERROR,
("IRDA: TdiAssociateAddress(), ObReferenceObjectByHandle() for %p failed, %X.\n",
pTdiParmsAssoc->AddressHandle,
Status));
}
else if (AddressFileObject->DeviceObject != pIrDADeviceObject ||
((UINT_PTR) AddressFileObject->FsContext2) != TDI_TRANSPORT_ADDRESS_FILE)
{
DEBUGMSG(DBG_ERROR,("IRDA: TdiAssociateAddress(), Bad handle %p.\n",
pTdiParmsAssoc->AddressHandle));
ObDereferenceObject(AddressFileObject);
Status = STATUS_INVALID_HANDLE;
}
else
{
PIRDA_CONN_OBJ pConn;
PIRDA_ADDR_OBJ pAddr;
CTELockHandle hAddrLock;
CTELockHandle hLock;
pConn = (PIRDA_CONN_OBJ) pIrpSp->FileObject->FsContext;
CTEAssert(IS_VALID_CONN(pConn));
pAddr = (PIRDA_ADDR_OBJ) AddressFileObject->FsContext;
CTEAssert(IS_VALID_ADDR(pAddr));
DEBUGMSG(DBG_TDI, ("IRDA: TdiAssociateAddress AddrObj:%p ConnObj:%p\n",
pAddr, pConn));
GET_CONN_LOCK(pConn, &hLock);
GET_ADDR_LOCK(pAddr, &hAddrLock);
if (pConn->pAddr != NULL) {
ObDereferenceObject(AddressFileObject);
Status = STATUS_ADDRESS_ALREADY_ASSOCIATED;
ASSERT(0);
} else {
//
// don't want the address file object going away while we have a connection object pointing to it
//
pConn->AddressFileObject=AddressFileObject;
// Link IRDA_CONN_OBJ to IRDA_ADDR_OBJ.
pConn->pAddr = pAddr;
// Add IRDA_CONN_OBJ to ConnObjList anchored on IRDA_ADDR_OBJ.
pConn->pNext = pAddr->ConnObjList;
pAddr->ConnObjList = pConn;
CTEMemCopy(&pConn->LocalAddr,&pAddr->LocalAddr, sizeof(TDI_ADDRESS_IRDA));
pConn->IsServer = pAddr->IsServer;
pConn->LocalLsapSel = pAddr->LocalLsapSel;
DumpObjects();
Status = STATUS_SUCCESS;
}
FREE_ADDR_LOCK(pAddr, hAddrLock);
FREE_CONN_LOCK(pConn, hLock);
}
pIrp->IoStatus.Status = Status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
return Status;
}
NTSTATUS
TdiDisassociateAddress(PIRP pIrp, PIO_STACK_LOCATION pIrpSp)
{
PIRDA_CONN_OBJ pConn, pPrevConnObj;
PIRDA_ADDR_OBJ pAddr;
CTELockHandle hLock;
CTELockHandle hAddrLock;
NTSTATUS Status = STATUS_SUCCESS;
pConn = (PIRDA_CONN_OBJ) pIrpSp->FileObject->FsContext;
CTEAssert(IS_VALID_CONN(pConn));
if (pConn->pAddr == NULL)
{
CTEAssert(pConn->pAddr != NULL);
Status = STATUS_INVALID_ADDRESS_COMPONENT; //TDI_BAD_ADDR;
goto done;
}
// normally when the peer disconnects I indicate the
// disconnect to AFD and go to IRDA_CONN_CLOSING state.
// AFD then calls TdiDisconnect and I go into IRDA_CONN_CREATED.
// AFD then disassociates the address. In some cases however,
// AFD does not call TdiDisconnect before it disassociates so
// I'll do it.
if (pConn->ConnState != IRDA_CONN_CREATED)
{
TdiDisconnect(NULL, NULL, pConn);
}
CTEAssert(pConn->ConnState == IRDA_CONN_CREATED);
GET_CONN_LOCK(pConn, &hLock);
pAddr = pConn->pAddr;
CTEAssert(IS_VALID_ADDR(pAddr));
DEBUGMSG(DBG_TDI, ("IRDA: TdiDisassociateAddress() AddrObj:%p ConnObj:%p\n",
pAddr, pConn));
GET_ADDR_LOCK(pAddr, &hAddrLock);
// if pConn is first in the list, remove it from the list
if (pAddr->ConnObjList == pConn)
pAddr->ConnObjList = pConn->pNext;
else
{
// find the previous IRDA_CONN_OBJ
pPrevConnObj = pAddr->ConnObjList;
while (pPrevConnObj && pPrevConnObj->pNext != pConn)
{
pPrevConnObj = pPrevConnObj->pNext;
}
// remove pConn from the list
if (pPrevConnObj)
{
pPrevConnObj->pNext = pConn->pNext;
}
}
DumpObjects();
pConn->pAddr=NULL;
//
// done with this address object
//
ObDereferenceObject(pConn->AddressFileObject);
FREE_ADDR_LOCK(pAddr, hAddrLock);
FREE_CONN_LOCK(pConn, hLock);
done:
pIrp->IoStatus.Status = Status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
return Status;
}
NTSTATUS
ConnectRcToNtStatus(UINT IrlmpRc)
{
switch (IrlmpRc)
{
case IRLMP_LSAP_SEL_IN_USE:
case IRLMP_IN_EXCLUSIVE_MODE:
return STATUS_ADDRESS_ALREADY_EXISTS;
case IRLMP_LINK_IN_USE:
return STATUS_ACCESS_DENIED;
case IRLMP_IAS_QUERY_IN_PROGRESS:
// I've serialized IAS requests, should never happen
CTEAssert(0);
return STATUS_CONNECTION_RESET; //STATUS_CONNECTION_ABORTED;
case IRLMP_BAD_DEV_ADDR:
return STATUS_INVALID_ADDRESS_COMPONENT;
}
return STATUS_CONNECTION_RESET; //STATUS_CONNECTION_ABORTED;
}
NTSTATUS
InitiateConnection(PIRDA_CONN_OBJ pConn, PIRP pIrp)
{
IRDA_MSG IMsg;
UINT rc;
DEBUGMSG(DBG_TDI, ("IRDA: Initiate connection to Dev:%02X%02X%02X%02X\n",
pConn->RemoteAddr.irdaDeviceID[0],
pConn->RemoteAddr.irdaDeviceID[1],
pConn->RemoteAddr.irdaDeviceID[2],
pConn->RemoteAddr.irdaDeviceID[3]
));
DEBUGMSG(DBG_TDI, (" LocalLsapSel:%d, RemoteLsapSel:%d\n",
pConn->LocalLsapSel, pConn->RemoteLsapSel));
IMsg.Prim = IRLMP_CONNECT_REQ;
RtlCopyMemory(IMsg.IRDA_MSG_RemoteDevAddr,
pConn->RemoteAddr.irdaDeviceID,
IRDA_DEV_ADDR_LEN);
IMsg.IRDA_MSG_RemoteLsapSel = pConn->RemoteLsapSel;
IMsg.IRDA_MSG_pQos = NULL;
IMsg.IRDA_MSG_pConnData = NULL;
IMsg.IRDA_MSG_ConnDataLen = 0;
IMsg.IRDA_MSG_LocalLsapSel = pConn->LocalLsapSel;
IMsg.IRDA_MSG_pContext = pConn;
IMsg.IRDA_MSG_UseTtp = pConn->pAddr->UseIrlptMode ? FALSE:TRUE;
IMsg.IRDA_MSG_TtpCredits = TTP_RECV_CREDITS;
IMsg.IRDA_MSG_MaxSDUSize = TTP_RECV_MAX_SDU;
#if DBG
pConn->CreditsExtended += TTP_RECV_CREDITS;
#endif
pConn->TtpRecvCreditsLeft = TTP_RECV_CREDITS;
#if DBG
pIrp->IoStatus.Information=1;
#endif
//
// pend the irp, now incase the confermation happened quickly
//
PendIrp(&ConnIrpList, pIrp, NULL, FALSE);
rc = IrlmpDown(NULL, &IMsg);
pIrp=NULL;
switch (rc)
{
case SUCCESS:
//
// TDI needed the IrlmpContext immediately so it is
// now returned in the request message
pConn->IrlmpContext = IMsg.IRDA_MSG_pContext;
break;
case IRLAP_REMOTE_DISCOVERY_IN_PROGRESS_ERR:
//
// failed, get the irp back off the queue if possible
//
pIrp=GetIrpOnConnIrpList(pConn);
if (pIrp != NULL) {
//
// we got it back, attempt to retry the connection
//
RetryConnection(pConn, pIrp);
}
break;
default:
DEBUGMSG(DBG_ERROR, ("IRDA: IRLMP_CONNECT_REQ failed %d\n", rc));
//
// failed, get the irp back off the queue if possible
//
pIrp=GetIrpOnConnIrpList(pConn);
if (pIrp != NULL) {
pIrp->IoStatus.Status=ConnectRcToNtStatus(rc);
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
}
break;
}
return STATUS_PENDING;
}
UINT
SendIasQuery(PIRP pIrp, PIO_STACK_LOCATION pIrpSp)
{
IRDA_MSG IMsg;
if ((UINT_PTR) pIrpSp->FileObject->FsContext2 == TDI_CONNECTION_FILE)
{
// connection object querying remote IAS for LsapSel
PTDI_CONNECTION_INFORMATION pReqConnInfo;
PTDI_REQUEST_KERNEL_CONNECT pTdiParmsConn;
PTRANSPORT_ADDRESS pTranAddr;
PTDI_ADDRESS_IRDA pIrdaAddr;
PIRDA_CONN_OBJ pConn = pIrpSp->FileObject->FsContext;
if (!ValidConnectObject(pConn))
{
return 1;
}
CTEAssert(IS_VALID_CONN(pConn));
pTdiParmsConn = (PTDI_REQUEST_KERNEL_CONNECT) &(pIrpSp->Parameters);
pReqConnInfo = pTdiParmsConn->RequestConnectionInformation;
pTranAddr = (PTRANSPORT_ADDRESS) pReqConnInfo->RemoteAddress;
pIrdaAddr = (PTDI_ADDRESS_IRDA) pTranAddr->Address[0].Address;
RtlCopyMemory(pvIasQuery->irdaDeviceID,
pIrdaAddr->irdaDeviceID,
IRDA_DEV_ADDR_LEN);
strcpy(pvIasQuery->irdaClassName, pIrdaAddr->irdaServiceName);
if (pConn->pAddr->UseIrlptMode)
{
// I can't beleive this crap
if (pConn->pAddr->UseIrlptMode == IRLPT_MODE1)
{
strcpy(pvIasQuery->irdaAttribName, IasAttribName_IrLMPLsapSel);
pConn->pAddr->UseIrlptMode = IRLPT_MODE2;
}
else
{
strcpy(pvIasQuery->irdaAttribName, IasAttribName_IrLMPLsapSel2);
pConn->pAddr->UseIrlptMode = IRLPT_MODE1;
}
}
else
{
strcpy(pvIasQuery->irdaAttribName, IasAttribName_TTPLsapSel);
}
pvIasQuery->irdaAttribType = 0; // development purposes only
}
else
{
// A getsockopt(IRLMP_IAS_QUERY)
IAS_QUERY *pIasQuery = pIrp->AssociatedIrp.SystemBuffer;
CTEAssert(pIrpSp->FileObject->FsContext2 == (PVOID) TDI_CONTROL_CHANNEL_FILE);
if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(IAS_QUERY))
{
return 1;
}
RtlCopyMemory(pvIasQuery->irdaDeviceID,
pIasQuery->irdaDeviceID,
IRDA_DEV_ADDR_LEN);
strncpy(pvIasQuery->irdaClassName, pIasQuery->irdaClassName, IAS_MAX_CLASSNAME);
strncpy(pvIasQuery->irdaAttribName, pIasQuery->irdaAttribName, IAS_MAX_ATTRIBNAME);
}
IMsg.Prim = IRLMP_GETVALUEBYCLASS_REQ;
IMsg.IRDA_MSG_pIasQuery = pvIasQuery;
IMsg.IRDA_MSG_AttribLen = sizeof(IasBuf) - sizeof(IAS_QUERY);
return IrlmpDown(NULL, &IMsg);
}
VOID
PendingIasRequestCallback(
struct CTEEvent *Event,
PVOID Arg)
{
CTELockHandle hLock;
UINT rc;
CTEGetLock(&IrdaLock, &hLock);
if (pIasIrp != NULL) // Is there an Ias query in progress?
{
CTEFreeLock(&IrdaLock, hLock);
return;
}
while (!IsListEmpty(&IasIrpList)) {
LIST_ENTRY *pListEntry;
PIRP Irp;
PVOID OldCancelRoutine;
pListEntry = RemoveHeadList(&IasIrpList);
Irp=CONTAINING_RECORD(pListEntry, IRP, Tail.Overlay.ListEntry);
Irp->Tail.Overlay.ListEntry.Blink=NULL;
OldCancelRoutine=IoSetCancelRoutine(Irp,NULL);
if (OldCancelRoutine == NULL) {
//
// the irp is in the process of being canceled
//
Irp=NULL;
continue;
}
pIasIrp = Irp;
break;
}
if (pIasIrp == NULL) {
CTEFreeLock(&IrdaLock, hLock);
return;
}
CTEFreeLock(&IrdaLock, hLock);
rc = SendIasQuery(pIasIrp, IoGetCurrentIrpStackLocation(pIasIrp));
if (rc != SUCCESS)
{
IRDA_MSG IMsg;
// Make a fake GetValueByClass confirm
IMsg.Prim = IRLMP_GETVALUEBYCLASS_CONF;
IMsg.IRDA_MSG_IASStatus = IRLMP_IAS_FAILED;
IrlmpGetValueByClassConf(&IMsg);
}
}
NTSTATUS
InitiateIasQuery(
PIRP pIrp,
PIO_STACK_LOCATION pIrpSp,
PIRDA_CONN_OBJ pConn)
{
NTSTATUS Status;
CTELockHandle hLock;
UINT rc;
DEBUGMSG(DBG_TDI, ("IRDA: InitiateIasQuery() \n"));
CTEGetLock(&IrdaLock, &hLock);
// only can send 1 IAS query at a time
if (pIasIrp != NULL) {
PendIrp(&IasIrpList, pIrp, NULL, TRUE);
CTEFreeLock(&IrdaLock, hLock);
} else {
//
// now a current IAS irp
//
pIasIrp = pIrp;
IoMarkIrpPending(pIrp);
CTEFreeLock(&IrdaLock, hLock);
rc = SendIasQuery(pIrp, pIrpSp);
if (rc != SUCCESS) {
//
// failed,
//
Status = ConnectRcToNtStatus(rc);
DEBUGMSG(DBG_ERROR,
("IRDA: IRLMP_GETVALUEBYCLASS_REQ failed, rc %d\n",
rc));
CTEGetLock(&IrdaLock, &hLock);
if ((pIasIrp != NULL) && (pIasIrp == pIrp)) {
pIasIrp = NULL;
// Retry the the connection if this query is for a
// connection setup and the query failed because
// the peer was discovering us
if (!pConn) {
//
// not a connection attempt
//
CTEFreeLock(&IrdaLock, hLock);
pIrp->IoStatus.Status=Status;
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
#if DBG
pIrp=NULL;
#endif
CTEGetLock(&IrdaLock, &hLock);
} else {
if (rc == IRLAP_REMOTE_DISCOVERY_IN_PROGRESS_ERR) {
//
// retry, the irp will either be put on a queue for later processing or
// complete if the retry count has been exceeded
//
CTEFreeLock(&IrdaLock, hLock);
RetryConnection(pConn, pIrp);
} else {
//
// failed for some other reason, just complete
//
CTEFreeLock(&IrdaLock, hLock);
pIrp->IoStatus.Status=Status;
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
#if DBG
pIrp=NULL;
#endif
CTEGetLock(&IrdaLock, &hLock);
}
}
} else {
ASSERT(0);
}
if (!IsListEmpty(&IasIrpList))
{
if (CTEScheduleEvent(&PendingIasEvent, NULL) == FALSE)
{
CTEAssert(0);
}
}
CTEFreeLock(&IrdaLock, hLock);
}
}
return STATUS_PENDING;
}
VOID
IndicateDisconnect(
PIRDA_CONN_OBJ pConn,
ULONG DisconnectFlags)
{
if (pConn->pAddr->pEventDisconnect != NULL) {
if (pConn->pAddr->pEventDisconnect(
pConn->pAddr->pEventDisconnectContext,
pConn->ClientContext, 0, NULL, 0, NULL,
DisconnectFlags) != STATUS_SUCCESS)
{
DEBUGMSG(DBG_ERROR, (" EventDisconnect() failed\r\n"));
ASSERT(0);
}
}
if (DisconnectFlags == TDI_DISCONNECT_ABORT)
{
DEBUGMSG(DBG_TDI, ("IRDA: pConn:%p, indicated abortive disconnect to client %p\n",
pConn, pConn->ClientContext));
TdiDisconnect(NULL, NULL, pConn);
}
else
{
DEBUGMSG(DBG_TDI, ("IRDA: pConn:%p, indicated graceful disconnect to client %p\n",
pConn, pConn->ClientContext));
}
}
NTSTATUS
TdiConnect(
PIRP pIrp,
PIO_STACK_LOCATION pIrpSp)
{
PTDI_CONNECTION_INFORMATION pReqConnInfo, pRetConnInfo;
PTDI_REQUEST_KERNEL_CONNECT pTdiParmsConn;
PIRDA_CONN_OBJ pConn = pIrpSp->FileObject->FsContext;
PTRANSPORT_ADDRESS pTranAddr;
PTDI_ADDRESS_IRDA pIrdaAddr;
NTSTATUS Status;
int RemLsapSel;
CTEAssert((UINT_PTR) pIrpSp->FileObject->FsContext2 == TDI_CONNECTION_FILE);
CTEAssert(IS_VALID_CONN(pConn));
CTEAssert(pConn->ConnState == IRDA_CONN_CREATED ||
pConn->ConnState == IRDA_CONN_OPENING);
pTdiParmsConn = (PTDI_REQUEST_KERNEL_CONNECT) &(pIrpSp->Parameters);
pReqConnInfo = pTdiParmsConn->RequestConnectionInformation;
pTranAddr = (PTRANSPORT_ADDRESS) pReqConnInfo->RemoteAddress;
pIrdaAddr = (PTDI_ADDRESS_IRDA) pTranAddr->Address[0].Address;
CTEAssert(pTranAddr->TAAddressCount == 1);
// Will either complete the Irp now with one of the following errors:
// (see InitiateConnection/InitiateIasQuery)
//
// LsapSel already in use or link in exclusive mode:
// WSAEADDRINUSE - STATUS_ADDRESS_ALREADY_EXISTS
// Link in use:
// WSAEACCESS - STATUS_ACCESS_DENIED
// Unspecified error:
// WSAECONNABORTED - STATUS_CONNECTION_ABORTED
// Request to device that is not in Irlmp's discovery list
// WSAEADDRNOTAVAIL - STATUS_INVALID_ADDRESS_COMPONENT
// Blank service name:
// WASEAFAULT - STATUS_ACCESS_VIOLATION
//
// or pend the irp and complete with (see CompleteConnection):
//
// Connect request to disconnected LSAP:
// WSAECONNREFUSED - STATUS_CONNECTION_REFUSED
// Mac media busy or remote discovery in progress &
// Remote Lsap respsonse timeout:
// WSAETIMEDOUT
// Unspecified error:
// WSAECONNABORTED - STATUS_CONNECTION_ABORTED
DEBUGMSG(DBG_TDI, ("IRDA: TdiConnect(retry:%d) ConnObj:%p to Dev:%02X%02X%02X%02X Service:%s\n",
pConn->RetryConnCount, pConn,
pIrdaAddr->irdaDeviceID[0],
pIrdaAddr->irdaDeviceID[1],
pIrdaAddr->irdaDeviceID[2],
pIrdaAddr->irdaDeviceID[3],
pIrdaAddr->irdaServiceName));
// Two ways to connect to remote:
// 1. Directly to remote LsapSel - remote address is of the form
// "LSAP-SELx" where x is the remote LsapSel. Initiate an
// IrLMP connection and pend the Irp on the ConnIrpList
// 2. To a remote service. Query the remote IAS database for the
// LsapSel of the given service. Pend the Irp on the IasIrpList.
// When the Ias query completes, initiate an IrLMP connection and
// pend the Irp on the ConnIrpList.
pConn->RetryConnCount += 1;
RtlCopyMemory(pConn->RemoteAddr.irdaDeviceID,
pIrdaAddr->irdaDeviceID, IRDA_DEV_ADDR_LEN);
strcpy(pConn->RemoteAddr.irdaServiceName,
pIrdaAddr->irdaServiceName);
pConn->ConnState = IRDA_CONN_OPENING;
if (pIrdaAddr->irdaServiceName[0] == 0)
{
Status = STATUS_ACCESS_VIOLATION;
}
else if (pConn->IsServer)
{
Status = STATUS_INVALID_DEVICE_REQUEST;
}
else if ((RemLsapSel =
GetLsapSelServiceName(pIrdaAddr->irdaServiceName)) != 0)
{
if (RemLsapSel == -1)
{
DEBUGMSG(DBG_TDI, ("IRDA: TdiConnect() failed, bad LsapSel in service name\n"));
Status = STATUS_INVALID_ADDRESS_COMPONENT;
}
else
{
pConn->RemoteLsapSel = RemLsapSel;
Status = InitiateConnection(pConn, pIrp);
}
}
else
{
Status = InitiateIasQuery(pIrp, pIrpSp, pConn);
}
if (Status != STATUS_PENDING)
{
pConn->ConnState = IRDA_CONN_CREATED;
pIrp->IoStatus.Status = Status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
}
return Status;
}
//*************************************************************************
//
// Irda's disconnect handler. If passed a connection object, then this is
// a disconnect generated internally by the stack. Otherwise called by
// client to disconnect peer.
// This isolates the cleanup code.
NTSTATUS
TdiDisconnect(
PIRP pIrp,
PIO_STACK_LOCATION pIrpSp,
PIRDA_CONN_OBJ pConn)
{
CTELockHandle hLock;
PTDI_REQUEST_KERNEL_DISCONNECT pReqDisc = NULL;
if (!pConn)
{
// AFD initated, connection object in the Irp
CTEAssert(pIrp);
pConn = pIrpSp->FileObject->FsContext;
pReqDisc = (PTDI_REQUEST_KERNEL_DISCONNECT) &pIrpSp->Parameters;
}
DEBUGMSG(DBG_TDI, ("IRDA: TdiDisconnect(%s) ConnObj:%p State %d Irlmp:%p\n",
pIrp ? "external":"internal", pConn, pConn->ConnState, pConn->IrlmpContext));
CTEAssert(IS_VALID_CONN(pConn));
GET_CONN_LOCK(pConn, &hLock);
ConnectionUp(pConn, FALSE);
while (!IsListEmpty(&pConn->RecvBufList))
{
LIST_ENTRY *pListEntry;
PIRDA_RECV_BUF pRecvBuf;
pListEntry = RemoveHeadList(&pConn->RecvBufList);
ASSERT(pListEntry);
pRecvBuf = CONTAINING_RECORD(pListEntry, IRDA_RECV_BUF, Linkage);
FreeIrdaBuf(RecvBufPool, pRecvBuf);
}
pConn->ConnState = IRDA_CONN_CREATED;
FREE_CONN_LOCK(pConn, hLock);
IrdaDisconnectIrlmp(pConn);
if (pIrp)
{
// Indicate the disconnect back to the client
// This is because we don't support half close.
// so AFD may hang the app if the app has done
// a shutdown(SD_SEND). Really, AFD should handle
// this correctly because I don't support
// TDI_SERVICE_ORDERLY_RELEASE. Vadim admits that
// AFD should handle this but he doesn't want to
// break legacy transports.
if (pConn->pAddr->pEventDisconnect != NULL) {
pConn->pAddr->pEventDisconnect(
pConn->pAddr->pEventDisconnectContext,
pConn->ClientContext, 0, NULL, 0, NULL,
TDI_DISCONNECT_ABORT);
}
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
}
return STATUS_SUCCESS;
}
NTSTATUS
TdiSend(
PIRP pIrp,
PIO_STACK_LOCATION pIrpSp)
{
PIRDA_CONN_OBJ pConn = pIrpSp->FileObject->FsContext;
CTELockHandle hLock;
NTSTATUS Status;
CTEAssert(((UINT_PTR) pIrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
CTEAssert(IS_VALID_CONN(pConn));
// IrLMP likes passive level only
if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
{
DEBUGMSG(DBG_TDI, ("IRDA: TdiSend() at DISPATCH_LEVEL\n"));
GET_CONN_LOCK(pConn, &hLock);
PendIrp(&pConn->SendIrpPassiveList, pIrp, pConn, TRUE);
#if DBG
pIrp=NULL;
#endif
Status=STATUS_PENDING;
if (CTEScheduleEvent(&pConn->SendEvent, pConn) == FALSE) {
LIST_ENTRY *pListEntry;
pListEntry = RemoveHeadList(&pConn->SendIrpPassiveList);
pIrp = CONTAINING_RECORD(pListEntry, IRP, Tail.Overlay.ListEntry);
if (IoSetCancelRoutine(pIrp, NULL) == NULL) {
//
// Cancel routine is going to run. Mark Irp so cancel
// routine won't attempt to remove it from the list
//
pIrp->Tail.Overlay.ListEntry.Flink = NULL;
} else {
pIrp->IoStatus.Status=STATUS_UNEXPECTED_NETWORK_ERROR;
FREE_CONN_LOCK(pConn, hLock);
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
#if DBG
pIrp=NULL;
#endif
GET_CONN_LOCK(pConn, &hLock);
}
ASSERT(0);
}
FREE_CONN_LOCK(pConn, hLock);
if (Status != STATUS_PENDING)
{
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = Status;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
}
return Status;
}
else
{
return TdiSendAtPassive(pIrp, pIrpSp);
}
}
VOID
TdiSendAtPassiveCallback(struct CTEEvent *Event, PVOID Arg)
{
PIRDA_CONN_OBJ pConn = Arg;
CTELockHandle hLock;
LIST_ENTRY *pListEntry;
PIRP pIrp;
CTEAssert(IS_VALID_CONN(pConn));
GET_CONN_LOCK(pConn, &hLock);
while (!IsListEmpty(&pConn->SendIrpPassiveList))
{
pListEntry = RemoveHeadList(&pConn->SendIrpPassiveList);
ASSERT(pListEntry);
pIrp = CONTAINING_RECORD(pListEntry, IRP, Tail.Overlay.ListEntry);
if (IoSetCancelRoutine(pIrp, NULL) == NULL)
{
// Cancel routine is going to run. Mark Irp so cancel
// routine won't attempt to remove it from the list
pIrp->Tail.Overlay.ListEntry.Flink = NULL;
CTEFreeLock(&IrdaLock, hLock);
continue;
}
FREE_CONN_LOCK(pConn, hLock);
TdiSendAtPassive(pIrp, IoGetCurrentIrpStackLocation(pIrp));
GET_CONN_LOCK(pConn, &hLock);
}
FREE_CONN_LOCK(pConn, hLock);
}
NTSTATUS
TdiSendAtPassive(
PIRP pIrp,
PIO_STACK_LOCATION pIrpSp)
{
PTDI_REQUEST_KERNEL_SEND pSendParms = (PTDI_REQUEST_KERNEL_SEND) &pIrpSp->Parameters;
PIRDA_CONN_OBJ pConn = pIrpSp->FileObject->FsContext;
NTSTATUS Status;
IRDA_MSG *pMsg;
CTEAssert(((UINT_PTR) pIrpSp->FileObject->FsContext2) == TDI_CONNECTION_FILE);
CTEAssert(IS_VALID_CONN(pConn));
if (pConn->pAddr->UseIrlptMode &&
pSendParms->SendLength > (ULONG)pConn->SendMaxSDU)
{
DEBUGMSG(DBG_ERROR, ("IRDA: TdiSend() error buffer overflow, max %d\n",
pConn->SendMaxSDU));
Status = STATUS_BUFFER_OVERFLOW;
}
else if (!pSendParms->SendLength)
{
DEBUGMSG(DBG_ERROR, ("IRDA: TdiSend() length of 0\n"));
Status = STATUS_SUCCESS;
}
else if (pConn->ConnState != IRDA_CONN_OPEN)
{
DEBUGMSG(DBG_TDI, ("IRDA: TdiSend() ConnObj:%p error conn reset\n",
pConn));
Status = STATUS_CONNECTION_RESET; //STATUS_CONNECTION_ABORTED;
if (pConn->ConnState == IRDA_CONN_CLOSING)
{
DEBUGMSG(DBG_ERROR, ("IRDA: Send after indicated disconnect, indicate abortive disconnect\n"));
// We've indicated a graceful disconnect to AFD, but AFD
// was in the middle of sending. Because Irda doesn't support
// graceful closes, we have to now indicate an abortive
// disconnect to AFD.
IndicateDisconnect(pConn, TDI_DISCONNECT_ABORT);
}
}
else if ((pMsg = AllocIrdaBuf(IrdaMsgPool)) == NULL)
{
DEBUGMSG(DBG_TDI, ("IRDA: TdiSend() ConnObj:%p returning STATUS_INSUFFICIENT_RESOURCES\n",
pConn));
Status = STATUS_INSUFFICIENT_RESOURCES;
}
else
{
UINT rc;
CTELockHandle hLock;
// We can't allow the cancelling of send IRPs because
// the stack may have passed ownership of the MDL contained
// in this IRP to the NDIS driver.
GET_CONN_LOCK(pConn, &hLock);
InsertTailList(&pConn->SendIrpList, &pIrp->Tail.Overlay.ListEntry);
IoMarkIrpPending(pIrp);
FREE_CONN_LOCK(pConn, hLock);
Status = STATUS_PENDING;
pIrp->IoStatus.Information = pSendParms->SendLength;
DEBUGMSG(DBG_TDI, ("IRDA: TdiSend() ConnObj:%p %d bytes, pend Irp:%p\n",
pConn, pSendParms->SendLength, pIrp));
pMsg->Prim = IRLMP_DATA_REQ;
pMsg->DataContext = pIrp->MdlAddress;
pMsg->IRDA_MSG_pTdiSendCompCnxt = pIrp;
pMsg->IRDA_MSG_IrCOMM_9Wire = pConn->pAddr->Use9WireMode;
if ((rc = IrlmpDown(pConn->IrlmpContext, pMsg)) != SUCCESS)
{
DEBUGMSG(DBG_ERROR, ("IRDA: IRLMP_DATA_REQ failed %d\n", rc));
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = STATUS_CONNECTION_RESET;
GET_CONN_LOCK(pConn, &hLock);
RemoveEntryList(&pIrp->Tail.Overlay.ListEntry);
FREE_CONN_LOCK(pConn, hLock);
//
// complete it now
//
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
pIrp=NULL;
FreeIrdaBuf(IrdaMsgPool, pMsg);
}
return STATUS_PENDING;
}
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = Status;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
return Status;
}
//*************************************************************************
//
// Irda's receive handler. Called to resume receiving of data after AFD
// or client has stopped taking indicated data (see IrlmpDataInd).
// Data will have been buffered on the connection's RecvBufList.
//
NTSTATUS
TdiReceive(
PIRP pIrp,
PIO_STACK_LOCATION pIrpSp)
{
PTDI_REQUEST_KERNEL_RECEIVE pRecvReq;
PIRDA_CONN_OBJ pConn = pIrpSp->FileObject->FsContext;
ULONG BytesTaken = 0;
CTELockHandle hLock;
PIRDA_RECV_BUF pRecvBuf;
LIST_ENTRY *pListEntry, *pListEntryNext;
NTSTATUS Status= STATUS_SUCCESS;
PIRDA_ADDR_OBJ pAddr;
DEBUGMSG(DBG_TDI, ("IRDA: TdiReceive() ConnObj:%p. credits=%d\n", pConn, pConn->TtpRecvCreditsLeft));
CTEAssert(IS_VALID_CONN(pConn));
pAddr = pConn->pAddr;
CTEAssert(IS_VALID_ADDR(pAddr));
GET_CONN_LOCK(pConn, &hLock);
pRecvReq = (PTDI_REQUEST_KERNEL_RECEIVE) &(pIrpSp->Parameters);
if (!IsListEmpty(&pConn->RecvBufList)) {
//
// the list is not empty
//
pListEntry = RemoveHeadList(&pConn->RecvBufList);
pRecvBuf = CONTAINING_RECORD(pListEntry, IRDA_RECV_BUF, Linkage);
//
// copy what we can
//
Status=TdiCopyBufferToMdl(&pRecvBuf->Data[0],
pRecvBuf->Offset,
pRecvBuf->Len,
pIrp->MdlAddress,
0,
&BytesTaken
);
if (Status != STATUS_SUCCESS) {
//
// some sort of problem
//
if (Status == STATUS_BUFFER_OVERFLOW) {
//
// the irp could no hold all the data, need to adjust the recvbuf
// values to indace what is left
//
pRecvBuf->Len -= BytesTaken;
pRecvBuf->Offset += BytesTaken;
//
// need to put it back on the list
//
InsertHeadList(&pConn->RecvBufList, pListEntry);
DEBUGMSG(DBG_TDI, (" RecvBuf copied only %d of %d\n",
BytesTaken, pRecvBuf->Len));
} else {
//
// could not get a system address for the mdl, just return the status
//
InsertHeadList(&pConn->RecvBufList, pListEntry);
BytesTaken=0;
DEBUGMSG(DBG_TDI, (" RecvBuf could not map MDL\n"));
}
} else {
//
// copied it all
//
DEBUGMSG(DBG_TDI, (" RecvBuf %p copied all %d\n", pRecvBuf, BytesTaken));
}
FREE_CONN_LOCK(pConn, hLock);
pIrp->IoStatus.Information = BytesTaken;
pIrp->IoStatus.Status = Status;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
pIrp=NULL;
GET_CONN_LOCK(pConn, &hLock);
}
else
{
DEBUGMSG(DBG_ERROR, ("IRDA: Pending TDI_RECEIVE Irp %p\n", pIrp));
PendIrp(&pConn->RecvIrpList, pIrp, pConn, TRUE);
pIrp=NULL;
Status=STATUS_PENDING;
FREE_CONN_LOCK(pConn, hLock);
return Status;
}
// Still more buffered data, indicate to client through EventReceive handler
while (!(IsListEmpty(&pConn->RecvBufList)) && Status != STATUS_DATA_NOT_ACCEPTED)
{
pListEntry = RemoveHeadList(&pConn->RecvBufList);
FREE_CONN_LOCK(pConn, hLock);
pRecvBuf = CONTAINING_RECORD(pListEntry, IRDA_RECV_BUF, Linkage);
Status = pAddr->pEventReceive(
pAddr->pEventReceiveContext,
pConn->ClientContext,
TDI_RECEIVE_NORMAL | \
(pRecvBuf->FinalSeg ? TDI_RECEIVE_ENTIRE_MESSAGE : 0),
pRecvBuf->Len,
pRecvBuf->Len,
&BytesTaken,
&pRecvBuf->Data[pRecvBuf->Offset],
&pIrp);
DEBUGMSG(DBG_TDI, (" Next RecvBuf %p, indicated %d\n",
pRecvBuf, pRecvBuf->Len));
switch (Status)
{
case STATUS_MORE_PROCESSING_REQUIRED:
CTEAssert(BytesTaken == 0);
CTEAssert(pIrp);
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
pRecvReq = (PTDI_REQUEST_KERNEL_RECEIVE) &pIrpSp->Parameters;
CTEAssert(pRecvReq->ReceiveLength >= pRecvBuf->Len);
TdiCopyBufferToMdl(
&pRecvBuf->Data[pRecvBuf->Offset],
0,
pRecvBuf->Len,
pIrp->MdlAddress,
0,
&BytesTaken);
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = BytesTaken;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
// fall through
case STATUS_SUCCESS:
CTEAssert(BytesTaken == pRecvBuf->Len);
FreeIrdaBuf(RecvBufPool, pRecvBuf);
DEBUGMSG(DBG_TDI, (" RecvBuf copied %d\n", BytesTaken));
break;
case STATUS_DATA_NOT_ACCEPTED:
CTEAssert(BytesTaken == 0);
DEBUGMSG(DBG_TDI, (" No bytes taken\n"));
GET_CONN_LOCK(pConn, &hLock);
InsertHeadList(&pConn->RecvBufList, pListEntry);
FREE_CONN_LOCK(pConn, hLock);
break;
default:
CTEAssert(0);
}
GET_CONN_LOCK(pConn, &hLock);
}
// Has the client taken all buffered data?
if (IsListEmpty(&pConn->RecvBufList))
{
CTEAssert(pConn->RecvBusy)
pConn->RecvBusy = FALSE;
if (pConn->ConnState == IRDA_CONN_OPEN)
{
// Start up peer again
if (pConn->TtpRecvCreditsLeft <= TTP_CREDIT_ADVANCE_THRESH)
{
IRDA_MSG IMsg;
int CreditsLeft;
CreditsLeft = pConn->TtpRecvCreditsLeft;
pConn->TtpRecvCreditsLeft = TTP_RECV_CREDITS;
FREE_CONN_LOCK(pConn, hLock);
IMsg.Prim = IRLMP_MORECREDIT_REQ;
IMsg.IRDA_MSG_TtpCredits = TTP_RECV_CREDITS - CreditsLeft;
#if DBG
pConn->CreditsExtended += (TTP_RECV_CREDITS - CreditsLeft);
#endif
IrlmpDown(pConn->IrlmpContext, &IMsg);
return STATUS_SUCCESS;
}
}
else if (pConn->ConnState == IRDA_CONN_CLOSING)
{
ULONG DiscFlags = TDI_DISCONNECT_RELEASE;
if (!IsListEmpty(&pConn->SendIrpList))
{
DEBUGMSG(DBG_TDI, (" SendIrpList not empty, indicate abortive disconnect\n"));
DiscFlags = TDI_DISCONNECT_ABORT;
}
FREE_CONN_LOCK(pConn, hLock);
// all buffer data has been delivered for the connection
// that has was previously disconnected by the peer. Notify client
// of the disconnect
IndicateDisconnect(pConn, DiscFlags);
return STATUS_SUCCESS;
}
}
FREE_CONN_LOCK(pConn, hLock);
return STATUS_SUCCESS;
}
ULONG
GetMdlChainByteCount(
PMDL pMdl)
{
ULONG Count = 0;
while (pMdl != NULL)
{
Count += MmGetMdlByteCount(pMdl);
pMdl = pMdl->Next;
}
return(Count);
}
//*************************************************************************
//
// Copy discovered device information from internal buffer to
// user buffer in Winsock format (extracting hints and characters
// set)
//
VOID
CopyDevToDevInfo(PIRDA_DEVICE_INFO pDevInfo, IRDA_DEVICE *pDevice)
{
BOOLEAN GotHint1 = FALSE;
BOOLEAN GotHint2 = FALSE;
BOOLEAN GotChar = FALSE;
BOOLEAN MoreHints = FALSE;
int i, j;
RtlCopyMemory(pDevInfo->irdaDeviceID,pDevice->DevAddr, IRDA_DEV_ADDR_LEN);
CTEMemSet(pDevInfo->irdaDeviceName, 0, sizeof(pDevInfo->irdaDeviceName));
pDevInfo->irdaDeviceHints1 = 0;
pDevInfo->irdaDeviceHints2 = 0;
pDevInfo->irdaCharSet = 0;
j = 0;
for (i = 0; i < pDevice->DscvInfoLen; i++)
{
if (GotHint1 == FALSE)
{
GotHint1 = TRUE;
pDevInfo->irdaDeviceHints1 = pDevice->DscvInfo[i];
if ((pDevInfo->irdaDeviceHints1) & 0x80)
MoreHints = TRUE;
continue;
}
if (GotHint2 == FALSE && MoreHints)
{
GotHint2 = TRUE;
pDevInfo->irdaDeviceHints2 = pDevice->DscvInfo[i];
if ((pDevInfo->irdaDeviceHints2) & 0x80)
MoreHints = TRUE;
else
MoreHints = FALSE;
continue;
}
if (MoreHints)
{
if ((pDevice->DscvInfo[i]) & 0x80)
MoreHints = TRUE;
else
MoreHints = FALSE;
continue;
}
if (GotChar == FALSE)
{
GotChar = TRUE;
pDevInfo->irdaCharSet = pDevice->DscvInfo[i];
continue;
}
pDevInfo->irdaDeviceName[j++] = pDevice->DscvInfo[i];
if (j > sizeof(pDevInfo->irdaDeviceName))
break;
}
}
//*************************************************************************
//
// Run through the ConnIrpList and find the Irp associated with the
// given connection object
//
PIRP
GetIrpOnConnIrpList(PIRDA_CONN_OBJ pConn)
{
PIRDA_CONN_OBJ pConnOnList;
CTELockHandle hLock;
PIO_STACK_LOCATION pIrpSp;
LIST_ENTRY *pListEntry;
PIRP pIrp = NULL;
CTEGetLock(&IrdaLock, &hLock);
// Remove the connect irp from the ConnIrpList
for (pListEntry = ConnIrpList.Flink;
pListEntry != &ConnIrpList;
pListEntry = pListEntry->Flink)
{
pIrp = CONTAINING_RECORD(pListEntry, IRP, Tail.Overlay.ListEntry);
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
pConnOnList = (PIRDA_CONN_OBJ) pIrpSp->FileObject->FsContext;
if (pConnOnList == pConn) {
break;
}
pIrp = NULL;
}
if (pIrp != NULL) {
//
// we got a irp
//
#if DBG
pIrp->IoStatus.Information=0;
#endif
if (IoSetCancelRoutine(pIrp, NULL) == NULL) {
// It was already cancelled or is in the process
DEBUGMSG(DBG_TDI, ("IRDA: Connect Irp not on list, must have been cancelled\n"));
pIrp=NULL;
} else {
RemoveEntryList(&pIrp->Tail.Overlay.ListEntry);
}
}
CTEFreeLock(&IrdaLock, hLock);
return pIrp;
}
//*************************************************************************
//
// TimerExpiration routine to retry a connection attempt do to
// remote discovery in progress
//
VOID
RetryConnTimerExp(PVOID Context)
{
PIRDA_CONN_OBJ pConn = Context;
PIRP pIrp;
DEBUGMSG(DBG_TDI, ("IRDA: RetryConnect timer expired\n"));
if (pIrp = GetIrpOnConnIrpList(pConn))
{
TdiConnect(pIrp, IoGetCurrentIrpStackLocation(pIrp));
}
REFDEL(&pConn->RefCnt, 'RMIT');
}
//************************************************************************
//
// RetryConnection if remote discovery in progress.
// Returns:
// STATUS_PENDING - a retry will be attempted. The Irp is placed on the
// ConnIrpList.
// STATUS_CANCELLED - the Irp could not be pended because it was cancelled
// STATUS_IO_TIMEOUT - no more retries left.
//
VOID
RetryConnection(PIRDA_CONN_OBJ pConn, PIRP pIrp)
{
CTELockHandle hLock;
NTSTATUS Status = STATUS_IO_TIMEOUT;
IoMarkIrpPending(pIrp);
if (pConn->RetryConnCount <= BUSY_LINK_CONN_RETRIES)
{
DEBUGMSG(DBG_TDI, ("IRDA: Media busy or remote dscv in progress, retry(%d) connection\n",
pConn->RetryConnCount));
IrdaDisconnectIrlmp(pConn);
#if DBG
pIrp->IoStatus.Information=2;
#endif
PendIrp(&ConnIrpList, pIrp, NULL, FALSE);
Status=STATUS_PENDING;
pConn->RetryConnTimer.Context = pConn;
REFADD(&pConn->RefCnt, 'RMIT');
IrdaTimerStart(&pConn->RetryConnTimer);
} else {
pIrp->IoStatus.Status = Status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
}
return;
}
//*************************************************************************
//
// Asyncronous completetion of a client connection request.
// This routine also completes a failed connection.
//
VOID
CompleteConnection(PIRDA_CONN_OBJ pConn, IRDA_MSG *pMsg)
{
PIRP pIrp;
BOOLEAN RetryConn = FALSE;
if ((pIrp = GetIrpOnConnIrpList(pConn)) == NULL)
{
DbgPrint("IRDA: CompleteConnection: could not find irp\n");
ASSERT(pIrp);
}
else
{
if (pMsg->Prim == IRLMP_DISCONNECT_IND)
{
pConn->ConnState = IRDA_CONN_CREATED;
switch (pMsg->IRDA_MSG_DiscReason)
{
case IRLMP_DISC_LSAP:
// WSAECONNREFUSED
pIrp->IoStatus.Status = STATUS_CONNECTION_REFUSED;
break;
case IRLMP_IRLAP_REMOTE_DISCOVERY_IN_PROGRESS:
case IRLMP_MAC_MEDIA_BUSY:
RetryConn = TRUE;
case IRLMP_IRLAP_CONN_FAILED:
case IRLMP_NO_RESPONSE_LSAP:
// WASETIMEDOUT
pIrp->IoStatus.Status = STATUS_IO_TIMEOUT;
break;
default:
// WSECONNABORTED
pIrp->IoStatus.Status = STATUS_CONNECTION_RESET; //STATUS_CONNECTION_ABORTED;
}
if (RetryConn) {
//
// the irp will be queued or complete, by this function
//
RetryConnection(pConn, pIrp);
return;
}
}
else // IRLMP_CONNECT_CONF
{
pConn->SendMaxSDU = pMsg->IRDA_MSG_MaxSDUSize;
pConn->SendMaxPDU = pMsg->IRDA_MSG_MaxPDUSize;
pConn->ConnState = IRDA_CONN_OPEN;
pIrp->IoStatus.Status = STATUS_SUCCESS;
DEBUGMSG(DBG_TDI, ("IRDA: Completing TdiConnect co:%p\n", pConn));
ConnectionUp(pConn, TRUE);
}
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
}
}
//*************************************************************************
//
//
//
VOID
CompleteDscvIrpList(LIST_ENTRY *pIrpList, IRDA_MSG *pMsg)
{
PIO_STACK_LOCATION pIrpSp;
PDEVICELIST pDevList;
PIRP pIrp;
LIST_ENTRY *pListEntry;
ULONG BytesWritten;
ULONG BufLen;
IRDA_DEVICE *pDevice;
ULONG DevCnt;
NTSTATUS Status;
CTELockHandle hLock;
CTEGetLock(&IrdaLock, &hLock);
while (!IsListEmpty(pIrpList)) {
pListEntry = RemoveHeadList(pIrpList);
pIrp = CONTAINING_RECORD(pListEntry, IRP, Tail.Overlay.ListEntry);
if (IoSetCancelRoutine(pIrp, NULL) == NULL) {
//
// Cancel routine is going to run. Mark Irp so cancel
// routine won't attempt to remove it from the list
//
pIrp->Tail.Overlay.ListEntry.Flink = NULL;
} else {
//
// not canceled
//
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
pDevList = pIrp->AssociatedIrp.SystemBuffer;
BufLen = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
if (BufLen < sizeof(IRDA_DEVICE_INFO))
{
DEBUGMSG(DBG_DISCOVERY, ("IRDA: IRLMP_DISCOVERY_REQ failed, buf too small\n"));
BytesWritten = 0;
Status = STATUS_BUFFER_TOO_SMALL;
}
else if (pMsg->IRDA_MSG_DscvStatus != IRLAP_DISCOVERY_COMPLETED)
{
DEBUGMSG(DBG_DISCOVERY, ("IRDA: IRLMP_DISCOVERY_REQ failed\n"));
BytesWritten = 0;
Status = STATUS_UNEXPECTED_NETWORK_ERROR;
}
else
{
//
// start with the device count at the begining of the list
//
BytesWritten = sizeof(pDevList->numDevice);
DevCnt = 0;
if (pMsg->IRDA_MSG_pDevList != NULL)
{
for (pDevice = (IRDA_DEVICE * ) pMsg->IRDA_MSG_pDevList->Flink;
(LIST_ENTRY *) pDevice != pMsg->IRDA_MSG_pDevList;
pDevice = (IRDA_DEVICE *) pDevice->Linkage.Flink)
{
if (BufLen < (BytesWritten + sizeof(IRDA_DEVICE_INFO)))
{
DEBUGMSG(DBG_ERROR, ("IRDA: Found more devices, but user buffer too small.\n"));
break;
}
CopyDevToDevInfo(&pDevList->Device[DevCnt], pDevice);
BytesWritten += sizeof(IRDA_DEVICE_INFO);
DevCnt++;
}
}
pDevList->numDevice = DevCnt;
Status = STATUS_SUCCESS;
}
CTEFreeLock(&IrdaLock, hLock);
pIrp->IoStatus.Status = Status;
pIrp->IoStatus.Information = BytesWritten;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
CTEGetLock(&IrdaLock, &hLock);
}
}
CTEFreeLock(&IrdaLock, hLock);
}
//*************************************************************************
//
// Process IRMLP_DISCOVERY_CONFIRM - Completes client discovery
// request Irp stored on DscvIrpList
//
VOID
IrlmpDiscoveryConf(IRDA_MSG *pMsg)
{
CTELockHandle hLock;
DEBUGMSG(DBG_DISCOVERY, ("IRDA: IRLMP_DISCOVERY_CONF\n"));
// Complete regular discovery Irp list
CompleteDscvIrpList(&DscvIrpList, pMsg);
CTEGetLock(&IrdaLock, &hLock);
// Complete lazy discoveries if device list has changed
if (!IsListEmpty(&LazyDscvIrpList))
{
IRDA_DEVICE *pDevice;
UINT CurrLazyDscvMacAddrs = 0;
// Lazy discovery Irps are completed if the newly discovered
// device list has changed since the last discovery.
// We determine that the device list has changed by storing
// the value of the Mac addresses added together from the
// last discovery
if (pMsg->IRDA_MSG_DscvStatus == IRLAP_DISCOVERY_COMPLETED)
{
for (pDevice = (IRDA_DEVICE * ) pMsg->IRDA_MSG_pDevList->Flink;
(LIST_ENTRY *) pDevice != pMsg->IRDA_MSG_pDevList;
pDevice = (IRDA_DEVICE *) pDevice->Linkage.Flink)
{
CurrLazyDscvMacAddrs += *(UINT*)pDevice->DevAddr;
}
if (CurrLazyDscvMacAddrs == LazyDscvMacAddrs)
{
CTEFreeLock(&IrdaLock, hLock);
return;
}
LazyDscvMacAddrs = CurrLazyDscvMacAddrs;
}
LazyDscvTimerRunning = FALSE;
CTEFreeLock(&IrdaLock, hLock);
IrdaTimerStop(&LazyDscvTimer);
CompleteDscvIrpList(&LazyDscvIrpList, pMsg);
CTEGetLock(&IrdaLock, &hLock);
}
CTEFreeLock(&IrdaLock, hLock);
}
//*************************************************************************
//
// Process IRLMP_CONNECT_IND. Call client connect handler if we find
// matching address object
//
VOID
IrlmpConnectInd(IRDA_MSG *pMsg)
{
PIRDA_ADDR_OBJ pAddr;
CTELockHandle hLock;
IRDA_MSG IMsg;
PIRDA_CONN_OBJ pConn;
BOOLEAN AcceptConnection = FALSE;
PIRP pAcceptIrp = NULL;
DEBUGMSG(DBG_TDI, ("IRDA: IRLMP_CONNECT_IND\n"));
// Get the LinkStatus immediately so we'll have the link speed
// when we indicate the incoming connection to RasIrda which
// immediately requests link speed through an ioctl.
IMsg.Prim = IRLAP_STATUS_REQ;
IMsg.IRDA_MSG_pLinkStatus = &LinkStatus;
IrlmpDown(pMsg->IRDA_MSG_pContext, &IMsg);
CTEGetLock(&IrdaLock, &hLock);
// Find the address object with LocalLsapSel that matches
// the one in the CONNECT_IND
for (pAddr = AddrObjList; pAddr != NULL; pAddr = pAddr->pNext)
{
if (pAddr->LocalLsapSel == pMsg->IRDA_MSG_LocalLsapSel)
break;
}
CTEFreeLock(&IrdaLock, hLock);
if (pAddr && pAddr->pEventConnect)
{
UCHAR RemAddrBuf[sizeof(TRANSPORT_ADDRESS) + sizeof(TDI_ADDRESS_IRDA)-1];
PTRANSPORT_ADDRESS pRemAddr = (PTRANSPORT_ADDRESS) RemAddrBuf;
PTDI_ADDRESS_IRDA pIrdaAddr = (PTDI_ADDRESS_IRDA) pRemAddr->Address[0].Address;
NTSTATUS Status;
CONNECTION_CONTEXT ClientContext;
pRemAddr->TAAddressCount = 1;
pRemAddr->Address[0].AddressLength = sizeof(SOCKADDR_IRDA) - 2;
pRemAddr->Address[0].AddressType = AF_IRDA;
RtlCopyMemory(pIrdaAddr->irdaDeviceID,
pMsg->IRDA_MSG_RemoteDevAddr,
IRDA_DEV_ADDR_LEN);
SetLsapSelAddr(pMsg->IRDA_MSG_RemoteLsapSel,
pIrdaAddr->irdaServiceName);
Status = pAddr->pEventConnect(
pAddr->pEventConnectContext,
sizeof(RemAddrBuf),
pRemAddr,
0, NULL, 0, NULL,
&ClientContext,
&pAcceptIrp);
if (Status != STATUS_MORE_PROCESSING_REQUIRED)
{
DEBUGMSG(DBG_ERROR, ("IRDA: EventConnect failed %X\n", Status));
}
else
{
ASSERT(pAcceptIrp);
CTEGetLock(&IrdaLock, &hLock);
for (pConn = pAddr->ConnObjList;
pConn != NULL;
pConn = pConn->pNext)
{
if (pConn->ClientContext == ClientContext)
break;
}
if (!pConn)
{
CTEAssert(0);
pAcceptIrp->IoStatus.Status = STATUS_INVALID_ADDRESS_COMPONENT;
CTEFreeLock(&IrdaLock, hLock);
IoCompleteRequest (pAcceptIrp, IO_NETWORK_INCREMENT);
}
else
{
ASSERT(pConn->ConnState == IRDA_CONN_CREATED);
pConn->ConnState = IRDA_CONN_OPEN;
pConn->RemoteLsapSel = pMsg->IRDA_MSG_RemoteLsapSel;
pConn->SendMaxSDU = pMsg->IRDA_MSG_MaxSDUSize;
pConn->SendMaxPDU = pMsg->IRDA_MSG_MaxPDUSize;
pConn->IrlmpContext = pMsg->IRDA_MSG_pContext;
pConn->TtpRecvCreditsLeft = TTP_RECV_CREDITS;
/* IRDA_MSG_pQOS ignored */
RtlCopyMemory(&pConn->RemoteAddr,
pIrdaAddr, sizeof(TDI_ADDRESS_IRDA));
pAcceptIrp->IoStatus.Status = STATUS_SUCCESS;
CTEFreeLock(&IrdaLock, hLock);
IoCompleteRequest (pAcceptIrp, IO_NETWORK_INCREMENT);
DEBUGMSG(DBG_TDI, (" ConnObj:%p connected, Loc:%s,%d Rem:%s,%d\n",
pConn,
pConn->LocalAddr.irdaServiceName,
pConn->LocalLsapSel,
pConn->RemoteAddr.irdaServiceName,
pConn->RemoteLsapSel));
AcceptConnection = TRUE;
}
}
}
if (AcceptConnection)
{
IMsg.Prim = IRLMP_CONNECT_RESP;
IMsg.IRDA_MSG_pConnData = NULL;
IMsg.IRDA_MSG_ConnDataLen = 0;
IMsg.IRDA_MSG_pContext = pConn;
IMsg.IRDA_MSG_MaxSDUSize = TTP_RECV_MAX_SDU;
IMsg.IRDA_MSG_TtpCredits = TTP_RECV_CREDITS;
#if DBG
pConn->CreditsExtended += TTP_RECV_CREDITS;
#endif
ConnectionUp(pConn, TRUE);
}
else
{
DEBUGMSG(DBG_TDI, (" declining connection\n"));
IMsg.Prim = IRLMP_DISCONNECT_REQ;
IMsg.IRDA_MSG_pDiscData = NULL;
IMsg.IRDA_MSG_DiscDataLen = 0;
}
IrlmpDown(pMsg->IRDA_MSG_pContext, &IMsg);
}
VOID
IrlmpDisconnectInd(PIRDA_CONN_OBJ pConn, IRDA_MSG *pMsg)
{
CTELockHandle hLock;
DEBUGMSG(DBG_TDI, ("IRDA: IRLMP_DISCONNECT_IND ConnObj:%p (Irlmp:%p)\n", pConn,
pConn->IrlmpContext));
switch (pConn->ConnState)
{
case IRDA_CONN_CLOSING:
case IRDA_CONN_CREATED:
break;
case IRDA_CONN_OPENING:
{
CompleteConnection(pConn, pMsg);
break;
}
case IRDA_CONN_OPEN:
{
ULONG DiscFlags;
if (pMsg->IRDA_MSG_DiscReason == IRLMP_USER_REQUEST)
{
DEBUGMSG(DBG_TDI, (" ConnObj:%p graceful disconnect\n",
pConn));
DiscFlags = TDI_DISCONNECT_RELEASE;
}
else
{
DEBUGMSG(DBG_TDI, (" ConnObj:%p abortive disconnect\n",
pConn));
DiscFlags = TDI_DISCONNECT_ABORT;
}
GET_CONN_LOCK(pConn, &hLock);
pConn->ConnState = IRDA_CONN_CLOSING;
if (IsListEmpty(&pConn->RecvBufList) ||
DiscFlags == TDI_DISCONNECT_ABORT)
{
if (!IsListEmpty(&pConn->SendIrpList))
{
DEBUGMSG(DBG_TDI, (" SendIrpList not empty, indicate abortive disconnect\n"));
DiscFlags = TDI_DISCONNECT_ABORT;
}
FREE_CONN_LOCK(pConn, hLock);
IndicateDisconnect(pConn, DiscFlags);
}
else
{
DEBUGMSG(DBG_TDI, (" receive data has been buffered, not indicating disconnect to client\n"));
FREE_CONN_LOCK(pConn, hLock);
}
break;
}
default:
CTEAssert(0);
}
}
VOID
IrlmpConnectConf(PIRDA_CONN_OBJ pConn, IRDA_MSG *pMsg)
{
DEBUGMSG(DBG_TDI, ("IRDA: IRLMP_CONNECT_CONF ConnObj:%p\n",
pConn));
switch (pConn->ConnState)
{
case IRDA_CONN_CLOSING:
case IRDA_CONN_CREATED:
case IRDA_CONN_OPEN:
CTEAssert(0);
break;
case IRDA_CONN_OPENING:
CompleteConnection(pConn, pMsg);
break;
}
}
VOID
IrlmpGetValueByClassConf(IRDA_MSG *pMsg)
{
CTELockHandle hLock;
LIST_ENTRY *pListEntry;
UINT rc;
BOOLEAN RetryConn = FALSE;
DEBUGMSG(DBG_TDI, ("IRDA: IRLMP_GETVALUEBYCLASS_CONF\n"));
CTEGetLock(&IrdaLock, &hLock);
if (pIasIrp != NULL) {
PIRP pIrp;
PIO_STACK_LOCATION pIrpSp;
NTSTATUS Status = STATUS_CONNECTION_REFUSED;
pIrp = pIasIrp;
pIasIrp = NULL;
CTEFreeLock(&IrdaLock, hLock);
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
// getsockopt IAS query on connection object??
// I think not, helper will open a control channel.
// i.e. I am making the assumption that this IAS response is
// from a LsapSel value query and a connection will now
// be initiated
if ((UINT_PTR)pIrpSp->FileObject->FsContext2 == TDI_CONNECTION_FILE) {
PIRDA_CONN_OBJ pConn = pIrpSp->FileObject->FsContext;
CTEAssert(IS_VALID_CONN(pConn));
if (pConn->ConnState != IRDA_CONN_OPENING) {
Status = STATUS_CONNECTION_ABORTED;
} else {
if (pMsg->IRDA_MSG_IASStatus != IRLMP_IAS_SUCCESS &&
pMsg->IRDA_MSG_IASStatus != IRLMP_IAS_SUCCESS_LISTLEN_GREATER_THAN_ONE) {
DEBUGMSG(DBG_TDI, ("IRDA: IAS Query failed %d\n",
pMsg->IRDA_MSG_IASStatus));
if (pMsg->IRDA_MSG_IASStatus < IRLMP_IAS_NO_SUCH_OBJECT) {
Status = STATUS_IO_TIMEOUT;
}
if (pMsg->IRDA_MSG_IASStatus == IRLMP_MAC_MEDIA_BUSY ||
pMsg->IRDA_MSG_IASStatus == IRLMP_IRLAP_REMOTE_DISCOVERY_IN_PROGRESS) {
RetryConn = TRUE;
} else {
if (pConn->pAddr->UseIrlptMode == IRLPT_MODE2) {
//
// I just can't beleive this crap
// Try querying for "LSAPSel" rather than "LsapSel"
//
Status = InitiateIasQuery(pIrp, pIrpSp, pConn);
}
}
} else {
//
// it worked
//
if (pMsg->IRDA_MSG_pIasQuery->irdaAttribType != IAS_ATTRIB_VAL_INTEGER) {
CTEAssert(0);
} else {
//
// we got the lsap, proceed with the connection
//
pConn->RemoteLsapSel = pMsg->IRDA_MSG_pIasQuery->irdaAttribute.irdaAttribInt;
Status = InitiateConnection(pConn, pIrp);
}
}
if (Status != STATUS_PENDING) {
// failing the connection
pConn->ConnState = IRDA_CONN_CREATED;
if (RetryConn) {
//
// the irp will queue or completed, by this function
//
RetryConnection(pConn, pIrp);
pIrp=NULL;
} else {
//
// the request failed
//
pIrp->IoStatus.Status = Status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
}
}
}
} else {
//
// control file object
//
IAS_QUERY *pIasQuery = pIrp->AssociatedIrp.SystemBuffer;
ULONG ResultLen = sizeof(IAS_QUERY);
Status = STATUS_SUCCESS;
if (pMsg->IRDA_MSG_IASStatus != IRLMP_IAS_SUCCESS &&
pMsg->IRDA_MSG_IASStatus != IRLMP_IAS_SUCCESS_LISTLEN_GREATER_THAN_ONE) {
DEBUGMSG(DBG_TDI, ("IRDA: IAS Query failed %d\n",
pMsg->IRDA_MSG_IASStatus));
if (pMsg->IRDA_MSG_IASStatus < IRLMP_IAS_NO_SUCH_OBJECT) {
Status = STATUS_IO_TIMEOUT;
} else {
Status = STATUS_CONNECTION_REFUSED;
}
ResultLen = 0;
} else {
RtlCopyMemory(pIasQuery, pvIasQuery, sizeof(IAS_QUERY));
}
pIrp->IoStatus.Status = Status;
pIrp->IoStatus.Information = ResultLen;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
}
} else {
ASSERT(pIasIrp != NULL);
CTEFreeLock(&IrdaLock, hLock);
}
CTEGetLock(&IrdaLock, &hLock);
// Start the next Ias query if one is on the list and
// there is not one in progress
if (!IsListEmpty(&IasIrpList) && pIasIrp == NULL)
{
if (CTEScheduleEvent(&PendingIasEvent, NULL) == FALSE)
{
CTEAssert(0);
}
}
CTEFreeLock(&IrdaLock, hLock);
}
VOID
IrlmpDataConf(PIRDA_CONN_OBJ pConn, IRDA_MSG *pMsg)
{
CTELockHandle hLock;
LIST_ENTRY *pListEntry;
PIRP pIrp = NULL;
CTEAssert(IS_VALID_CONN(pConn));
// find the irp
GET_CONN_LOCK(pConn, &hLock);
// the desired irp should always be at the head of the list
// so this search will be short
for (pListEntry = pConn->SendIrpList.Flink;
pListEntry != &pConn->SendIrpList;
pListEntry = pListEntry->Flink)
{
pIrp = CONTAINING_RECORD(pListEntry, IRP, Tail.Overlay.ListEntry);
if (pIrp == (PIRP) pMsg->IRDA_MSG_pTdiSendCompCnxt)
{
RemoveEntryList(pListEntry);
break;
}
pIrp = NULL;
}
FREE_CONN_LOCK(pConn, hLock);
if (pIrp)
{
NTSTATUS Status;
if (pMsg->IRDA_MSG_DataStatus == IRLMP_DATA_REQUEST_COMPLETED)
{
Status = STATUS_SUCCESS;
}
else
{
Status = STATUS_GRACEFUL_DISCONNECT;
}
DEBUGMSG(DBG_TDI, ("IRDA: IRLMP_DATA_CONF %s ConnObj:%p %d bytes, Irp:%p\n",
Status == STATUS_SUCCESS ? "Success":"Failed",
pConn, (ULONG)pIrp->IoStatus.Information, pIrp));
pIrp->IoStatus.Status = Status;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
}
else
{
DEBUGMSG(DBG_TDI, ("IRDA: IRLMP_DATA_CONF ConnObj:%p, Irp:%p NOT FOUND! pMsg=%p\n",
pConn, pMsg->IRDA_MSG_pTdiSendCompCnxt, pMsg));
ASSERT(0);
}
FreeIrdaBuf(IrdaMsgPool, pMsg);
}
VOID
BufferRecv(
PIRDA_CONN_OBJ pConn,
UCHAR *pData,
ULONG BytesAvailable,
UINT FinalSeg)
{
PIRDA_RECV_BUF pRecvBuf;
// Assumes conn lock is held
pRecvBuf = AllocIrdaBuf(RecvBufPool);
CTEAssert(pRecvBuf);
if (pRecvBuf)
{
InsertTailList(&pConn->RecvBufList, &pRecvBuf->Linkage);
pRecvBuf->Offset = 0;
pRecvBuf->Len = BytesAvailable;
pRecvBuf->FinalSeg = FinalSeg;
RtlCopyMemory(pRecvBuf->Data, pData,
pRecvBuf->Len);
}
DEBUGMSG(DBG_TDI, (" ConnObj:%p, %d bytes buffered at %p\n",
pConn, pRecvBuf->Len, pRecvBuf));
}
VOID
IrlmpDataInd(PIRDA_CONN_OBJ pConn, IRDA_MSG *pMsg)
{
NTSTATUS Status;
PIRDA_ADDR_OBJ pAddr = pConn->pAddr;
ULONG BytesAvailable, BytesTakenTotal, BytesTaken, BytesToCopy;
PIRP pIrp = NULL;
CTELockHandle hLock;
LIST_ENTRY *pListEntry;
UCHAR *pData;
UINT FinalSeg;
CTEAssert(IS_VALID_ADDR(pAddr));
// remove IrCOMM header byte
if (pAddr->Use9WireMode)
{
if (*pMsg->IRDA_MSG_pRead != 0)
{
DEBUGMSG(DBG_ERROR, ("IRDA: 9 wire first byte not zero!! Tossing packet\n"));
return;
}
pMsg->IRDA_MSG_pRead += 1;
}
#if DBG_CHECKSUM
// print first and last 4 bytes of frame to help isolate
// data corruption problem. Should be used with sledge
if ((pMsg->IRDA_MSG_pWrite - pMsg->IRDA_MSG_pRead) > 20)
DEBUGMSG(1, ("R(%X): %c%c%c%c, %c%c%c%c (%X)\n",
pMsg->IRDA_MSG_pRead,
*(pMsg->IRDA_MSG_pRead),
*(pMsg->IRDA_MSG_pRead+1),
*(pMsg->IRDA_MSG_pRead+2),
*(pMsg->IRDA_MSG_pRead+3),
*(pMsg->IRDA_MSG_pWrite-4),
*(pMsg->IRDA_MSG_pWrite-3),
*(pMsg->IRDA_MSG_pWrite-2),
*(pMsg->IRDA_MSG_pWrite-1),
pConn));
#endif
BytesAvailable = (ULONG) (pMsg->IRDA_MSG_pWrite - pMsg->IRDA_MSG_pRead);
BytesTakenTotal = 0;
pData = pMsg->IRDA_MSG_pRead;
FinalSeg = pMsg->IRDA_MSG_SegFlags & SEG_FINAL ? 1 : 0;
#if DBG
pConn->TotalFramesCnt += 1;
pConn->TotalByteCount += BytesAvailable;
#endif
GET_CONN_LOCK(pConn, &hLock);
pConn->TtpRecvCreditsLeft--;
CTEAssert(pConn->TtpRecvCreditsLeft >= 0);
if (pConn->ConnState != IRDA_CONN_OPEN)
{
DEBUGMSG(DBG_TDI, (" connection not open (state %d), ignoring\n",
pConn->ConnState));
FREE_CONN_LOCK(pConn, hLock);
return;
}
if (pConn->RecvBusy)
{
DEBUGMSG(DBG_TDI, ("IRDA: IRLMP_DATA_IND pConnObj:%p busy\n", pConn));
BufferRecv(pConn, pData, BytesAvailable, FinalSeg);
FREE_CONN_LOCK(pConn, hLock);
return;
}
FREE_CONN_LOCK(pConn, hLock);
do
{
PIO_STACK_LOCATION pIrpSp;
PTDI_REQUEST_KERNEL_RECEIVE pRecvReq;
pIrp = NULL;
GET_CONN_LOCK(pConn, &hLock);
if (!IsListEmpty(&pConn->RecvIrpList))
{
pListEntry = RemoveHeadList(&pConn->RecvIrpList);
pIrp = CONTAINING_RECORD(pListEntry, IRP, Tail.Overlay.ListEntry);
if (IoSetCancelRoutine(pIrp, NULL) == NULL)
{
// Cancel routine is going to run. Indicate to the
// cancel routine that the Irp has already been removed
// from the list by setting Flink to NULL
pIrp->Tail.Overlay.ListEntry.Flink = NULL;
pIrp = NULL;
}
else
{
BytesTaken = 0;
Status = STATUS_MORE_PROCESSING_REQUIRED;
DEBUGMSG(DBG_ERROR, ("IRDA: IRLMP_DATA_IND, complete pending receive irp:%p\n",
pIrp));
}
}
FREE_CONN_LOCK(pConn, hLock);
if (pIrp == NULL) {
DEBUGMSG(DBG_TDI, ("IRDA: IRLMP_DATA_IND pConnObj:%p, indicate %d bytes\n",
pConn, BytesAvailable));
if (pAddr->pEventReceive) {
Status = pAddr->pEventReceive(
pAddr->pEventReceiveContext,
pConn->ClientContext,
TDI_RECEIVE_NORMAL | \
(FinalSeg ? TDI_RECEIVE_ENTIRE_MESSAGE : 0),
BytesAvailable,
BytesAvailable,
&BytesTaken,
pData,
&pIrp
);
} else {
BytesTaken= BytesAvailable;
Status=STATUS_SUCCESS;
}
BytesTakenTotal += BytesTaken;
BytesAvailable -= BytesTaken;
pData += BytesTaken;
}
switch (Status)
{
case STATUS_MORE_PROCESSING_REQUIRED:
CTEAssert(pIrp);
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
pRecvReq = (PTDI_REQUEST_KERNEL_RECEIVE) &pIrpSp->Parameters;
BytesToCopy = BytesAvailable <= pRecvReq->ReceiveLength ?
BytesAvailable : pRecvReq->ReceiveLength;
TdiCopyBufferToMdl(pData, // Source
0, // Source offset
BytesToCopy, // Number of bytes to copy
pIrp->MdlAddress,// Destination
0, // Destination offset
&BytesTaken); // actual bytes copied
CTEAssert(BytesTaken == BytesToCopy);
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = BytesTaken;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
BytesTakenTotal += BytesTaken;
BytesAvailable -= BytesTaken;
pData += BytesTaken;
// fall through
case STATUS_SUCCESS:
#if DBG
if (Status == STATUS_SUCCESS)
{
DEBUGMSG(DBG_TDI, (" client took indicated data, BytesLeft %d, BytesTaken %d\n",
BytesAvailable, BytesTaken));
}
else
{
DEBUGMSG(DBG_TDI, (" Completed Irp %p, BytesLeft %d, BytesTaken %d\n",
pIrp, BytesAvailable, BytesTaken));
}
#endif
GET_CONN_LOCK(pConn, &hLock);
// Advance credit to peer
DEBUGMSG(DBG_TDI, (" TtpRecvCreditsLeft = %d\n",pConn->TtpRecvCreditsLeft));
if (pConn->TtpRecvCreditsLeft <= TTP_CREDIT_ADVANCE_THRESH)
{
int CreditsLeft;
IRDA_MSG IMsg;
CreditsLeft = pConn->TtpRecvCreditsLeft;
pConn->TtpRecvCreditsLeft = TTP_RECV_CREDITS;
FREE_CONN_LOCK(pConn, hLock);
IMsg.Prim = IRLMP_MORECREDIT_REQ;
IMsg.IRDA_MSG_TtpCredits = TTP_RECV_CREDITS - CreditsLeft;
#if DBG
pConn->CreditsExtended += (TTP_RECV_CREDITS - CreditsLeft);
#endif
IrlmpDown(pConn->IrlmpContext, &IMsg);
}
else
{
FREE_CONN_LOCK(pConn, hLock);
}
break;
case STATUS_DATA_NOT_ACCEPTED:
GET_CONN_LOCK(pConn, &hLock);
if (!IsListEmpty(&pConn->RecvIrpList))
{
FREE_CONN_LOCK(pConn, hLock);
continue;
}
pConn->RecvBusy = TRUE;
BufferRecv(pConn, pData, BytesAvailable, FinalSeg);
FREE_CONN_LOCK(pConn, hLock);
break;
}
} while (Status != STATUS_DATA_NOT_ACCEPTED &&
BytesAvailable);
}
UINT
TdiUp(void *pContext, IRDA_MSG *pMsg)
{
PIRDA_CONN_OBJ pConn = pContext;
CTEAssert(pConn ? IS_VALID_CONN(pConn) : 1);
switch (pMsg->Prim)
{
case IRLMP_DISCOVERY_CONF:
IrlmpDiscoveryConf(pMsg);
break;
case IRLMP_DISCOVERY_IND:
break;
case IRLMP_CONNECT_IND:
IrlmpConnectInd(pMsg);
break;
case IRLMP_DISCONNECT_IND:
IrlmpDisconnectInd(pConn, pMsg);
break;
case IRLMP_CONNECT_CONF:
IrlmpConnectConf(pConn, pMsg);
break;
case IRLMP_GETVALUEBYCLASS_CONF:
IrlmpGetValueByClassConf(pMsg);
break;
case IRLMP_DATA_CONF:
IrlmpDataConf(pConn, pMsg);
break;
case IRLMP_DATA_IND:
IrlmpDataInd(pConn, pMsg);
break;
case IRLAP_STATUS_IND:
{
CTELockHandle hLock;
PIRLINK_STATUS pLinkStatus = (PIRLINK_STATUS) pMsg->IRDA_MSG_pLinkStatus;
if (CTEMemCmp(pLinkStatus->ConnectedDeviceId,
LinkStatus.ConnectedDeviceId,
IRDA_DEV_ADDR_LEN) == 0)
{
if (pLinkStatus->Flags == LF_INTERRUPTED)
{
ConnectionStatusChange(NULL, CONNECTION_INTERRUPTED);
}
else if ((pLinkStatus->Flags & LF_CONNECTED) && ConnectionInterrupted)
{
ConnectionStatusChange(NULL, CONNECTION_UP);
}
}
/*
CTEGetLock(&IrdaLock, &hLock);
// we update the status only when it changes
// No longer interested in send and receives status
((PIRLINK_STATUS) (pMsg->IRDA_MSG_pLinkStatus))->Flags &= ~(LF_TX | LF_RX);
if (CTEMemCmp(&LinkStatus, pLinkStatus, sizeof(IRLINK_STATUS)) != 0)
{
CTEMemCopy(&LinkStatus, pLinkStatus, sizeof(IRLINK_STATUS));
LinkStatusUpdated = TRUE;
}
if (LinkStatusUpdated)
{
PLIST_ENTRY pListEntry;
PIRP pIrp;
pListEntry = RemoveHeadList(&StatusIrpList);
if (pListEntry != &StatusIrpList)
{
pIrp = CONTAINING_RECORD(pListEntry, IRP, Tail.Overlay.ListEntry);
if (IoSetCancelRoutine(pIrp, NULL) == NULL)
{
// Cancel routine is going to run. Mark Irp so cancel
// routine won't attempt to remove it from the list
pIrp->Tail.Overlay.ListEntry.Flink = NULL;
CTEFreeLock(&IrdaLock, hLock);
}
else
{
CTEMemCopy(pIrp->AssociatedIrp.SystemBuffer,
&LinkStatus, sizeof(IRLINK_STATUS));
CTEFreeLock(&IrdaLock, hLock);
pIrp->IoStatus.Information = sizeof(IRLINK_STATUS);
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
LinkStatusUpdated = FALSE;
}
}
else
{
CTEFreeLock(&IrdaLock, hLock);
}
}
else
{
CTEFreeLock(&IrdaLock, hLock);
}
*/
break;
}
case IRLMP_ACCESSMODE_CONF:
default:
DEBUGMSG(DBG_ERROR,
("IRDA: TdiUp(), Bad prim %s.\n", IrDAPrimTxt(pMsg->Prim)));
break;
}
return SUCCESS;
}
VOID
LazyDscvTimerExp(PVOID Context)
{
IRDA_MSG IMsg;
CTELockHandle hLock;
DEBUGMSG(DBG_DISCOVERY, ("IRDA: Lazy discovery timer expired\n"));
CTEGetLock(&IrdaLock, &hLock);
if (!IsListEmpty(&LazyDscvIrpList))
{
UINT OriginalTimeout;
UINT RandInc;
CTEFreeLock(&IrdaLock, hLock);
// Randomize lazy discovery time +1, +0, or -1
RandSeed = RandSeed * 0x3F57A10B + 1;
RandInc = RandSeed % 3;
OriginalTimeout = LazyDscvTimer.Timeout;
LazyDscvTimer.Timeout += (RandInc * 1000) - 1000;
IMsg.Prim = IRLMP_DISCOVERY_REQ;
IMsg.IRDA_MSG_SenseMedia = TRUE;
IrlmpDown(NULL, &IMsg);
IrdaTimerStart(&LazyDscvTimer);
LazyDscvTimer.Timeout = OriginalTimeout;
return;
}
else
{
LazyDscvTimerRunning = FALSE;
DEBUGMSG(DBG_TDI, ("IRDA: IrpList empty, ending lazy discovery\n"));
}
CTEFreeLock(&IrdaLock, hLock);
}
VOID CancelIrp(
PDEVICE_OBJECT DeviceObject,
PIRP pIrp)
{
CTELockHandle hLock;
DEBUGMSG(DBG_TDI, ("IRDA: Cancel Irp:%p\n", pIrp));
CTEGetLock(&IrdaLock, &hLock);
if (pIrp->Tail.Overlay.ListEntry.Flink != NULL) {
RemoveEntryList(&(pIrp->Tail.Overlay.ListEntry));
}
CTEFreeLock(&IrdaLock, hLock);
IoReleaseCancelSpinLock(pIrp->CancelIrql);
pIrp->IoStatus.Status = STATUS_CANCELLED;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
}
VOID CancelConnObjIrp(
PDEVICE_OBJECT DeviceObject,
PIRP pIrp)
{
PIRDA_CONN_OBJ pConn;
PIO_STACK_LOCATION pIrpSp;
CTELockHandle hLock;
DEBUGMSG(DBG_TDI, ("IRDA: Cancel ConnObj Irp:%p\n", pIrp));
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
pConn = pIrpSp->FileObject->FsContext;
CTEAssert(IS_VALID_CONN(pConn));
GET_CONN_LOCK(pConn, &hLock);
if (pIrp->Tail.Overlay.ListEntry.Flink != NULL)
{
RemoveEntryList(&(pIrp->Tail.Overlay.ListEntry));
}
FREE_CONN_LOCK(pConn, hLock);
DbgPrint("irda: irp %p canceled\n",pIrp);
IoReleaseCancelSpinLock(pIrp->CancelIrql);
pIrp->IoStatus.Status = STATUS_CANCELLED;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
}
VOID
PendIrp(
PLIST_ENTRY pList,
PIRP pIrp,
PIRDA_CONN_OBJ pConn,
BOOLEAN LockHeld)
{
CTELockHandle hLock;
PIRP IrpToComplete=NULL;
if (!LockHeld)
{
if (pConn)
{
GET_CONN_LOCK(pConn, &hLock);
}
else
{
CTEGetLock(&IrdaLock, &hLock);
}
}
InsertTailList(pList, &pIrp->Tail.Overlay.ListEntry);
IoMarkIrpPending(pIrp);
if (pConn)
{
IoSetCancelRoutine(pIrp, CancelConnObjIrp);
}
else
{
IoSetCancelRoutine(pIrp, CancelIrp);
}
pIrp->IoStatus.Status = STATUS_PENDING;
if (pIrp->Cancel)
{
if (IoSetCancelRoutine(pIrp, NULL) != NULL)
{
//
// My cancel routine was still set in the Irp so
// the Io manager never had a chance to call it
//
RemoveEntryList(&pIrp->Tail.Overlay.ListEntry);
pIrp->IoStatus.Status = STATUS_CANCELLED;
pIrp->IoStatus.Information = 0;
//
// since we may be holding a spinlock here we don't want to complete the
// irp now
//
IrpToComplete=pIrp;
#if DBG
pIrp=NULL;
#endif
}
}
if (!LockHeld)
{
if (pConn)
{
FREE_CONN_LOCK(pConn, hLock);
}
else
{
CTEFreeLock(&IrdaLock, hLock);
}
}
if (IrpToComplete != NULL) {
IoCompleteRequest(IrpToComplete, 0);
}
return ;
}
int
GetUnusedLsapSel()
{
PIRDA_ADDR_OBJ pAddr;
int LastLsapSel;
int LsapSel = gNextLsapSel;
// Assumes AddrObjList lock is held
LastLsapSel = LsapSel - 1;
if (LastLsapSel < IRDA_MIN_LSAP_SEL)
{
LastLsapSel = IRDA_MAX_LSAP_SEL;
}
while (LsapSel != LastLsapSel)
{
for (pAddr = AddrObjList; pAddr != NULL; pAddr = pAddr->pNext)
{
if (pAddr->LocalLsapSel == LsapSel)
break;
}
if (pAddr == NULL || pAddr->LocalLsapSel != LsapSel)
{
gNextLsapSel = LsapSel + 1;
if (gNextLsapSel > IRDA_MAX_LSAP_SEL)
{
gNextLsapSel = IRDA_MIN_LSAP_SEL;
}
return LsapSel;
}
LsapSel += 1;
if (LsapSel > IRDA_MAX_LSAP_SEL)
{
LsapSel = IRDA_MIN_LSAP_SEL;
}
}
return -1;
}
VOID
SetLsapSelAddr(
int LsapSel,
CHAR *ServiceName)
{
int Digit, i;
int StrLen = 0;
CHAR Str[4];
while (LsapSel > 0 && StrLen < 3)
{
Digit = LsapSel % 10;
LsapSel = LsapSel / 10;
Str[StrLen] = Digit + '0';
StrLen++;
}
RtlCopyMemory(ServiceName, LSAPSEL_TXT, LSAPSEL_TXTLEN);
for (i = 0; i < StrLen; i++)
ServiceName[i + LSAPSEL_TXTLEN] = Str[StrLen - 1 - i];
ServiceName[StrLen + LSAPSEL_TXTLEN] = 0;
}
BOOLEAN
MyStrEqual(
CHAR *Str1,
CHAR *Str2,
int Len)
{
while (*Str1 == *Str2 && Len--)
{
if (*Str1 == 0)
return TRUE;
Str1++; Str2++;
}
return FALSE;
}
#if 1
char *
IrpMJTxt(
PIO_STACK_LOCATION pIrpSp)
{
static char *MJTxt[] =
{
"IRP_MJ_CREATE",
"IRP_MJ_CREATE_NAMED_PIPE",
"IRP_MJ_CLOSE",
"IRP_MJ_READ",
"IRP_MP_MJ_WRITE",
"IRP_MJ_QUERY_INFO",
"IRP_MJ_SET_INFO",
"IRP_MJ_QUERY_EA",
"IRP_MJ_SET_EA",
"IRP_MJ_FLUSH_BUFFERS",
"IRP_MJ_QUERY_VOLUME_INFO",
"IRP_MJ_SET_VOLUME_INFO",
"IRP_MJ_DIRECTORY_CTRL",
"IRP_MJ_FILE_SYSTEM_CTRL",
"IRP_MJ_DEV_CONTROL",
"IRP_MJ_INTERNAL_DEV_CTRL",
"IRP_MJ_SHUTDOWN",
"IRP_MJ_LOCK_CTRL",
"IRP_MJ_CLEANUP",
"IRP_MJ_CREATE_MAILSLOT",
"IRP_MJ_QUERY_SECURITY",
"IRP_MJ_SET_SECURITY",
"IRP_MJ_QUERY_POWER",
"IRP_MJ_SET_POWER",
"IRP_MJ_DEV_CHANGE",
"IRP_MJ_QUERY_QUOTA",
"IRP_MJ_SET_QUOTA",
"IRP_MJ_PNP_POWER",
};
if (pIrpSp->MajorFunction < sizeof(MJTxt) / sizeof(char *))
{
return(MJTxt[pIrpSp->MajorFunction]);
}
return "UNKNOWN IRP_MJ_";
}
char *
IrpTdiTxt(
PIO_STACK_LOCATION pIrpSp)
{
static char *TdiTxt[] =
{
"UNKNOWN TDI_",
"TDI_ASSOC_ADDR",
"TDI_DISASSOC_ADDR",
"TDI_CONNECT",
"TDI_LISTEN",
"TDI_ACCEPT",
"TDI_DISC",
"TDI_SEND",
"TDI_RECV",
"TDI_SEND_DATAGRAM",
"TDI_RECV_DATAGRAM",
"TDI_SET_HANDLER",
"TDI_QUERY_INFO",
"TDI_SET_INFO",
"TDI_ACTION"
};
if (pIrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)
{
if (pIrpSp->MinorFunction < sizeof(TdiTxt) / sizeof(char *))
{
return(TdiTxt[pIrpSp->MinorFunction]);
}
else
return "UNKNOWN TDI_";
}
return "";
}
char *
IrpTdiObjTypeTxt(
PIO_STACK_LOCATION pIrpSp)
{
switch((UINT_PTR) pIrpSp->FileObject->FsContext2)
{
case TDI_TRANSPORT_ADDRESS_FILE: return "AddrObj";
case TDI_CONNECTION_FILE: return "ConnObj";
case TDI_CONTROL_CHANNEL_FILE: return "CtrlObj";
}
return "UNKNOWN";
}
char *
TdiEventTxt(
int EventType)
{
switch(EventType)
{
case TDI_EVENT_CONNECT: return "TDI_EVENT_CONN";
case TDI_EVENT_DISCONNECT: return "TDI_EVENT_DISC";
case TDI_EVENT_RECEIVE: return "TDI_EVENT_RECV";
case TDI_EVENT_ERROR: return "TDI_EVENT_ERR";
case TDI_EVENT_RECEIVE_DATAGRAM: return "TDI_EVENT_RECV_DATAGRAM";
case TDI_EVENT_RECEIVE_EXPEDITED: return "TDI_EVENT_RECV_EXPEDITED";
}
return "UNKNOWN TDI_EVENT_";
}
void
DumpObjects(void)
{
PIRDA_ADDR_OBJ pAddr;
PIRDA_CONN_OBJ pConn;
pAddr = AddrObjList;
/*
while (pAddr != NULL)
{
DEBUGMSG(DBG_TDI,
(" AddrObj:%X Loc:\"%s\",%d ConnObjList:%X pNext:%X\n",
pAddr,
pAddr->LocalAddr.irdaServiceName,
pAddr->LocalLsapSel,
pAddr->ConnObjList,
pAddr->pNext));
pConn = pAddr->ConnObjList;
while (pConn != NULL)
{
DEBUGMSG(DBG_TDI,
(" ConnObj:%X Loc:\"%s\",%d Rem:\"%s\",%d State:%d AddrObj:%X pNext:%X\n",
pConn,
pConn->LocalAddr.irdaServiceName,
pConn->LocalLsapSel,
pConn->RemoteAddr.irdaServiceName,
pConn->RemoteLsapSel,
pConn->ConnState,
pConn->pAddr,
pConn->pNext));
pConn = pConn->pNext;
}
pAddr = pAddr->pNext;
}
*/
}
char *
IrDAPrimTxt(
IRDA_SERVICE_PRIM Prim)
{
static char *IrDAPrimTxt[] =
{
"MAC_DATA_REQ",
"MAC_DATA_IND",
"MAC_DATA_RESP",
"MAC_DATA_CONF",
"MAC_CONTROL_REQ",
"MAC_CONTROL_CONF",
"IRLAP_DISCOVERY_REQ",
"IRLAP_DISCOVERY_IND",
"IRLAP_DISCOVERY_CONF",
"IRLAP_CONNECT_REQ",
"IRLAP_CONNECT_IND",
"IRLAP_CONNECT_RESP",
"IRLAP_CONNECT_CONF",
"IRLAP_DISCONNECT_REQ",
"IRLAP_DISCONNECT_IND",
"IRLAP_DATA_REQ",
"IRLAP_DATA_IND",
"IRLAP_DATA_CONF",
"IRLAP_UDATA_REQ",
"IRLAP_UDATA_IND",
"IRLAP_UDATA_CONF",
"IRLAP_STATUS_IND",
"IRLAP_FLOWON_REQ",
"IRLMP_DISCOVERY_REQ",
"IRLMP_DISCOVERY_IND",
"IRLMP_DISCOVERY_CONF",
"IRLMP_CONNECT_REQ",
"IRLMP_CONNECT_IND",
"IRLMP_CONNECT_RESP",
"IRLMP_CONNECT_CONF",
"IRLMP_DISCONNECT_REQ",
"IRLMP_DISCONNECT_IND",
"IRLMP_DATA_REQ",
"IRLMP_DATA_IND",
"IRLMP_DATA_CONF",
"IRLMP_UDATA_REQ",
"IRLMP_UDATA_IND",
"IRLMP_UDATA_CONF",
"IRLMP_ACCESSMODE_REQ",
"IRLMP_ACCESSMODE_IND",
"IRLMP_ACCESSMODE_CONF",
"IRLMP_MORECREDIT_REQ",
"IRLMP_GETVALUEBYCLASS_REQ",
"IRLMP_GETVALUEBYCLASS_CONF",
"IRLMP_REGISTERLSAP_REQ",
"IRLMP_ADDATTRIBUTE_REQ",
"IRLMP_DELATTRIBUTE_REQ",
};
if (Prim < sizeof(IrDAPrimTxt) / sizeof(char *))
{
return(IrDAPrimTxt[Prim]);
}
return "UNKNOWN PRIMITIVE";
}
char *
TdiQueryTxt(LONG Type)
{
switch(Type)
{
case TDI_QUERY_BROADCAST_ADDRESS: return "TDI_QUERY_BROADCAST_ADDRESS";
case TDI_QUERY_PROVIDER_INFO: return "TDI_QUERY_PROVIDER_INFO";
case TDI_QUERY_ADDRESS_INFO: return "TDI_QUERY_ADDRES_INFO";
case TDI_QUERY_CONNECTION_INFO: return "TDI_QUERY_CONNECTION_INFO";
case TDI_QUERY_PROVIDER_STATISTICS: return "TDI_QUERY_PROVIDER_STATISTICS";
default: return "Unknown TDI_QUERY_INFO";
}
}
#endif