// ***************************** // // Copyright (c) 1990 Microsoft Corporation // // Module Name: // // tpstress.c // // Abstract: // // This module implements the Test Protocol Stress routines and the // basic controls for stressing the MAC. // // Author: // // Tom Adams (tomad) 15-Dec-1990 // // Environment: // // Kernel mode // // Revision History: // // Sanjeev Katariya(sanjeevk) // 3-16-93 Bug#2874: TpStressFreeResources(). // 4-8-93 Bug#2874: Added routine TpStressFreePostResetResources() to be able to // call it thru the routine and its associated completion routine. // 4-8-1993 Added ARCNET Support // 5-14-1993 Bug#6583 Re-arranged and cleaned up TpStressDpc for CYCLICAL testing // // Tim Wynsma (timothyw) // 5-18-94 Fixed warnings; general cleanup // // **************************** #include #include #include "tpdefs.h" #include "media.h" #include "tpprocs.h" // // Forward references // VOID TpStressDpc( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SysArg1, IN PVOID SysArg2 ); VOID TpStressServerDpc( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SysArg1, IN PVOID SysArg2 ); VOID TpStressStatsDpc( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SysArg1, IN PVOID SysArg2 ); VOID TpStressEndReqDpc( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SysArg1, IN PVOID SysArg2 ); VOID TpStressFinalDpc( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SysArg1, IN PVOID SysArg2 ); VOID TpStressFreeClient( IN POPEN_BLOCK OpenP ); VOID TpStressFreeServer( IN POPEN_BLOCK OpenP ); VOID TpStressFreePostResetResources( IN POPEN_BLOCK OpenP ); VOID TpStressRegister2Dpc( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SysArg1, IN PVOID SysArg2 ); // // ******************** // NDIS_STATUS TpStressStart( IN POPEN_BLOCK OpenP, IN PSTRESS_ARGUMENTS StressArguments ) // -------------------- // // Routine Description: // // This is the main routine of the NDIS 3.0 Stress Tool. This routine // opens the proper MAC adapter, creates the data structures used to // control the test, runs the specific test, and then cleans up. // // The flow of an actual test is controlled through a series of packet // protocols sent from a Client machine to any responding Server machines. // Initially the Client sends a REGISTER_REQ packet to an agreed upon // address that all servers have registered as a multicast address. Any // Server receiving this packet responds directly to the Client with a // REGISTER_RESP packet stating that the Server will participate in the // test. At this point the Client begins to send the actual test packets, // TEST_REQ, to each registered Server, who in turn responds with a // TEST_RESP packet. At the end of a test run the Client sends each // Server a STATS_REQ packet requesting that the Server print it's test // statistic. Finally the Client sends a TEST_END packet which causes // each Server to tear down it's test control data structures and end // the test. // // Arguments: // // None. // // Return Value: // // None. // // ---------------------- { NDIS_STATUS Status; PNDIS_PACKET Packet = NULL; PSTRESS_ARGUMENTS Args = NULL; PSERVER_INFO Server = NULL; INT i, j; INT ClientNumPackets = 100; // put in environment. INT ServerNumPackets = 100; UINT PacketFilter; LARGE_INTEGER DueTime; PPENDING PPend; // // Set the StartStarted flag to true indicating that we are running // a stress test, it will be set to false later if the initialization // fails. Set the stress cleanup flags Final and Ended to false. // This will disable any early unexpected cleanup. // OpenP->Stress->StressStarted = TRUE; OpenP->Stress->StressFinal = FALSE; OpenP->Stress->StressEnded = FALSE; // // Increment the reference count on the OpenBlock stating that an async // test is running and must be ended prior to closing the adapter on this // open. // TpAddReference( OpenP ); // // Initialize the test arguments structure using the arguments passed // in from the command line. // OpenP->Stress->Arguments = StressArguments; // // Set up new Args pointer for easier access to the arguments. // Args = OpenP->Stress->Arguments; // // Initialize the random number generator. // TpSetRandom(); // // Initialize the data buffer used for the data in each packet. // TpStressInitDataBuffer( OpenP,2 * OpenP->Media->MaxPacketLen ); if ( OpenP->Stress->DataBuffer[0] == NULL || OpenP->Stress->DataBuffer[1] == NULL || OpenP->Stress->DataBufferMdl[0] == NULL || OpenP->Stress->DataBufferMdl[1] == NULL ) { TpPrint0("TpStressStart: failed to init Data Buffer\n"); Status = NDIS_STATUS_RESOURCES; goto clean_up; } // // Allocate the global counter storage and zero the counters. // Status = NdisAllocateMemory((PVOID *)&OpenP->GlobalCounters, sizeof( GLOBAL_COUNTERS ), 0, HighestAddress ); if ( Status != NDIS_STATUS_SUCCESS ) { IF_TPDBG (TP_DEBUG_RESOURCES) { TpPrint0("TpStressStart: failed to allocate counters.\n"); } Status = NDIS_STATUS_RESOURCES; goto clean_up; } else { NdisZeroMemory((PVOID)OpenP->GlobalCounters,sizeof( GLOBAL_COUNTERS )); } NdisAllocatePacketPool( &Status, &OpenP->Stress->PacketHandle, 50, sizeof( PROTOCOL_RESERVED ) ); if ( Status != NDIS_STATUS_SUCCESS ) { TpPrint0("TpStressStart: could not allocate OpenP packet pool\n"); goto clean_up; } else { OpenP->Stress->PoolInitialized = TRUE; } // // Then initialize the PPENDING buffer. // TpInitializePending( OpenP->Stress->Pend ); if (( Args->MemberType == TP_SERVER ) || ( Args->MemberType == BOTH )) { // // Allocate memory for the server storage and packet pool, initialize // it and the CLIENT_INFO array contained. // Status = NdisAllocateMemory((PVOID *)&OpenP->Stress->Server, sizeof( SERVER_STORAGE ), 0, HighestAddress ); if ( Status != NDIS_STATUS_SUCCESS ) { TpPrint0("TpStressStart: could not allocate Server storage memory\n"); Status = NDIS_STATUS_RESOURCES; goto clean_up; } else { NdisZeroMemory( OpenP->Stress->Server,sizeof( SERVER_STORAGE )); } OpenP->Stress->Server->NumClients = 0 ; OpenP->Stress->Server->ActiveClients = 0; OpenP->Stress->Server->PoolInitialized = FALSE; OpenP->Stress->Server->PadByte = 0xFF; OpenP->Stress->Server->PacketHandle = NULL; OpenP->Stress->Server->TransmitPool = NULL; OpenP->Stress->Server->PadLong = 0xFFFFFFFF; for ( i=0 ; i < MAX_CLIENTS ; i++ ) { OpenP->Stress->Server->Clients[i].ClientInstance = 0xFF; OpenP->Stress->Server->Clients[i].ClientReference = 0xFF; OpenP->Stress->Server->Clients[i].DataChecking = FALSE; OpenP->Stress->Server->Clients[i].TestEnding = FALSE; OpenP->Stress->Server->Clients[i].ServerResponseType = -1; OpenP->Stress->Server->Clients[i].LastSequenceNumber = 0; OpenP->Stress->Server->Clients[i].Counters = NULL; } NdisAllocatePacketPool( &Status, &OpenP->Stress->Server->PacketHandle, 200, // should be environment.server... sizeof( PROTOCOL_RESERVED ) ); if ( Status != NDIS_STATUS_SUCCESS ) { TpPrint0("TpStressStart: could not allocate server packet pool\n"); goto clean_up; } else { OpenP->Stress->Server->PoolInitialized = TRUE; } // // The server always gets it's TEST_RESP packets from a transmit // pool, so create it now. // OpenP->Stress->Server->TransmitPool = TpStressCreateTransmitPool( OpenP, OpenP->Stress->Server->PacketHandle, Args->PacketMakeUp, TEST_RESP, Args->ResponseType, Args->PacketSize, ServerNumPackets, TRUE ); if ( OpenP->Stress->Server->TransmitPool == NULL ) { TpPrint0("TpStressStart: could not create server transmit pool\n"); Status = NDIS_STATUS_RESOURCES; goto clean_up; } // // Set the stressing flag, thus enabling the TpStress protocol // handler routines, and the stopstress flag to allow the TpStress // Dpc to be queued. // OpenP->Stress->Stressing = TRUE; OpenP->Stress->StopStressing = FALSE; // // Now setup the card to receive packets. // // // STARTCHANGE // if ( OpenP->Media->MediumType == NdisMedium802_5 ) // Tokenring { // // add the stress functional address "C0-00-00-01-00-00" // Status = TpStressSetFunctionalAddress( OpenP, (PUCHAR)&OpenP->Environment->StressAddress[2], FALSE ); if (( Status != NDIS_STATUS_SUCCESS ) && ( Status != NDIS_STATUS_PENDING )) { TpPrint0("TpStressStart: failed to set Functional Address.\n"); goto clean_up; } PacketFilter = NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_FUNCTIONAL; } else if (OpenP->Media->MediumType == NdisMedium802_3) // Ethernet { // // or the stress multicast address "07-07-07-07-07-07" // Status = TpStressAddMulticastAddress( OpenP, (PUCHAR)OpenP->Environment->StressAddress, FALSE ); if (( Status != NDIS_STATUS_SUCCESS ) && ( Status != NDIS_STATUS_PENDING )) { TpPrint0("TpStressStart: failed to add Test Multicast address.\n"); goto clean_up; } PacketFilter = NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_MULTICAST; } else if (OpenP->Media->MediumType == NdisMediumFddi) // Fddi { // // or the stress multicast address "07-07-07-07-07-07" // Status = TpStressAddLongMulticastAddress( OpenP, (PUCHAR)OpenP->Environment->StressAddress, FALSE ); if (( Status != NDIS_STATUS_SUCCESS ) && ( Status != NDIS_STATUS_PENDING )) { TpPrint0("TpStressStart: failed to add Test Multicast address.\n"); goto clean_up; } PacketFilter = NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_MULTICAST; } else if (OpenP->Media->MediumType == NdisMediumArcnet878_2) // ARCNET { // // ARCNET does not support the concept of multicast(group) addressing. // It works it two modes only, either directed or broadcast. So will use // the broadcast for setting up client server connections and thereafter // use the directed addresses // PacketFilter = NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST; } // // STOPCHANGE // // // Set the packet filter to accept the following packet types. // Status = TpStressSetPacketFilter( OpenP,PacketFilter ); if (( Status != NDIS_STATUS_SUCCESS ) && ( Status != NDIS_STATUS_PENDING )) { TpPrint0("TpStressStart: failed to set packet filter.\n"); goto clean_up; } if ( Args->MemberType == TP_SERVER ) { // // Initialize the DPC used to call TpStressServerDpc, and // TpStressFinalDpc. // KeInitializeDpc(&OpenP->Stress->TpStressDpc, TpStressServerDpc, (PVOID)OpenP ); KeInitializeDpc(&OpenP->Stress->TpStressFinalDpc, TpStressFinalDpc, (PVOID)OpenP ); // // and then set the flag allowing the receive handler to // accept and process test packets. // Args->BeginReceives = TRUE; // // The Server's main body of work is performed in the receive // handler, TpStressReceive, and the receive completion routine, // TpStressReceiveComplete. Once the Client sends the END_REQ // packet the server will break out of the busy loop, clean up and // exit. So, for now the server simply queues a DPC at which time // the server examines the stop flags, and if true, cleans up and // exits. // // // Queue the first instance of the DPC and return. // if ( !KeInsertQueueDpc( &OpenP->Stress->TpStressDpc, NULL, NULL) ) { IF_TPDBG ( TP_DEBUG_DPC ) { TpPrint0("TpStressStart failed to queue the TpStressServerDpc.\n"); } Status = NDIS_STATUS_FAILURE; goto clean_up; } } } if (( Args->MemberType == TP_CLIENT ) || ( Args->MemberType == BOTH )) { // // Allocate memory for the client storage and packet pool, initialize // it and the SERVER_INFO array contained. // Status = NdisAllocateMemory((PVOID *)&OpenP->Stress->Client, sizeof( CLIENT_STORAGE ), 0, HighestAddress ); if ( Status != NDIS_STATUS_SUCCESS ) { TpPrint0("TpStressStart: could not allocate client storage.\n"); goto clean_up; } else { NdisZeroMemory( OpenP->Stress->Client,sizeof( CLIENT_STORAGE )); } OpenP->Stress->Client->NumServers = 0 ; OpenP->Stress->Client->NextServer = 0 ; OpenP->Stress->Client->ActiveServers = 0; OpenP->Stress->Client->PoolInitialized = FALSE; OpenP->Stress->Client->PacketHandle = NULL; OpenP->Stress->Client->TransmitPool = NULL; OpenP->Stress->Client->PacketSize = sizeof( STRESS_PACKET ); OpenP->Stress->Client->BufferSize = 1; OpenP->Stress->Client->SizeIncrease = OpenP->Media->MaxPacketLen/150; for ( i=0 ; i < MAX_SERVERS ; i++ ) { OpenP->Stress->Client->Servers[i].ServerInstance = 0xFF; OpenP->Stress->Client->Servers[i].ClientReference = 0xFF; OpenP->Stress->Client->Servers[i].ServerReference = 0xFF; OpenP->Stress->Client->Servers[i].ServerActive = FALSE; OpenP->Stress->Client->Servers[i].WindowReset = 0; OpenP->Stress->Client->Servers[i].SequenceNumber = 1; if ( Args->WindowEnabled == TRUE ) { OpenP->Stress->Client->Servers[i].MaxSequenceNumber = OpenP->Environment->WindowSize; } else { OpenP->Stress->Client->Servers[i].MaxSequenceNumber = 0xFFFFFFFF; } OpenP->Stress->Client->Servers[i].LastSequenceNumber = 0; OpenP->Stress->Client->Servers[i].PacketDelay = 0; OpenP->Stress->Client->Servers[i].DelayLength = Args->DelayLength; OpenP->Stress->Client->Servers[i].WindowReset = 0; } NdisAllocatePacketPool( &Status, &OpenP->Stress->Client->PacketHandle, 200, // 1000, // should 200 be environment... sizeof( PROTOCOL_RESERVED ) ); if ( Status != NDIS_STATUS_SUCCESS ) { TpPrint0("TpStressStart: could not allocate client packet pool\n"); goto clean_up; } else { OpenP->Stress->Client->PoolInitialized = TRUE; } if ( Args->PacketsFromPool == TRUE ) { OpenP->Stress->Client->TransmitPool = TpStressCreateTransmitPool( OpenP, OpenP->Stress->Client->PacketHandle, Args->PacketMakeUp, TEST_REQ, Args->ResponseType, Args->PacketSize, ClientNumPackets, FALSE ); if ( OpenP->Stress->Client->TransmitPool == NULL ) { TpPrint0("TpStressStart: could not create TP packet pool\n"); Status = NDIS_STATUS_RESOURCES; goto clean_up; } } // // Initialize the DPCs to call TpStressDpc, TpStressReg2Dpc, // TpStressStatsDpc, TpStressEndReqDpc and TpStressFinalDpc. // KeInitializeDpc(&OpenP->Stress->TpStressDpc, TpStressDpc, (PVOID)OpenP ); KeInitializeDpc(&OpenP->Stress->TpStressReg2Dpc, TpStressRegister2Dpc, (PVOID)OpenP ); KeInitializeDpc(&OpenP->Stress->TpStressStatsDpc, TpStressStatsDpc, (PVOID)OpenP ); KeInitializeDpc(&OpenP->Stress->TpStressEndReqDpc, TpStressEndReqDpc, (PVOID)OpenP ); KeInitializeDpc(&OpenP->Stress->TpStressFinalDpc, TpStressFinalDpc, (PVOID)OpenP ); // // and then set the flag to enable packets being received // to be handled. // Args->BeginReceives = TRUE; // // Set the stressing flag, thus enabling the TpStress protocol // handler routines, and the stopstress flag to allow the // TpStress Dpc to be queued. // OpenP->Stress->Stressing = TRUE; OpenP->Stress->StopStressing = FALSE; if ( Args->MemberType == TP_CLIENT ) { // // Set the packet filter to accept directed packets only. // PacketFilter = NDIS_PACKET_TYPE_DIRECTED; Status = TpStressSetPacketFilter( OpenP,PacketFilter ); if (( Status != NDIS_STATUS_SUCCESS ) && ( Status != NDIS_STATUS_PENDING )) { TpPrint0("TpStressStart: failed to set packet filter.\n"); goto clean_up; } } // // We are now ready to begin the test, send several instances // of the REGISTER_REQ packet to the STRESS_MULTICAST/FUNCTIONAL // address. // TpPrint0("TpStress: starting search for servers\n"); PPend = OpenP->Stress->Pend; for ( j=0;j<10;j++ ) { // // Construct the REGISTER_REQ packet and send it. // Packet = TpStressCreatePacket( OpenP, OpenP->Stress->Client->PacketHandle, Args->PacketMakeUp, 0, // ServerInstance OpenP->OpenInstance, REGISTER_REQ, Args->ResponseType, OpenP->Environment->StressAddress, sizeof( STRESS_PACKET ), sizeof( STRESS_PACKET ), (ULONG)j, 0L,0,0, Args->DataChecking ); if ( Packet == NULL ) { TpPrint1("TpStressStart: failed to build REGISTER_REQ packet #%d\n",j); Status = NDIS_STATUS_RESOURCES; goto clean_up; } TpStressSend( OpenP,Packet,NULL ); // // Pause momentarily before sending the next packet. // for (;;) { DueTime.HighPart = -1; // So it will be relative. DueTime.LowPart = (ULONG)(-4 * ONE_HUNDREDTH_SECOND ); KeDelayExecutionThread(KernelMode, TRUE, &DueTime); NdisAcquireSpinLock( &PPend->SpinLock ); if (PPend->PendingPackets) { NdisReleaseSpinLock( &PPend->SpinLock ); } else { NdisReleaseSpinLock( &PPend->SpinLock ); break; } } } TpPrint0("TpStress: done with search for servers\n"); // // If no servers have registered there is no point in running // the test, clean up and return. // if ( OpenP->Stress->Client->NumServers == 0 ) { TpPrint0("TpStressStart: No servers registered, exiting\n"); Status = TP_STATUS_NO_SERVERS; goto clean_up; } // // Show what servers are registered. // for ( i=0;i<(INT)OpenP->Stress->Client->NumServers;i++ ) { IF_TPDBG ( TP_DEBUG_DPC ) { TpPrint2("\nServer %d: open %d, ", i, OpenP->Stress->Client->Servers[i].ServerInstance); // // STARTCHANGE // if ( OpenP->Media->MediumType == NdisMediumArcnet878_2 ) { TpPrint1("address %02X\n", OpenP->Stress->Client->Servers[i].Address[0]); } else { TpPrint6("address %02X-%02X-%02X-%02X-%02X-%02X\n", OpenP->Stress->Client->Servers[i].Address[0], OpenP->Stress->Client->Servers[i].Address[1], OpenP->Stress->Client->Servers[i].Address[2], OpenP->Stress->Client->Servers[i].Address[3], OpenP->Stress->Client->Servers[i].Address[4], OpenP->Stress->Client->Servers[i].Address[5]); } // // STOPCHANGE // } } // // Initialize the multi-purpose counter used for the up-for-air // delay, stats dpc and end dpc, and the Register_Req2 counter. // OpenP->Stress->FirstIteration = TRUE; OpenP->Stress->Counter = 0; OpenP->Stress->Reg2Counter = 0; // // Queue the first instance of the Stress DPC. // DueTime.HighPart = -1; // So it will be relative. DueTime.LowPart = (ULONG)(- ( 5 * ONE_SECOND )); if ( KeSetTimer(&OpenP->Stress->TpStressTimer, DueTime, &OpenP->Stress->TpStressDpc )) { IF_TPDBG ( TP_DEBUG_DPC ) { TpPrint0("TpStressStart failed to queue the TpStressDpc.\n"); } Status = NDIS_STATUS_FAILURE; goto clean_up; } // // Queue the first instance of the Register2 DPC and return. // if ( !KeInsertQueueDpc( &OpenP->Stress->TpStressReg2Dpc, NULL, NULL )) { IF_TPDBG ( TP_DEBUG_DPC ) { TpPrint0("TpStressStart failed to queue the TpStressReg2Dpc.\n"); } Status = NDIS_STATUS_FAILURE; goto clean_up; } } return NDIS_STATUS_PENDING; clean_up: IF_TPDBG ( TP_DEBUG_DISPATCH ) { TpPrint1("TpStressStart failed to start: returned %s\n", TpGetStatus( Status )); } NdisAcquireSpinLock( &OpenP->SpinLock ); if ( OpenP->Stress->StressIrp != NULL ) { OpenP->Stress->StressIrp->IoStatus.Status = Status; } NdisReleaseSpinLock( &OpenP->SpinLock ); return Status; } VOID TpStressDpc( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SysArg1, IN PVOID SysArg2 ) // ------- // // Routine Description: // // Arguments: // // Return Value: // // ----------- { POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext); PSTRESS_ARGUMENTS Args; PCLIENT_STORAGE Client; NDIS_STATUS Status; UCHAR ServerNum; PSERVER_INFO Server; BOOLEAN ContinueSending = TRUE; LARGE_INTEGER DueTime; UNREFERENCED_PARAMETER( Dpc ); UNREFERENCED_PARAMETER( SysArg1 ); UNREFERENCED_PARAMETER( SysArg2 ); Args = OpenP->Stress->Arguments; Client = OpenP->Stress->Client; // // This is the main loop of a stress test, in this loop RANDOM or // FIXED size packets are sent to each server depending on the delay // intervals and window size. Packets are sent one to a server, as // the client loops through each server, and then repeats, if a // window is closed for a given server, or the packet delay has not // been reached that server will be skipped over. The client will // continue to loop thru the servers sending packets until either // all the packets have been sent, or all the iterations have been // iterated. NOTE: setting the ServerActive flag to false on all // the servers will also result in the test ending. // // // If this is the beginning of the test, get the Start Time // for later statistics computation. // if ( OpenP->Stress->FirstIteration == TRUE ) { KeQuerySystemTime( &OpenP->Stress->StartTime ); OpenP->Stress->FirstIteration = FALSE; } // // If the Stress Irp has been cancelled then clean up and leave. // NdisAcquireSpinLock( &OpenP->SpinLock ); if (( OpenP->Stress->StressIrp == NULL ) || ( OpenP->Stress->StressIrp->Cancel == TRUE )) { NdisReleaseSpinLock( &OpenP->SpinLock ); OpenP->Stress->StopStressing = TRUE; } else if ( Client->ActiveServers <= 0 ) { NdisReleaseSpinLock( &OpenP->SpinLock ); // // There are no more active servers so just end the test here. // IF_TPDBG ( TP_DEBUG_DPC ) { TpPrint1("TpStressDpc: WARNING - Client Open Instance %d ending test.\n", OpenP->OpenInstance); TpPrint0("\tNo remaining active stress servers\n"); } OpenP->Stress->StopStressing = TRUE; } else if (( Args->PacketType == RANDOMSIZE ) || ( Args->PacketType == FIXEDSIZE )) { NdisReleaseSpinLock( &OpenP->SpinLock ); // // Start looping sending packets until one of the conditions // is met for stopping and requeueing a new DPC to send later. // The possible conditions are Packet Delay not met, Window for // a given server is closed or there are no available packets. // while ( ContinueSending == TRUE ) { // // As long as there are still packets to send or loops to // iterate continue sending packets. // if (( Args->Iterations++ >= Args->TotalIterations ) || ( Args->AllPacketsSent == TRUE )) { break; } else { // // Set the packets sent flag to true, it will be reset to // false later in the loop if there are really packets left // to send. // Args->AllPacketsSent = TRUE; // // Now loop through each of the servers starting with the // server we left of with at the end of the last DPC. // for ( ServerNum = Client->NextServer; ServerNum < Client->NumServers; ServerNum++ ) { Server = &Client->Servers[ServerNum]; // // If this server is still active and we have not sent all // the packets required to this it, then continue with // the send process. // if (( Server->ServerActive == TRUE ) && ( Server->SequenceNumber <= Args->TotalPackets )) { // // Set the flag indicating there are more packets // to be sent. // Args->AllPacketsSent = FALSE; // // Now check if the Client has waited long enough to // send another packet to this server. // if (( Server->PacketDelay++ >= Server->DelayLength ) && ( Server->SequenceNumber <= Server->MaxSequenceNumber )) { // // And if so, allocate a packet and send it to // the server. // Status = TpStressClientSend(OpenP, Client->PacketHandle, Client->TransmitPool, Server->Address, OpenP->OpenInstance, Server->ServerInstance, TEST_REQ, Server->SequenceNumber, 0, // MaxSeqNum: not used in TEST_REQ pkts. Server->ClientReference, Server->ServerReference, Client->PacketSize, Client->BufferSize ); if ( Status == NDIS_STATUS_SUCCESS ) { Server->SequenceNumber++; Server->PacketDelay = 0; if ( Args->DelayType == RANDOMDELAY ) { Server->DelayLength = TpGetRandom(0,Args->DelayLength); } } else { // // No packets available to send now. // Queue a new DPC and exit. // ContinueSending = FALSE; break; } // // If the window is not open, check to see if the // server is presumed dead. // } else if (( Args->WindowEnabled == TRUE ) && ( Server->PacketDelay > MAX_PACKET_DELAY )) { // Put MaxPacketDelay in environment? // // We have reset this servers window the maximum // number of times and it still is not responding // so we will remove it from the active servers. // if ( Server->WindowReset >= MAX_WINDOW_RESETS ) { IF_TPDBG ( TP_DEBUG_DPC ) { TpPrint2( "TpStressDpc: WARNING - Client Open Instance %d marking Server %d as Inactive.\n", OpenP->OpenInstance,Server->ServerInstance); } Server->ServerActive = FALSE; Client->ActiveServers--; // // This server may still be alive, so reset the // window to the initial state causing WINDOW_SIZE // more packets to be sent to the server on the // next pass through the loop. // } else { // // The packet delay for this server has exceeded // the maximum packet delay, and we are sending // with windowing enabled, so blast out Window // Size more packets. // IF_TPDBG ( TP_DEBUG_DPC ) { TpPrint1("TpStressDpc: WARNING - Client Open Instance %d\n", OpenP->OpenInstance); TpPrint2("\tincreasing Server %d MaxSequenceNumber to %d\n", Server->ServerInstance, Server->MaxSequenceNumber + OpenP->Environment->WindowSize ); } Server->MaxSequenceNumber += OpenP->Environment->WindowSize; Server->PacketDelay = 0; Server->WindowReset++; Client->NextServer++; ContinueSending = FALSE; break; } Client->NextServer++; break; } else { // // Either the window for this server is closed, // or the delay has not expired. Queue a new DPC, // and exit. We will start with the next server // with the next DPC. // Client->NextServer++; ContinueSending = FALSE; break; } } } // // We have come to the end of the server array, start again // at the beginning on the next FOR loop. // Client->NextServer = 0; } } } else // PacketType == CYCLICAL { // // STARTCHANGE // // SanjeevK // // This piece of code contain one too many nested loops. It needs to be cleaned // The cleanup will be instituted at a later date. For the time being the // loop control will be clearly marked with entry and exit conditions // NdisReleaseSpinLock( &OpenP->SpinLock ); if ( Client->PacketSize == 0 ) { // // We have just started the test, so set the PacketSize and // BufferSize to their minimum startimg sizes. // Client->PacketSize = sizeof( STRESS_PACKET ); Client->BufferSize = 1; } // // SanjeevK // // MARK EXTERIOR CONTROL // // NOTE // // All loops have control exit conditions. The code has been semi-cleaned // for recognizable operation. Breaks of jumping between control loops // has been minimized // // // This condition if valid gets executed once. If the total iteration count // is greater than 1, the work is DPCd and on re-entering takes on the // values set in the control global arguments. That is why it is very important // to not set the global control values on entry but on exit of a control // since work can be DPC'd from any part within the control loops. // if ( Args->Iterations < Args->TotalIterations ) { // // FIRST CONTROL LOOP. // Execute until we exceed MAX_PACKET_LENGTH. // while ( Client->PacketSize <= OpenP->Media->MaxPacketLen ) { // // SECOND CONTROL LOOP. // Execute till the buffer size has gone // thru a cycle of ( 1,Current Packet Size ) // while ( Client->BufferSize <= Client->PacketSize ) { // // Disable the above while loop if... // if ( Args->PacketMakeUp != KNOWN ) { Client->BufferSize = Client->PacketSize; Client->SizeIncrease = 1; } // // THIRD CONTROL LOOP // Execute the same code path for all registered/valid stress servers // for (ServerNum=Client->NextServer;ServerNum < Client->NumServers;ServerNum++) { Server = &Client->Servers[ServerNum]; // // If this server is still active then // continue with the send process. // if ( Server->ServerActive == TRUE ) { if (( Server->PacketDelay++ >= Server->DelayLength ) && ( Server->SequenceNumber <= Server->MaxSequenceNumber )) { Status = TpStressClientSend(OpenP, Client->PacketHandle, Client->TransmitPool, Server->Address, OpenP->OpenInstance, Server->ServerInstance, TEST_REQ, Server->SequenceNumber, 0, // MaxSeqNum: not used in TEST_REQ. Server->ClientReference, Server->ServerReference, Client->PacketSize, Client->BufferSize ); if ( Status == NDIS_STATUS_SUCCESS ) { Server->SequenceNumber++; Server->PacketDelay = 0; if (Args->DelayType == RANDOMDELAY) { Server->DelayLength = TpGetRandom(0,Args->DelayLength); } } else { // // No packets are available to send now, // So set the flag to queue a new DPC // and exit. // goto breakout; } // END of if ( Status == NDIS_STATUS_SUCCESS ) } else if (( Args->WindowEnabled == TRUE ) && ( Server->PacketDelay > MAX_PACKET_DELAY )) { // // We have reset this servers window the maximum // number of times and it still is not responding // so we will remove it from the active servers. // if ( Server->WindowReset >= MAX_WINDOW_RESETS ) { // // Since the window size for the server has exceeded // the maximum times it could have been reset, mark this // server as inactive and decrement the number of // active servers by one // IF_TPDBG ( TP_DEBUG_DPC ) { TpPrint2( "TpStressDpc: WARNING - Client Open Instance %d marking Server %d as Inactive.\n", OpenP->OpenInstance,Server->ServerInstance); } Server->ServerActive = FALSE; Client->ActiveServers--; } else { // // This server may still be alive, so reset the // window to the initial state causing WINDOW_SIZE // more packets to be sent to the server on the // next pass through the loop. // // The packet delay for this server has exceeded // the maximum packet delay, and we are sending // with windowing enabled, so blast out // WindowSize more packets. // IF_TPDBG ( TP_DEBUG_DPC ) { TpPrint1("TpStressDpc: WARNING - Client Open Instance %d\n", OpenP->OpenInstance); TpPrint2("\tincreasing Server %d MaxSequenceNumber to %d\n", Server->ServerInstance, Server->MaxSequenceNumber + OpenP->Environment->WindowSize ); } Server->MaxSequenceNumber += OpenP->Environment->WindowSize; Server->PacketDelay = 0; Server->WindowReset++; } // END of if ( Server->WindowReset >= MAX_WINDOW_RESETS ) Client->NextServer++; goto breakout; } else { // // Either the window for this server is closed // or the delay has not expired yet. Queue a // new DPC and exit. We will start with the // next server with the next DPC. // Client->NextServer++; ContinueSending = FALSE; goto breakout; } // END of if (( Args->WindowEnabled == TRUE ) && // ( Server->PacketDelay > MAX_PACKET_DELAY )) } // END of if ( Server->ServerActive == TRUE ) } // END of FOR loop. Indicates we have dealt with all servers in the list // // CONTROL EXIT CONDITION // Client->NextServer = 0; // // SanjeevK // // NOTE // // This code section was badly nested within another looping section // This simply needs to reside outside the loop // // ORIGINAL COMMENT // // If we have succesfully sent this packet // to the last server in the list, then // move on to the next packetsize/buffersize // combination. // // Client->BufferSize += Client->SizeIncrease; } // END of while ( Client->BufferSize <= Client->PacketSize ) // // CONTROL EXIT CONDITION // Client->BufferSize = 1; Client->PacketSize += Client->SizeIncrease; } // END of while ( Client->PacketSize <= OpenP->Media->MaxPacketLen ) // // CONTROL EXIT CONDITION // Client->PacketSize = sizeof( STRESS_PACKET); // // We have completed one full iteration of CYCLICAL // packets, inc the counter. // Args->Iterations++; } // END of if ( Args->Iterations < Args->TotalIterations ) } // END of the else PacketType == CYCLICAL breakout: // // If the StopStress flag has been set by a command line call, or // we have sent all the packets requested or completed the required // number of iterations, then end the stress routine and clean up. // if (( OpenP->Stress->StopStressing == TRUE ) || ( Args->AllPacketsSent == TRUE ) || ( Args->Iterations >= Args->TotalIterations )) { // // Set the stop stress flag to halt the Register2Dpc routine // now, if it was already set this will do nothing. // OpenP->Stress->StopStressing = TRUE; OpenP->Stress->Counter = 0; // // Set the time for when to queue the TpStressStatsDpc routine. // DueTime.HighPart = -1; // So it will be relative. DueTime.LowPart = (ULONG)(- ( 5 * ONE_SECOND )); if ( KeSetTimer(&OpenP->Stress->TpStressTimer, DueTime, &OpenP->Stress->TpStressStatsDpc )) { IF_TPDBG ( TP_DEBUG_DPC ) { TpPrint0("TpStressDpc set StressEnd timer while timer existed.\n"); } } } else { // // Otherwise the test should continue, so insert the next timer in // the timer queue and exit. This will queue the next instance of // the TpStressDpc routine when the timer goes off. // if ( OpenP->Stress->Counter == OpenP->Environment->StressDelayInterval ) { DueTime.HighPart = -1; // So it will be relative. DueTime.LowPart = (ULONG) (- ((LONG) OpenP->Environment->UpForAirDelay )); OpenP->Stress->Counter = 0; } else { DueTime.HighPart = -1; // So it will be relative. DueTime.LowPart = (ULONG)(- ((LONG) OpenP->Environment->StandardDelay )); OpenP->Stress->Counter++; } if ( KeSetTimer(&OpenP->Stress->TpStressTimer, DueTime, &OpenP->Stress->TpStressDpc )) { IF_TPDBG ( TP_DEBUG_DPC ) { TpPrint0("TpStressDpc set Stress timer while timer existed.\n"); } } } } VOID TpStressServerDpc( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SysArg1, IN PVOID SysArg2 ) // --------- // // Routine Description: // // Arguments: // // Return Value: // // --------- { POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext); LARGE_INTEGER DueTime; UNREFERENCED_PARAMETER( Dpc ); UNREFERENCED_PARAMETER( SysArg1 ); UNREFERENCED_PARAMETER( SysArg2 ); DueTime.HighPart = -1; // relative time. DueTime.LowPart = (ULONG)(- ( ONE_SECOND )); // // If the Stress Irp has been cancelled then clean up and leave. // NdisAcquireSpinLock( &OpenP->SpinLock ); if (( OpenP->Stress->StressIrp == NULL ) || ( OpenP->Stress->StressIrp->Cancel == TRUE )) { OpenP->Stress->StopStressing = TRUE; } NdisReleaseSpinLock( &OpenP->SpinLock ); if ( OpenP->Stress->StopStressing == TRUE ) { // // Either we have received an END_TEST packet from the last // Client we are stressing, or we have received a command from // the user interface to stop the test, set the IoStatusBlock // status field, and end it. // NdisAcquireSpinLock( &OpenP->SpinLock ); if ( OpenP->Stress->StressIrp != NULL ) { OpenP->Stress->StressIrp->IoStatus.Status = NDIS_STATUS_SUCCESS; } NdisReleaseSpinLock( &OpenP->SpinLock ); if ( KeSetTimer(&OpenP->Stress->TpStressTimer, DueTime, &OpenP->Stress->TpStressFinalDpc )) { IF_TPDBG ( TP_DEBUG_DPC ) { TpPrint0("TpStressServerDpc set Stress timer while timer existed.\n"); } } } else { // // Otherwise the test should continue, so insert the next timer in // the timer queue and exit. This will queue the next instance of // the TpStressServerDpc routine when the timer goes off. // if ( KeSetTimer(&OpenP->Stress->TpStressTimer, DueTime, &OpenP->Stress->TpStressDpc )) { IF_TPDBG ( TP_DEBUG_DPC ) { TpPrint0("TpStressServerDpc set Stress timer while timer existed.\n"); } } } } VOID TpStressStatsDpc( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SysArg1, IN PVOID SysArg2 ) // --------- // // Routine Description: // // Arguments: // // Return Value: // // ----------- { POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext); PSTRESS_ARGUMENTS Args; PCLIENT_STORAGE Client; UCHAR ServerNum; LARGE_INTEGER DueTime; PNDIS_PACKET Packet; UNREFERENCED_PARAMETER( Dpc ); UNREFERENCED_PARAMETER( SysArg1 ); UNREFERENCED_PARAMETER( SysArg2 ); Args = OpenP->Stress->Arguments; Client = OpenP->Stress->Client; // // If the Stress Irp has been cancelled then skip the stats requesting. // NdisAcquireSpinLock( &OpenP->SpinLock ); if (( OpenP->Stress->StressIrp != NULL ) && ( OpenP->Stress->StressIrp->Cancel == FALSE )) { NdisReleaseSpinLock( &OpenP->SpinLock ); // // Write the client statistics to the Results buffer, and send // STATS_REQ packets to each server request the servers test stats. // if ( OpenP->Stress->Counter == 0 ) { KeQuerySystemTime( &OpenP->Stress->EndTime ); TpCopyClientStatistics( OpenP ); TpPrintClientStatistics( OpenP ); } for ( ServerNum=0 ; ServerNum < Client->NumServers ; ServerNum++ ) { Packet = TpStressCreatePacket( OpenP, Client->PacketHandle, Args->PacketMakeUp, Client->Servers[ServerNum].ServerInstance, OpenP->OpenInstance, STATS_REQ, Args->ResponseType, Client->Servers[ServerNum].Address, 64, 32, OpenP->Stress->Counter, OpenP->Stress->Counter, Client->Servers[ServerNum].ClientReference, Client->Servers[ServerNum].ServerReference, Args->DataChecking ); if ( Packet == NULL ) { IF_TPDBG( TP_DEBUG_RESOURCES ) { TpPrint0("TpStressDpc: failed to create STATS_REQ Packet\n"); } } else { TpStressSend( OpenP,Packet,NULL ); } } } else { NdisReleaseSpinLock( &OpenP->SpinLock ); OpenP->Stress->StopStressing = TRUE; } if ( OpenP->Stress->Counter++ < 10 ) { // // requeue the StatsDpc. // DueTime.HighPart = -1; // So it will be relative. DueTime.LowPart = (ULONG)(- ( ONE_TENTH_SECOND )); if ( KeSetTimer(&OpenP->Stress->TpStressTimer, DueTime, &OpenP->Stress->TpStressStatsDpc )) { IF_TPDBG ( TP_DEBUG_DPC ) { TpPrint0("TpStressDpc set StressEnd timer while timer existed.\n"); } } } else { // // reset the multipurpose counter. // OpenP->Stress->Counter = 0; // // Then set the next timer for the EndDpc. // DueTime.HighPart = -1; // So it will be relative. DueTime.LowPart = (ULONG)(- ( 5 * ONE_SECOND )); if ( KeSetTimer(&OpenP->Stress->TpStressTimer, DueTime, &OpenP->Stress->TpStressEndReqDpc )) { IF_TPDBG ( TP_DEBUG_DPC ) { TpPrint0("TpStressDpc set Stress timer while timer existed.\n"); } } } } VOID TpStressEndReqDpc( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SysArg1, IN PVOID SysArg2 ) // ------- // // Routine Description: // // Arguments: // // Return Value: // // ------- { POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext); PSTRESS_ARGUMENTS Args; PCLIENT_STORAGE Client; UCHAR ServerNum; LARGE_INTEGER DueTime; PNDIS_PACKET Packet; UNREFERENCED_PARAMETER( Dpc ); UNREFERENCED_PARAMETER( SysArg1 ); UNREFERENCED_PARAMETER( SysArg2 ); Args = OpenP->Stress->Arguments; Client = OpenP->Stress->Client; // // If the Stress Irp has been cancelled then skip the stats requesting. // NdisAcquireSpinLock( &OpenP->SpinLock ); if (( OpenP->Stress->StressIrp != NULL ) && ( OpenP->Stress->StressIrp->Cancel == FALSE )) { NdisReleaseSpinLock( &OpenP->SpinLock ); // // Send an end request packet to each of the servers. // for ( ServerNum=0;ServerNumNumServers;ServerNum++ ) { Packet = TpStressCreatePacket( OpenP, Client->PacketHandle, Args->PacketMakeUp, Client->Servers[ServerNum].ServerInstance, OpenP->OpenInstance, END_REQ, Args->ResponseType, Client->Servers[ServerNum].Address, 64, 32, OpenP->Stress->Counter, OpenP->Stress->Counter, Client->Servers[ServerNum].ClientReference, Client->Servers[ServerNum].ServerReference, Args->DataChecking ); if ( Packet == NULL ) { IF_TPDBG( TP_DEBUG_RESOURCES ) { TpPrint0("TpStressDpc: failed to create END_REQ Packet\n"); } } else { TpStressSend( OpenP,Packet,NULL ); } } } else { NdisReleaseSpinLock( &OpenP->SpinLock ); OpenP->Stress->StopStressing = TRUE; } if ( OpenP->Stress->Counter++ < 10 ) { // // requeue the StatsDpc. // DueTime.HighPart = -1; // So it will be relative. DueTime.LowPart = (ULONG)(- ( ONE_TENTH_SECOND )); if ( KeSetTimer(&OpenP->Stress->TpStressTimer, DueTime, &OpenP->Stress->TpStressEndReqDpc )) { IF_TPDBG ( TP_DEBUG_DPC ) { TpPrint0("TpStressDpc set StressEnd timer while timer existed.\n"); } } } else { // // reset the multi-purpose counter. // OpenP->Stress->Counter = 0; // // Then set the next timer for the EndDpc. // DueTime.HighPart = -1; // So it will be relative. DueTime.LowPart = (ULONG)(- ( 10 * ONE_SECOND )); if ( KeSetTimer(&OpenP->Stress->TpStressTimer, DueTime, &OpenP->Stress->TpStressFinalDpc )) { IF_TPDBG ( TP_DEBUG_DPC ) { TpPrint0("TpStressDpc set Stress timer while timer existed.\n"); } } } } VOID TpStressFinalDpc( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SysArg1, IN PVOID SysArg2 ) // -------- // // Routine Description: // // Arguments: // // Return Value: // // -------- { POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext); NDIS_STATUS Status; PSTRESS_ARGUMENTS Args = NULL; PSERVER_INFO Server = NULL; UINT i; LARGE_INTEGER DueTime; UNREFERENCED_PARAMETER( Dpc ); UNREFERENCED_PARAMETER( SysArg1 ); UNREFERENCED_PARAMETER( SysArg2 ); Args = OpenP->Stress->Arguments; // // Check to see if all packets sent on this open have completed, // If they have not all completed see if we have waited long // enough. long enough being 10 one second delayed cycles // through TpStressEndDcp. // if ((((( Args->MemberType == TP_CLIENT ) && ( Args->PacketsFromPool == FALSE )) && ( OpenP->Stress->Pend->PendingPackets != 0 )) // // We are a Client getting each packet from the NdisPacketPool and // all the packets from the NdisPacketPool have not completed, or ... // || (( Args->PacketsFromPool == TRUE ) && ( OpenP->Stress->Pend->PacketPendNumber != OpenP->Stress->Pend->PacketCompleteNumber ))) // // We are getting the packets from the TP_PACKET_POOL, and // all the TpPoolPackets that pended have not completed and ... // && ( OpenP->Stress->Counter++ < 10 )) { // // We have not waited through 10 cycles of TpStressFinalDpc // Then reset the timer for this dpc to try again later. // DueTime.HighPart = -1; // So it will be relative. DueTime.LowPart = (ULONG)(- ( 1 * ONE_SECOND )); if ( KeSetTimer(&OpenP->Stress->TpStressTimer, DueTime, &OpenP->Stress->TpStressFinalDpc )) { IF_TPDBG ( TP_DEBUG_DPC ) { TpPrint0("TpStressDpc set Stress timer while timer existed.\n"); } } } else { // // Time to clean up, so first check if there are any packets // still in the pending queue representing packets that were // sent, pended, and have not completed. We only do this if // we are a Client, the server only part is handled at the // End_Req packet receipt time. // if (( Args->MemberType != TP_SERVER ) && ( OpenP->Stress->Pend->PendingPackets != 0 )) { // // There are packets in the pend queue, so print out there // addresses, and break. // IF_TPDBG( TP_DEBUG_DPC ) { TpPrint1("TpStressFinalDpc: The following %d packets are still in the\n", OpenP->Stress->Pend->PendingPackets); TpPrint1(" Client's Pend Queue for Open Instance %d.\n", OpenP->OpenInstance); TpPrint1(" Pend Queue = %lX\n\n", OpenP->Stress->Pend); for ( i=0 ; iStress->Pend->Packets[i] != NULL ) && ( OpenP->Stress->Pend->Packets[i] != (PNDIS_PACKET)-1 )) { TpPrint1("\t\t%lX\n", OpenP->Stress->Pend->Packets[i]); } } // TpBreakPoint(); } TpInitializePending( OpenP->Stress->Pend ); } // // Write the stress results into the ioctl buffer to be passed // back to the user application. // TpStressWriteResults( OpenP ); // // if we have set a functional address or added a multicast // address then clear it now. // if ( Args->MemberType != TP_CLIENT ) { if ( OpenP->Media->MediumType == NdisMedium802_5 ) // Token Ring { Status = TpStressSetFunctionalAddress( OpenP, (PUCHAR)NULL_ADDRESS, TRUE ); if (( Status != NDIS_STATUS_SUCCESS ) && ( Status != NDIS_STATUS_PENDING )) { IF_TPDBG( TP_DEBUG_NDIS_CALLS ) { TpPrint1( "TpStressServerCleanUp: failed to clear Functional Address--Status = %s\n", TpGetStatus(Status)); } } } else if (OpenP->Media->MediumType == NdisMedium802_3) // Ethernet { Status = TpStressAddMulticastAddress( OpenP, (PUCHAR)NULL_ADDRESS, TRUE ); if (( Status != NDIS_STATUS_SUCCESS ) && ( Status != NDIS_STATUS_PENDING )) { IF_TPDBG( TP_DEBUG_NDIS_CALLS ) { TpPrint1( "TpStressServerCleanUp: failed to delete Multicast Address--Status = %s\n", TpGetStatus(Status)); } } } else if (OpenP->Media->MediumType == NdisMediumFddi) // Fddi { Status = TpStressAddLongMulticastAddress( OpenP, (PUCHAR)NULL_ADDRESS, TRUE ); if (( Status != NDIS_STATUS_SUCCESS ) && ( Status != NDIS_STATUS_PENDING )) { IF_TPDBG( TP_DEBUG_NDIS_CALLS ) { TpPrint1( "TpStressServerCleanUp: failed to delete Multicast Address--Status = %s\n", TpGetStatus(Status)); } } } // And if you are Arcnet, do nothing } OpenP->Stress->StressFinal = TRUE; // // And clear the packet filter on the card by setting it // to null. // Status = TpStressSetPacketFilter( OpenP,0 ); if (( Status != NDIS_STATUS_SUCCESS ) && ( Status != NDIS_STATUS_PENDING )) { IF_TPDBG( TP_DEBUG_NDIS_CALLS ) { TpPrint0("TpStressFinalDpc: failed to reset packet filter.\n"); } } } } VOID TpStressCleanUp( IN POPEN_BLOCK OpenP ) // ------ // // Routine Description: // // This routine is used to clean up after a failed attempt to start a // stress test. // // Arguments: // // OpenP - a pointer to the OPEN_BLOCK containing the structures to be // deallocated. // // Return Value: // // None. // // ------ { PSTRESS_ARGUMENTS Args = NULL; PSERVER_INFO Server = NULL; NDIS_STATUS Status; Args = OpenP->Stress->Arguments; // // Set the stop stress flag to halt the Register2Dpc routine // now, if it was already set this will do nothing. // OpenP->Stress->StopStressing = TRUE; OpenP->Stress->Stressing = FALSE; // // if we have set a functional address or added a multicast // address then clear it now. // if ( Args->MemberType != TP_CLIENT ) { if ( OpenP->Media->MediumType == NdisMedium802_5 ) { Status = TpStressSetFunctionalAddress( OpenP, (PUCHAR)NULL_ADDRESS, TRUE ); if (( Status != NDIS_STATUS_SUCCESS ) && ( Status != NDIS_STATUS_PENDING )) { IF_TPDBG( TP_DEBUG_NDIS_CALLS ) { TpPrint1( "TpStressServerCleanUp: failed to clear Functional Address--Status = %s\n", TpGetStatus(Status)); } } } else if (OpenP->Media->MediumType == NdisMedium802_3) { Status = TpStressAddMulticastAddress( OpenP, (PUCHAR)NULL_ADDRESS, TRUE ); if (( Status != NDIS_STATUS_SUCCESS ) && ( Status != NDIS_STATUS_PENDING )) { IF_TPDBG( TP_DEBUG_NDIS_CALLS ) { TpPrint1( "TpStressServerCleanUp: failed to delete Multicast Address--Status = %s\n", TpGetStatus(Status)); } } } else if (OpenP->Media->MediumType == NdisMediumFddi) { Status = TpStressAddLongMulticastAddress( OpenP, (PUCHAR)NULL_ADDRESS, TRUE ); if (( Status != NDIS_STATUS_SUCCESS ) && ( Status != NDIS_STATUS_PENDING )) { IF_TPDBG( TP_DEBUG_NDIS_CALLS ) { TpPrint1( "TpStressServerCleanUp: failed to delete Multicast Address--Status = %s\n", TpGetStatus(Status)); } } } // And if you are ARCNET do nothing } // // And clear the packet filter on the card by setting it // to null. // Status = TpStressSetPacketFilter( OpenP,0 ); if (( Status != NDIS_STATUS_SUCCESS ) && ( Status != NDIS_STATUS_PENDING )) { IF_TPDBG( TP_DEBUG_NDIS_CALLS ) { TpPrint0("TpStressFinalDpc: failed to reset packet filter.\n"); } } OpenP->Stress->StressFinal = TRUE; // // Clean up the various data structures allocated during initialization // TpStressFreeResources( OpenP ); NdisAcquireSpinLock( &OpenP->SpinLock ); if ( OpenP->Stress->StressIrp != NULL ) { OpenP->Stress->StressIrp->IoStatus.Status = NDIS_STATUS_FAILURE; } NdisReleaseSpinLock( &OpenP->SpinLock ); } VOID TpStressFreeResources( IN POPEN_BLOCK OpenP ) // ------------- // // Changes in functionality: SanjeevK // // The RESET should occur prior to resource de-allocation. This is because // all requests to the adapter in question working over the OPEN_BLOCK should // be completed since they use the resources allocated by the open block in question. // After the RESET has completed, the resources are de-allocated // // Assumption // // OpenP cannot be a NULL at this point and time // // Descrption // // This function is responsible for clearing the adapter followed by dis-associating // any resources(memory blocks) which have been associated with an OPEN_BLOCK. // // ------------- { NDIS_STATUS Status; // Sanjeevk : STARTCHANGE // // Initialize the Open block pointer for RESET // Status = NdisAllocateMemory((PVOID *)&OpenP->ResetReqHndl, sizeof( TP_REQUEST_HANDLE ), 0, HighestAddress ); if ( Status != NDIS_STATUS_SUCCESS ) { IF_TPDBG (TP_DEBUG_RESOURCES) { TpPrint0("TpStressFreeResources: unable to allocate Reset Request Handle.\n"); } NdisAcquireSpinLock( &OpenP->SpinLock ); if ( OpenP->Irp != NULL ) { OpenP->Irp->IoStatus.Status = NDIS_STATUS_RESOURCES; } NdisReleaseSpinLock( &OpenP->SpinLock ); } else { // // Perform the RESET on the adapter // NdisZeroMemory( OpenP->ResetReqHndl,sizeof( TP_REQUEST_HANDLE )); // // And initialize the Reset Request block // OpenP->ResetReqHndl->Signature = FUNC_REQUEST_HANDLE_SIGNATURE; OpenP->ResetReqHndl->Open = OpenP; OpenP->ResetReqHndl->RequestPended = TRUE; // // Indicate that cleanup is required once the RESET completes // This is to ensure that the either this routine or the completion // routine will take care of the cleanup OpenP->ResetReqHndl->u.RESET_REQ.PostResetStressCleanup = TRUE; // // And now issue the RESET // OpenP->Stress->Resetting = TRUE; Status = TpStressReset( OpenP ); } // // If the RESET has not gotten pended in which case there is the possibility // of a reset failure we will still proceed and free up the resources // if ( Status != NDIS_STATUS_PENDING ) { // // Indicate that we will take care of the post reset cleanup // and that the completion routine does not have to take care of it // OpenP->ResetReqHndl->u.RESET_REQ.PostResetStressCleanup = FALSE; TpStressResetComplete( OpenP,Status ); // // Free up the various data structures allocated during the // initialization phase. // OpenP->Stress->StressEnded = TRUE; // // Free up the resources associated with this instance of the stress test // TpStressFreePostResetResources( OpenP ); // // Decrement the reference count on the OpenBlock stating this // instance of an async test is no longer running, and the adapter // may be closed if requested. // TpRemoveReference( OpenP ); } // Sanjeevk : STOPCHANGE } VOID TpStressFreeClient( IN POPEN_BLOCK OpenP ) { UCHAR i; if ( OpenP->Stress->Client != NULL ) { if ( OpenP->Stress->Arguments->PacketsFromPool == TRUE ) { TpStressFreeTransmitPool( OpenP->Stress->Client->TransmitPool ); } if ( OpenP->Stress->Client->PoolInitialized == TRUE ) { NdisFreePacketPool( OpenP->Stress->Client->PacketHandle ); OpenP->Stress->Client->PoolInitialized = FALSE; } for ( i=0;iStress->Client->NumServers;i++ ) { if ( OpenP->Stress->Client->Servers[i].Counters != NULL ) { NdisFreeMemory( (PVOID)OpenP->Stress->Client->Servers[i].Counters,0,0 ); } } NdisFreeMemory( OpenP->Stress->Client,0,0 ); OpenP->Stress->Client = NULL; } } VOID TpStressFreeServer( IN POPEN_BLOCK OpenP ) { UCHAR i; if ( OpenP->Stress->Server != NULL ) { TpStressFreeTransmitPool( OpenP->Stress->Server->TransmitPool ); if ( OpenP->Stress->Server->PoolInitialized == TRUE ) { NdisFreePacketPool( OpenP->Stress->Server->PacketHandle ); OpenP->Stress->Server->PoolInitialized = FALSE; } for ( i=0;iStress->Server->NumClients;i++ ) { if ( OpenP->Stress->Server->Clients[i].Counters != NULL ) { NdisFreeMemory( (PVOID)OpenP->Stress->Server->Clients[i].Counters,0,0 ); } } NdisFreeMemory( OpenP->Stress->Server,0,0 ); OpenP->Stress->Server = NULL; } } VOID TpStressFreePostResetResources( IN POPEN_BLOCK OpenP ) { if (( OpenP != NULL ) && ( OpenP->Stress->Arguments != NULL )) { if (( OpenP->Stress->Arguments->MemberType == TP_CLIENT ) || ( OpenP->Stress->Arguments->MemberType == BOTH )) { TpStressFreeClient( OpenP ); } if (( OpenP->Stress->Arguments->MemberType == TP_SERVER ) || ( OpenP->Stress->Arguments->MemberType == BOTH )) { TpStressFreeServer( OpenP ); } if (OpenP->Stress->PoolInitialized == TRUE ) { NdisFreePacketPool( OpenP->Stress->PacketHandle ); OpenP->Stress->PoolInitialized = FALSE; } // // SanjeevK: Free up the data buffer and associated MDL resources // TpStressFreeDataBuffers( OpenP ); TpStressFreeDataBufferMdls( OpenP ); NdisFreeMemory( OpenP->Stress->Arguments,0,0 ); OpenP->Stress->Arguments = NULL; // // Deallocate the global counters, and their spinlock. // if ( OpenP->GlobalCounters != NULL ) { NdisFreeMemory( (PVOID)OpenP->GlobalCounters,0,0 ); OpenP->GlobalCounters = NULL; } } } VOID TpStressRegister2Dpc( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SysArg1, IN PVOID SysArg2 ) /*++ Routine Description: Arguments: Return Value: --*/ { POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext); PSTRESS_ARGUMENTS Args; LARGE_INTEGER DueTime; PNDIS_PACKET Packet; UNREFERENCED_PARAMETER( Dpc ); UNREFERENCED_PARAMETER( SysArg1 ); UNREFERENCED_PARAMETER( SysArg2 ); // // If the Stress Irp has been cancelled then clean up and leave. // NdisAcquireSpinLock( &OpenP->SpinLock ); if (( OpenP->Stress->StressIrp == NULL ) || ( OpenP->Stress->StressIrp->Cancel == TRUE )) { NdisReleaseSpinLock( &OpenP->SpinLock ); OpenP->Stress->StopStressing = TRUE; return; } NdisReleaseSpinLock( &OpenP->SpinLock ); if (( OpenP->Stress->StopStressing == FALSE ) && ( OpenP->Stress->Client->NumServers < MAX_SERVERS )) { Args = OpenP->Stress->Arguments; if (( OpenP->Stress->Reg2Counter < 60 ) || (( OpenP->Stress->Reg2Counter % 60 ) == 0 )) { // // We are now ready to begin the test, send a REGISTER_REQ // packet to the STRESS_MULTICAST/FUNCTIONAL address. // // Construct the REGISTER_REQ2 packet and send it. // Packet = TpStressCreatePacket( OpenP, OpenP->Stress->Client->PacketHandle, Args->PacketMakeUp, 0, // ServerInstance OpenP->OpenInstance, REGISTER_REQ2, Args->ResponseType, OpenP->Environment->StressAddress, sizeof( STRESS_PACKET ), sizeof( STRESS_PACKET ), 0,0L,0,0, Args->DataChecking ); if ( Packet == NULL ) { IF_TPDBG ( TP_DEBUG_DPC ) { TpPrint0("TpStressRegister2Dpc: failed to build REGISTER_REQ2 packet\n"); } } else { TpStressSend( OpenP,Packet,NULL ); } } // // We will continue requeueing this Dpc for 6 minutes. The first // minute we will send once every second then for the next five // minutes send only one request each minute. // if ( OpenP->Stress->Reg2Counter++ < 360 ) { // // Now requeue the Dpc to run try again next time. // DueTime.HighPart = -1; DueTime.LowPart = (ULONG)(- ( ONE_SECOND )); if ( KeSetTimer(&OpenP->Stress->TpStressReg2Timer, DueTime, &OpenP->Stress->TpStressReg2Dpc )) { IF_TPDBG ( TP_DEBUG_DPC ) { TpPrint0("TpStressRegister2Dpc set TpStressReg2Timer while timer existed.\n"); } } } } }