|
|
/*++
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>
static LARGE_INTEGER Magic10000 = {0xe219652c, 0xd1b71758};
#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
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; DbgMsgInit();
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); }
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%lx, Unsupported %s.\n", pIrp, IrpMJTxt(pIrpSp))); Status = STATUS_INVALID_DEVICE_REQUEST; break; } CTEAssert(Status != TDI_PENDING);
DEBUGMSG(DBG_TDI_IRP, ("IRDA: Completing Irp:%X, 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:%X)\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:%X (fo:%X)\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:%X (fo:%X)\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 %X\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:%X\n", pIrpSp->FileObject->FsContext)); break; case TDI_CONNECTION_FILE: DEBUGMSG(DBG_TDI_IRP, ("IRDA: Cleanup ConnObj:%X\n", pIrpSp->FileObject->FsContext)); break; case TDI_CONTROL_CHANNEL_FILE: {
CTELockHandle hLock;
DEBUGMSG(DBG_TDI_IRP, ("IRDA: Cleanup control channel (fo:%X)\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:%X)\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%lx %s %s FileObj:0x%lx %s:0x%lx.\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%lx %s %s FileObj:0x%lx %s:0x%lx, 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%lx %s %s FileObj:0x%lx %s:0x%lx, 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:%X %s FileObj:%X %s:%X 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: { IRDA_MSG IMsg; 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:%X use IrLPT mode\n", pAddr)); pAddr->UseIrlptMode = IRLPT_MODE1; } if (*pOptions & OPT_9WIRE_MODE) { DEBUGMSG(DBG_TDI, ("IRDA: AddrObj:%X 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:%X, 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 { CTELockHandle hLock; 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:%X ah:%X\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 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:%X, %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:%X, %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; } if (Status == STATUS_SUCCESS) { if (DataLen < InfoSize) { DEBUGMSG(1, ("IRDA: Buffer overflow in TdiQueryInformation\n")); Status = STATUS_BUFFER_OVERFLOW; } else { TdiCopyBufferToMdl(&InfoBuf, 0, InfoSize, pIrp->MdlAddress, 0, &BytesCopied);
CTEAssert(BytesCopied == InfoSize); } } pIrp->IoStatus.Status = Status; pIrp->IoStatus.Information = 0;
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:%X, Handler:%X, Context:%X \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:%X\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; } 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); } }
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:%X\n", pConn)); } else { DEBUGMSG(DBG_TDI, ("IRDA: IrdaDisconnectIrlmp co %X, IrlmpContext == NULL\n", pConn)); } }
VOID FreeConnObject(PIRDA_CONN_OBJ pConn) { IRDA_FREE_MEM(pConn); } NTSTATUS TdiCloseConnection(PIRDA_CONN_OBJ pConn) { DEBUGMSG(DBG_TDI, ("IRDA: TdiCloseConnecion() ConnObj:%X\n", pConn));
CTEAssert(IS_VALID_CONN(pConn));
if (pConn->ConnState != IRDA_CONN_CREATED) { TdiDisconnect(NULL, NULL, pConn); }
if (pConn->pAddr != NULL) {
PIRDA_ADDR_OBJ pAddr=pConn->pAddr; PIRDA_CONN_OBJ pPrevConnObj; CTELockHandle hLock; CTELockHandle hAddrLock;
GET_CONN_LOCK(pConn, &hLock);
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();
FREE_ADDR_LOCK(pAddr, hAddrLock); 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 %X 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 %X.\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:%X ConnObj:%X\n", pAddr, pConn));
GET_CONN_LOCK(pConn, &hLock);
GET_ADDR_LOCK(pAddr, &hAddrLock); if (pConn->pAddr != NULL) { Status = STATUS_ADDRESS_ALREADY_ASSOCIATED; ASSERT(0); } else { // 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);
ObDereferenceObject(AddressFileObject); } 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);
pAddr = pConn->pAddr; CTEAssert(IS_VALID_ADDR(pAddr));
DEBUGMSG(DBG_TDI, ("IRDA: TdiDisassociateAddress() AddrObj:%X ConnObj:%X\n", pAddr, pConn));
GET_CONN_LOCK(pConn, &hLock); 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;
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", EXPDEVID(pConn->RemoteAddr.irdaDeviceID))); 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);
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);
}
}
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:%X, indicated abortive disconnect to client %X\n", pConn, pConn->ClientContext)); TdiDisconnect(NULL, NULL, pConn); } else { DEBUGMSG(DBG_TDI, ("IRDA: pConn:%X, indicated graceful disconnect to client %X\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:%X to Dev:%02X%02X%02X%02X Service:%s\n", pConn->RetryConnCount, pConn, EXPDEVID(pIrdaAddr->irdaDeviceID), 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:%X State %d Irlmp:%X\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:%X 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:%X 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:%X %d bytes, pend Irp:%X\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);
pListEntry = RemoveHeadList(&pConn->RecvBufList); if (pListEntry && pListEntry != &pConn->RecvBufList) { pRecvBuf = CONTAINING_RECORD(pListEntry, IRDA_RECV_BUF, Linkage); if (pRecvBuf->Len > pRecvReq->ReceiveLength) { // Put back on list, not enough room for all the data
InsertHeadList(&pConn->RecvBufList, pListEntry); Status = TdiCopyBufferToMdl(&pRecvBuf->Data[pRecvBuf->Offset], 0, pRecvReq->ReceiveLength, pIrp->MdlAddress, 0, &BytesTaken); CTEAssert(Status == STATUS_SUCCESS); CTEAssert(pRecvReq->ReceiveLength == BytesTaken);
pRecvBuf->Len -= BytesTaken; pRecvBuf->Offset += BytesTaken; DEBUGMSG(DBG_TDI, (" RecvBuf copied only %d of %d\n", BytesTaken, pRecvBuf->Len)); } else { TdiCopyBufferToMdl(&pRecvBuf->Data[pRecvBuf->Offset], 0, pRecvBuf->Len, pIrp->MdlAddress, 0, &BytesTaken); CTEAssert(pRecvBuf->Len == BytesTaken); FreeIrdaBuf(RecvBufPool, pRecvBuf); DEBUGMSG(DBG_TDI, (" RecvBuf %X copied all %d\n", pRecvBuf, BytesTaken)); } FREE_CONN_LOCK(pConn, hLock);
pIrp->IoStatus.Information = BytesTaken; pIrp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
GET_CONN_LOCK(pConn, &hLock); } else { DEBUGMSG(DBG_ERROR, ("IRDA: Pending TDI_RECEIVE Irp %X\n", pIrp));
PendIrp(&pConn->RecvIrpList, pIrp, pConn, TRUE); 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 %X, 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:%X\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; while (!IsListEmpty(pIrpList)) { CTEGetLock(&IrdaLock, &hLock); pListEntry = RemoveHeadList(pIrpList); if (pListEntry == NULL || pListEntry == pIrpList) { CTEFreeLock(&IrdaLock, hLock); break; } 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; } CTEFreeLock(&IrdaLock, hLock); 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 { 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; } pIrp->IoStatus.Status = Status; pIrp->IoStatus.Information = BytesWritten; IoCompleteRequest(pIrp, IO_NO_INCREMENT); } } //*************************************************************************
//
// 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);
// 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) { return; } LazyDscvMacAddrs = CurrLazyDscvMacAddrs; } CTEGetLock(&IrdaLock, &hLock);
LazyDscvTimerRunning = FALSE; CTEFreeLock(&IrdaLock, hLock); IrdaTimerStop(&LazyDscvTimer); CompleteDscvIrpList(&LazyDscvIrpList, pMsg); } }
//*************************************************************************
//
// 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:%X 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:%X (Irlmp:%X)\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:%X graceful disconnect\n", pConn)); DiscFlags = TDI_DISCONNECT_RELEASE; } else { DEBUGMSG(DBG_TDI, (" ConnObj:%X 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:%X\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; NTSTATUS Status = STATUS_SUCCESS; ULONG ResultLen = sizeof(IAS_QUERY);
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:%X %d bytes, Irp:%X\n", Status == STATUS_SUCCESS ? "Success":"Failed", pConn, pIrp->IoStatus.Information, pIrp)); pIrp->IoStatus.Status = Status; IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT); } else { DEBUGMSG(DBG_TDI, ("IRDA: IRLMP_DATA_CONF ConnObj:%X, Irp:%X NOT FOUND! pMsg=%X\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:%X, %d bytes buffered at %X\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:%X 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:%X\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:%X\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); 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 DBG
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
|