// You must wait Completion Event If not, It can be crashed !!! NTSTATUS LpxTdiListen_LSTrans( IN PFILE_OBJECT ConnectionFileObject, IN PTDI_LISTEN_CONTEXT TdiListenContext, IN PULONG Flags, IN PLARGE_INTEGER TimeOut ) { UNREFERENCED_PARAMETER(TimeOut); return LpxTdiListenWithCompletionEvent(ConnectionFileObject, TdiListenContext, Flags); }
NTSTATUS DraidListenConnection( PDRAID_LISTEN_CONTEXT ListenContext ) { NTSTATUS status; // KIRQL oldIrql; KeClearEvent(&ListenContext->TdiListenContext.CompletionEvent); status = LpxTdiOpenConnection( &ListenContext->ListenFileHandle, &ListenContext->ListenFileObject, NULL); if(!NT_SUCCESS(status)) { ASSERT(FALSE);// This should not happen return status; } // 3. Associate address status = LpxTdiAssociateAddress( ListenContext->ListenFileObject, ListenContext->AddressFileHandle ); if(!NT_SUCCESS(status)) { ASSERT(FALSE); LpxTdiCloseConnection(ListenContext->ListenFileHandle, ListenContext->ListenFileObject); return status; } // 4. Start listening ListenContext->Flags = TDI_QUERY_ACCEPT; //??? status = LpxTdiListenWithCompletionEvent( ListenContext->ListenFileObject, &ListenContext->TdiListenContext, &ListenContext->Flags ); if(!NT_SUCCESS(status)) { ASSERT(FALSE); // May be this can be happen if multiple instances of this function is called with same address LpxTdiDisassociateAddress(ListenContext->ListenFileObject); LpxTdiCloseConnection(ListenContext->ListenFileHandle, ListenContext->ListenFileObject); return status; } return status; }
static NTSTATUS PrimaryOpenOneListenSocket( PPRIMARY_LISTEN_SOCKET listenSock, PLPX_ADDRESS NICAddr ) { NTSTATUS ntStatus; HANDLE addressFileHandle = NULL; PFILE_OBJECT addressFileObject = NULL; HANDLE listenFileHandle = NULL; PFILE_OBJECT listenFileObject = NULL; SPY_LOG_PRINT( LFS_DEBUG_PRIMARY_INFO, ("PrimaryOpenOneSocket: Entered\n")); listenSock->Active = FALSE; RtlCopyMemory( listenSock->NICAddress.Node, NICAddr->Node, ETHER_ADDR_LENGTH ); // // open a address. // ntStatus = LpxTdiOpenAddress( &addressFileHandle, &addressFileObject, NICAddr ); if(!NT_SUCCESS(ntStatus)) { ASSERT(LPX_BUG); return ntStatus; } listenSock->Active = TRUE; KeClearEvent( &listenSock->TdiListenContext.CompletionEvent ); listenSock->AddressFileHandle = addressFileHandle; listenSock->AddressFileObject = addressFileObject; ntStatus = MakeConnectionObject(addressFileHandle, addressFileObject, &listenFileHandle, &listenFileObject); if(!NT_SUCCESS(ntStatus)) { ASSERT(LPX_BUG); LpxTdiCloseAddress (addressFileHandle, addressFileObject); listenSock->Active = FALSE; return STATUS_UNSUCCESSFUL; } listenSock->ListenFileHandle = listenFileHandle; listenSock->ListenFileObject = listenFileObject; SPY_LOG_PRINT( LFS_DEBUG_PRIMARY_INFO, ( "PrimaryOpenOneListenSocket: opened a address:'%02X:%02X:%02X:%02X:%02X:%02X 0x%04X'\n", NICAddr->Node[0],NICAddr->Node[1],NICAddr->Node[2], NICAddr->Node[3],NICAddr->Node[4],NICAddr->Node[5], NTOHS(NICAddr->Port) ) ); listenSock->Flags = TDI_QUERY_ACCEPT; ntStatus = LpxTdiListenWithCompletionEvent( listenSock->ListenFileObject, &listenSock->TdiListenContext, &listenSock->Flags ); if(!NT_SUCCESS(ntStatus)) { ASSERT(LPX_BUG); LpxTdiDisassociateAddress(listenFileObject); LpxTdiCloseConnection(listenFileHandle, listenFileObject); LpxTdiCloseAddress (addressFileHandle, addressFileObject); listenSock->Active = FALSE; ntStatus = STATUS_UNSUCCESSFUL; } return ntStatus; }
NTSTATUS BindListenSockets( IN PPRIMARY Primary ) { NTSTATUS ntStatus; PSOCKETLPX_ADDRESS_LIST socketLpxAddressList; LONG idx_addr; SPY_LOG_PRINT( LFS_DEBUG_PRIMARY_INFO, ("BindListenSockets: Entered\n")); Primary->Agent.ActiveListenSocketCount = 0; socketLpxAddressList = &Primary->Agent.SocketLpxAddressList; ntStatus = LpxTdiGetAddressList( socketLpxAddressList ); if(!NT_SUCCESS(ntStatus)) { //ASSERT(LPX_BUG); return ntStatus; } if(socketLpxAddressList->iAddressCount <= 0) { SPY_LOG_PRINT( LFS_DEBUG_PRIMARY_INFO, ( "BindListenSockets: No NICs in the host.\n") ); return STATUS_UNSUCCESSFUL; } if(socketLpxAddressList->iAddressCount > MAX_SOCKETLPX_INTERFACE) socketLpxAddressList->iAddressCount = MAX_SOCKETLPX_INTERFACE; for(idx_addr = 0; idx_addr < socketLpxAddressList->iAddressCount; idx_addr ++) { LPX_ADDRESS NICAddr; HANDLE addressFileHandle = NULL; PFILE_OBJECT addressFileObject = NULL; HANDLE listenFileHandle = NULL; PFILE_OBJECT listenFileObject = NULL; Primary->Agent.ListenSocket[idx_addr].Active = FALSE; if( (0 == socketLpxAddressList->SocketLpx[idx_addr].LpxAddress.Node[0]) && (0 == socketLpxAddressList->SocketLpx[idx_addr].LpxAddress.Node[1]) && (0 == socketLpxAddressList->SocketLpx[idx_addr].LpxAddress.Node[2]) && (0 == socketLpxAddressList->SocketLpx[idx_addr].LpxAddress.Node[3]) && (0 == socketLpxAddressList->SocketLpx[idx_addr].LpxAddress.Node[4]) && (0 == socketLpxAddressList->SocketLpx[idx_addr].LpxAddress.Node[5]) ) { SPY_LOG_PRINT( LFS_DEBUG_PRIMARY_INFO, ( "BindListenSockets: We don't use SocketLpx device.\n")); continue; } RtlCopyMemory( &Primary->Agent.ListenSocket[idx_addr].NICAddress, &socketLpxAddressList->SocketLpx[idx_addr].LpxAddress, sizeof(LPX_ADDRESS) ); RtlCopyMemory( &NICAddr, &socketLpxAddressList->SocketLpx[idx_addr].LpxAddress, sizeof(LPX_ADDRESS) ); NICAddr.Port = HTONS(Primary->Agent.ListenPort); // // open a address. // ntStatus = LpxTdiOpenAddress( &addressFileHandle, &addressFileObject, &NICAddr ); if(!NT_SUCCESS(ntStatus)) { ASSERT(LPX_BUG); continue; } Primary->Agent.ListenSocket[idx_addr].Active = TRUE; KeInitializeEvent(&Primary->Agent.ListenSocket[idx_addr].TdiListenContext.CompletionEvent, NotificationEvent, FALSE); Primary->Agent.ListenSocket[idx_addr].AddressFileHandle = addressFileHandle; Primary->Agent.ListenSocket[idx_addr].AddressFileObject = addressFileObject; Primary->Agent.ActiveListenSocketCount ++; ntStatus = MakeConnectionObject(addressFileHandle, addressFileObject, &listenFileHandle, &listenFileObject); if(!NT_SUCCESS(ntStatus)) { ASSERT(LPX_BUG); LpxTdiCloseAddress (addressFileHandle, addressFileObject); Primary->Agent.ListenSocket[idx_addr].Active = FALSE; Primary->Agent.ActiveListenSocketCount --; continue; } Primary->Agent.ListenSocket[idx_addr].ListenFileHandle = listenFileHandle; Primary->Agent.ListenSocket[idx_addr].ListenFileObject = listenFileObject; SPY_LOG_PRINT( LFS_DEBUG_PRIMARY_INFO, ( "BindListenSockets: opened a address:'%02X:%02X:%02X:%02X:%02X:%02X 0x%04X'\n", NICAddr.Node[0],NICAddr.Node[1],NICAddr.Node[2], NICAddr.Node[3],NICAddr.Node[4],NICAddr.Node[5], NTOHS(NICAddr.Port) ) ); Primary->Agent.ListenSocket[idx_addr].Flags = TDI_QUERY_ACCEPT; ntStatus = LpxTdiListenWithCompletionEvent( Primary->Agent.ListenSocket[idx_addr].ListenFileObject, &Primary->Agent.ListenSocket[idx_addr].TdiListenContext, &Primary->Agent.ListenSocket[idx_addr].Flags ); if(!NT_SUCCESS(ntStatus)) { ASSERT(LPX_BUG); LpxTdiDisassociateAddress(listenFileObject); LpxTdiCloseConnection(listenFileHandle, listenFileObject); LpxTdiCloseAddress (addressFileHandle, addressFileObject); Primary->Agent.ListenSocket[idx_addr].Active = FALSE; Primary->Agent.ActiveListenSocketCount --; continue; } } return STATUS_SUCCESS; }
VOID PrimaryAgentThreadProc( IN PPRIMARY Primary ) { BOOLEAN primaryAgentThreadExit = FALSE; ULONG listenSocketIndex; PKWAIT_BLOCK waitBlocks; SPY_LOG_PRINT( LFS_DEBUG_PRIMARY_INFO, ("PrimaryAgentThreadProc: Start\n")); Primary->Agent.Flags |= PRIMARY_AGENT_INITIALIZING; // // Allocate wait block // waitBlocks = ExAllocatePool(NonPagedPool, sizeof(KWAIT_BLOCK) * MAXIMUM_WAIT_OBJECTS); if(waitBlocks == NULL) { ASSERT(LFS_REQUIRED); PsTerminateSystemThread(STATUS_INSUFFICIENT_RESOURCES); } for(listenSocketIndex=0; listenSocketIndex<MAX_SOCKETLPX_INTERFACE; listenSocketIndex++) KeInitializeEvent( &Primary->Agent.ListenSocket[listenSocketIndex].TdiListenContext.CompletionEvent, NotificationEvent, FALSE ); BindListenSockets( Primary ); Primary->Agent.Flags |= PRIMARY_AGENT_START; KeSetEvent(&Primary->Agent.ReadyEvent, IO_DISK_INCREMENT, FALSE); while(primaryAgentThreadExit == FALSE) { PKEVENT events[MAXIMUM_WAIT_OBJECTS]; LONG eventCnt; ULONG i; LARGE_INTEGER timeOut; NTSTATUS ntStatus; PLIST_ENTRY primaryAgentRequestEntry; ASSERT(MAX_SOCKETLPX_INTERFACE + 1 <= MAXIMUM_WAIT_OBJECTS); eventCnt = 0; events[eventCnt++] = &Primary->Agent.RequestEvent; if(!BooleanFlagOn(Primary->Agent.Flags, PRIMARY_AGENT_SHUTDOWN)) { for(i=0; i<MAX_SOCKETLPX_INTERFACE; i++) { if(Primary->Agent.ListenSocket[i].TdiListenContext.Irp && Primary->Agent.ListenSocket[i].Active) { events[eventCnt++] = &Primary->Agent.ListenSocket[i].TdiListenContext.CompletionEvent; } else { // events[eventCnt++] = NULL; // I wanna set NULL, But It's not Work events[eventCnt++] = &Primary->Agent.ListenSocket[i].TdiListenContext.CompletionEvent; } } ASSERT(eventCnt == MAX_SOCKETLPX_INTERFACE + 1); } timeOut.QuadPart = - 5 * HZ; ntStatus = KeWaitForMultipleObjects( eventCnt, events, WaitAny, Executive, KernelMode, TRUE, &timeOut, waitBlocks ); if(ntStatus == STATUS_TIMEOUT) { continue; } SPY_LOG_PRINT( LFS_DEBUG_PRIMARY_TRACE, ("PrimaryAgentThreadProc: NTSTATUS:%lu\n", ntStatus)); if(!NT_SUCCESS(ntStatus) || ntStatus >= eventCnt) { ASSERT(LFS_UNEXPECTED); SetFlag(Primary->Agent.Flags, PRIMARY_AGENT_ERROR); primaryAgentThreadExit = TRUE; continue; } KeClearEvent(events[ntStatus]); if(0 == ntStatus) { SPY_LOG_PRINT( LFS_DEBUG_PRIMARY_TRACE, ("PrimaryAgentThreadProc: RequestEvent received\n")); while(primaryAgentRequestEntry = ExInterlockedRemoveHeadList( &Primary->Agent.RequestQueue, &Primary->Agent.RequestQSpinLock ) ) { PPRIMARY_AGENT_REQUEST primaryAgentRequest; primaryAgentRequest = CONTAINING_RECORD( primaryAgentRequestEntry, PRIMARY_AGENT_REQUEST, ListEntry ); switch(primaryAgentRequest->RequestType) { case PRIMARY_AGENT_REQ_DISCONNECT: { CloseListenSockets( Primary, FALSE ); break; } case PRIMARY_AGENT_REQ_SHUTDOWN: { CloseListenSockets( Primary, TRUE ); SetFlag(Primary->Agent.Flags, PRIMARY_AGENT_SHUTDOWN); break; } case PRIMARY_AGENT_REQ_DOWN: primaryAgentThreadExit = TRUE; break; // // added to adapt network card changes. // case PRIMARY_AGENT_REQ_NIC_DISABLED: SPY_LOG_PRINT( LFS_DEBUG_PRIMARY_INFO, ("PrimaryAgentThreadProc: PRIMARY_AGENT_REQ_NIC_DISABLED\n")); PrimaryAgentNICDisabled(Primary, &primaryAgentRequest->AddressList); break; case PRIMARY_AGENT_REQ_NIC_ENABLED: SPY_LOG_PRINT( LFS_DEBUG_PRIMARY_TRACE, ("PrimaryAgentThreadProc: PRIMARY_AGENT_REQ_NIC_ENABLED\n")); PrimaryAgentNICEnabled(Primary, &primaryAgentRequest->AddressList); break; default: ASSERT(LFS_BUG); SetFlag(Primary->Agent.Flags, PRIMARY_AGENT_ERROR); break; } if(primaryAgentRequest->Synchronous == TRUE) KeSetEvent(&primaryAgentRequest->CompleteEvent, IO_DISK_INCREMENT, FALSE); else DereferencePrimaryAgentRequest( primaryAgentRequest ); } continue; } ASSERT(1 <= ntStatus && ntStatus < eventCnt); // LpxEvent if( 1 <= ntStatus && ntStatus <= MAX_SOCKETLPX_INTERFACE ) // Connected { NTSTATUS tdiStatus; HANDLE listenFileHandle; PFILE_OBJECT listenFileObject; HANDLE connFileHandle; PFILE_OBJECT connFileObject; PPRIMARY_LISTEN_SOCKET listenSocket; LPX_ADDRESS remoteAddress; listenSocket = &Primary->Agent.ListenSocket[ntStatus-1]; // // retreive a connection file and remote address. // connFileHandle = listenSocket->ListenFileHandle; connFileObject = listenSocket->ListenFileObject; RtlCopyMemory(&remoteAddress, &listenSocket->TdiListenContext.RemoteAddress, sizeof(LPX_ADDRESS)); listenSocket->TdiListenContext.Irp = NULL; listenSocket->ListenFileHandle = NULL; listenSocket->ListenFileObject = NULL; KeClearEvent(&listenSocket->TdiListenContext.CompletionEvent); if(!listenSocket->Active) { SPY_LOG_PRINT( LFS_DEBUG_PRIMARY_INFO, ("ListenSocket is not active. Maybe a NIC disabled.\n")); continue; } else if(listenSocket->TdiListenContext.Status != STATUS_SUCCESS) { LpxTdiCloseAddress ( listenSocket->AddressFileHandle, listenSocket->AddressFileObject ); listenSocket->Active = FALSE; Primary->Agent.ActiveListenSocketCount --; SPY_LOG_PRINT( LFS_DEBUG_PRIMARY_INFO, ("Listen IRP #%d failed.\n", ntStatus)); continue; } SPY_LOG_PRINT( LFS_DEBUG_PRIMARY_INFO, ("PrimaryAgentThreadProc: Connect from %02X:%02X:%02X:%02X:%02X:%02X 0x%4X\n", listenSocket->TdiListenContext.RemoteAddress.Node[0], listenSocket->TdiListenContext.RemoteAddress.Node[1], listenSocket->TdiListenContext.RemoteAddress.Node[2], listenSocket->TdiListenContext.RemoteAddress.Node[3], listenSocket->TdiListenContext.RemoteAddress.Node[4], listenSocket->TdiListenContext.RemoteAddress.Node[5], NTOHS(listenSocket->TdiListenContext.RemoteAddress.Port) )); // // Make a new listen connection first of all to get another connection. // It must be earlier than start a session that takes long time. // Primary cannot accept a connection before it creates a new listen object. // tdiStatus = MakeConnectionObject( listenSocket->AddressFileHandle, listenSocket->AddressFileObject, &listenFileHandle, &listenFileObject ); if(!NT_SUCCESS(tdiStatus)) { ASSERT(LPX_BUG); LpxTdiCloseAddress ( listenSocket->AddressFileHandle, listenSocket->AddressFileObject ); listenSocket->Active = FALSE; Primary->Agent.ActiveListenSocketCount --; goto start_session; } listenSocket->ListenFileHandle = listenFileHandle; listenSocket->ListenFileObject = listenFileObject; listenSocket->Flags = TDI_QUERY_ACCEPT; tdiStatus = LpxTdiListenWithCompletionEvent( listenSocket->ListenFileObject, &listenSocket->TdiListenContext, &listenSocket->Flags ); if(!NT_SUCCESS(tdiStatus)) { ASSERT(LPX_BUG); LpxTdiDisassociateAddress(listenFileObject); LpxTdiCloseConnection(listenFileHandle, listenFileObject); LpxTdiCloseAddress ( listenSocket->AddressFileHandle, listenSocket->AddressFileObject ); listenSocket->Active = FALSE; Primary->Agent.ActiveListenSocketCount --; } start_session: // // start a session. // Primary_AcceptConnection(Primary, connFileHandle, connFileObject, ntStatus-1, &remoteAddress); continue; } } for(listenSocketIndex=0; listenSocketIndex<MAX_SOCKETLPX_INTERFACE; listenSocketIndex++) KeClearEvent(&Primary->Agent.ListenSocket[listenSocketIndex].TdiListenContext.CompletionEvent); // // Free wait blocks // ExFreePool(waitBlocks); SPY_LOG_PRINT( LFS_DEBUG_PRIMARY_INFO, ("PrimaryAgentThreadProc: PsTerminateSystemThread\n")); Primary->Agent.Flags |= PRIMARY_AGENT_TERMINATED; PsTerminateSystemThread(STATUS_SUCCESS); }