Windows NT 4.0 source code leak
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

// ------------------------------------------------
//
// 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, &ltemp);
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;
}