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