mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2162 lines
68 KiB
2162 lines
68 KiB
// ------------------------------------------------
|
|
//
|
|
// Copyright (c) 1990 Microsoft Corporation
|
|
//
|
|
// Module Name:
|
|
//
|
|
// perf.c
|
|
//
|
|
// Abstract:
|
|
//
|
|
// This file contains the source for the netcard performance tests
|
|
//
|
|
// Author:
|
|
//
|
|
// Tim Wynsma (timothyw) 4-27-1994
|
|
//
|
|
// Environment:
|
|
//
|
|
// Kernel mode
|
|
//
|
|
//
|
|
// Changes:
|
|
// 5-18-1994 (timothyw)
|
|
// Requested changes to performance function and output (part 1)
|
|
// 6-08-1994 (timothyw)
|
|
// Changed perf tests to client/server model (part 2)
|
|
//
|
|
// --------------------------------------------------
|
|
|
|
|
|
#include <ndis.h>
|
|
|
|
#include "tpdefs.h"
|
|
#include "media.h"
|
|
#include "tpprocs.h"
|
|
#include "string.h"
|
|
|
|
|
|
//
|
|
// local constants..
|
|
//
|
|
|
|
#define MINIMUM_PERF_PACKET 60
|
|
#define PACKETS_PER_BURST 5
|
|
|
|
#define PERFMODE_SEND 0 // client sends to any address
|
|
#define PERFMODE_SENDTOSRV 1 // client sends to server
|
|
#define PERFMODE_SENDWITHACK 2 // client sends to server, server ACKS
|
|
#define PERFMODE_SENDANDRCV 3 // client sends to server, server sends to client
|
|
#define PERFMODE_RECEIVE 4 // server sends to client
|
|
#define PERFMODE_REQANDRCV 5 // server sends to client when get REQ message
|
|
#define PERFMODE_SHUTDOWN 6 // client shuts down server
|
|
|
|
#define REQ_DATA 0
|
|
#define REQ_INITGO 1
|
|
#define REQ_ACK 2
|
|
#define REQ_RES 3
|
|
|
|
//
|
|
// defines for the packet signature of each type, and for the packet
|
|
// types themselves
|
|
//
|
|
|
|
// "ID" portion of packet signature. This is added to base to get actual signature
|
|
|
|
#define PERF_DATA_ID 0x00000000 // test data message
|
|
#define PERF_ACKREQ_ID 0x00000001 // ACK or REQ message
|
|
#define PERF_START_ID 0x00000002 // INIT or GO message
|
|
#define PERF_DONE_ID 0x00000003 // REQRES or SRVDONE message
|
|
#define PERF_STOP_ID 0x00000004 // STOPSRV or SRVDOWN message
|
|
#define PERF_NOGO_ID 0x00000005 // NOGO message
|
|
#define PERF_RESULTS_ID 0x00000006 // RETRES message
|
|
#define PERF_ID_MASK 0x00000007 // mask for ID
|
|
|
|
#define PERF_BASE 0x76543210 // base signature
|
|
#define PERF_SERVER 0x00000008 // offset from base of server ids
|
|
|
|
// signatures used by client (messages sent to server)
|
|
|
|
#define PERF_CLTDATA_SIGNATURE (PERF_BASE + PERF_DATA_ID)
|
|
#define PERF_REQ_SIGNATURE (PERF_BASE + PERF_ACKREQ_ID)
|
|
#define PERF_INIT_SIGNATURE (PERF_BASE + PERF_START_ID)
|
|
#define PERF_REQRES_SIGNATURE (PERF_BASE + PERF_DONE_ID)
|
|
#define PERF_STOPSRV_SIGNATURE (PERF_BASE + PERF_STOP_ID)
|
|
|
|
// signatures used by server (messages sent to client)
|
|
|
|
#define PERF_SRVDATA_SIGNATURE (PERF_BASE + PERF_SERVER + PERF_DATA_ID)
|
|
#define PERF_ACK_SIGNATURE (PERF_BASE + PERF_SERVER + PERF_ACKREQ_ID)
|
|
#define PERF_GO_SIGNATURE (PERF_BASE + PERF_SERVER + PERF_START_ID)
|
|
#define PERF_SRVDONE_SIGNATURE (PERF_BASE + PERF_SERVER + PERF_DONE_ID)
|
|
#define PERF_SRVDOWN_SIGNATURE (PERF_BASE + PERF_SERVER + PERF_STOP_ID)
|
|
#define PERF_NOGO_SIGNATURE (PERF_BASE + PERF_SERVER + PERF_NOGO_ID)
|
|
#define PERF_RETRES_SIGNATURE (PERF_BASE + PERF_SERVER + PERF_RESULTS_ID)
|
|
|
|
//
|
|
// structures of special (info) packet types used by performance tests
|
|
// structures MUST be packed
|
|
|
|
#include <packon.h>
|
|
|
|
typedef struct _INFO_PACKET_INFO
|
|
{
|
|
ULONG Signature;
|
|
ULONG PacketSize;
|
|
ULONG Mode;
|
|
ULONG Length;
|
|
ULONG Count;
|
|
ULONG Delay;
|
|
UCHAR Address[ADDRESS_LENGTH];
|
|
ULONG CheckSum;
|
|
} INFO_PACKET_INFO;
|
|
|
|
typedef INFO_PACKET_INFO UNALIGNED *PINFO_PACKET_INFO;
|
|
|
|
|
|
typedef struct _RESULTS_PACKET_INFO
|
|
{
|
|
ULONG Signature;
|
|
ULONG PacketSize;
|
|
ULONG PacketsSent;
|
|
ULONG SendErrors;
|
|
ULONG PacketsReceived;
|
|
ULONG ElapsedTime;
|
|
ULONG SelfReceives;
|
|
ULONG Restarts;
|
|
ULONG CheckSum;
|
|
} RESULTS_PACKET_INFO;
|
|
typedef RESULTS_PACKET_INFO UNALIGNED *PRESULTS_PACKET_INFO;
|
|
|
|
|
|
typedef struct _DATA_PACKET_INFO
|
|
{
|
|
ULONG Signature;
|
|
ULONG PacketSize;
|
|
ULONG CheckSum;
|
|
} DATA_PACKET_INFO;
|
|
|
|
typedef DATA_PACKET_INFO UNALIGNED *PDATA_PACKET_INFO;
|
|
|
|
typedef struct _PERF_PACKET
|
|
{
|
|
MEDIA_HEADER media;
|
|
union
|
|
{
|
|
INFO_PACKET_INFO info;
|
|
DATA_PACKET_INFO data;
|
|
RESULTS_PACKET_INFO results;
|
|
} u;
|
|
} PERF_PACKET;
|
|
typedef PERF_PACKET UNALIGNED *PPERF_PACKET;
|
|
|
|
#include <packoff.h>
|
|
|
|
//
|
|
// local functions
|
|
//
|
|
|
|
PTP_REQUEST_HANDLE
|
|
TpPerfAllocatePacket( IN POPEN_BLOCK OpenP,
|
|
IN ULONG PacketSize );
|
|
|
|
NDIS_STATUS
|
|
TpPerfInitialize( IN OUT POPEN_BLOCK OpenP);
|
|
|
|
VOID
|
|
TpPerfDeallocate( IN OUT POPEN_BLOCK OpenP);
|
|
|
|
|
|
NDIS_STATUS
|
|
TpPerfSend( IN POPEN_BLOCK OpenP );
|
|
|
|
VOID
|
|
TpPerfSendDpc( IN PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SysArg1,
|
|
IN PVOID SysArg2 );
|
|
|
|
VOID
|
|
TpPerfRestart( IN PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SysArg1,
|
|
IN PVOID SysArg2 );
|
|
|
|
VOID
|
|
TpPerformEndDpc( IN PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SysArg1,
|
|
IN PVOID SysArg2 );
|
|
|
|
VOID
|
|
TpPerfWriteResults( IN PPERF_BLOCK Perform,
|
|
IN PRESULTS_PACKET_INFO Info);
|
|
|
|
|
|
VOID
|
|
TpPerfSetPacketData(POPEN_BLOCK OpenP,
|
|
PUCHAR TmpBuf,
|
|
ULONG Signature,
|
|
PUCHAR DestAddr,
|
|
ULONG PacketSize);
|
|
|
|
VOID
|
|
TpPerfTestCompleted(PPERF_BLOCK Perform);
|
|
|
|
|
|
NDIS_STATUS
|
|
TpPerfLowPriorityReceive( POPEN_BLOCK OpenP,
|
|
PINFO_PACKET_INFO ReceivePacketInfo,
|
|
ULONG MessageId);
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
//
|
|
// Function: TpPerfServer
|
|
//
|
|
// Arguments: OpenP -- pointer to open block for instance
|
|
//
|
|
// Returns: Completion status
|
|
//
|
|
// Descript: This function starts up the PerformServer command
|
|
//
|
|
// ---------------------------------------------------------------
|
|
|
|
NDIS_STATUS
|
|
TpPerfServer( POPEN_BLOCK OpenP )
|
|
{
|
|
NDIS_STATUS Status;
|
|
PTP_REQUEST_HANDLE RequestHandle;
|
|
|
|
//
|
|
// Allocate the performance structure, and do necessary initializations
|
|
//
|
|
|
|
Status = TpPerfInitialize(OpenP);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
return Status;
|
|
}
|
|
OpenP->Perform->IsServer = TRUE;
|
|
OpenP->Perform->MaskId = PERF_BASE;
|
|
|
|
//
|
|
// yes, I know that OpenP->Perform->ServerAddress is 00-00-00-00-00-00
|
|
// at this point
|
|
//
|
|
RequestHandle = TpPerfAllocatePacket( OpenP, MINIMUM_PERF_PACKET);
|
|
if (RequestHandle == NULL)
|
|
{
|
|
TpPerfDeallocate(OpenP);
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
OpenP->Perform->GoInitReq = RequestHandle;
|
|
|
|
RequestHandle = TpPerfAllocatePacket( OpenP, MINIMUM_PERF_PACKET);
|
|
if (RequestHandle == NULL)
|
|
{
|
|
TpPerfDeallocate(OpenP);
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
OpenP->Perform->AckReq = RequestHandle;
|
|
|
|
RequestHandle = TpPerfAllocatePacket( OpenP, MINIMUM_PERF_PACKET);
|
|
if (RequestHandle == NULL)
|
|
{
|
|
TpPerfDeallocate(OpenP);
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
OpenP->Perform->ResReq = RequestHandle;
|
|
|
|
TpAddReference( OpenP );
|
|
|
|
return NDIS_STATUS_PENDING;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
//
|
|
// Function: TpPerfClient
|
|
//
|
|
// Arguments: OpenP -- pointer to open block for instance
|
|
// CmdArgs -- Arguments given in tpctl to PerformClient command
|
|
//
|
|
// Returns: Completion status
|
|
//
|
|
// Descript: This function starts up the PerformClient command
|
|
//
|
|
// ---------------------------------------------------------------
|
|
|
|
|
|
NDIS_STATUS
|
|
TpPerfClient( POPEN_BLOCK OpenP,
|
|
PCMD_ARGS CmdArgs )
|
|
{
|
|
PUCHAR p, q, s, t;
|
|
ULONG i;
|
|
PTP_REQUEST_HANDLE RequestHandle;
|
|
NDIS_STATUS Status;
|
|
PPERF_BLOCK Perform;
|
|
PPERF_RESULTS OutputBuffer;
|
|
|
|
//
|
|
// Allocate the performance structure, and do necessary initializations
|
|
//
|
|
|
|
Status = TpPerfInitialize(OpenP);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
return Status;
|
|
}
|
|
Perform = OpenP->Perform;
|
|
Perform->IsServer = FALSE;
|
|
Perform->MaskId = PERF_BASE + PERF_SERVER;
|
|
|
|
//
|
|
// set so no data is avail if aborted
|
|
//
|
|
OutputBuffer = MmGetSystemAddressForMdl( Perform->PerformIrp->MdlAddress );
|
|
OutputBuffer->ResultsExist = FALSE;
|
|
|
|
// Now, deal with the arguments..
|
|
|
|
Perform->NumberOfPackets = CmdArgs->ARGS.TPPERF.PerfNumPackets;
|
|
Perform->PacketDelay = CmdArgs->ARGS.TPPERF.PerfDelay;
|
|
Perform->PerformMode = CmdArgs->ARGS.TPPERF.PerfMode;
|
|
|
|
if ( CmdArgs->ARGS.TPPERF.PerfPacketSize > OpenP->Media->MaxPacketLen )
|
|
{
|
|
Perform->PacketSize = OpenP->Media->MaxPacketLen;
|
|
IF_TPDBG ( TP_DEBUG_IOCTL_ARGS )
|
|
{
|
|
TpPrint1("TpPerfClient: Invalid PacketSize, using %d\n", Perform->PacketSize);
|
|
}
|
|
}
|
|
else if ( CmdArgs->ARGS.TPPERF.PerfPacketSize < MINIMUM_PERF_PACKET )
|
|
{
|
|
Perform->PacketSize = MINIMUM_PERF_PACKET;
|
|
IF_TPDBG ( TP_DEBUG_IOCTL_ARGS )
|
|
{
|
|
TpPrint1("TpPerfClient: Invalid PacketSize, using %d\n", Perform->PacketSize);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Perform->PacketSize = CmdArgs->ARGS.TPPERF.PerfPacketSize;
|
|
}
|
|
|
|
p = Perform->ServerAddress;
|
|
q = CmdArgs->ARGS.TPPERF.PerfServerAddr;
|
|
s = Perform->ClientAddress;
|
|
t = CmdArgs->ARGS.TPPERF.PerfSendAddr;
|
|
|
|
|
|
for ( i=0 ; i < OpenP->Media->AddressLen; i++ )
|
|
{
|
|
*p++ = *q++;
|
|
*s++ = *t++;
|
|
}
|
|
|
|
//
|
|
// only PERFMODE_SEND does not use a info packet (it assumes its sending to
|
|
// never-never land)
|
|
//
|
|
|
|
if (Perform->PerformMode != PERFMODE_SEND)
|
|
{
|
|
//
|
|
// NULL_ADDRESS is not a valid server address
|
|
//
|
|
if ( RtlCompareMemory( Perform->ServerAddress,
|
|
NULL_ADDRESS,
|
|
OpenP->Media->AddressLen ) == OpenP->Media->AddressLen )
|
|
{
|
|
TpPrint0("TpPerfClient: server address may not equal NULL_ADDRESS\n");
|
|
TpPerfDeallocate(OpenP);
|
|
return NDIS_STATUS_FAILURE;
|
|
}
|
|
|
|
Perform->WhichReq = REQ_INITGO;
|
|
|
|
//
|
|
// Set up the info send packet and request.
|
|
//
|
|
|
|
RequestHandle = TpPerfAllocatePacket( OpenP, MINIMUM_PERF_PACKET);
|
|
if (RequestHandle == NULL)
|
|
{
|
|
TpPerfDeallocate(OpenP);
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
Perform->GoInitReq = RequestHandle;
|
|
|
|
TpPerfSetPacketData(OpenP,
|
|
RequestHandle->u.PERF_REQ.Buffer,
|
|
((Perform->PerformMode < PERFMODE_SHUTDOWN)
|
|
? PERF_INIT_SIGNATURE
|
|
: PERF_STOPSRV_SIGNATURE),
|
|
Perform->ServerAddress,
|
|
MINIMUM_PERF_PACKET);
|
|
|
|
//
|
|
// if needed, Set up the data request send packet and request.
|
|
//
|
|
if (Perform->PerformMode == PERFMODE_REQANDRCV)
|
|
{
|
|
RequestHandle = TpPerfAllocatePacket( OpenP, MINIMUM_PERF_PACKET);
|
|
if (RequestHandle == NULL)
|
|
{
|
|
TpPerfDeallocate(OpenP);
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
Perform->AckReq = RequestHandle;
|
|
|
|
TpPerfSetPacketData(OpenP,
|
|
RequestHandle->u.PERF_REQ.Buffer,
|
|
PERF_REQ_SIGNATURE,
|
|
Perform->ServerAddress,
|
|
MINIMUM_PERF_PACKET);
|
|
}
|
|
|
|
//
|
|
// If needed, set up the request server results send packet and request.
|
|
//
|
|
|
|
if (Perform->PerformMode < PERFMODE_SHUTDOWN)
|
|
{
|
|
RequestHandle = TpPerfAllocatePacket( OpenP, MINIMUM_PERF_PACKET);
|
|
if (RequestHandle == NULL)
|
|
{
|
|
TpPerfDeallocate(OpenP);
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
Perform->ResReq = RequestHandle;
|
|
|
|
TpPerfSetPacketData(OpenP,
|
|
RequestHandle->u.PERF_REQ.Buffer,
|
|
PERF_REQRES_SIGNATURE,
|
|
Perform->ServerAddress,
|
|
MINIMUM_PERF_PACKET);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Perform->WhichReq = REQ_DATA;
|
|
}
|
|
|
|
//
|
|
// if necessary, set up the data send packet and request
|
|
//
|
|
|
|
if (Perform->PerformMode <= PERFMODE_SENDANDRCV)
|
|
{
|
|
RequestHandle = TpPerfAllocatePacket( OpenP, Perform->PacketSize);
|
|
if (RequestHandle == NULL)
|
|
{
|
|
TpPerfDeallocate(OpenP);
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
Perform->DataReq = RequestHandle;
|
|
|
|
TpPerfSetPacketData(OpenP,
|
|
RequestHandle->u.PERF_REQ.Buffer,
|
|
PERF_CLTDATA_SIGNATURE,
|
|
Perform->ServerAddress,
|
|
Perform->PacketSize);
|
|
|
|
if (Perform->PerformMode == PERFMODE_SENDWITHACK)
|
|
{
|
|
Perform->SendBurstCount = PACKETS_PER_BURST;
|
|
}
|
|
else
|
|
{
|
|
Perform->SendBurstCount = Perform->NumberOfPackets+1;
|
|
}
|
|
Perform->ReceiveBurstCount = Perform->NumberOfPackets+1;
|
|
}
|
|
else if (Perform->PerformMode == PERFMODE_REQANDRCV)
|
|
{
|
|
Perform->ReceiveBurstCount = PACKETS_PER_BURST;
|
|
}
|
|
else
|
|
{
|
|
Perform->ReceiveBurstCount = Perform->NumberOfPackets+1;
|
|
}
|
|
|
|
TpAddReference( OpenP );
|
|
|
|
//
|
|
// We will be probably be sending more than one packet, so queue TpPerfSendDpc
|
|
// and return Pending to the user, the DPC will send the packets,
|
|
// and after all the packets have been sent complete the request.
|
|
//
|
|
|
|
if ( !KeInsertQueueDpc( &Perform->PerformSendDpc, NULL, NULL ))
|
|
{
|
|
IF_TPDBG ( TP_DEBUG_DPC )
|
|
{
|
|
TpPrint0("TpPerfSend failed to queue the TpPerfSendDpc.\n");
|
|
}
|
|
|
|
NdisAcquireSpinLock( &OpenP->SpinLock );
|
|
if ( Perform->PerformIrp != NULL )
|
|
{
|
|
Perform->PerformIrp->IoStatus.Status = NDIS_STATUS_FAILURE;
|
|
}
|
|
NdisReleaseSpinLock( &OpenP->SpinLock );
|
|
|
|
TpPerfDeallocate(OpenP);
|
|
return NDIS_STATUS_FAILURE;
|
|
}
|
|
return NDIS_STATUS_PENDING;
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------
|
|
//
|
|
// Function: TpPerfInitialize
|
|
//
|
|
// Arguments: OpenP -- ptr to current open instance
|
|
//
|
|
// Returns: Status
|
|
//
|
|
// Descript: This function allocates the PERF_BLOCK structure, and initializes
|
|
// necessary components of it..
|
|
//
|
|
// ---------------------------------------------
|
|
|
|
NDIS_STATUS
|
|
TpPerfInitialize( IN OUT POPEN_BLOCK OpenP)
|
|
{
|
|
NDIS_STATUS Status;
|
|
|
|
// Sanity check
|
|
|
|
IF_TPDBG (TP_DEBUG_RESOURCES)
|
|
{
|
|
if (OpenP->Perform != NULL)
|
|
{
|
|
TpPrint0("TpPerfInitialize: OpenP->Perform is not NULL !\n");
|
|
TpBreakPoint();
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
|
|
//
|
|
// First allocate the Performance struct.
|
|
//
|
|
|
|
if ( (NdisAllocateMemory( (PVOID *)&OpenP->Perform,
|
|
sizeof( PERF_BLOCK ),
|
|
0,
|
|
HighestAddress) ) != NDIS_STATUS_SUCCESS)
|
|
{
|
|
IF_TPDBG (TP_DEBUG_RESOURCES)
|
|
{
|
|
TpPrint0("TpPerfInitialize: failed to allocate PERF_BLOCK struct\n");
|
|
}
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// zero everything for starters..
|
|
//
|
|
|
|
NdisZeroMemory( OpenP->Perform, sizeof( PERF_BLOCK ));
|
|
|
|
//
|
|
// Allocate the Send PacketPool.
|
|
//
|
|
|
|
NdisAllocatePacketPool( &Status,
|
|
&OpenP->Perform->PacketHandle,
|
|
NUMBER_OF_POOL_PACKETS,
|
|
sizeof( PROTOCOL_RESERVED ) );
|
|
|
|
if ( Status != NDIS_STATUS_SUCCESS )
|
|
{
|
|
IF_TPDBG (TP_DEBUG_RESOURCES)
|
|
{
|
|
TpPrint0("TpPerfInitialize: could not allocate Packet Pool\n");
|
|
}
|
|
NdisFreeMemory( OpenP->Perform,0,0 );
|
|
OpenP->Perform = NULL;
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Initialize the Perform DPCs
|
|
//
|
|
|
|
KeInitializeDpc(&OpenP->Perform->PerformSendDpc, // performance send
|
|
TpPerfSendDpc,
|
|
(PVOID)OpenP );
|
|
|
|
KeInitializeDpc(&OpenP->Perform->PerformEndDpc,
|
|
TpPerformEndDpc,
|
|
(PVOID)OpenP );
|
|
|
|
KeInitializeDpc(&OpenP->Perform->PerformRestartDpc,
|
|
TpPerfRestart,
|
|
(PVOID)OpenP);
|
|
|
|
|
|
KeInitializeTimer( &OpenP->Perform->PerformTimer );
|
|
|
|
//
|
|
// other things we can initialize here
|
|
//
|
|
|
|
OpenP->Perform->PerformIrp = OpenP->Irp;
|
|
OpenP->Irp = NULL;
|
|
|
|
OpenP->Perform->Active = TRUE;
|
|
OpenP->PerformanceTest = TRUE;
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------------------
|
|
//
|
|
// Function: TpPerfDeallocate
|
|
//
|
|
// Arguments: OpenP -- ptr to current open instance
|
|
//
|
|
// Returns: none
|
|
//
|
|
// Descript: This function frees up everything if allocations fail, or when
|
|
// we are ending performance testing
|
|
//
|
|
// -------------------------------------------------
|
|
|
|
|
|
VOID
|
|
TpPerfDeallocate( IN OUT POPEN_BLOCK OpenP)
|
|
{
|
|
OpenP->PerformanceTest = FALSE;
|
|
|
|
if (OpenP->Perform->GoInitReq)
|
|
{
|
|
TpFuncFreePacket( OpenP->Perform->GoInitReq->u.SEND_REQ.Packet,
|
|
OpenP->Perform->GoInitReq->u.SEND_REQ.PacketSize );
|
|
NdisFreeMemory( OpenP->Perform->GoInitReq,0,0 );
|
|
}
|
|
|
|
if (OpenP->Perform->AckReq)
|
|
{
|
|
TpFuncFreePacket( OpenP->Perform->AckReq->u.SEND_REQ.Packet,
|
|
OpenP->Perform->AckReq->u.SEND_REQ.PacketSize );
|
|
NdisFreeMemory( OpenP->Perform->AckReq,0,0 );
|
|
}
|
|
|
|
if (OpenP->Perform->ResReq)
|
|
{
|
|
TpFuncFreePacket( OpenP->Perform->ResReq->u.SEND_REQ.Packet,
|
|
OpenP->Perform->ResReq->u.SEND_REQ.PacketSize );
|
|
NdisFreeMemory( OpenP->Perform->ResReq,0,0 );
|
|
}
|
|
|
|
if (OpenP->Perform->DataReq)
|
|
{
|
|
TpFuncFreePacket( OpenP->Perform->DataReq->u.SEND_REQ.Packet,
|
|
OpenP->Perform->DataReq->u.SEND_REQ.PacketSize );
|
|
NdisFreeMemory( OpenP->Perform->DataReq,0,0 );
|
|
}
|
|
|
|
NdisFreePacketPool( OpenP->Perform->PacketHandle );
|
|
|
|
NdisFreeMemory( OpenP->Perform,0,0 );
|
|
OpenP->Perform = NULL;
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------
|
|
//
|
|
// Function: TpPerfAllocatePacket
|
|
//
|
|
// Arguments: OpenP -- ptr to current open instance
|
|
// PacketSize -- size of packet being allocated --
|
|
// range is checked by caller
|
|
//
|
|
// Returns: ptr to request structure for packet if successful, else NULL
|
|
//
|
|
// Descript: This function allocates all send packets used in performance tests
|
|
//
|
|
// ---------------------------------------------
|
|
|
|
|
|
PTP_REQUEST_HANDLE
|
|
TpPerfAllocatePacket( IN POPEN_BLOCK OpenP,
|
|
IN ULONG PacketSize )
|
|
|
|
{
|
|
NDIS_STATUS Status;
|
|
PPROTOCOL_RESERVED ProtRes;
|
|
PNDIS_PACKET Packet;
|
|
PNDIS_BUFFER Buffer;
|
|
PUCHAR TmpBuf;
|
|
PTP_REQUEST_HANDLE RequestHandle;
|
|
|
|
//
|
|
// first, check to make sure media type is ok.
|
|
// This makes sure that this check is done in "main" thread, not
|
|
// in a DPC somewhere
|
|
|
|
switch( OpenP->Media->MediumType )
|
|
{
|
|
case NdisMediumDix:
|
|
case NdisMedium802_3:
|
|
case NdisMedium802_5:
|
|
case NdisMediumFddi:
|
|
case NdisMediumArcnet878_2:
|
|
break;
|
|
|
|
default:
|
|
IF_TPDBG ( TP_DEBUG_RESOURCES )
|
|
{
|
|
TpPrint0("TpPerfAllocatePacket: Unsupported MAC Type\n");
|
|
}
|
|
return (PTP_REQUEST_HANDLE)NULL;
|
|
}
|
|
|
|
|
|
NdisAllocatePacket( &Status,
|
|
&Packet,
|
|
OpenP->Perform->PacketHandle );
|
|
|
|
if ( Status != NDIS_STATUS_SUCCESS )
|
|
{
|
|
TpPrint1("TpPerfAllocatePacket: NdisAllocatePacket failed %s\n", TpGetStatus( Status ));
|
|
return (PTP_REQUEST_HANDLE)NULL;
|
|
}
|
|
|
|
ProtRes = PROT_RES( Packet );
|
|
ProtRes->Pool.PacketHandle = &OpenP->Perform->PacketHandle;
|
|
ProtRes->InstanceCounters = NULL;
|
|
|
|
//
|
|
// start of things partially copied from TpFuncInitPacketHeader
|
|
//
|
|
|
|
|
|
Status = NdisAllocateMemory((PVOID *)&TmpBuf,
|
|
PacketSize,
|
|
0,
|
|
HighestAddress );
|
|
|
|
if ( Status != NDIS_STATUS_SUCCESS )
|
|
{
|
|
IF_TPDBG ( TP_DEBUG_RESOURCES )
|
|
{
|
|
TpPrint0("TpFuncInitPacketHeader: failed to allocate TmpBuf\n");
|
|
}
|
|
return (PTP_REQUEST_HANDLE)NULL;
|
|
}
|
|
NdisZeroMemory( (PVOID)TmpBuf,PacketSize );
|
|
|
|
// data is in 2 or three buffers. The first is always 14 bytes, and the second is
|
|
// always 46 bytes. (giving a total of 60 bytes). If Packetsize > 60 bytes, the
|
|
// third buffer is created with a size of (Packetsize-60) bytes
|
|
|
|
// first, the "media header" = 14 bytes
|
|
|
|
NdisAllocateBuffer( &Status,
|
|
&Buffer,
|
|
NULL, // pool handle, not currently used in NT
|
|
TmpBuf,
|
|
sizeof (MEDIA_HEADER));
|
|
|
|
if ( Status != NDIS_STATUS_SUCCESS )
|
|
{
|
|
TpPrint0("TpPerfAllocatePacket: failed to create the MDL\n");
|
|
TpFuncFreePacket( Packet, PacketSize );
|
|
return (PTP_REQUEST_HANDLE)NULL;
|
|
}
|
|
|
|
//
|
|
// And chain it to the back of the packet.
|
|
//
|
|
|
|
NdisChainBufferAtBack( Packet,Buffer );
|
|
|
|
// next, the "protocol" info (plus some data) = 46 bytes (46+14=60)
|
|
|
|
NdisAllocateBuffer( &Status,
|
|
&Buffer,
|
|
NULL, // pool handle, not currently used in NT
|
|
TmpBuf+sizeof(MEDIA_HEADER),
|
|
MINIMUM_PERF_PACKET - sizeof(MEDIA_HEADER));
|
|
|
|
if ( Status != NDIS_STATUS_SUCCESS )
|
|
{
|
|
TpPrint0("TpPerfAllocatePacket: failed to create the MDL\n");
|
|
TpFuncFreePacket( Packet, PacketSize );
|
|
return (PTP_REQUEST_HANDLE)NULL;
|
|
}
|
|
|
|
//
|
|
// And chain it to the back of the packet.
|
|
//
|
|
|
|
NdisChainBufferAtBack( Packet,Buffer );
|
|
|
|
// finally, if we need more than 60 bytes, add a buffer with the rest..
|
|
|
|
if (PacketSize > MINIMUM_PERF_PACKET)
|
|
{
|
|
NdisAllocateBuffer( &Status,
|
|
&Buffer,
|
|
NULL, // pool handle, not currently used in NT
|
|
TmpBuf+MINIMUM_PERF_PACKET,
|
|
PacketSize-MINIMUM_PERF_PACKET);
|
|
|
|
if ( Status != NDIS_STATUS_SUCCESS )
|
|
{
|
|
TpPrint0("TpPerfAllocatePacket: failed to create the MDL\n");
|
|
TpFuncFreePacket( Packet, PacketSize );
|
|
return (PTP_REQUEST_HANDLE)NULL;
|
|
}
|
|
|
|
//
|
|
// And chain it to the back of the packet.
|
|
//
|
|
|
|
NdisChainBufferAtBack( Packet,Buffer );
|
|
}
|
|
|
|
Status = NdisAllocateMemory((PVOID *)&RequestHandle,
|
|
sizeof( TP_REQUEST_HANDLE ),
|
|
0,
|
|
HighestAddress );
|
|
|
|
if ( Status != NDIS_STATUS_SUCCESS )
|
|
{
|
|
TpPrint0("TpPerfAllocatePacket: unable to allocate Request Handle.\n");
|
|
return (PTP_REQUEST_HANDLE)NULL;
|
|
}
|
|
else
|
|
{
|
|
NdisZeroMemory( RequestHandle,sizeof( TP_REQUEST_HANDLE ));
|
|
}
|
|
|
|
RequestHandle->Signature = SEND_REQUEST_HANDLE_SIGNATURE;
|
|
RequestHandle->Open = OpenP;
|
|
RequestHandle->RequestPended = TRUE;
|
|
RequestHandle->Irp = OpenP->Perform->PerformIrp;
|
|
|
|
RequestHandle->u.PERF_REQ.Packet = Packet;
|
|
RequestHandle->u.PERF_REQ.PacketSize = PacketSize;
|
|
RequestHandle->u.PERF_REQ.SendPacket = TRUE;
|
|
RequestHandle->u.PERF_REQ.Buffer = TmpBuf;
|
|
|
|
ProtRes = PROT_RES( Packet );
|
|
ProtRes->RequestHandle = RequestHandle;
|
|
|
|
//
|
|
// Set the check sum in the PROTOCOL RESERVED Section of the
|
|
// packet header to ensure it is not touched while the packet
|
|
// is in the hands of the MAC.
|
|
//
|
|
|
|
ProtRes->CheckSum = TpSetCheckSum( (PUCHAR)ProtRes,
|
|
sizeof( PROTOCOL_RESERVED ) - sizeof( ULONG ) );
|
|
|
|
return RequestHandle;
|
|
|
|
}
|
|
|
|
// -----------------------------------------------------
|
|
//
|
|
// Function: TpPerfSetPacketData
|
|
//
|
|
// Arguments: OpenP -- ptr to current open instance
|
|
// TmpBuf -- ptr to memory allocated for packet data
|
|
// Signature -- packet type signature to use
|
|
// DestAddr -- address to which packet will be sent
|
|
// PacketSize -- bytes allocated for packet
|
|
//
|
|
// Returns: None
|
|
//
|
|
// Descript: stuffs data into a packet
|
|
//
|
|
// -----------------------------------------------------
|
|
|
|
VOID
|
|
TpPerfSetPacketData(POPEN_BLOCK OpenP,
|
|
PUCHAR TmpBuf,
|
|
ULONG Signature,
|
|
PUCHAR DestAddr,
|
|
ULONG PacketSize)
|
|
{
|
|
PPERF_PACKET TmpBuffer = (PPERF_PACKET)TmpBuf;
|
|
PUCHAR p;
|
|
PUCHAR q;
|
|
PUCHAR SrcAddr = OpenP->StationAddress;
|
|
USHORT DataSizeShort;
|
|
USHORT i;
|
|
PPERF_BLOCK Perform = OpenP->Perform;
|
|
|
|
|
|
if (DestAddr != NULL) // only do this on first pass
|
|
{
|
|
switch( OpenP->Media->MediumType )
|
|
{
|
|
case NdisMediumDix:
|
|
case NdisMedium802_3:
|
|
p = TmpBuffer->media.e.DestAddress;
|
|
q = TmpBuffer->media.e.SrcAddress;
|
|
DataSizeShort = (USHORT)( PacketSize - OpenP->Media->HeaderSize );
|
|
TmpBuffer->media.e.PacketSize_Hi = (UCHAR)( DataSizeShort >> 8 );
|
|
TmpBuffer->media.e.PacketSize_Lo = (UCHAR)DataSizeShort;
|
|
break;
|
|
|
|
case NdisMedium802_5:
|
|
TmpBuffer->media.tr.AC = 0x10;
|
|
TmpBuffer->media.tr.FC = 0x40;
|
|
p = TmpBuffer->media.tr.DestAddress;
|
|
q = TmpBuffer->media.tr.SrcAddress;
|
|
break;
|
|
|
|
case NdisMediumFddi:
|
|
TmpBuffer->media.fddi.FC = 0x57;
|
|
p = TmpBuffer->media.fddi.DestAddress;
|
|
q = TmpBuffer->media.fddi.SrcAddress;
|
|
break;
|
|
|
|
case NdisMediumArcnet878_2:
|
|
TmpBuffer->media.a.ProtocolID = ARCNET_DEFAULT_PROTOCOLID;
|
|
p = TmpBuffer->media.a.DestAddress;
|
|
q = TmpBuffer->media.a.SrcAddress;
|
|
break;
|
|
|
|
default:
|
|
TpBreakPoint();
|
|
}
|
|
|
|
for ( i = 0 ; i < OpenP->Media->AddressLen ; i++ )
|
|
{
|
|
*p++ = *DestAddr++;
|
|
*q++ = *SrcAddr++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// initialize the packet information header
|
|
//
|
|
|
|
if ((Signature == PERF_SRVDATA_SIGNATURE) || (Signature == PERF_CLTDATA_SIGNATURE))
|
|
{
|
|
ULONG DataFieldSize;
|
|
PUCHAR DataField;
|
|
|
|
TmpBuffer->u.data.Signature = Signature;
|
|
TmpBuffer->u.data.PacketSize = PacketSize;
|
|
TmpBuffer->u.data.CheckSum = TpSetCheckSum( (PUCHAR)&TmpBuffer->u.data,
|
|
sizeof(DATA_PACKET_INFO) - sizeof(ULONG) );
|
|
DataField = TmpBuf + sizeof (MEDIA_HEADER) + sizeof (DATA_PACKET_INFO);
|
|
DataFieldSize = PacketSize - (sizeof (MEDIA_HEADER) + sizeof (DATA_PACKET_INFO) );
|
|
for ( i = 0 ; i < DataFieldSize ; i++ )
|
|
{
|
|
*DataField++ = (UCHAR)i;
|
|
}
|
|
}
|
|
else if (Signature == PERF_RETRES_SIGNATURE)
|
|
{
|
|
TmpBuffer->u.results.Signature = PERF_RETRES_SIGNATURE;
|
|
TmpBuffer->u.results.PacketSize = PacketSize;
|
|
TmpBuffer->u.results.PacketsSent = Perform->SendCount;
|
|
TmpBuffer->u.results.SendErrors = Perform->SendFailCount;
|
|
TmpBuffer->u.results.PacketsReceived = Perform->ReceiveCount;
|
|
TmpBuffer->u.results.ElapsedTime = Perform->PerfSendTotalTime.LowPart;
|
|
TmpBuffer->u.results.SelfReceives = Perform->SelfReceiveCount;
|
|
TmpBuffer->u.results.Restarts = Perform->RestartCount;
|
|
|
|
TmpBuffer->u.results.CheckSum = TpSetCheckSum( (PUCHAR)&TmpBuffer->u.results,
|
|
sizeof(RESULTS_PACKET_INFO) - sizeof(ULONG) );
|
|
}
|
|
else
|
|
{
|
|
|
|
TmpBuffer->u.info.Signature = Signature;
|
|
if (DestAddr != NULL)
|
|
{
|
|
ULONG i;
|
|
PUCHAR r,s;
|
|
|
|
TmpBuffer->u.info.PacketSize = PacketSize;
|
|
TmpBuffer->u.info.Mode = Perform->PerformMode;
|
|
TmpBuffer->u.info.Length = Perform->PacketSize;
|
|
TmpBuffer->u.info.Count = Perform->NumberOfPackets;
|
|
TmpBuffer->u.info.Delay = Perform->PacketDelay;
|
|
r = TmpBuffer->u.info.Address;
|
|
s = Perform->ClientAddress;
|
|
for (i=0; i < ADDRESS_LENGTH; i++)
|
|
{
|
|
*r++ = *s++;
|
|
}
|
|
}
|
|
TmpBuffer->u.info.CheckSum = TpSetCheckSum( (PUCHAR)&TmpBuffer->u.info,
|
|
sizeof(INFO_PACKET_INFO) - sizeof(ULONG) );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------
|
|
//
|
|
// Function: TpPerfSendDpc
|
|
//
|
|
// Arguments: Dpc -- ignored
|
|
// DeferredContext -- actually ptr to open instance
|
|
// SysArg1 -- ignored
|
|
// SysArg2 -- ignored
|
|
//
|
|
// Returns: none
|
|
//
|
|
// Descript: This function is used to start the sending of packets
|
|
// Further packets are sent via TpPerfSendComplete
|
|
//
|
|
// -------------------------------------------
|
|
|
|
|
|
VOID
|
|
TpPerfSendDpc(
|
|
IN PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SysArg1,
|
|
IN PVOID SysArg2
|
|
)
|
|
|
|
{
|
|
POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext);
|
|
NDIS_STATUS Status;
|
|
PTP_REQUEST_HANDLE RequestHandle;
|
|
|
|
UNREFERENCED_PARAMETER( Dpc );
|
|
UNREFERENCED_PARAMETER( SysArg1 );
|
|
UNREFERENCED_PARAMETER( SysArg2 );
|
|
|
|
|
|
switch(OpenP->Perform->WhichReq)
|
|
{
|
|
case REQ_DATA:
|
|
RequestHandle = OpenP->Perform->DataReq;
|
|
++OpenP->Perform->SendCount;
|
|
OpenP->Perform->PerfSendTotalTime =
|
|
RtlLargeIntegerNegate(KeQueryPerformanceCounter(NULL));
|
|
break;
|
|
case REQ_INITGO:
|
|
RequestHandle = OpenP->Perform->GoInitReq;
|
|
break;
|
|
case REQ_ACK:
|
|
RequestHandle = OpenP->Perform->AckReq;
|
|
break;
|
|
case REQ_RES:
|
|
RequestHandle = OpenP->Perform->ResReq;
|
|
break;
|
|
}
|
|
|
|
++OpenP->Perform->PacketsPending;
|
|
|
|
NdisSend( &Status,OpenP->NdisBindingHandle, RequestHandle->u.PERF_REQ.Packet );
|
|
|
|
if ( Status != NDIS_STATUS_PENDING )
|
|
{
|
|
TpPerfSendComplete( OpenP, RequestHandle->u.PERF_REQ.Packet, Status );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------
|
|
//
|
|
// Function: TpPerfSendComplete
|
|
//
|
|
// Arguments: ProtocolBindingContext -- actually ptr to open instance
|
|
// Packet -- the packet that was just sent
|
|
// Status -- final status of the send operation
|
|
//
|
|
// Returns: none
|
|
//
|
|
// Descript: This function is called after the netcard driver actually
|
|
// sends the packet. It is responsible for sending the next
|
|
// packet (if there is one to be sent)
|
|
//
|
|
// -----------------------------------------------
|
|
|
|
|
|
VOID
|
|
TpPerfSendComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN PNDIS_PACKET Packet,
|
|
IN NDIS_STATUS Status
|
|
)
|
|
|
|
|
|
{
|
|
POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext);
|
|
PPERF_BLOCK Perform = OpenP->Perform;
|
|
PPROTOCOL_RESERVED ProtRes;
|
|
PTP_REQUEST_HANDLE RequestHandle;
|
|
PNDIS_BUFFER Buffer;
|
|
LARGE_INTEGER DueTime;
|
|
ULONG MessageId;
|
|
|
|
|
|
|
|
ProtRes = PROT_RES( Packet );
|
|
RequestHandle = ProtRes->RequestHandle;
|
|
|
|
senddidnotpend:
|
|
|
|
if ( Perform->Active == TRUE )
|
|
{
|
|
//
|
|
// Make sure it is one of our packets
|
|
//
|
|
if (( RequestHandle->Signature == SEND_REQUEST_HANDLE_SIGNATURE ) &&
|
|
( RequestHandle->u.PERF_REQ.SendPacket == TRUE ))
|
|
{
|
|
//
|
|
// Packet was sent by the PERF command, decrement the
|
|
// counter tracking the number of outstanding functional packets,
|
|
// and if the send succeeded increment the completion counter.
|
|
//
|
|
|
|
--Perform->PacketsPending;
|
|
|
|
//
|
|
// doesn't do any good to reverse logic here (at least for x86)
|
|
// so just put up with the 1 jump
|
|
//
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// If we are running on TokenRing the following two "failures"
|
|
// are not considered failures NDIS_STATUS_NOT_RECOGNIZED -
|
|
// no one on the ring recognized the address as theirs, or
|
|
// NDIS_STATUS_NOT_COPIED - no one on the ring copied the
|
|
// packet, so we need to special case this and not count
|
|
// these as failures.
|
|
//
|
|
// SanjeevK : Even FDDI returns the same errors as 802.5
|
|
//
|
|
|
|
if ( ( NdisMediumArray[OpenP->MediumIndex] == NdisMedium802_5 ) ||
|
|
( NdisMediumArray[OpenP->MediumIndex] == NdisMediumFddi ) ||
|
|
( NdisMediumArray[OpenP->MediumIndex] == NdisMediumArcnet878_2) )
|
|
{
|
|
if (( Status != NDIS_STATUS_NOT_RECOGNIZED ) &&
|
|
( Status != NDIS_STATUS_NOT_COPIED ))
|
|
{
|
|
++Perform->SendFailCount;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
++Perform->SendFailCount;
|
|
}
|
|
}
|
|
|
|
//
|
|
// not checking the checksum of the PROTOCOL_RESERVED section
|
|
// here, because that stuff was done in functional testing
|
|
//
|
|
|
|
MessageId = ((PPERF_PACKET)RequestHandle->u.PERF_REQ.Buffer)->u.info.Signature
|
|
- PERF_BASE;
|
|
|
|
//
|
|
// deal with performance test messages first
|
|
//
|
|
|
|
if ((MessageId & PERF_ID_MASK) == PERF_DATA_ID)
|
|
{
|
|
if ( ++Perform->PacketsSent < Perform->NumberOfPackets )
|
|
{
|
|
//
|
|
// if in a mode where never wait for ack or req, don't
|
|
// bother with spin-lock, etc, even though this causes
|
|
// repetitious code...
|
|
//
|
|
if ((Perform->PerformMode != PERFMODE_SENDWITHACK) &&
|
|
(Perform->PerformMode != PERFMODE_REQANDRCV))
|
|
{
|
|
++Perform->PacketsPending;
|
|
++Perform->SendCount;
|
|
|
|
if (!Perform->PacketDelay)
|
|
{
|
|
NdisSend( &Status,OpenP->NdisBindingHandle,Packet );
|
|
if ( Status == NDIS_STATUS_PENDING )
|
|
{
|
|
return;
|
|
}
|
|
goto senddidnotpend; // avoid recursion
|
|
}
|
|
//
|
|
// delay code
|
|
//
|
|
else
|
|
{
|
|
KeStallExecutionProcessor(10 * Perform->PacketDelay);
|
|
NdisSend( &Status,OpenP->NdisBindingHandle,Packet );
|
|
if ( Status == NDIS_STATUS_PENDING )
|
|
{
|
|
return;
|
|
}
|
|
goto senddidnotpend; // avoid recursion
|
|
}
|
|
}
|
|
|
|
//
|
|
// send another packet if SendBurstCount has not run out
|
|
// otherwise, wait for REQ or ACK (and setup timeout?)
|
|
//
|
|
NdisAcquireSpinLock( &OpenP->SpinLock );
|
|
if (--Perform->SendBurstCount != 0)
|
|
{
|
|
NdisReleaseSpinLock( &OpenP->SpinLock );
|
|
++Perform->PacketsPending;
|
|
++Perform->SendCount;
|
|
|
|
if (!Perform->PacketDelay)
|
|
{
|
|
NdisSend( &Status,OpenP->NdisBindingHandle,Packet );
|
|
if ( Status == NDIS_STATUS_PENDING )
|
|
{
|
|
return;
|
|
}
|
|
goto senddidnotpend; // avoid recursion
|
|
}
|
|
//
|
|
// delay code
|
|
//
|
|
else
|
|
{
|
|
KeStallExecutionProcessor(10 * Perform->PacketDelay);
|
|
NdisSend( &Status,OpenP->NdisBindingHandle,Packet );
|
|
if ( Status == NDIS_STATUS_PENDING )
|
|
{
|
|
return;
|
|
}
|
|
goto senddidnotpend; // avoid recursion
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NdisReleaseSpinLock( &OpenP->SpinLock );
|
|
DueTime.HighPart = 0xFFFFFFFF; // So it will be relative.
|
|
DueTime.LowPart = (ULONG)(-(ONE_TENTH_SECOND));
|
|
|
|
if ( KeSetTimer(&Perform->PerformTimer,
|
|
DueTime,
|
|
&Perform->PerformRestartDpc ))
|
|
{
|
|
IF_TPDBG ( TP_DEBUG_DPC )
|
|
{
|
|
TpPrint0(
|
|
"TpPerfSendComplete: set PerformTimer while timer existed(4).\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TpPerfTestCompleted(Perform);
|
|
}
|
|
return;
|
|
}
|
|
|
|
//
|
|
// deal with all other messages
|
|
//
|
|
switch ( MessageId)
|
|
{
|
|
//
|
|
// info messages sent by server. Nothing special to do
|
|
// when send is complete
|
|
//
|
|
case PERF_ACKREQ_ID: // client: REQ message
|
|
case (PERF_ACKREQ_ID + PERF_SERVER): // server: ACK message
|
|
case PERF_START_ID: // client: INIT message
|
|
case PERF_DONE_ID: // client: REQRES message
|
|
case (PERF_DONE_ID + PERF_SERVER): // server: SRVDONE message
|
|
case PERF_STOP_ID: // client: STOPSRV message
|
|
case (PERF_NOGO_ID + PERF_SERVER): // server: NOGO message
|
|
return; // client waits for server message
|
|
// server waits for client response
|
|
|
|
//
|
|
// we are a server, and we just got done sending a GO message
|
|
// if we are a sender, send the first performance packet
|
|
//
|
|
case (PERF_START_ID + PERF_SERVER): // server: GO message
|
|
if (Perform->PerformMode >= PERFMODE_SENDANDRCV)
|
|
{
|
|
//
|
|
// server needs to send data to client. start it up
|
|
//
|
|
Perform->WhichReq = REQ_DATA;
|
|
|
|
DueTime.HighPart = 0xFFFFFFFF; // So it will be relative.
|
|
DueTime.LowPart = (ULONG)(-(ONE_HUNDREDTH_SECOND*2));
|
|
|
|
if ( KeSetTimer(&Perform->PerformTimer,
|
|
DueTime,
|
|
&Perform->PerformSendDpc ))
|
|
{
|
|
IF_TPDBG ( TP_DEBUG_DPC )
|
|
{
|
|
TpPrint0(
|
|
"TpPerfSendComplete: set PerformTimer while timer existed(1).\n");
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
|
|
//
|
|
// we are a server, and we just got done sending the final results
|
|
// to the client. finish shutting down from this test
|
|
//
|
|
|
|
case (PERF_RESULTS_ID + PERF_SERVER): // server: sent results
|
|
if (Perform->DataReq) // clean up, then wait for INIT message
|
|
{
|
|
TpFuncFreePacket( Perform->DataReq->u.SEND_REQ.Packet,
|
|
Perform->DataReq->u.SEND_REQ.PacketSize );
|
|
NdisFreeMemory( Perform->DataReq,0,0 );
|
|
Perform->DataReq = NULL;
|
|
}
|
|
return;
|
|
|
|
//
|
|
// we are a server, and we just got done acknowledging a shut-down request
|
|
// from the client. finish up with the shutdown.
|
|
//
|
|
case (PERF_STOP_ID + PERF_SERVER): // server: acknowledged shutdown
|
|
// request cleansup, then exit
|
|
DueTime.HighPart = 0xFFFFFFFF; // So it will be relative.
|
|
DueTime.LowPart = (ULONG)(-(ONE_SECOND));
|
|
|
|
if ( KeSetTimer(&Perform->PerformTimer,
|
|
DueTime,
|
|
&Perform->PerformEndDpc ))
|
|
{
|
|
IF_TPDBG ( TP_DEBUG_DPC )
|
|
{
|
|
TpPrint0(
|
|
"TpPerfSendComplete: set PerformTimer while timer existed(2).\n");
|
|
}
|
|
}
|
|
return;
|
|
|
|
default: // illegal message
|
|
TpPrint0("TpPerfSendComplete: unknown message\n");
|
|
TpBreakPoint();
|
|
return;
|
|
|
|
|
|
}
|
|
} // if (RequestSignature == ..
|
|
|
|
else
|
|
{
|
|
//
|
|
// this is not one of ours. we should never, ever get here...
|
|
//
|
|
TpPrint0("TpPerfSendComplete: Not one of ours--why are we here?");
|
|
NdisUnchainBufferAtFront( Packet,&Buffer );
|
|
NdisFreeMemory( MmGetMdlVirtualAddress( Buffer ),0,0 );
|
|
TpFreeBuffer( Buffer );
|
|
NdisFreePacket( Packet );
|
|
NdisFreeMemory( RequestHandle,0,0 );
|
|
return;
|
|
}
|
|
} // if (Perform->Active)
|
|
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------
|
|
//
|
|
// TpPerfTestCompleted
|
|
//
|
|
// Arguments: OpenP -- ptr to current open instance
|
|
//
|
|
// Returns: none
|
|
//
|
|
// Descript: This code deals with cleanup that needs to be done at the
|
|
// end of a send test
|
|
//
|
|
// ----------------------------------------------------------
|
|
|
|
VOID
|
|
TpPerfTestCompleted(PPERF_BLOCK Perform)
|
|
{
|
|
LARGE_INTEGER scale;
|
|
LARGE_INTEGER ltemp;
|
|
LARGE_INTEGER DueTime;
|
|
PKDPC DpcPtr;
|
|
|
|
Perform->PerfSendTotalTime = RtlLargeIntegerAdd( Perform->PerfSendTotalTime,
|
|
KeQueryPerformanceCounter(&scale));
|
|
|
|
Perform->PerfSendTotalTime = RtlExtendedIntegerMultiply(Perform->PerfSendTotalTime, 1000);
|
|
Perform->PerfSendTotalTime = RtlLargeIntegerDivide(Perform->PerfSendTotalTime,
|
|
scale, <emp);
|
|
|
|
if (Perform->IsServer)
|
|
{
|
|
DpcPtr = &Perform->PerformSendDpc;
|
|
Perform->WhichReq = REQ_ACK; // SRVDONE message
|
|
}
|
|
|
|
//
|
|
// must be client..
|
|
//
|
|
else if (Perform->PerformMode == PERFMODE_SEND)
|
|
{
|
|
//
|
|
// Write the statistics to the send results outputbuffer.
|
|
//
|
|
|
|
TpPerfWriteResults( Perform, NULL );
|
|
DpcPtr = &Perform->PerformEndDpc;
|
|
}
|
|
|
|
else
|
|
{
|
|
if (Perform->PerformMode == PERFMODE_SENDANDRCV)
|
|
{
|
|
if (!Perform->Testing)
|
|
{
|
|
Perform->Testing = TRUE;
|
|
return;
|
|
}
|
|
}
|
|
Perform->WhichReq = REQ_RES;
|
|
DpcPtr = &Perform->PerformSendDpc;
|
|
}
|
|
|
|
DueTime.HighPart = 0xFFFFFFFF; // So it will be relative.
|
|
DueTime.LowPart = (ULONG)(-(ONE_SECOND));
|
|
|
|
|
|
if ( KeSetTimer(&Perform->PerformTimer,
|
|
DueTime,
|
|
DpcPtr ))
|
|
{
|
|
IF_TPDBG ( TP_DEBUG_DPC )
|
|
{
|
|
TpPrint0( "TpPerfTestCompleted: set PerformTimer while timer existed.\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------
|
|
//
|
|
// Function: TpPerfReceive
|
|
//
|
|
// Arguments: ProtocolBindingContext -- actually ptr to current open instance
|
|
// LookaheadBuffer -- ptr to actual data received (after header)
|
|
// LookaheadBufferSize -- valid bytes in LookaheadBuffer
|
|
// PacketSize -- total size of packet (excluding header)
|
|
//
|
|
// Returns: Status
|
|
//
|
|
// Descript: This function deals with packets received by this netcard open instance
|
|
// Some packets are counted, some just thrown away, some result in other
|
|
// packets being sent
|
|
//
|
|
// -------------------------------------------------------
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
TpPerfReceive(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN PVOID LookaheadBuffer,
|
|
IN UINT LookaheadBufferSize,
|
|
IN UINT PacketSize
|
|
)
|
|
|
|
{
|
|
POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext);
|
|
PPERF_BLOCK Perform = OpenP->Perform;
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
PINFO_PACKET_INFO ReceivePacketInfo;
|
|
PNDIS_PACKET Packet;
|
|
ULONG MessageId;
|
|
|
|
//
|
|
// if we are not active (ie, shutting down) skip everything
|
|
//
|
|
|
|
if (Perform->Active)
|
|
{
|
|
//
|
|
// The LookAhead Buffer has been adjusted to point to the beginning of the
|
|
// PACKET_INFO structure
|
|
//
|
|
ReceivePacketInfo = (PINFO_PACKET_INFO)LookaheadBuffer;
|
|
|
|
//
|
|
// All valid messages have a signature of 0x7654321X.
|
|
// Using the MaskId, convert all valid messages to 0x0000000X.
|
|
// invalid messages will have other bits set. Messages that we
|
|
// managed to send to ourselves will be in range 0x08 to 0x0f.
|
|
// messages we expect will be in range 0x00 to 0x07
|
|
//
|
|
MessageId = ReceivePacketInfo->Signature ^ Perform->MaskId;
|
|
//
|
|
// trivially discard all unrecognized messages
|
|
//
|
|
if (MessageId < (PERF_SERVER + PERF_ID_MASK))
|
|
{
|
|
//
|
|
// first, deal with performance test messages which were received
|
|
//
|
|
if ( MessageId == PERF_DATA_ID)
|
|
{
|
|
++Perform->ReceiveCount;
|
|
|
|
//
|
|
// Check to see if we need to send an ACK (or a REQ )
|
|
// note that the info packet will already be set up correctly
|
|
//
|
|
if (--Perform->ReceiveBurstCount != 0)
|
|
{
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
Perform->ReceiveBurstCount = PACKETS_PER_BURST;
|
|
Packet = Perform->AckReq->u.PERF_REQ.Packet;
|
|
++Perform->PacketsPending;
|
|
|
|
NdisSend( &Status,OpenP->NdisBindingHandle,Packet );
|
|
if ( Status == NDIS_STATUS_PENDING )
|
|
{
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
TpPerfSendComplete( OpenP, Packet, Status );
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
}
|
|
//
|
|
// second, deal with ACK and REQ messages
|
|
//
|
|
else if (MessageId == PERF_ACKREQ_ID)
|
|
{
|
|
NdisAcquireSpinLock( &OpenP->SpinLock );
|
|
if (Perform->SendBurstCount == 0)
|
|
{
|
|
Perform->SendBurstCount = PACKETS_PER_BURST;
|
|
NdisReleaseSpinLock( &OpenP->SpinLock );
|
|
KeCancelTimer(&Perform->PerformTimer);
|
|
|
|
Packet = Perform->DataReq->u.PERF_REQ.Packet;
|
|
++Perform->SendCount;
|
|
++Perform->PacketsPending;
|
|
|
|
NdisSend( &Status,OpenP->NdisBindingHandle,Packet );
|
|
if ( Status != NDIS_STATUS_PENDING )
|
|
{
|
|
TpPerfSendComplete( OpenP, Packet, Status );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Perform->SendBurstCount += PACKETS_PER_BURST;
|
|
NdisReleaseSpinLock( &OpenP->SpinLock );
|
|
}
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
//
|
|
// deal with other valid messages
|
|
//
|
|
else if ((MessageId & PERF_SERVER) == 0) // check other valid messages
|
|
{
|
|
return TpPerfLowPriorityReceive(OpenP, ReceivePacketInfo, MessageId);
|
|
}
|
|
//
|
|
// deal with messages that we probably sent to ourselves
|
|
// while it it POSSIBLE that we got a random message that will
|
|
// fit this criteria, we are ignoring that for now
|
|
//
|
|
else
|
|
{
|
|
Perform->SelfReceiveCount++;
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
return NDIS_STATUS_SUCCESS; // don't fail..
|
|
}
|
|
|
|
|
|
// ------------------------------------------------
|
|
//
|
|
// Function: TpPerfLowPriorityReceive
|
|
//
|
|
// Arguments: OpenP -- ptr to current open instance
|
|
// ReceivePacketInfo -- data received from other end of wire
|
|
// MessageId -- which message we received
|
|
//
|
|
// Returns: Status
|
|
//
|
|
// Descript: This function does the initialization required
|
|
// when the server receives the PERF_INIT message
|
|
//
|
|
// -------------------------------------------------
|
|
|
|
NDIS_STATUS
|
|
TpPerfLowPriorityReceive( POPEN_BLOCK OpenP,
|
|
PINFO_PACKET_INFO ReceivePacketInfo,
|
|
ULONG MessageId)
|
|
{
|
|
PPERF_BLOCK Perform = OpenP->Perform;
|
|
PUCHAR r,s;
|
|
ULONG i;
|
|
PTP_REQUEST_HANDLE RequestHandle;
|
|
PNDIS_PACKET Packet;
|
|
LARGE_INTEGER DueTime;
|
|
PKDPC DpcPtr;
|
|
|
|
|
|
switch(MessageId)
|
|
{
|
|
case PERF_DONE_ID: // REQRES or SRVDONE message
|
|
if (Perform->IsServer)
|
|
{
|
|
//
|
|
// client sent request for final results of test (on server side)
|
|
// test had better be complete. Shut down test and send message
|
|
// to client with those results
|
|
//
|
|
TpPerfSetPacketData(OpenP,
|
|
Perform->ResReq->u.PERF_REQ.Buffer,
|
|
PERF_RETRES_SIGNATURE,
|
|
NULL,
|
|
MINIMUM_PERF_PACKET);
|
|
|
|
Perform->WhichReq = REQ_RES;
|
|
DpcPtr = &Perform->PerformSendDpc;
|
|
DueTime.LowPart = (ULONG)(-(ONE_SECOND));
|
|
Perform->Testing = FALSE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// server is done sending data. if only server was sending, get
|
|
// stats now . if both were sending, get stats now if we are also
|
|
// done. Otherwise, set flags to get data when we are done sending
|
|
//
|
|
if (Perform->PerformMode == PERFMODE_SENDANDRCV)
|
|
{
|
|
if (!Perform->Testing)
|
|
{
|
|
Perform->Testing = TRUE;
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
}
|
|
Perform->WhichReq = REQ_RES;
|
|
DpcPtr = &Perform->PerformSendDpc;
|
|
DueTime.LowPart = (ULONG)(-(ONE_SECOND));
|
|
}
|
|
break;
|
|
|
|
|
|
case PERF_STOP_ID: // STOPSRV or SRVDOWN message
|
|
if (Perform->IsServer)
|
|
{
|
|
//
|
|
// client just sent message to server telling server to
|
|
// shut down, and go back to tpctl for next command
|
|
//
|
|
TpPerfSetPacketData(OpenP,
|
|
Perform->GoInitReq->u.PERF_REQ.Buffer,
|
|
PERF_SRVDOWN_SIGNATURE,
|
|
ReceivePacketInfo->Address,
|
|
MINIMUM_PERF_PACKET);
|
|
|
|
Perform->WhichReq = REQ_INITGO;
|
|
DpcPtr = &Perform->PerformSendDpc;
|
|
DueTime.LowPart = (ULONG)(-(ONE_SECOND));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// server is shutting down. We need to do the same
|
|
//
|
|
DpcPtr = &Perform->PerformEndDpc;
|
|
DueTime.LowPart = (ULONG)(-(ONE_SECOND));
|
|
}
|
|
break;
|
|
|
|
|
|
case PERF_NOGO_ID: // NOGO message
|
|
//
|
|
// server just sent message that it is unable to perform the
|
|
// requested test. Clean up and exit (to tpctl)
|
|
//
|
|
DpcPtr = &Perform->PerformEndDpc;
|
|
DueTime.LowPart = (ULONG)(-(ONE_SECOND));
|
|
break;
|
|
|
|
|
|
case PERF_RESULTS_ID: // RETRES message
|
|
//
|
|
// just received final results of this test from the server
|
|
// send data to tpctl, cleanup, and exit
|
|
//
|
|
//
|
|
// Write the statistics to the send results outputbuffer.
|
|
//
|
|
|
|
TpPerfWriteResults( Perform, (PRESULTS_PACKET_INFO)ReceivePacketInfo);
|
|
DpcPtr = &Perform->PerformEndDpc;
|
|
DueTime.LowPart = (ULONG)(-(ONE_SECOND));
|
|
break;
|
|
|
|
case PERF_START_ID: // INIT or GO message
|
|
if (!Perform->IsServer)
|
|
{
|
|
if (Perform->DataReq)
|
|
{
|
|
Perform->WhichReq = REQ_DATA;
|
|
DpcPtr = &Perform->PerformSendDpc;
|
|
DueTime.LowPart = (ULONG)(-(ONE_HUNDREDTH_SECOND));
|
|
break;
|
|
}
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
if (Perform->Testing) // Got 2nd request, not done with 1st
|
|
{
|
|
TpPrint0("TpPerfReceive: Server got INIT while already running!\n");
|
|
if (Perform->DataReq)
|
|
{
|
|
TpFuncFreePacket( Perform->DataReq->u.SEND_REQ.Packet,
|
|
Perform->DataReq->u.SEND_REQ.PacketSize );
|
|
NdisFreeMemory( Perform->DataReq,0,0 );
|
|
}
|
|
}
|
|
//
|
|
// copy info we will need from message
|
|
//
|
|
Perform->PerformMode = ReceivePacketInfo->Mode;
|
|
Perform->PacketSize = ReceivePacketInfo->Length;
|
|
Perform->NumberOfPackets = ReceivePacketInfo->Count;
|
|
Perform->PacketDelay = ReceivePacketInfo->Delay;
|
|
r = Perform->ClientAddress;
|
|
s = ReceivePacketInfo->Address;
|
|
for (i=0; i < ADDRESS_LENGTH; i++)
|
|
{
|
|
*r++ = *s++;
|
|
}
|
|
//
|
|
// initialize counters
|
|
//
|
|
Perform->SendCount = 0;
|
|
Perform->SendFailCount = 0;
|
|
Perform->ReceiveCount = 0;
|
|
Perform->PacketsSent = 0;
|
|
Perform->PerformEndDpcCount = 0;
|
|
Perform->PacketsPending = 0;
|
|
Perform->Testing = FALSE;
|
|
Perform->SelfReceiveCount = 0;
|
|
Perform->SendBurstCount = 0;
|
|
Perform->ReceiveBurstCount = 0;
|
|
Perform->RestartCount = 0;
|
|
//
|
|
// if we will be sending test data (not just info messages), then
|
|
// set up the necessary buffer. If it fails, send a NOGO message
|
|
//
|
|
if (Perform->PerformMode >= PERFMODE_SENDANDRCV)
|
|
{
|
|
RequestHandle = TpPerfAllocatePacket( OpenP, Perform->PacketSize);
|
|
if (RequestHandle == NULL)
|
|
{
|
|
TpPrint0("TpPerfReceive: Server unable to allocate data packet\n");
|
|
RequestHandle = Perform->GoInitReq;
|
|
Packet = RequestHandle->u.PERF_REQ.Packet;
|
|
|
|
TpPerfSetPacketData(OpenP,
|
|
RequestHandle->u.PERF_REQ.Buffer,
|
|
PERF_NOGO_SIGNATURE,
|
|
Perform->ClientAddress,
|
|
MINIMUM_PERF_PACKET);
|
|
|
|
Perform->WhichReq = REQ_INITGO;
|
|
DpcPtr = &Perform->PerformSendDpc;
|
|
DueTime.LowPart = (ULONG)(-(ONE_SECOND));
|
|
break;
|
|
}
|
|
Perform->DataReq = RequestHandle;
|
|
|
|
TpPerfSetPacketData(OpenP,
|
|
RequestHandle->u.PERF_REQ.Buffer,
|
|
PERF_SRVDATA_SIGNATURE,
|
|
Perform->ClientAddress,
|
|
Perform->PacketSize);
|
|
|
|
if (Perform->PerformMode == PERFMODE_REQANDRCV)
|
|
{
|
|
Perform->SendBurstCount = PACKETS_PER_BURST;
|
|
}
|
|
else
|
|
{
|
|
Perform->SendBurstCount = Perform->NumberOfPackets+1;
|
|
}
|
|
Perform->ReceiveBurstCount = Perform->NumberOfPackets+1;
|
|
}
|
|
|
|
else if (Perform->PerformMode == PERFMODE_SENDWITHACK)
|
|
{
|
|
Perform->ReceiveBurstCount = PACKETS_PER_BURST;
|
|
}
|
|
else
|
|
{
|
|
Perform->ReceiveBurstCount = Perform->NumberOfPackets+1;
|
|
}
|
|
|
|
//
|
|
// all set--initialize the AckReq message, and
|
|
// send the client the GO message
|
|
//
|
|
Perform->Testing = TRUE;
|
|
|
|
switch(Perform->PerformMode)
|
|
{
|
|
case PERFMODE_SENDTOSRV:
|
|
case PERFMODE_SENDWITHACK:
|
|
TpPerfSetPacketData(OpenP,
|
|
Perform->AckReq->u.PERF_REQ.Buffer,
|
|
PERF_ACK_SIGNATURE,
|
|
Perform->ClientAddress,
|
|
MINIMUM_PERF_PACKET);
|
|
break;
|
|
default:
|
|
TpPerfSetPacketData(OpenP,
|
|
Perform->AckReq->u.PERF_REQ.Buffer,
|
|
PERF_SRVDONE_SIGNATURE,
|
|
Perform->ClientAddress,
|
|
MINIMUM_PERF_PACKET);
|
|
break;
|
|
}
|
|
TpPerfSetPacketData(OpenP,
|
|
Perform->ResReq->u.PERF_REQ.Buffer,
|
|
PERF_RETRES_SIGNATURE,
|
|
Perform->ClientAddress,
|
|
MINIMUM_PERF_PACKET);
|
|
|
|
TpPerfSetPacketData(OpenP,
|
|
Perform->GoInitReq->u.PERF_REQ.Buffer,
|
|
PERF_GO_SIGNATURE,
|
|
Perform->ClientAddress,
|
|
MINIMUM_PERF_PACKET);
|
|
|
|
DpcPtr = &Perform->PerformSendDpc;
|
|
DueTime.LowPart = (ULONG)(-(ONE_SECOND));
|
|
Perform->WhichReq = REQ_INITGO;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
TpPrint0("TpPerfReceive: Client received unrecognized message\n");
|
|
return NDIS_STATUS_NOT_RECOGNIZED;
|
|
}
|
|
|
|
//
|
|
// drop thru to here if need to fire something off with the timer...
|
|
//
|
|
|
|
DueTime.HighPart = 0xFFFFFFFF; // So it will be relative.
|
|
|
|
if ( KeSetTimer(&Perform->PerformTimer,
|
|
DueTime,
|
|
DpcPtr ))
|
|
{
|
|
IF_TPDBG ( TP_DEBUG_DPC )
|
|
{
|
|
TpPrint0( "TpPerfLowPriorityReceive: set PerformTimer while timer existed.\n");
|
|
}
|
|
}
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
// --------------------------------------------
|
|
//
|
|
// Function: TpPerformEndDpc
|
|
//
|
|
// Arguments: Dpc -- not used
|
|
// DeferredContext -- actually ptr to current open instance
|
|
// SysArg1 -- not used
|
|
// SysArg2 -- not used
|
|
//
|
|
// Returns: none
|
|
//
|
|
// Descript: This function is called when it is time to shut down
|
|
// the current performance command
|
|
//
|
|
// -------------------------------------------
|
|
|
|
VOID
|
|
TpPerformEndDpc(
|
|
IN PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SysArg1,
|
|
IN PVOID SysArg2
|
|
)
|
|
{
|
|
POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext);
|
|
PPERF_BLOCK Perform = OpenP->Perform;
|
|
LARGE_INTEGER DueTime;
|
|
|
|
UNREFERENCED_PARAMETER( Dpc );
|
|
UNREFERENCED_PARAMETER( SysArg1 );
|
|
UNREFERENCED_PARAMETER( SysArg2 );
|
|
|
|
//
|
|
// See if we have any outstanding packets left to complete. If we do,
|
|
// then we will reset the time to queue this dpc routine again in one
|
|
// second, if after ten requeue the packet has still no completed we
|
|
// assume it will never complete and return the results and finish.
|
|
//
|
|
|
|
NdisAcquireSpinLock( &OpenP->SpinLock );
|
|
|
|
if ((( Perform->PerformIrp != NULL ) &&
|
|
( Perform->PerformIrp->Cancel == FALSE )) &&
|
|
(( Perform->PacketsPending != 0 ) &&
|
|
( Perform->PerformEndDpcCount++ < 10 )))
|
|
{
|
|
NdisReleaseSpinLock( &OpenP->SpinLock );
|
|
|
|
DueTime.HighPart = -1; // So it will be relative.
|
|
DueTime.LowPart = (ULONG)(-(ONE_SECOND));
|
|
|
|
if ( KeSetTimer(&Perform->PerformTimer,
|
|
DueTime,
|
|
&Perform->PerformEndDpc ))
|
|
{
|
|
IF_TPDBG ( TP_DEBUG_DPC )
|
|
{
|
|
TpPrint0("TpPerformEndDpc: set PerformTimer while timer existed.\n");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// and if the IoStatus.Status has not been set, then set it.
|
|
//
|
|
|
|
if ( (Perform->PerformIrp != NULL) &&
|
|
(Perform->PerformIrp->IoStatus.Status == NDIS_STATUS_PENDING ))
|
|
{
|
|
Perform->PerformIrp->IoStatus.Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
NdisReleaseSpinLock( &OpenP->SpinLock );
|
|
|
|
//
|
|
// Now set the sending flag to indicate that we are no longer
|
|
// SENDing packets.
|
|
//
|
|
|
|
Perform->Active = FALSE;
|
|
|
|
//
|
|
// and 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.
|
|
//
|
|
|
|
|
|
if (Perform->PerformIrp != NULL)
|
|
{
|
|
TpRemoveReference( OpenP );
|
|
IoMarkIrpPending( Perform->PerformIrp );
|
|
|
|
IoAcquireCancelSpinLock( &Perform->PerformIrp->CancelIrql );
|
|
IoSetCancelRoutine( Perform->PerformIrp,NULL );
|
|
IoReleaseCancelSpinLock( Perform->PerformIrp->CancelIrql );
|
|
|
|
IoCompleteRequest( Perform->PerformIrp,IO_NETWORK_INCREMENT );
|
|
|
|
Perform->PerformIrp = NULL;
|
|
}
|
|
TpPerfDeallocate(OpenP);
|
|
}
|
|
|
|
// --------------------------------------------
|
|
//
|
|
// Function: TpPerfRestart
|
|
//
|
|
// Arguments: Dpc -- not used
|
|
// DeferredContext -- actually ptr to current open instance
|
|
// SysArg1 -- not used
|
|
// SysArg2 -- not used
|
|
//
|
|
// Returns: none
|
|
//
|
|
// Descript: This function is called when it is necessary to restart
|
|
// a send without there having been a REQ or ACK received
|
|
//
|
|
// -------------------------------------------
|
|
|
|
VOID
|
|
TpPerfRestart(
|
|
IN PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SysArg1,
|
|
IN PVOID SysArg2
|
|
)
|
|
{
|
|
POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext);
|
|
PPERF_BLOCK Perform = OpenP->Perform;
|
|
NDIS_STATUS Status;
|
|
|
|
NdisAcquireSpinLock( &OpenP->SpinLock );
|
|
if (Perform->SendBurstCount == 0)
|
|
{
|
|
Perform->SendBurstCount = 1;
|
|
NdisReleaseSpinLock( &OpenP->SpinLock );
|
|
Perform->RestartCount++;
|
|
++Perform->SendCount;
|
|
++Perform->PacketsPending;
|
|
|
|
NdisSend( &Status,OpenP->NdisBindingHandle, Perform->DataReq->u.PERF_REQ.Packet );
|
|
if ( Status != NDIS_STATUS_PENDING )
|
|
{
|
|
TpPerfSendComplete( OpenP, Perform->DataReq->u.PERF_REQ.Packet, Status );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------
|
|
//
|
|
// Function: TpPerfWriteResults
|
|
//
|
|
// Arguments: Perform -- ptr to perform block structure
|
|
// Info -- ptr to data received from server (may be NULL)
|
|
//
|
|
// Returns: none
|
|
//
|
|
// Descript: This function writes the Performance test statistics into the
|
|
// output buffer passed in by the ioctl call. NOTE: the
|
|
// OpenP->SpinLock must be held when making this call
|
|
//
|
|
// ------------------------------------------------------------------
|
|
|
|
|
|
VOID
|
|
TpPerfWriteResults( IN PPERF_BLOCK Perform,
|
|
IN PRESULTS_PACKET_INFO Info)
|
|
{
|
|
PPERF_RESULTS OutputBuffer;
|
|
|
|
//
|
|
// Get the output buffer out of the MDL stored in the IRP, and map
|
|
// it so we may write the statistics to it.
|
|
//
|
|
|
|
if (( Perform->PerformIrp != NULL ) &&
|
|
( Perform->PerformIrp->Cancel == FALSE ))
|
|
{
|
|
OutputBuffer = MmGetSystemAddressForMdl( Perform->PerformIrp->MdlAddress );
|
|
|
|
//
|
|
// Write the statistics to the outbuffer
|
|
//
|
|
|
|
OutputBuffer->Signature = PERF_RESULTS_SIGNATURE;
|
|
OutputBuffer->ResultsExist = TRUE;
|
|
OutputBuffer->Mode = Perform->PerformMode;
|
|
OutputBuffer->PacketSize = Perform->PacketSize;
|
|
OutputBuffer->PacketCount = Perform->NumberOfPackets;
|
|
OutputBuffer->Milliseconds = Perform->PerfSendTotalTime.LowPart;
|
|
OutputBuffer->Sends = Perform->SendCount;
|
|
OutputBuffer->SendFails = Perform->SendFailCount;
|
|
OutputBuffer->Receives = Perform->ReceiveCount;
|
|
OutputBuffer->SelfReceives = Perform->SelfReceiveCount;
|
|
OutputBuffer->Restarts = Perform->RestartCount;
|
|
|
|
if (Info != NULL)
|
|
{
|
|
OutputBuffer->S_Milliseconds = Info->ElapsedTime;
|
|
OutputBuffer->S_Sends = Info->PacketsSent;
|
|
OutputBuffer->S_SendFails = Info->SendErrors;
|
|
OutputBuffer->S_Receives = Info->PacketsReceived;
|
|
OutputBuffer->S_SelfReceives = Info->SelfReceives;
|
|
OutputBuffer->S_Restarts = Info->Restarts;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
TpPerfAbort(POPEN_BLOCK OpenP)
|
|
{
|
|
LARGE_INTEGER DueTime;
|
|
PPERF_BLOCK Perform = OpenP->Perform;
|
|
|
|
//
|
|
// We want to stop any active client and/or server on this open
|
|
// instance from running the performance routines, so clear the
|
|
// Active flag, queue up the EndDpc function, and wait for it
|
|
// to finish
|
|
//
|
|
|
|
Perform->Active = FALSE;
|
|
|
|
DueTime.HighPart = 0xFFFFFFFF; // So it will be relative.
|
|
DueTime.LowPart = (ULONG)(-(ONE_SECOND));
|
|
|
|
for(;;)
|
|
{
|
|
KeCancelTimer(&Perform->PerformTimer);
|
|
if ( KeSetTimer(&Perform->PerformTimer,
|
|
DueTime,
|
|
&Perform->PerformEndDpc ))
|
|
{
|
|
IF_TPDBG ( TP_DEBUG_DPC )
|
|
{
|
|
TpPrint0( "TpPerfAbort: set PerformTimer while timer existed.\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// And wait for them to finish.
|
|
//
|
|
|
|
while ( OpenP->PerformanceTest == TRUE )
|
|
{
|
|
/* NULL */ ;
|
|
}
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|