diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/ndis/testprot/tpdrvr/tpfunc.c | 4639 |
1 files changed, 4639 insertions, 0 deletions
diff --git a/private/ntos/ndis/testprot/tpdrvr/tpfunc.c b/private/ntos/ndis/testprot/tpdrvr/tpfunc.c new file mode 100644 index 000000000..d94998c87 --- /dev/null +++ b/private/ntos/ndis/testprot/tpdrvr/tpfunc.c @@ -0,0 +1,4639 @@ +// ------------------------ +// +// Copyright (c) 1990 Microsoft Corporation +// +// Module Name: +// +// tpfunc.c +// +// Abstract: +// +// +// Author: +// +// Tom Adams (tomad) 9-Jul-1991 +// +// Environment: +// +// Kernel mode, FSD +// +// Revision History: +// +// Sanjeev Katariya (sanjeevk) +// +// 4-6-1993 Bug #5203: Changed the routine TpFuncOpenAdapter() to fill in the information +// of the media type for use by the TPCTL. This was done in order +// for TPCTL to make a decision on the OID to use when submitting +// requests to add/change mulicast addresses. +// +// 4-9-1993 Bug #5886: Changed TpFuncSendComplete() to zero out the private section of the +// NDIS_PACKET. Should the MAC access this section now after having made +// a call and to NdisSendComplete(), it will be forced to deal with +// or incorrect data +// +// 4-12-1993 Added ARCNET support +// +// Tim Wynsma (timothyw) +// 4-27-94 Added performance tests +// 5-18-94 Got rid of warnings; added some debug +// 6-08-94 Chgd perf test to client/server +// +// ----------------------------- + + +#include <ndis.h> + +#include "tpdefs.h" +#include "media.h" +#include "tpprocs.h" +#include "string.h" + + +VOID +TpFuncResend(POPEN_BLOCK OpenP, + PTP_REQUEST_HANDLE SendReqHndl); + + + +NDIS_STATUS +TpFuncOpenAdapter( + IN POPEN_BLOCK OpenP, + IN UCHAR OpenInstance, + IN PCMD_ARGS CmdArgs + ) + +// ------------ +// +// Routine Description: +// +// This routine opens the request NDIS adapter and sets up the OpenBlock +// accordingly. If the call to NdisOpenAdapter does not pend, then a call +// will be made to TpFuncRequestComplete to complete the request and +// signal the application that it has finished, otherwise this call will +// be made the MAC itself once the request has finished. +// +// Arguments: +// +// +// Return Value: +// +// NDIS_STATUS - This routine always returns NDIS_STATUS_PENDING as it +// will either really pend and be completed later, or we +// will fake a completion request that will complete it +// at that time. +// +// ------------------ + + +{ + NTSTATUS Status = STATUS_SUCCESS; + NDIS_STATUS DriverStatus = NDIS_STATUS_SUCCESS; + NDIS_STATUS RequestStatus = NDIS_STATUS_SUCCESS; + STRING AdapterString; + NDIS_STRING NdisAdapterString; + NDIS_STATUS OpenErrorStatus; + UINT NameLength; + PNDIS_REQUEST Request = NULL; + PUCHAR InformationBuffer = NULL; + ULONG OidIndex; + PUCHAR p, q; + ULONG i; + PREQUEST_RESULTS OutputBuffer; + BOOLEAN GotCardAddress = FALSE; + ULONG MediaArraySize; + + + // + // Determine determine whether this instance of the Adapter is already + // opened. + // + + if ( OpenP->OpenInstance != (UCHAR)-1 ) + { + // + // If it has, then we will fail this request, and continue. We will + // not create a new Open Instance overwriting an existing one. + // + + IF_TPDBG ( TP_DEBUG_NDIS_CALLS ) + { + TpPrint1("TpFuncOpenAdapter: An open already exists for this Open Instance %d\n", + OpenInstance); + } + Status = NDIS_STATUS_OPEN_FAILED; + } + else + { + // + // First allocate the request handle and set it up as if the request + // pended. If it does not pend we will reset the flags later; before + // calling the completion routine. + // + + TP_ASSERT ( OpenP->OpenReqHndl == NULL ); + + Status = NdisAllocateMemory((PVOID *)&OpenP->OpenReqHndl, + sizeof( TP_REQUEST_HANDLE ), + 0, + HighestAddress ); + + if ( Status != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG (TP_DEBUG_RESOURCES) + { + TpPrint0("TpFuncOpenAdapter: unable to allocate Request Handle.\n"); + } + Status = NDIS_STATUS_RESOURCES; + goto cleanup; + } + else + { + NdisZeroMemory( OpenP->OpenReqHndl,sizeof( TP_REQUEST_HANDLE )); + } + + OpenP->OpenReqHndl->Signature = OPEN_REQUEST_HANDLE_SIGNATURE; + OpenP->OpenReqHndl->Open = OpenP; + OpenP->OpenReqHndl->RequestPended = FALSE; + + KeInitializeEvent( &OpenP->OpenReqHndl->u.OPEN_REQ.OpenEvent, + SynchronizationEvent, + FALSE ); + // + // Otherwise initialize the adapter string for the call ... + // + + TP_ASSERT( OpenP->AdapterName == NULL ); + + NameLength = strlen( CmdArgs->ARGS.OPEN_ADAPTER.AdapterName ) + 1; + + Status = NdisAllocateMemory((PVOID *)&OpenP->AdapterName, + 8 + NameLength, + 0, + HighestAddress ); + + if ( Status != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG (TP_DEBUG_RESOURCES) + { + TpPrint0("TpFuncOpenAdapter: failed to allocate adapter name buffer.\n"); + } + Status = NDIS_STATUS_RESOURCES; + goto cleanup; + } + else + { + NdisZeroMemory( OpenP->AdapterName,8 + NameLength ); + } + + NdisMoveMemory( OpenP->AdapterName,"\\Device\\",8 ); + + NdisMoveMemory( OpenP->AdapterName + 8, + CmdArgs->ARGS.OPEN_ADAPTER.AdapterName, + NameLength ); + + RtlInitString( &AdapterString,(PSZ)OpenP->AdapterName ); + + Status = RtlAnsiStringToUnicodeString( (PUNICODE_STRING)&NdisAdapterString, + (PANSI_STRING)&AdapterString, + TRUE ); + + TP_ASSERT( NT_SUCCESS( Status )); + + // + // And make the actual NdisOpenAdapter Call. + // + + if (CmdArgs->ARGS.OPEN_ADAPTER.NoArcNet) // force encapsulated ethernet + { + MediaArraySize = NDIS_MEDIUM_ARRAY_SIZE - 1; + } + else + { + MediaArraySize = NDIS_MEDIUM_ARRAY_SIZE; + } + + + NdisOpenAdapter(&DriverStatus, + &OpenErrorStatus, + &OpenP->NdisBindingHandle, + &OpenP->MediumIndex, + NdisMediumArray, + MediaArraySize, + OpenP->NdisProtocolHandle, + (NDIS_HANDLE)OpenP, + &NdisAdapterString, + 0, + NULL ); + + RtlFreeUnicodeString( &NdisAdapterString ); + + if ( DriverStatus == NDIS_STATUS_PENDING ) + { + Status = KeWaitForSingleObject( &OpenP->OpenReqHndl->u.OPEN_REQ.OpenEvent, + Executive, + KernelMode, + FALSE, + NULL ); + + if ( Status != STATUS_SUCCESS ) + { + IF_TPDBG ( TP_DEBUG_NT_STATUS ) + { + TpPrint1("TpFuncOpenAdapter: KeWaitForSingleObject returned %s\n", + TpGetStatus(Status) ); + } + goto cleanup; + } + + DriverStatus = OpenP->OpenReqHndl->u.OPEN_REQ.RequestStatus; + + if ( DriverStatus != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG ( TP_DEBUG_NDIS_CALLS ) + { + TpPrint1("TpFuncOpenAdapter: NdisOpenAdapter returned %s\n", + TpGetStatus( DriverStatus )); + } + goto cleanup; + } + } + else if ( DriverStatus != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG ( TP_DEBUG_NDIS_CALLS ) + { + TpPrint1("TpFuncOpenAdapter: NdisOpenAdapter returned %s\n", + TpGetStatus( DriverStatus )); + } + goto cleanup; + } + + // + // The open was a success, so set the open instance on + // the open block. + // + + OpenP->OpenInstance = OpenInstance; + + // + // and initialize the stress address depending on the medium type + // of the adapter opened. + // + + switch ( NdisMediumArray[OpenP->MediumIndex] ) + { + case NdisMedium802_5: + for ( i=0 ; i < ADDRESS_LENGTH ; i++ ) + { + OpenP->Environment->StressAddress[i] = STRESS_FUNCTIONAL[i]; + } + break; + + case NdisMediumFddi: + case NdisMediumDix: + case NdisMedium802_3: + for ( i=0;i<ADDRESS_LENGTH;i++ ) + { + OpenP->Environment->StressAddress[i] = STRESS_MULTICAST[i]; + } + break; + // + // STARTCHANGE + // + case NdisMediumArcnet878_2: + TP_ASSERT (MediaArraySize == NDIS_MEDIUM_ARRAY_SIZE) + + for ( i=0;i<ADDRESS_LENGTH;i++ ) + { + OpenP->Environment->StressAddress[i] = STRESS_ARCNET_BROADCAST[i]; + } + break; + // + // STOPCHANGE + // + default: + IF_TPDBG ( TP_DEBUG_RESOURCES ) + { + TpPrint0("TpFuncOpenAdapter: Unsupported MAC Type\n"); + } + DriverStatus = NDIS_STATUS_UNSUPPORTED_MEDIA; + goto cleanup; + } + + // + // Now allocate the Ndis Request structure to hold the query + // information requests in. + // + + Status = NdisAllocateMemory((PVOID *)&Request, + sizeof( NDIS_REQUEST ), + 0, + HighestAddress ); + + if ( Status != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG (TP_DEBUG_RESOURCES) + { + TpPrint0("TpFuncOpenAdapter: unable to allocate Ndis Request buffer.\n"); + } + Status = NDIS_STATUS_RESOURCES; + goto cleanup; + } + else + { + NdisZeroMemory( Request,sizeof( NDIS_REQUEST )); + } + + Request->RequestType = NdisRequestQueryInformation; + + // + // Now query the card address and the maximum frame size + // from the MAC. Determine the necessary size of the + // information buffer to fit the station address, and + // allocate it. + // + + // + // STARTCHANGE + // + if ( NdisMediumArray[OpenP->MediumIndex] == NdisMedium802_3 ) + { + OidIndex = TpLookUpOidInfo( OID_802_3_CURRENT_ADDRESS ); + } + else if ( NdisMediumArray[OpenP->MediumIndex] == NdisMedium802_5 ) + { + OidIndex = TpLookUpOidInfo( OID_802_5_CURRENT_ADDRESS ); + } + else if ( NdisMediumArray[OpenP->MediumIndex] == NdisMediumFddi ) + { + OidIndex = TpLookUpOidInfo( OID_FDDI_LONG_CURRENT_ADDR ); + } + else if ( NdisMediumArray[OpenP->MediumIndex] == NdisMediumArcnet878_2 ) + { + OidIndex = TpLookUpOidInfo( OID_ARCNET_CURRENT_ADDRESS ); + } + // + // STOPCHANGE + // + + Status = NdisAllocateMemory((PVOID *)&InformationBuffer, + OidArray[OidIndex].Length, + 0, + HighestAddress ); + + if ( Status != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG (TP_DEBUG_RESOURCES) + { + TpPrint0("TpFuncOpenAdapter: unable to allocate Information Buffer.\n"); + } + Status = NDIS_STATUS_RESOURCES; + goto cleanup; + } + else + { + NdisZeroMemory( InformationBuffer,OidArray[OidIndex].Length); + } + + Request->DATA.QUERY_INFORMATION.Oid = OidArray[OidIndex].Oid; + Request->DATA.QUERY_INFORMATION.InformationBuffer = InformationBuffer; + Request->DATA.QUERY_INFORMATION.InformationBufferLength = OidArray[OidIndex].Length; + + // + // and then make the request + // + + NdisRequest( &RequestStatus,OpenP->NdisBindingHandle,Request ); + + if ( RequestStatus == NDIS_STATUS_PENDING ) + { + Status = KeWaitForSingleObject( &OpenP->OpenReqHndl->u.OPEN_REQ.OpenEvent, + Executive, + KernelMode, + FALSE, + NULL ); + + if ( Status != STATUS_SUCCESS ) + { + IF_TPDBG ( TP_DEBUG_NT_STATUS ) + { + TpPrint1("TpFuncOpenAdapter: KeWaitForSingleObject returned %s\n",Status ); + } + goto cleanup; + } + + RequestStatus = OpenP->OpenReqHndl->u.OPEN_REQ.RequestStatus; + + if ( RequestStatus != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG ( TP_DEBUG_NDIS_CALLS ) + { + TpPrint1( + "TpFuncOpenAdapter: NdisRequest Query Station Address failed: returned %s\n", + TpGetStatus( RequestStatus )); + } + goto cleanup; + } + } + else if ( RequestStatus != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG ( TP_DEBUG_NDIS_CALLS ) + { + TpPrint1( + "TpFuncOpenAdapter: NdisRequest Query Station Address failed returned %s\n", + TpGetStatus( RequestStatus )); + } + goto cleanup; + } + + GotCardAddress = TRUE; + + p = OpenP->StationAddress; + q = (PUCHAR)InformationBuffer; + + // + // STARTCHANGE + // + for ( i=0;i<OidArray[OidIndex].Length;i++ ) + { + *p++ = *q++; + } + // + // STOPCHANGE + // + + // + // Then determine the necessary size of the information buffer + // to allocate, and allocate it. + // + + OidIndex = TpLookUpOidInfo( OID_GEN_MAXIMUM_TOTAL_SIZE ); + + NdisZeroMemory( InformationBuffer,OidArray[OidIndex].Length ); + + Request->RequestType = NdisRequestQueryInformation; + + Request->DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE; + Request->DATA.QUERY_INFORMATION.InformationBuffer = InformationBuffer; + Request->DATA.QUERY_INFORMATION.InformationBufferLength = OidArray[OidIndex].Length; + // + // and then make the request + // + + NdisRequest( &RequestStatus,OpenP->NdisBindingHandle,Request ); + + if ( RequestStatus == NDIS_STATUS_PENDING ) + { + Status = KeWaitForSingleObject( &OpenP->OpenReqHndl->u.OPEN_REQ.OpenEvent, + Executive, + KernelMode, + FALSE, + NULL ); + + if ( Status != STATUS_SUCCESS ) + { + IF_TPDBG ( TP_DEBUG_NT_STATUS ) + { + TpPrint1("TpFuncOpenAdapter: KeWaitForSingleObject returned %s\n",Status ); + } + goto cleanup; + } + + RequestStatus = OpenP->OpenReqHndl->u.OPEN_REQ.RequestStatus; + + if ( RequestStatus != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG ( TP_DEBUG_NDIS_CALLS ) + { + TpPrint1("TpFuncOpenAdapter: NdisRequest Max Frame Size failed: returned %s\n", + TpGetStatus( RequestStatus )); + } + goto cleanup; + } + } + else if ( RequestStatus != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG ( TP_DEBUG_NDIS_CALLS ) + { + TpPrint1("TpFuncOpenAdapter: NdisRequest Max Frame Size failed: returned %s\n", + TpGetStatus( RequestStatus )); + } + goto cleanup; + } + + Status = TpInitMedia( OpenP,*(PULONG)InformationBuffer ); + + if ( Status != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG ( TP_DEBUG_INITIALIZE ) + { + TpPrint1("TpFuncOpenAdapter: TpInitMedia failed. returned %s\n", + TpGetStatus( Status )); + } + goto cleanup; + } + + + // + // SANJEEVK: NEW: BUG#2930 NTRAID\NTBUG + // + + // + // Set the lookahead size to the max supported by the card + // Later on if we don't like it we can change it + // + + // + // QUERY the OID_GEN_MAXIMUM_LOOKAHEAD + // + OidIndex = TpLookUpOidInfo( OID_GEN_MAXIMUM_LOOKAHEAD ); + + NdisZeroMemory( InformationBuffer,OidArray[OidIndex].Length ); + + Request->RequestType = NdisRequestQueryInformation; + + Request->DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_LOOKAHEAD; + Request->DATA.QUERY_INFORMATION.InformationBuffer = InformationBuffer; + Request->DATA.QUERY_INFORMATION.InformationBufferLength = OidArray[OidIndex].Length; + + // + // and then make the request + // + + NdisRequest( &RequestStatus,OpenP->NdisBindingHandle,Request ); + + if ( RequestStatus == NDIS_STATUS_PENDING ) + { + Status = KeWaitForSingleObject( &OpenP->OpenReqHndl->u.OPEN_REQ.OpenEvent, + Executive, + KernelMode, + FALSE, + NULL ); + + if ( Status != STATUS_SUCCESS ) + { + IF_TPDBG ( TP_DEBUG_NT_STATUS ) + { + TpPrint1("TpFuncOpenAdapter: KeWaitForSingleObject returned %s\n",Status ); + } + + goto cleanup; + } + + RequestStatus = OpenP->OpenReqHndl->u.OPEN_REQ.RequestStatus; + + if ( RequestStatus != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG ( TP_DEBUG_NDIS_CALLS ) + { + TpPrint1( + "TpFuncOpenAdapter: NdisRequest QueryMaxLookAhead failed: returned %s\n", + TpGetStatus( RequestStatus )); + } + goto cleanup; + } + } + else if ( RequestStatus != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG ( TP_DEBUG_NDIS_CALLS ) + { + TpPrint1("TpFuncOpenAdapter: NdisRequest QueryMaxLookAhead failed: returned %s\n", + TpGetStatus( RequestStatus )); + } + goto cleanup; + } + + + // + // And now set the card with the maximum value + // + OidIndex = TpLookUpOidInfo( OID_GEN_CURRENT_LOOKAHEAD ); + + Request->RequestType = NdisRequestSetInformation; + + Request->DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_LOOKAHEAD; + Request->DATA.SET_INFORMATION.InformationBuffer = InformationBuffer; + Request->DATA.SET_INFORMATION.InformationBufferLength = OidArray[OidIndex].Length; + + // + // and then make the request + // + + NdisRequest( &RequestStatus,OpenP->NdisBindingHandle,Request ); + + if ( RequestStatus == NDIS_STATUS_PENDING ) + { + Status = KeWaitForSingleObject( &OpenP->OpenReqHndl->u.OPEN_REQ.OpenEvent, + Executive, + KernelMode, + FALSE, + NULL ); + + if ( Status != STATUS_SUCCESS ) + { + IF_TPDBG ( TP_DEBUG_NT_STATUS ) + { + TpPrint1("TpFuncOpenAdapter: KeWaitForSingleObject returned %s\n",Status ); + } + goto cleanup; + } + RequestStatus = OpenP->OpenReqHndl->u.OPEN_REQ.RequestStatus; + + if ( RequestStatus != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG ( TP_DEBUG_NDIS_CALLS ) + { + TpPrint1( + "TpFuncOpenAdapter: NdisRequest SetCurrentLookAhead to MAXLOOKAHEAD failed: returned %s\n", + TpGetStatus( RequestStatus )); + } + goto cleanup; + } + } + else if ( RequestStatus != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG ( TP_DEBUG_NDIS_CALLS ) + { + TpPrint1( + "TpFuncOpenAdapter: NdisRequest SetCurrentLookAhead to MAXLOOKAHEAD failed: returned %s\n", + TpGetStatus( RequestStatus )); + } + goto cleanup; + } + + // + // ENDNEW + // + + // + // If we are on ethernet query the multicast list size for + // use in later tests. + // + + if ( NdisMediumArray[OpenP->MediumIndex] == NdisMedium802_3 ) + { + OidIndex = TpLookUpOidInfo( OID_802_3_MAXIMUM_LIST_SIZE ); + + NdisZeroMemory( InformationBuffer,OidArray[OidIndex].Length); + + Request->RequestType = NdisRequestQueryInformation; + + Request->DATA.QUERY_INFORMATION.Oid = OID_802_3_MAXIMUM_LIST_SIZE; + Request->DATA.QUERY_INFORMATION.InformationBuffer = InformationBuffer; + Request->DATA.QUERY_INFORMATION.InformationBufferLength = OidArray[OidIndex].Length; + + // + // and then make the request + // + + NdisRequest( &RequestStatus,OpenP->NdisBindingHandle,Request ); + + if ( RequestStatus == NDIS_STATUS_PENDING ) + { + Status = KeWaitForSingleObject( &OpenP->OpenReqHndl->u.OPEN_REQ.OpenEvent, + Executive, + KernelMode, + FALSE, + NULL ); + + if ( Status != STATUS_SUCCESS ) + { + IF_TPDBG ( TP_DEBUG_NT_STATUS ) + { + TpPrint1("TpFuncOpenAdapter: KeWaitForSingleObject returned %s\n",Status ); + } + goto cleanup; + } + RequestStatus = OpenP->OpenReqHndl->u.OPEN_REQ.RequestStatus; + + if ( RequestStatus != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG ( TP_DEBUG_NDIS_CALLS ) + { + TpPrint1( + "TpFuncOpenAdapter: NdisRequest Max Frame Size failed: returned %s\n", + TpGetStatus( RequestStatus )); + } + goto cleanup; + } + } + else if ( RequestStatus != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG ( TP_DEBUG_NDIS_CALLS ) + { + TpPrint1("TpFuncOpenAdapter: NdisRequest Max Frame Size failed: returned %s\n", + TpGetStatus( RequestStatus )); + } + goto cleanup; + } + OpenP->Environment->MulticastListSize = *(PULONG)InformationBuffer; + } + + if ( NdisMediumArray[OpenP->MediumIndex] == NdisMediumFddi ) + { + OidIndex = TpLookUpOidInfo( OID_FDDI_LONG_MAX_LIST_SIZE ); + + NdisZeroMemory( InformationBuffer,OidArray[OidIndex].Length); + + Request->RequestType = NdisRequestQueryInformation; + + Request->DATA.QUERY_INFORMATION.Oid = OID_FDDI_LONG_MAX_LIST_SIZE; + Request->DATA.QUERY_INFORMATION.InformationBuffer = InformationBuffer; + Request->DATA.QUERY_INFORMATION.InformationBufferLength = OidArray[OidIndex].Length; + + // + // and then make the request + // + + NdisRequest( &RequestStatus,OpenP->NdisBindingHandle,Request ); + + if ( RequestStatus == NDIS_STATUS_PENDING ) + { + Status = KeWaitForSingleObject( &OpenP->OpenReqHndl->u.OPEN_REQ.OpenEvent, + Executive, + KernelMode, + FALSE, + NULL ); + + if ( Status != STATUS_SUCCESS ) + { + IF_TPDBG ( TP_DEBUG_NT_STATUS ) + { + TpPrint1("TpFuncOpenAdapter: KeWaitForSingleObject returned %s\n",Status ); + } + goto cleanup; + } + + RequestStatus = OpenP->OpenReqHndl->u.OPEN_REQ.RequestStatus; + + if ( RequestStatus != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG ( TP_DEBUG_NDIS_CALLS ) + { + TpPrint1( + "TpFuncOpenAdapter: NdisRequest Max Frame Size failed: returned %s\n", + TpGetStatus( RequestStatus )); + } + goto cleanup; + } + } + else if ( RequestStatus != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG ( TP_DEBUG_NDIS_CALLS ) + { + TpPrint1("TpFuncOpenAdapter: NdisRequest Max Frame Size failed: returned %s\n", + TpGetStatus( RequestStatus )); + } + goto cleanup; + } + OpenP->Environment->MulticastListSize = *(PULONG)InformationBuffer; + } + } + + +cleanup: + NdisAcquireSpinLock( &OpenP->SpinLock ); + + if ( OpenP->Irp != NULL ) + { + OutputBuffer = MmGetSystemAddressForMdl( OpenP->Irp->MdlAddress ); + + OutputBuffer->Signature = OPEN_RESULTS_SIGNATURE; + OutputBuffer->RequestPended = OpenP->OpenReqHndl->RequestPended; + OutputBuffer->RequestStatus = DriverStatus; + + if (( Status == STATUS_SUCCESS ) && + ( DriverStatus == NDIS_STATUS_SUCCESS )) + { + OutputBuffer->OpenRequestStatus = RequestStatus; + + if ( RequestStatus != NDIS_STATUS_SUCCESS ) + { + OutputBuffer->OID = Request->DATA.QUERY_INFORMATION.Oid; + + OutputBuffer->BytesReadWritten = Request->DATA.QUERY_INFORMATION.BytesWritten; + + OutputBuffer->BytesNeeded = Request->DATA.QUERY_INFORMATION.BytesNeeded; + + // + // Since a portion of the call failed, i.e. one of the query + // info calls, we are failing the whole call, and need to + // reset the card open info. + // + + OpenP->OpenInstance = 0xFF; + + if ( OpenP->Media != NULL ) + { + NdisFreeMemory( OpenP->Media,0,0 ); + OpenP->Media = NULL; + } + + } + else if ( GotCardAddress == TRUE ) + { + PNDIS_MEDIUM MediumType = (PNDIS_MEDIUM)OutputBuffer->InformationBuffer; + // + // Sanjeevk: Bug #5203 + // + // Comment + // + // This is where the user provided buffer thru the IOCTL + // is filled out with the address and the media type + // + + // + // Copy the Media type into the buffer. The media type + // has been initialized by a call to TpInitMedia() earlier + // on in this function. + // + *MediumType = OpenP->Media->MediumType; + + // + // Copy the adapter address into the buffer + // + p = OutputBuffer->InformationBuffer + sizeof( NDIS_MEDIUM ); + q = OpenP->StationAddress; + + for ( i=0;i<OpenP->Media->AddressLen;i++ ) + { + *p++ = *q++; + } + + } + } + } + + OpenP->Irp->IoStatus.Status = Status; + + NdisReleaseSpinLock( &OpenP->SpinLock ); + + if ( OpenP->OpenReqHndl != NULL ) + { + NdisFreeMemory( OpenP->OpenReqHndl,0,0 ); + OpenP->OpenReqHndl = NULL; + } + + if ((( DriverStatus != NDIS_STATUS_SUCCESS ) || + ( RequestStatus != NDIS_STATUS_SUCCESS )) && + ( OpenP->AdapterName != NULL )) + { + + NdisFreeMemory( OpenP->AdapterName,0,0 ); + OpenP->AdapterName = NULL; + } + + if ( Request != NULL ) + { + NdisFreeMemory( Request,0,0 ); + } + + if ( InformationBuffer != NULL ) + { + NdisFreeMemory( InformationBuffer,0,0 ); + } + + return Status; +} + + + +VOID +TpFuncOpenComplete( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_STATUS Status, + IN NDIS_STATUS OpenErrorStatus + ) + +{ + POPEN_BLOCK OpenP = (POPEN_BLOCK)ProtocolBindingContext; + ULONG NextEvent; + + TP_ASSERT( OpenP != NULL ); + + if (( OpenP->OpenReqHndl != NULL ) && + (( OpenP->OpenReqHndl->Signature == OPEN_REQUEST_HANDLE_SIGNATURE ) && + ( OpenP->OpenReqHndl->Open == OpenP ))) + { + IF_TPDBG(TP_DEBUG_DISPATCH) + { + TpPrint1("TpFuncOpenComplete Status = %s\n", TpGetStatus( Status )); + } + + OpenP->OpenReqHndl->RequestPended = TRUE; + OpenP->OpenReqHndl->u.OPEN_REQ.RequestStatus = Status; + + KeSetEvent( &OpenP->OpenReqHndl->u.OPEN_REQ.OpenEvent,0,FALSE ); + + } + else + { + // + // We are not expecting any Open requests to complete at this + // point, so stick this on the Event Queue. + // + + NdisAcquireSpinLock( &OpenP->EventQueue->SpinLock ); + + NextEvent = OpenP->EventQueue->Head + 1; + + if ( NextEvent == MAX_EVENT ) + { + NextEvent = 0; + } + + if ( NextEvent != OpenP->EventQueue->Tail ) + { + // + // There is room to add another event to the event queue. + // + + OpenP->EventQueue->Events[NextEvent].TpEventType = CompleteOpen; + OpenP->EventQueue->Head = NextEvent; + } + else + { + // + // The event queue is full, and this would have overflowed it, so + // mark the Head event overflow flag to show this. + // + + OpenP->EventQueue->Events[OpenP->EventQueue->Head].Overflow = TRUE; + } + NdisReleaseSpinLock( &OpenP->EventQueue->SpinLock ); + } +} + + + +NDIS_STATUS +TpFuncCloseAdapter( + IN POPEN_BLOCK OpenP + ) + +// -------- +// +// Routine Description: +// +// +// Arguments: +// +// +// Return Value: +// +// Status - +// +// ------ + +{ + NDIS_STATUS Status; + LARGE_INTEGER TimeOut; + + TP_ASSERT( OpenP->CloseReqHndl == NULL ); + + // + // First determine whether this instance of the Adapter is currently + // opened. + // + + if ( OpenP->OpenInstance == (UCHAR)-1 ) + { + // + // It is not already opened, so we will fail this call. + // + IF_TPDBG ( TP_DEBUG_NDIS_CALLS ) + { + TpPrint0("TpFuncCloseAdapter: An open does not exists for this Open Instance\n"); + } + + NdisAcquireSpinLock( &OpenP->SpinLock ); + + if ( OpenP->Irp != NULL ) + { + OpenP->Irp->IoStatus.Status = NDIS_STATUS_ADAPTER_NOT_FOUND; + } + NdisReleaseSpinLock( &OpenP->SpinLock ); + + return NDIS_STATUS_ADAPTER_NOT_FOUND; + } + else + { + // + // Otherwise allocate the request handle and set it up as if + // the request pended. If it does not pend we will reset the + // flags later before calling the completion routine. + // + + Status = NdisAllocateMemory((PVOID *)&OpenP->CloseReqHndl, + sizeof( TP_REQUEST_HANDLE ), + 0, + HighestAddress ); + + if ( Status != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG (TP_DEBUG_RESOURCES) + { + TpPrint0("TpFuncOpenAdapter: unable to allocate Request Handle.\n"); + } + NdisAcquireSpinLock( &OpenP->SpinLock ); + + if ( OpenP->Irp != NULL ) + { + OpenP->Irp->IoStatus.Status = NDIS_STATUS_RESOURCES; + } + NdisReleaseSpinLock( &OpenP->SpinLock ); + return NDIS_STATUS_RESOURCES; + } + else + { + NdisZeroMemory( OpenP->CloseReqHndl,sizeof( TP_REQUEST_HANDLE )); + } + + OpenP->CloseReqHndl->Signature = FUNC_REQUEST_HANDLE_SIGNATURE; + OpenP->CloseReqHndl->Open = OpenP; + OpenP->CloseReqHndl->RequestPended = TRUE; + OpenP->CloseReqHndl->Irp = OpenP->Irp; + + // + // Then we will attempt to close it. First set the + // open instance's closing flag to true, then signal all + // the async test protocol routines that are currently + // running to end. + // + + OpenP->Closing = TRUE; + + if ( OpenP->Stress->Stressing == TRUE ) + { + OpenP->Stress->StopStressing = TRUE; + } + + if ( OpenP->Send->Sending == TRUE ) + { + OpenP->Send->StopSending = TRUE; + } + + if ( OpenP->Receive->Receiving == TRUE ) + { + OpenP->Receive->StopReceiving = TRUE; + } + + // + // Then wait for all of the three asynchronous routines; + // STRESS, SEND and RECEIVE to finish. + // + + TimeOut.HighPart = -1; // so it will be relative. + TimeOut.LowPart = (ULONG)(-(ONE_TENTH_SECOND)); + + while ( OpenP->ReferenceCount > 0 ) + { + // Status = KeDelayExecutionThread( KernelMode,FALSE,&TimeOut ); + /* NULL */ ; + } + + // + // finally we will attempt to close it. + // + + NdisCloseAdapter( &Status,OpenP->NdisBindingHandle ); + + if (( Status != NDIS_STATUS_SUCCESS ) && + ( Status != NDIS_STATUS_PENDING )) + { + IF_TPDBG ( TP_DEBUG_NDIS_CALLS ) + { + TpPrint1("TpFuncCloseAdapter: NdisCloseAdapter returned %s\n", TpGetStatus(Status)); + } + } + + if ( Status != NDIS_STATUS_PENDING ) + { + // + // If the request did not pend, we should reset the pend flag, + // and the status flag in the OpenP->CloseReqHndl, and then + // call the completion handler ourselves. + // + + OpenP->CloseReqHndl->RequestPended = FALSE; + TpFuncCloseComplete( OpenP,Status ); + } + } + return NDIS_STATUS_PENDING; +} + + + +VOID +TpFuncCloseComplete( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_STATUS Status + ) +{ + POPEN_BLOCK OpenP = (POPEN_BLOCK)ProtocolBindingContext; + PREQUEST_RESULTS OutputBuffer; + USHORT i; + ULONG NextEvent; + + TP_ASSERT( OpenP != NULL ); + + if (( OpenP->CloseReqHndl != NULL ) && + (( OpenP->CloseReqHndl->Signature == FUNC_REQUEST_HANDLE_SIGNATURE ) && + ( OpenP->CloseReqHndl->Open == OpenP ))) + { + IF_TPDBG(TP_DEBUG_DISPATCH) + { + TpPrint1("TpFuncCloseComplete Status = %s\n", TpGetStatus( Status )); + } + + NdisAcquireSpinLock( &OpenP->SpinLock ); + + if ( OpenP->CloseReqHndl->Irp != NULL ) + { + OutputBuffer = MmGetSystemAddressForMdl( OpenP->CloseReqHndl->Irp->MdlAddress ); + + OutputBuffer->Signature = CLOSE_RESULTS_SIGNATURE; + OutputBuffer->RequestPended = OpenP->CloseReqHndl->RequestPended; + OutputBuffer->RequestStatus = Status; + + if ( Status == NDIS_STATUS_SUCCESS ) + { + // + // The close of the adapter was a success so set the flags + // in the OpenBlock back to the initial state, and reset + // the StationAddress to NULL. + // + + OpenP->NdisBindingHandle = NULL; + OpenP->OpenInstance = 0xFF; + OpenP->Closing = FALSE; + + if ( OpenP->AdapterName != NULL ) + { + NdisFreeMemory( OpenP->AdapterName,0,0 ); + OpenP->AdapterName = NULL; + } + + for ( i=0;i<OpenP->Media->AddressLen;i++ ) + { + OpenP->StationAddress[i] = 0x00; + } + + // + // We will also free the media block at this point because + // the info it contains may not hold for the next adapter + // open on this instance. + // + + if ( OpenP->Media != NULL ) + { + NdisFreeMemory( OpenP->Media,0,0 ); + OpenP->Media = NULL; + } + } + + TP_ASSERT(Status != NDIS_STATUS_PENDING); + + OpenP->CloseReqHndl->Irp->IoStatus.Status = Status; + + IoMarkIrpPending( OpenP->CloseReqHndl->Irp ); + + IoAcquireCancelSpinLock( &OpenP->CloseReqHndl->Irp->CancelIrql ); + IoSetCancelRoutine( OpenP->CloseReqHndl->Irp,NULL ); + IoReleaseCancelSpinLock( OpenP->CloseReqHndl->Irp->CancelIrql ); + + IoCompleteRequest( OpenP->CloseReqHndl->Irp,IO_NETWORK_INCREMENT ); + } + + NdisReleaseSpinLock( &OpenP->SpinLock ); + + NdisFreeMemory( OpenP->CloseReqHndl,0,0 ); + OpenP->CloseReqHndl = NULL; + } + else + { + // + // We are not expecting any requests to complete at this + // point, so stick this on the Event Queue. + // + + NdisAcquireSpinLock( &OpenP->EventQueue->SpinLock ); + + NextEvent = OpenP->EventQueue->Head + 1; + + if ( NextEvent == MAX_EVENT ) + { + NextEvent = 0; + } + + if ( NextEvent != OpenP->EventQueue->Tail ) + { + // + // There is room to add another event to the event queue. + // + + OpenP->EventQueue->Events[NextEvent].TpEventType = CompleteClose; + + OpenP->EventQueue->Head = NextEvent; + + // we should also stick some interesting info likje requesttype. + } + else + { + // + // The event queue is full, and this would have overflowed it, so + // mark the Head event overflow flag to show this. + // + OpenP->EventQueue->Events[OpenP->EventQueue->Head].Overflow = TRUE; + } + NdisReleaseSpinLock( &OpenP->EventQueue->SpinLock ); + } +} + + + +NDIS_STATUS +TpFuncReset( + IN POPEN_BLOCK OpenP + ) + +// ------------ +// +// Routine Description: +// +// +// Arguments: +// +// +// Return Value: +// +// Status - +// +// Change history: +// +// SanjeevK : During initial allocation during the reset, should the allocation fail, the spin +// lock for the OPEN_BLOCK was being acquired twice instead of being acquired +// and then released. Bug #3109 +// +// ------------ + +{ + NDIS_STATUS Status; + + TP_ASSERT( OpenP->ResetReqHndl == NULL ); + + Status = NdisAllocateMemory((PVOID *)&OpenP->ResetReqHndl, + sizeof( TP_REQUEST_HANDLE ), + 0, + HighestAddress ); + + if ( Status != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG (TP_DEBUG_RESOURCES) + { + TpPrint0("TpFuncReset: unable to allocate Request Handle.\n"); + } + NdisAcquireSpinLock( &OpenP->SpinLock ); + + if ( OpenP->Irp != NULL ) + { + OpenP->Irp->IoStatus.Status = NDIS_STATUS_RESOURCES; + } + + NdisReleaseSpinLock( &OpenP->SpinLock ); + + return NDIS_STATUS_RESOURCES; + } + else + { + NdisZeroMemory( OpenP->ResetReqHndl,sizeof( TP_REQUEST_HANDLE )); + } + + OpenP->ResetReqHndl->Signature = FUNC_REQUEST_HANDLE_SIGNATURE; + OpenP->ResetReqHndl->Open = OpenP; + OpenP->ResetReqHndl->RequestPended = TRUE; + OpenP->ResetReqHndl->Irp = OpenP->Irp; + + // + // Then make the call to RESET the adapter. + // + + NdisReset( &Status,OpenP->NdisBindingHandle ); + + if (( Status != NDIS_STATUS_SUCCESS ) && + ( Status != NDIS_STATUS_PENDING )) + { + IF_TPDBG(TP_DEBUG_NDIS_ERROR) + { + TpPrint1("TpFuncReset: NdisReset failed: returned %s\n", + TpGetStatus( Status )); + } + } + + if ( Status != NDIS_STATUS_PENDING ) + { + // + // If the request did not pend, we should reset the pend flag, + // and the status flag in the RequestHandle, and call the + // completion handler ourselves. + // + + OpenP->ResetReqHndl->RequestPended = FALSE; + TpFuncResetComplete( OpenP,Status ); + } + return NDIS_STATUS_PENDING; +} + + + +VOID +TpFuncResetComplete( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_STATUS Status + ) +{ + POPEN_BLOCK OpenP = (POPEN_BLOCK)ProtocolBindingContext; + PREQUEST_RESULTS OutputBuffer; + ULONG NextEvent; + + TP_ASSERT( OpenP != NULL ); + + if (( OpenP->ResetReqHndl != NULL ) && + (( OpenP->ResetReqHndl->Signature == FUNC_REQUEST_HANDLE_SIGNATURE ) && + ( OpenP->ResetReqHndl->Open == OpenP ))) + { + IF_TPDBG(TP_DEBUG_DISPATCH) + { + TpPrint1("TpFuncResetComplete Status = %s\n", + TpGetStatus( Status )); + } + NdisAcquireSpinLock( &OpenP->SpinLock ); + + if ( OpenP->ResetReqHndl->Irp != NULL ) + { + OutputBuffer = MmGetSystemAddressForMdl( OpenP->ResetReqHndl->Irp->MdlAddress ); + + OutputBuffer->Signature = RESET_RESULTS_SIGNATURE; + OutputBuffer->RequestPended = OpenP->ResetReqHndl->RequestPended; + OutputBuffer->RequestStatus = Status; + + OpenP->ResetReqHndl->Irp->IoStatus.Status = Status; + + TP_ASSERT( Status != NDIS_STATUS_PENDING ); + + IoMarkIrpPending( OpenP->ResetReqHndl->Irp ); + + IoAcquireCancelSpinLock( &OpenP->ResetReqHndl->Irp->CancelIrql ); + IoSetCancelRoutine( OpenP->ResetReqHndl->Irp,NULL ); + IoReleaseCancelSpinLock( OpenP->ResetReqHndl->Irp->CancelIrql ); + + IoCompleteRequest( OpenP->ResetReqHndl->Irp,IO_NETWORK_INCREMENT ); + } + NdisReleaseSpinLock( &OpenP->SpinLock ); + + NdisFreeMemory( OpenP->ResetReqHndl,0,0 ); + OpenP->ResetReqHndl = NULL; + } + else + { + // + // We are not expecting any requests to complete at this + // point, so stick this on the Event Queue. + // + NdisAcquireSpinLock( &OpenP->EventQueue->SpinLock ); + NextEvent = OpenP->EventQueue->Head + 1; + + if ( NextEvent == MAX_EVENT ) + { + NextEvent = 0; + } + + if ( NextEvent != OpenP->EventQueue->Tail ) + { + // + // There is room to add another event to the event queue. + // + + OpenP->EventQueue->Events[NextEvent].TpEventType = CompleteReset; + OpenP->EventQueue->Head = NextEvent; + + // we should also stick some interesting info likje requesttype. + } + else + { + // + // The event queue is full, and this would have overflowed it, so + // mark the Head event overflow flag to show this. + // + OpenP->EventQueue->Events[OpenP->EventQueue->Head].Overflow = TRUE; + } + + NdisReleaseSpinLock( &OpenP->EventQueue->SpinLock ); + } +} + + + +NDIS_STATUS +TpFuncRequestQueryInfo( + IN POPEN_BLOCK OpenP, + IN PCMD_ARGS CmdArgs, + IN OUT PIRP Irp, + IN PIO_STACK_LOCATION IrpSp + ) +{ + NDIS_STATUS Status; + PNDIS_REQUEST Request; + PUCHAR InformationBuffer; + ULONG OidIndex; + ULONG InfoBufLength; + + // + // First allocate a request handle structure to hold the + // test information in. + // + + TP_ASSERT( OpenP->RequestReqHndl == NULL ); + + Status = NdisAllocateMemory((PVOID *)&OpenP->RequestReqHndl, + sizeof( TP_REQUEST_HANDLE ), + 0, + HighestAddress ); + + if ( Status != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG (TP_DEBUG_RESOURCES) + { + TpPrint0("TpFuncRequestQueryInfo: unable to allocate Request Handle.\n"); + } + + NdisAcquireSpinLock( &OpenP->SpinLock ); + if ( OpenP->Irp != NULL ) + { + Irp->IoStatus.Status = NDIS_STATUS_RESOURCES; + } + NdisReleaseSpinLock( &OpenP->SpinLock ); + return NDIS_STATUS_RESOURCES; + } + else + { + NdisZeroMemory( OpenP->RequestReqHndl,sizeof( TP_REQUEST_HANDLE )); + } + + OpenP->RequestReqHndl->Signature = FUNC_REQUEST_HANDLE_SIGNATURE; + OpenP->RequestReqHndl->Open = OpenP; + OpenP->RequestReqHndl->RequestPended = TRUE; + OpenP->RequestReqHndl->Irp = Irp; + + OpenP->RequestReqHndl->u.INFO_REQ.IoControlCode = + IrpSp->Parameters.DeviceIoControl.IoControlCode; + + // + // Now allocate the Ndis Request structure to hold the + // query information request in. + // + + Status = NdisAllocateMemory((PVOID *)&Request, + sizeof( NDIS_REQUEST ), + 0, + HighestAddress ); + + if ( Status != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG (TP_DEBUG_RESOURCES) + { + TpPrint0("TpFuncRequestQueryInfo: unable to allocate Request.\n"); + } + + NdisAcquireSpinLock( &OpenP->SpinLock ); + if ( OpenP->Irp != NULL ) + { + Irp->IoStatus.Status = NDIS_STATUS_RESOURCES; + } + NdisReleaseSpinLock( &OpenP->SpinLock ); + return NDIS_STATUS_RESOURCES; + } + else + { + NdisZeroMemory( Request,sizeof( NDIS_REQUEST )); + } + + OpenP->RequestReqHndl->u.INFO_REQ.NdisRequestType = + Request->RequestType = NdisRequestQueryInformation; + + // + // Then determine the necessary size of the information buffer + // to allocate, and allocate it. + // + + OidIndex = TpLookUpOidInfo( CmdArgs->ARGS.TPQUERY.OID ); + + // + // If the OID we are going to call is for the Multicast List, then + // we will need a buffer of size MaxMulticastList * sizeof(Multicast) + // + + if (( CmdArgs->ARGS.TPQUERY.OID == OID_802_3_MULTICAST_LIST ) || + ( CmdArgs->ARGS.TPQUERY.OID == OID_FDDI_LONG_MULTICAST_LIST )) + { + InfoBufLength = OpenP->Environment->MulticastListSize * ADDRESS_LENGTH; + } + else + { + InfoBufLength = OidArray[OidIndex].Length; + } + + Status = NdisAllocateMemory((PVOID *)&InformationBuffer, + InfoBufLength, + 0, + HighestAddress ); + + if ( Status != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG (TP_DEBUG_RESOURCES) + { + TpPrint0("TpFuncRequestQueryInfo: unable to allocate Information Buffer.\n"); + } + + NdisAcquireSpinLock( &OpenP->SpinLock ); + if ( OpenP->Irp != NULL ) + { + Irp->IoStatus.Status = NDIS_STATUS_RESOURCES; + } + NdisReleaseSpinLock( &OpenP->SpinLock ); + return NDIS_STATUS_RESOURCES; + } + else + { + NdisZeroMemory( InformationBuffer,InfoBufLength ); + } + + Request->DATA.QUERY_INFORMATION.Oid = CmdArgs->ARGS.TPQUERY.OID; + Request->DATA.QUERY_INFORMATION.InformationBuffer = InformationBuffer; + Request->DATA.QUERY_INFORMATION.InformationBufferLength = InfoBufLength; + + OpenP->RequestReqHndl->u.INFO_REQ.OID = CmdArgs->ARGS.TPQUERY.OID; + OpenP->RequestReqHndl->u.INFO_REQ.InformationBuffer = InformationBuffer; + OpenP->RequestReqHndl->u.INFO_REQ.InformationBufferLength = InfoBufLength; + + NdisRequest( &Status,OpenP->NdisBindingHandle,Request ); + + if (( Status != NDIS_STATUS_SUCCESS ) && + ( Status != NDIS_STATUS_PENDING )) + { + IF_TPDBG ( TP_DEBUG_NDIS_ERROR ) + { + TpPrint1("TpFuncRequestQueryInfo: NdisRequest failed: returned %s\n", + TpGetStatus(Status)); + } + } + + if ( Status != NDIS_STATUS_PENDING ) + { + // + // If the request did not pend, we should reset the pend flag, + // and the status flag in the OpenP->RequestReqHndl, and call the + // completion handler ourselves. + // + + OpenP->RequestReqHndl->RequestPended = FALSE; + TpFuncRequestComplete( OpenP,Request,Status ); + } + return NDIS_STATUS_PENDING; +} + + + +NDIS_STATUS +TpFuncRequestSetInfo( + IN POPEN_BLOCK OpenP, + IN PCMD_ARGS CmdArgs, + IN OUT PIRP Irp, + IN PIO_STACK_LOCATION IrpSp + ) + +// ----------- +// +// Routine Description: +// +// +// Arguments: +// +// +// Return Value: +// +// Status - +// +// -------- + +{ + NDIS_STATUS Status; + PNDIS_REQUEST Request; + ULONG OidIndex; + PUCHAR InformationBuffer = NULL; + ULONG InfoBufLength = 0; + + // + // First allocate a request handle structure to hold the + // test information in. + // + + TP_ASSERT( OpenP->RequestReqHndl == NULL ); + + Status = NdisAllocateMemory((PVOID *)&OpenP->RequestReqHndl, + sizeof( TP_REQUEST_HANDLE ), + 0, + HighestAddress ); + + if ( Status != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG (TP_DEBUG_RESOURCES) + { + TpPrint0("TpFuncRequestSetInfo: unable to allocate Request Handle.\n"); + } + NdisAcquireSpinLock( &OpenP->SpinLock ); + if ( OpenP->Irp != NULL ) + { + Irp->IoStatus.Status = NDIS_STATUS_RESOURCES; + } + NdisReleaseSpinLock( &OpenP->SpinLock ); + return NDIS_STATUS_RESOURCES; + } + else + { + NdisZeroMemory( OpenP->RequestReqHndl,sizeof( TP_REQUEST_HANDLE )); + } + OpenP->RequestReqHndl->Signature = FUNC_REQUEST_HANDLE_SIGNATURE; + OpenP->RequestReqHndl->Open = OpenP; + OpenP->RequestReqHndl->RequestPended = TRUE; + OpenP->RequestReqHndl->Irp = Irp; + + OpenP->RequestReqHndl->u.INFO_REQ.IoControlCode = + IrpSp->Parameters.DeviceIoControl.IoControlCode; + + // + // Now allocate the Ndis Request structure to hold the request + // information in. + // + + Status = NdisAllocateMemory((PVOID *)&Request, + sizeof( NDIS_REQUEST ), + 0, + HighestAddress ); + + if ( Status != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG (TP_DEBUG_RESOURCES) + { + TpPrint0("TpFuncRequestSetInfo: unable to allocate Request.\n"); + } + + NdisAcquireSpinLock( &OpenP->SpinLock ); + if ( OpenP->Irp != NULL ) + { + Irp->IoStatus.Status = NDIS_STATUS_RESOURCES; + } + NdisReleaseSpinLock( &OpenP->SpinLock ); + return NDIS_STATUS_RESOURCES; + } + else + { + NdisZeroMemory( Request,sizeof( NDIS_REQUEST )); + } + + Request->RequestType = OpenP->RequestReqHndl->u.INFO_REQ.NdisRequestType + = NdisRequestSetInformation; + + OidIndex = TpLookUpOidInfo( CmdArgs->ARGS.TPSET.OID ); + + if (( CmdArgs->ARGS.TPSET.OID == OID_802_3_MULTICAST_LIST ) || + ( CmdArgs->ARGS.TPSET.OID == OID_FDDI_LONG_MULTICAST_LIST)) + { + InfoBufLength = OidArray[OidIndex].Length * CmdArgs->ARGS.TPSET.NumberMultAddrs; + } + else + { + InfoBufLength = OidArray[OidIndex].Length; + } + + // + // Now if the infobuffer is larger than zero bytes allocate it. + // With a multicast list size of zero we will just pass a null + // pointer. + // + + if ( InfoBufLength > 0 ) + { + Status = NdisAllocateMemory((PVOID *)&InformationBuffer, + InfoBufLength, + 0, + HighestAddress ); + + if ( Status != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG (TP_DEBUG_RESOURCES) + { + TpPrint0("TpFuncRequestSetInfo: unable to allocate Information Buffer.\n"); + } + + NdisAcquireSpinLock( &OpenP->SpinLock ); + if ( OpenP->Irp != NULL ) + { + Irp->IoStatus.Status = NDIS_STATUS_RESOURCES; + } + NdisReleaseSpinLock( &OpenP->SpinLock ); + return NDIS_STATUS_RESOURCES; + } + else + { + NdisZeroMemory( InformationBuffer,InfoBufLength); + } + } + + // + // Now set the generic setinfo information in both the Request + // Handle, and in the SET_INFO portion of the Request struct. + // + + OpenP->RequestReqHndl->u.INFO_REQ.OID = CmdArgs->ARGS.TPSET.OID; + OpenP->RequestReqHndl->u.INFO_REQ.InformationBuffer = InformationBuffer; + OpenP->RequestReqHndl->u.INFO_REQ.InformationBufferLength = InfoBufLength; + + Request->DATA.SET_INFORMATION.Oid = CmdArgs->ARGS.TPSET.OID; + Request->DATA.SET_INFORMATION.InformationBuffer = InformationBuffer; + Request->DATA.SET_INFORMATION.InformationBufferLength = InfoBufLength; + + switch( CmdArgs->ARGS.TPSET.OID ) + { + // + // and then add the OID specific information to the information + // section of the OVB for this request. + // + case OID_GEN_CURRENT_PACKET_FILTER: + *((PULONG)InformationBuffer) = (ULONG)CmdArgs->ARGS.TPSET.U.PacketFilter; + break; + + case OID_802_3_MULTICAST_LIST: + case OID_FDDI_LONG_MULTICAST_LIST: + // + // Initialize the multicast address string to pass to the request. + // + + NdisMoveMemory( InformationBuffer, + CmdArgs->ARGS.TPSET.U.MulticastAddress, + ADDRESS_LENGTH * CmdArgs->ARGS.TPSET.NumberMultAddrs ); + break; + + case OID_802_5_CURRENT_FUNCTIONAL: + case OID_802_5_CURRENT_GROUP: + // + // This is only valid if Driver Type is 802.5, should it be + // allowed if we are not working with a token ring driver ???? + // + + NdisMoveMemory( InformationBuffer, + &CmdArgs->ARGS.TPSET.U.FunctionalAddress, + FUNCTIONAL_ADDRESS_LENGTH ); + break; + + case OID_GEN_CURRENT_LOOKAHEAD: + *((PULONG)InformationBuffer) = (ULONG)CmdArgs->ARGS.TPSET.U.LookaheadSize; + break; + + default: + IF_TPDBG(TP_DEBUG_NDIS_CALLS) + { + TpPrint0("TpFuncRequestSetInfo: invalid OID to be passed to NdisRequest\n"); + } + NdisAcquireSpinLock( &OpenP->SpinLock ); + if ( OpenP->Irp != NULL ) + { + Irp->IoStatus.Status = NDIS_STATUS_INVALID_OID; + } + NdisReleaseSpinLock( &OpenP->SpinLock ); + return NDIS_STATUS_INVALID_OID; + + } // switch + + + // + // Now that the Request is set, make the actual call. + // + + NdisRequest( &Status,OpenP->NdisBindingHandle,Request ); + + if (( Status != NDIS_STATUS_SUCCESS ) && + ( Status != NDIS_STATUS_PENDING )) + { + IF_TPDBG(TP_DEBUG_NDIS_ERROR) + { + TpPrint1("TpFuncRequestSetInfo: NdisRequest failed: returned %s\n", + TpGetStatus(Status)); + } + } + + if ( Status != NDIS_STATUS_PENDING ) + { + // + // If the request did not pend, we should reset the pend flag, + // and the status flag in the OpenP->RequestReqHndl, and call the + // completion handler ourselves. + // + + OpenP->RequestReqHndl->RequestPended = FALSE; + TpFuncRequestComplete( OpenP,Request,Status ); + } + return NDIS_STATUS_PENDING; +} + + + +VOID +TpFuncRequestComplete( + IN NDIS_HANDLE ProtocolBindingContext, + IN PNDIS_REQUEST NdisRequest, + IN NDIS_STATUS Status + ) +{ + POPEN_BLOCK OpenP = (POPEN_BLOCK)ProtocolBindingContext; + PREQUEST_RESULTS OutputBuffer; + ULONG NextEvent; + + TP_ASSERT( OpenP != NULL ); + TP_ASSERT( NdisRequest != NULL ); + TP_ASSERT( Status != NDIS_STATUS_PENDING ); + + if (( OpenP->RequestReqHndl != NULL ) && + (( OpenP->RequestReqHndl->Signature == FUNC_REQUEST_HANDLE_SIGNATURE ) && + ( OpenP->RequestReqHndl->Open == OpenP ))) + { + IF_TPDBG(TP_DEBUG_DISPATCH) + { + TpPrint2("TpFuncRequestComplete RequestType = %d, Status = %s\n", + NdisRequest->RequestType, TpGetStatus( Status)); + } + + NdisAcquireSpinLock( &OpenP->SpinLock ); + + if ( OpenP->Irp != NULL ) + { + OutputBuffer = MmGetSystemAddressForMdl( OpenP->RequestReqHndl->Irp->MdlAddress ); + + OutputBuffer->Signature = REQUEST_RESULTS_SIGNATURE; + OutputBuffer->IoControlCode = OpenP->RequestReqHndl->u.INFO_REQ.IoControlCode; + OutputBuffer->RequestPended = OpenP->RequestReqHndl->RequestPended; + OutputBuffer->RequestStatus = Status; + + TP_ASSERT( NdisRequest->RequestType == + OpenP->RequestReqHndl->u.INFO_REQ.NdisRequestType ); + + OutputBuffer->NdisRequestType = NdisRequest->RequestType; + + if ( NdisRequest->RequestType == NdisRequestQueryInformation ) + { + TP_ASSERT( NdisRequest->DATA.QUERY_INFORMATION.Oid == + OpenP->RequestReqHndl->u.INFO_REQ.OID ); + + TP_ASSERT( NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer == + OpenP->RequestReqHndl->u.INFO_REQ.InformationBuffer ); + + OutputBuffer->OID = NdisRequest->DATA.QUERY_INFORMATION.Oid; + + TP_ASSERT( NdisRequest->DATA.QUERY_INFORMATION.BytesWritten <= + OpenP->RequestReqHndl->u.INFO_REQ.InformationBufferLength ); + + if ( Status == NDIS_STATUS_SUCCESS ) + { + // + // Then we must copy the information returned into the + // OutputBuffer. + // + + OutputBuffer->InformationBufferLength = + OpenP->RequestReqHndl->u.INFO_REQ.InformationBufferLength; + +// TP_ASSERT( NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength <= +// IOCTL_BUFFER_SIZE - sizeof( REQUEST_RESULTS )); + + NdisMoveMemory( OutputBuffer->InformationBuffer, + (PUCHAR)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer, + NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength ); + } + + OutputBuffer->BytesReadWritten = NdisRequest->DATA.QUERY_INFORMATION.BytesWritten; + OutputBuffer->BytesNeeded = NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded; + } + else if ( NdisRequest->RequestType == NdisRequestSetInformation ) + { + OutputBuffer->OID = OpenP->RequestReqHndl->u.INFO_REQ.OID; + + TP_ASSERT( NdisRequest->DATA.SET_INFORMATION.BytesRead <= + OpenP->RequestReqHndl->u.INFO_REQ.InformationBufferLength ); + + OutputBuffer->BytesReadWritten = NdisRequest->DATA.SET_INFORMATION.BytesRead; + OutputBuffer->BytesNeeded = NdisRequest->DATA.SET_INFORMATION.BytesNeeded; + } + else + { + TP_ASSERT( FALSE ); + } + + // + // Now set the return status to SUCCESS and complete the request. + // + OpenP->RequestReqHndl->Irp->IoStatus.Status = NDIS_STATUS_SUCCESS; + + IoMarkIrpPending( OpenP->RequestReqHndl->Irp ); + + IoAcquireCancelSpinLock( &OpenP->RequestReqHndl->Irp->CancelIrql ); + IoSetCancelRoutine( OpenP->RequestReqHndl->Irp,NULL ); + IoReleaseCancelSpinLock( OpenP->RequestReqHndl->Irp->CancelIrql ); + + IoCompleteRequest( OpenP->RequestReqHndl->Irp,IO_NETWORK_INCREMENT ); + } + NdisReleaseSpinLock( &OpenP->SpinLock ); + + // + // Finally free the request handle + // + + if (( NdisRequest->RequestType == NdisRequestQueryInformation ) || + ( NdisRequest->RequestType == NdisRequestQueryStatistics )) + { + NdisFreeMemory( NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer, 0,0 ); + } + else if ( NdisRequest->RequestType == NdisRequestSetInformation ) + { + if ( NdisRequest->DATA.SET_INFORMATION.InformationBufferLength > 0 ) + { + NdisFreeMemory( NdisRequest->DATA.SET_INFORMATION.InformationBuffer, 0,0 ); + } + } + else + { + TP_ASSERT( FALSE ); + } + + NdisFreeMemory( NdisRequest,0,0 ); + NdisFreeMemory( OpenP->RequestReqHndl,0,0 ); + OpenP->RequestReqHndl = NULL; + + } + else if (( OpenP->OpenReqHndl != NULL ) && + (( OpenP->OpenReqHndl->Open == OpenP ) && + ( OpenP->OpenReqHndl->Signature == OPEN_REQUEST_HANDLE_SIGNATURE ))) + { + KeSetEvent( &OpenP->OpenReqHndl->u.OPEN_REQ.OpenEvent,0,FALSE ); + } + else + { + // + // We are not expecting any requests to complete at this + // point, so stick this on the Event Queue. + // + + NdisAcquireSpinLock( &OpenP->EventQueue->SpinLock ); + + NextEvent = OpenP->EventQueue->Head + 1; + + if ( NextEvent == MAX_EVENT ) + { + NextEvent = 0; + } + + if ( NextEvent != OpenP->EventQueue->Tail ) + { + // + // There is room to add another event to the event queue. + // + + OpenP->EventQueue->Events[NextEvent].TpEventType = CompleteRequest; + OpenP->EventQueue->Head = NextEvent; + + // we should also stick some interesting info like requesttype. + } + else + { + // + // The event queue is full, and this would have overflowed it, so + // mark the Head event overflow flag to show this. + // + + OpenP->EventQueue->Events[OpenP->EventQueue->Head].Overflow = TRUE; + } + + NdisReleaseSpinLock( &OpenP->EventQueue->SpinLock ); + } +} + + + +NDIS_STATUS +TpFuncSend( + IN POPEN_BLOCK OpenP + ) + +// ---------- +// +// Routine Description: +// +// +// Arguments: +// +// +// Return Value: +// +// Status - +// +// --------- + +{ + // + // Increment the reference count on the OpenBlock stating that + // an async test is running and must be ended prior to closing + // the adapter on this open. Sending of only one packet although + // handled differently still will increment the ref count. + // + + TpAddReference( OpenP ); + + NdisZeroMemory( (PVOID)OpenP->Send->Counters, + sizeof( INSTANCE_COUNTERS ) ); + + // + // Initialize the SEND control flags, and reset the packet sending + // control counters. + // + + OpenP->Send->Sending = TRUE; + OpenP->Send->StopSending = FALSE; + OpenP->Send->PacketsSent = 0; + OpenP->Send->PacketsPending = 0; + OpenP->Send->SendEndDpcCount = 0; + + if ( OpenP->Send->NumberOfPackets == 1 ) + { + // + // We are only sending one packet so just call the send + // routine, don't queue it as a DPC. + // + TpFuncSendDpc( NULL,OpenP,NULL,NULL ); + } + else + { + // + // We will be sending more than one packet, so queue TpFuncSendDpc + // 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( &OpenP->Send->SendDpc, NULL, NULL )) + { + IF_TPDBG ( TP_DEBUG_DPC ) + { + TpPrint0("TpFuncSend failed to queue the TpFuncSendDpc.\n"); + } + + NdisAcquireSpinLock( &OpenP->SpinLock ); + + if ( OpenP->Send->SendIrp != NULL ) + { + OpenP->Send->SendIrp->IoStatus.Status = NDIS_STATUS_FAILURE; + } + NdisReleaseSpinLock( &OpenP->SpinLock ); + return NDIS_STATUS_FAILURE; + } + } + return NDIS_STATUS_PENDING; +} + + + +VOID +TpFuncInitializeSendArguments( + POPEN_BLOCK OpenP, + PCMD_ARGS CmdArgs + ) + +// ------------ +// +// Routine Description: +// +// This routine simply copies the arguments for Send into the Send +// struct on the Open Block. The send routines may then reference +// the arguments there after an asynchrnous call has returned. +// +// Arguments: +// +// OpenP - The open block represent this open instance, the location +// where the arguments will be stored. +// +// CmdArgs - The arguments passed in from the app for this test run. +// +// Return Value: +// +// None - the Send arguments are copied to the Open Block. +// +// ------------- + +{ + PUCHAR p, q, s, t; + ULONG i; + + OpenP->Send->NumberOfPackets = CmdArgs->ARGS.TPSEND.NumberOfPackets; + + if ( CmdArgs->ARGS.TPSEND.PacketSize > OpenP->Media->MaxPacketLen ) + { + OpenP->Send->PacketSize = OpenP->Media->MaxPacketLen; + IF_TPDBG ( TP_DEBUG_IOCTL_ARGS ) + { + TpPrint1("TpFuncInitializeSendArguments: Invalid PacketSize; using %d\n", + OpenP->Send->PacketSize); + } + } + else + { + OpenP->Send->PacketSize = CmdArgs->ARGS.TPSEND.PacketSize; + } + + p = OpenP->Send->DestAddress; + q = CmdArgs->ARGS.TPSEND.DestAddress; + s = OpenP->Send->ResendAddress; + t = CmdArgs->ARGS.TPSEND.ResendAddress; + + // + // STARTCHANGE + // + for ( i=0;i<OpenP->Media->AddressLen;i++ ) + { + *p++ = *q++; + *s++ = *t++; + } + + if (OpenP->Send->PacketSize < (sizeof(FUNC2_PACKET) + 4)) + { + OpenP->Send->ResendPackets = FALSE; + } + + else if ( OpenP->Media->MediumType == NdisMediumArcnet878_2 ) + { + // + // Since there is no concept of a NULL address we have no choice but + // to always use a resend address + // Addresses in arcnet range from 0x00 to 0xff where 0x00 is a broadcast + // address + // + OpenP->Send->ResendPackets = TRUE; + } + + else + { + if ( RtlCompareMemory( OpenP->Send->ResendAddress, + NULL_ADDRESS, + OpenP->Media->AddressLen ) != OpenP->Media->AddressLen ) + { + OpenP->Send->ResendPackets = TRUE; + } + else + { + OpenP->Send->ResendPackets = FALSE; + } + } + // + // STOPCHANGE + // +} + + + +VOID +TpFuncSendDpc( + IN PKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SysArg1, + IN PVOID SysArg2 + ) + +// ------------- +// +// Routine Description: +// +// +// Arguments: +// +// +// Return Value: +// +// Status - +// +// ----------- + +{ + POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext); + PTP_REQUEST_HANDLE RequestHandle; + NDIS_STATUS Status; + PNDIS_PACKET Packet; + LARGE_INTEGER DueTime; + PPROTOCOL_RESERVED ProtRes; + + UNREFERENCED_PARAMETER( Dpc ); + UNREFERENCED_PARAMETER( SysArg1 ); + UNREFERENCED_PARAMETER( SysArg2 ); + + Status = NdisAllocateMemory((PVOID *)&RequestHandle, + sizeof( TP_REQUEST_HANDLE ), + 0, + HighestAddress ); + + if ( Status != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG (TP_DEBUG_RESOURCES) + { + TpPrint0("TpFuncSendDpc: unable to allocate Request Handle.\n"); + } + + NdisAcquireSpinLock( &OpenP->SpinLock ); + if ( OpenP->Send->SendIrp != NULL ) + { + OpenP->Send->SendIrp->IoStatus.Status = NDIS_STATUS_RESOURCES; + } + NdisReleaseSpinLock( &OpenP->SpinLock ); + + TpFuncSendEndDpc( NULL,OpenP,NULL,NULL ); + return; + } + else + { + NdisZeroMemory( RequestHandle,sizeof( TP_REQUEST_HANDLE )); + } + + RequestHandle->Signature = SEND_REQUEST_HANDLE_SIGNATURE; + RequestHandle->Open = OpenP; + RequestHandle->RequestPended = TRUE; + RequestHandle->Irp = OpenP->Send->SendIrp; + + Packet = TpFuncAllocateSendPacket( OpenP ); + + if ( Packet == NULL ) + { + IF_TPDBG( TP_DEBUG_RESOURCES ) + { + TpPrint0("TpFuncSendDpc: Unable to create a Send packet\n"); + } + + NdisAcquireSpinLock( &OpenP->SpinLock ); + if ( OpenP->Send->SendIrp != NULL ) + { + OpenP->Send->SendIrp->IoStatus.Status = NDIS_STATUS_RESOURCES; + } + NdisReleaseSpinLock( &OpenP->SpinLock ); + + TpFuncSendEndDpc( NULL,OpenP,NULL,NULL ); + return; + } + + RequestHandle->u.SEND_REQ.Packet = Packet; + RequestHandle->u.SEND_REQ.PacketSize = OpenP->Send->PacketSize; + RequestHandle->u.SEND_REQ.SendPacket = TRUE; + + 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 ) ); + ++OpenP->Send->PacketsPending; + ++OpenP->Send->Counters->Sends; + + NdisSend( &Status,OpenP->NdisBindingHandle,Packet ); + + if ( Status != NDIS_STATUS_PENDING ) + { + --OpenP->Send->PacketsPending; + + if ( Status != NDIS_STATUS_SUCCESS ) + { + // + // If we are running on TokenRing the following to "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 + // + // STARTCHANGE + // + 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 )) + { + ++OpenP->Send->Counters->SendFails; + } + } + else + { + ++OpenP->Send->Counters->SendFails; + TpPrint1("Send failed: status = %s", TpGetStatus(Status)); + } + + // + // STOPCHANGE + // + } + + RequestHandle->RequestPended = FALSE; + + TpFuncSendComplete( OpenP,Packet,Status ); + } + else + { + ++OpenP->Send->Counters->SendPends; + } + + NdisAcquireSpinLock( &OpenP->SpinLock ); + + if ((( OpenP->Send->SendIrp != NULL ) && + ( OpenP->Send->SendIrp->Cancel == FALSE )) && + (( ++OpenP->Send->PacketsSent < OpenP->Send->NumberOfPackets ) && + ( OpenP->Send->StopSending == FALSE ))) + { + NdisReleaseSpinLock( &OpenP->SpinLock ); + + DueTime.HighPart = -1; // So it will be relative. + DueTime.LowPart = (ULONG)(-4 * (ONE_HUNDREDTH_SECOND)); + + if ( KeSetTimer(&OpenP->Send->SendTimer, + DueTime, + &OpenP->Send->SendDpc )) + { + IF_TPDBG ( TP_DEBUG_DPC ) + { + TpPrint0("TpFuncSendDpc set SendTimer while timer existed.\n"); + } + } + } + else + { + NdisReleaseSpinLock( &OpenP->SpinLock ); + + DueTime.HighPart = 0xFFFFFFFF; // So it will be relative. + DueTime.LowPart = (ULONG)(-(ONE_SECOND)); + + if ( KeSetTimer(&OpenP->Send->SendTimer, + DueTime, + &OpenP->Send->SendEndDpc )) + { + IF_TPDBG ( TP_DEBUG_DPC ) + { + TpPrint0("TpFuncSendDpc set SendTimer while timer existed(2).\n"); + } + } + } +} + + + +VOID +TpFuncSendEndDpc( + IN PKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SysArg1, + IN PVOID SysArg2 + ) + +// ------------- +// +// Routine Description: +// +// +// Arguments: +// +// +// Return Value: +// +// ------------ + +{ + POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext); + LARGE_INTEGER DueTime; + + UNREFERENCED_PARAMETER( Dpc ); + UNREFERENCED_PARAMETER( SysArg1 ); + UNREFERENCED_PARAMETER( SysArg2 ); + + // + // 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 ((( OpenP->Send->SendIrp != NULL ) && + ( OpenP->Send->SendIrp->Cancel == FALSE )) && + (( OpenP->Send->PacketsPending != 0 ) && + ( OpenP->Send->SendEndDpcCount++ < 10 ))) + { + NdisReleaseSpinLock( &OpenP->SpinLock ); + + DueTime.HighPart = -1; // So it will be relative. + DueTime.LowPart = (ULONG)(-(ONE_SECOND)); + + if ( KeSetTimer(&OpenP->Send->SendTimer, + DueTime, + &OpenP->Send->SendEndDpc )) + { + IF_TPDBG ( TP_DEBUG_DPC ) + { + TpPrint0("TpFuncSendEndDpc set SendTimer while timer existed.\n"); + } + } + return; + } + + // + // Write the statistics to the send results outputbuffer. + // + + if (( OpenP->Send->SendIrp != NULL ) && + ( OpenP->Send->SendIrp->Cancel == FALSE )) + { + TpWriteSendReceiveResults( OpenP->Send->Counters, + OpenP->Send->SendIrp ); + } + + // + // and if the IoStatus.Status has not been set, then set it. + // + + if ( (OpenP->Send->SendIrp != NULL) && + (OpenP->Send->SendIrp->IoStatus.Status == NDIS_STATUS_PENDING )) + { + OpenP->Send->SendIrp->IoStatus.Status = NDIS_STATUS_SUCCESS; + } + + NdisReleaseSpinLock( &OpenP->SpinLock ); + + // + // Now set the sending flag to indicate that we are no longer + // SENDing packets. + // + + OpenP->Send->Sending = 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 (OpenP->Send->SendIrp != NULL) + { + TpRemoveReference( OpenP ); + IoMarkIrpPending( OpenP->Send->SendIrp ); + + IoAcquireCancelSpinLock( &OpenP->Send->SendIrp->CancelIrql ); + IoSetCancelRoutine( OpenP->Send->SendIrp,NULL ); + IoReleaseCancelSpinLock( OpenP->Send->SendIrp->CancelIrql ); + + IoCompleteRequest( OpenP->Send->SendIrp,IO_NETWORK_INCREMENT ); + + OpenP->Send->SendIrp = NULL; + } +} + + + +VOID +TpFuncSendComplete( + IN NDIS_HANDLE ProtocolBindingContext, + IN PNDIS_PACKET Packet, + IN NDIS_STATUS Status + ) + +// --------- +// +// Routine Description: +// +// Arguments: +// +// Return Value: +// +// -------- + +{ + POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext); + PPROTOCOL_RESERVED ProtRes; + PTP_REQUEST_HANDLE SendReqHndl; + PNDIS_BUFFER Buffer; + ULONG NextEvent; + + TP_ASSERT( Packet != NULL ); + + // + // Zero out the private section reserved for the MAC out of the NDIS packet + // + RtlZeroMemory( (PVOID)Packet->MacReserved, sizeof( Packet->MacReserved ) ); + + ProtRes = PROT_RES( Packet ); + SendReqHndl = ProtRes->RequestHandle; + + TP_ASSERT( Packet == SendReqHndl->u.SEND_REQ.Packet ); + + // + // Where did this packet originate from ? + // + + if (( SendReqHndl->Signature == SEND_REQUEST_HANDLE_SIGNATURE ) && + ( SendReqHndl->u.SEND_REQ.SendPacket == TRUE )) + { + // + // If the packet was sent by the SEND command, then decrement the + // counter tracking the number of outstanding functional packets, + // and if the send succeeded increment the completion counter. + // + + if ( SendReqHndl->RequestPended ) + { + --OpenP->Send->PacketsPending; + + ++OpenP->Send->Counters->SendComps; + + if ( Status != NDIS_STATUS_SUCCESS ) + { + // + // If we are running on TokenRing the following to "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 + // + // STARTCHANGE + // + 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 )) + { + ++OpenP->Send->Counters->SendFails; + } + } + else + { + ++OpenP->Send->Counters->SendFails; + TpPrint1("Send failed: status = %s", TpGetStatus(Status)); + } + } + } + + // + // also check that the PROTOCOL_RESERVED section of the packet + // header was not touched. + // + + if ( !TpCheckSum( (PUCHAR)ProtRes, + sizeof( PROTOCOL_RESERVED ) - sizeof( ULONG ), + &ProtRes->CheckSum )) + { + ++OpenP->Send->Counters->SendFails; + TP_ASSERT( FALSE ); + } + + // + // then break the packet down and release its memory. + // + + TpFuncFreePacket( SendReqHndl->u.SEND_REQ.Packet,SendReqHndl->u.SEND_REQ.PacketSize ); + + NdisFreeMemory( SendReqHndl,0,0 ); + + } + else if (( SendReqHndl->Signature == SEND_REQUEST_HANDLE_SIGNATURE ) && + ( SendReqHndl->u.SEND_REQ.SendPacket == FALSE )) + { + // + // This packet was sent by an invocation of the RECEIVE command from + // TpFuncReceive when a RESEND packet was received. + // + + if ( SendReqHndl->RequestPended ) + { + --OpenP->Receive->PacketsPending; + + ++OpenP->Receive->Counters->SendComps; + + if ( Status != NDIS_STATUS_SUCCESS ) + { + // + // If we are running on TokenRing the following to "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 + // + // STARTCHANGE + // + + 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 )) + { + ++OpenP->Send->Counters->SendFails; + } + } + else + { + ++OpenP->Send->Counters->SendFails; + } + } + } + + // + // also check that the PROTOCOL_RESERVED section of the packet + // header was not touched. + // + + if ( !TpCheckSum( (PUCHAR)ProtRes, + sizeof( PROTOCOL_RESERVED ) - sizeof( ULONG ), + &ProtRes->CheckSum )) + { + ++OpenP->Send->Counters->SendFails; + TP_ASSERT( FALSE ); + } + + // + // then break the packet down and release its memory. + // + + NdisUnchainBufferAtFront( Packet,&Buffer ); + NdisFreeMemory( MmGetMdlVirtualAddress( Buffer ),0,0 ); + TpFreeBuffer( Buffer ); + NdisFreePacket( Packet ); + NdisFreeMemory( SendReqHndl,0,0 ); + + } + else if ( SendReqHndl->Signature == GO_REQUEST_HANDLE_SIGNATURE ) + { + // + // check that the PROTOCOL_RESERVED section of the packet + // header was not touched. + // + + // This is just a go packet, check that the PROTOCOL_RESERVED + // section of the packet header was not touched, then break + // the packet down and release its memory. + // + + if ( !TpCheckSum( (PUCHAR)ProtRes, + sizeof( PROTOCOL_RESERVED ) - sizeof( ULONG ), + &ProtRes->CheckSum )) + { + TP_ASSERT( FALSE ); + } + + NdisUnchainBufferAtFront( Packet,&Buffer ); + NdisFreeMemory( MmGetMdlVirtualAddress( Buffer ),0,0 ); + TpFreeBuffer( Buffer ); + NdisFreePacket( Packet ); + NdisFreeMemory( SendReqHndl,0,0 ); + + } + else + { + // + // An unexpected call to the send completion routine has been made. + // Since we are not expecting it, stick the information on the + // Event Queue. + // + + NdisAcquireSpinLock( &OpenP->EventQueue->SpinLock ); + + NextEvent = OpenP->EventQueue->Head + 1; + + if ( NextEvent == MAX_EVENT ) + { + NextEvent = 0; + } + + if ( NextEvent != OpenP->EventQueue->Tail ) + { + // + // There is room to add another event to the event queue. + // + + OpenP->EventQueue->Events[NextEvent].TpEventType = CompleteSend; + OpenP->EventQueue->Head = NextEvent; + } + else + { + // + // The event queue is full, and this would overflow it. + // + + OpenP->EventQueue->Events[OpenP->EventQueue->Head].Overflow = TRUE; + } + + NdisReleaseSpinLock( &OpenP->EventQueue->SpinLock ); + } + +} + + + +NDIS_STATUS +TpFuncInitializeReceive( + IN POPEN_BLOCK OpenP + ) + +// --------- +// +// Routine Description: +// +// +// Arguments: +// +// +// Return Value: +// +// Status - +// +// ------- + +{ + LARGE_INTEGER DueTime; + + NdisZeroMemory( (PVOID)OpenP->Receive->Counters, + sizeof( INSTANCE_COUNTERS ) ); + + // + // Initialize the RECEIVE control flags, and reset the packet + // sending control counters. + // + + OpenP->Receive->Receiving = TRUE; + OpenP->Receive->StopReceiving = FALSE; + OpenP->Receive->PacketsPending = 0; + OpenP->Receive->ReceiveEndDpcCount = 0; + + // + // The zero out the receive counters. + // + + NdisZeroMemory( (PVOID)OpenP->Receive->Counters, + sizeof( INSTANCE_COUNTERS ) ); + + // + // Initialize the DPCs used to call ReceiveDpc and ReceiveEndDpc. + // + + KeInitializeDpc(&OpenP->Receive->ReceiveDpc, + TpFuncReceiveDpc, + (PVOID)OpenP ); + + KeInitializeDpc(&OpenP->Receive->ReceiveEndDpc, + TpFuncReceiveEndDpc, + (PVOID)OpenP ); + + // + // And finally set the timer for the ReceiveDpc to queue the + // routine later. + // + + DueTime.HighPart = 0xFFFFFFFF; // So it will be relative. + DueTime.LowPart = (ULONG)(-(ONE_SECOND)); + + if ( KeSetTimer(&OpenP->Receive->ReceiveTimer, + DueTime, + &OpenP->Receive->ReceiveDpc )) + { + IF_TPDBG ( TP_DEBUG_DPC ) + { + TpPrint0("TpFuncReceiveDpc set Receive timer while timer existed.\n"); + } + } + + // + // Increment the reference count on the OpenBlock stating that + // an async test is running and must be ended prior to closing + // the adapter on this open. + // + + TpAddReference( OpenP ); + + return NDIS_STATUS_PENDING; +} + + + +NDIS_STATUS +TpFuncReceive( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_HANDLE MacReceiveContext, + IN PVOID HeaderBuffer, + IN UINT HeaderBufferSize, + IN PVOID LookaheadBuffer, + IN UINT LookaheadBufferSize, + IN UINT PacketSize + ) + +// ------------- +// +// Routine Description: +// +// Arguments: +// +// Return Value: +// +// ----------- + +{ + POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext); + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + PPACKET_INFO PacketInfo; + PTP_REQUEST_HANDLE RequestHandle; + PGO_PACKET_INFO GoPacketInfo; + PUCHAR Memory; + PUCHAR SrcAddr; + PNDIS_PACKET Packet; + PNDIS_BUFFER Buffer; + PPROTOCOL_RESERVED ProtRes; + UINT BytesTransferred; + UINT HeaderVariance = sizeof(MEDIA_HEADER)-HeaderBufferSize; + ULONG DataSize; + ULONG NextEvent; + ULONG i; + + // + // The LookAhead Buffer has been adjusted to point to the beggining of the + // PACKET_INFO structure + // + PacketInfo = (PPACKET_INFO)LookaheadBuffer; + + // + // Are we expecting to receive a packet at this time, and is this + // packet large enough to be a functional send packet, and is the + // signature in the packet header correct? + // + + if ((( OpenP->Receive->Receiving == TRUE ) && + ( PacketSize >= sizeof( PACKET_INFO ))) && + (( PacketInfo->Signature == FUNC1_PACKET_SIGNATURE ) || + ( PacketInfo->Signature == FUNC2_PACKET_SIGNATURE ))) + { + if ( OpenP->Receive->StopReceiving == TRUE ) + { + // + // The receive test is shutting down, so just count the packet. + // + + ++OpenP->Receive->Counters->Receives; + + if ( !TpCheckSum( (PUCHAR)PacketInfo, + sizeof( PACKET_INFO ) - sizeof( ULONG ), + (PULONG)&PacketInfo->CheckSum )) + { + ++OpenP->Receive->Counters->CorruptRecs; + } + } + else + { + // + // We are in the normal receiving mode, and have a good + // packet, so we will handle it as requested. + // + + ++OpenP->Receive->Counters->Receives; + + if ( !TpCheckSum( (PUCHAR)PacketInfo, + sizeof( PACKET_INFO ) - sizeof( ULONG ), + (PULONG)&PacketInfo->CheckSum )) + { + ++OpenP->Receive->Counters->CorruptRecs; + return NDIS_STATUS_NOT_RECOGNIZED; + } + + // + // Is there any thing in the packet other than the header?? + // + + // + // STARTCHANGE + // Please note that this packet size is NOT the PacketSize which + // we receive in the TestProtocolReceive but is + // + // PacketSize we get with IndicateReceive + the size of the header + // = TRUE PACKET SIZE + // + DataSize = ((PPACKET_INFO)LookaheadBuffer)->PacketSize - + ( sizeof( PACKET_INFO ) + sizeof( MEDIA_HEADER ) ); + // + // STOPCHANGE + // + + if ( DataSize > 0 ) + { + SrcAddr = (PUCHAR)HeaderBuffer + (ULONG)OpenP->Media->SrcAddrOffset; + OpenP->Receive->ResendType = + ( RtlCompareMemory(SrcAddr, + OpenP->StationAddress, + OpenP->Media->AddressLen) == OpenP->Media->AddressLen); + + // + // Allocate the request handle and set it up as if the request + // pended. If it does not pend we will reset the flags later before + // calling the completion routine. + // + + Status = NdisAllocateMemory((PVOID *)&RequestHandle, + sizeof( TP_REQUEST_HANDLE ), + 0, + HighestAddress ); + + if ( Status != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG( TP_DEBUG_RESOURCES ) + { + TpPrint0("TpFuncReceive: unable to allocated request handle.\n"); + } + + NdisAcquireSpinLock( &OpenP->SpinLock ); + if (OpenP->Receive->ReceiveIrp != NULL ) + { + OpenP->Receive->ReceiveIrp->IoStatus.Status = NDIS_STATUS_RESOURCES; + } + NdisReleaseSpinLock( &OpenP->SpinLock ); + return NDIS_STATUS_RESOURCES; + } + else + { + NdisZeroMemory( RequestHandle,sizeof( TP_REQUEST_HANDLE )); + } + + RequestHandle->Signature = FUNC_REQUEST_HANDLE_SIGNATURE; + RequestHandle->Open = OpenP; + RequestHandle->RequestPended = TRUE; + RequestHandle->u.TRANS_REQ.DataSize = DataSize; + + // + // Now allocate the memory to copy the packet data into. + // + + Status = NdisAllocateMemory((PVOID *)&Memory, + DataSize, + 0, + HighestAddress ); + + if ( Status != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG(TP_DEBUG_RESOURCES) + { + TpPrint0("TpFuncReceive: unable to allocate resend buffer memory.\n"); + } + NdisFreeMemory( RequestHandle,0,0 ); + + NdisAcquireSpinLock( &OpenP->SpinLock ); + if (OpenP->Receive->ReceiveIrp != NULL ) + { + OpenP->Receive->ReceiveIrp->IoStatus.Status = NDIS_STATUS_RESOURCES; + } + NdisReleaseSpinLock( &OpenP->SpinLock ); + return NDIS_STATUS_RESOURCES; + } + else + { + NdisZeroMemory( Memory,DataSize ); + } + + // + // Then allocate the buffer that will reference the memory, + // + + Buffer = IoAllocateMdl( Memory, + DataSize, + TRUE, + FALSE, + NULL ); + + if ( Buffer == NULL ) + { + IF_TPDBG(TP_DEBUG_RESOURCES) + { + TpPrint0("TpFuncReceive: unable to allocate resend mdl buffer\n"); + } + NdisFreeMemory( Memory,0,0 ); + NdisFreeMemory( RequestHandle,0,0 ); + + NdisAcquireSpinLock( &OpenP->SpinLock ); + if (OpenP->Receive->ReceiveIrp != NULL ) + { + OpenP->Receive->ReceiveIrp->IoStatus.Status = NDIS_STATUS_RESOURCES; + } + NdisReleaseSpinLock( &OpenP->SpinLock ); + return NDIS_STATUS_RESOURCES; + } + + MmBuildMdlForNonPagedPool( (PMDL)Buffer ); + + // + // and finally the NDIS_PACKET to pass to the NdisTransferData call. + // + + NdisAllocatePacket( &Status, + &Packet, + OpenP->Receive->PacketHandle ); + + if ( Status != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG(TP_DEBUG_RESOURCES) + { + TpPrint0("TpFuncReceive: unable to allocate resend packet\n"); + } + IoFreeMdl( Buffer ); + NdisFreeMemory( Memory,0,0 ); + NdisFreeMemory( RequestHandle,0,0 ); + + NdisAcquireSpinLock( &OpenP->SpinLock ); + if (OpenP->Receive->ReceiveIrp != NULL ) + { + OpenP->Receive->ReceiveIrp->IoStatus.Status = Status; + } + NdisReleaseSpinLock( &OpenP->SpinLock ); + return Status; + } + else + { + // + // Setup the protocol reserved portion of the packet so the + // completion routines know what and where to deallocate. + // + + ProtRes = PROT_RES( Packet ); + ProtRes->Pool.PacketHandle = OpenP->Receive->PacketHandle; + ProtRes->InstanceCounters = OpenP->Receive->Counters; + ProtRes->RequestHandle = RequestHandle; + + ProtRes->CheckSum = + TpSetCheckSum( (PUCHAR)ProtRes, + sizeof( PROTOCOL_RESERVED ) - sizeof( ULONG ) ); + + // + // reference the packet in the request handle. + // + + RequestHandle->u.TRANS_REQ.Packet = Packet; + } + + // + // Now chain the buffer to the packet. + // + + NdisChainBufferAtFront( Packet,Buffer ); + + // + // And transfer the data into the newly created packet. + // + + ++OpenP->Receive->Counters->XferData; + + // + // STARTCHANGE + // + NdisTransferData( &Status, + OpenP->NdisBindingHandle, + MacReceiveContext, + (sizeof(PACKET_INFO)+HeaderVariance), + DataSize, + Packet, + &BytesTransferred ); + // + // STOPCHANGE + // + + if ( Status == NDIS_STATUS_PENDING ) + { + // + // The deallocation of resources and any resending will + // be handled by the completion routine, so just count + // the transfer pending and split. + // + ++OpenP->Receive->Counters->XferDataPends; + } + else + { + // + // If the request did not pend, we should reset the + // pend flag, and the status flag in the RequestHandle, + // and then call the completion handler ourselves. + // + + RequestHandle->RequestPended = FALSE; + + TpFuncTransferDataComplete( OpenP, + Packet, + Status, + BytesTransferred ); + } + } + else + { + TpPrint2("Full packetsize = %d, true packetsize = %d\n", + ((PPACKET_INFO)LookaheadBuffer)->PacketSize, DataSize); + TpBreakPoint(); + } + } + } + else if (( PacketSize >= sizeof( GO_PACKET_INFO )) && + ( PacketInfo->Signature == GO_PACKET_SIGNATURE )) + { + GoPacketInfo = (PGO_PACKET_INFO)LookaheadBuffer; + SrcAddr = (PUCHAR)HeaderBuffer + (ULONG)OpenP->Media->SrcAddrOffset; + + if ( !TpCheckSum( (PUCHAR)GoPacketInfo, + sizeof( GO_PACKET_INFO ) - sizeof( ULONG ), + (PULONG)&GoPacketInfo->CheckSum )) + { + Status = NDIS_STATUS_NOT_RECOGNIZED; + } + else + { + NdisAcquireSpinLock( &OpenP->Pause->SpinLock ); + + if ((( OpenP->Pause->GoReceived == TRUE ) || + + // + // We have not finished processing the last GO packet, + // and a new one has arrived. We can't accept it until + // the last GO has been handled. We will ignore this + // packet. + // + + ((( GoPacketInfo->PacketType == TP_GO ) && + ( GoPacketInfo->TestSignature == OpenP->Pause->TestSignature )) && + ( GoPacketInfo->UniqueSignature == OpenP->Pause->UniqueSignature ))) || + + // + // Or we have finished handling the last GO packet, and + // received another one for the same PAUSE before the + // GO sender received and handled the GO_ACK packet. + // We will ignore this packet also. + // + + ( RtlCompareMemory( SrcAddr, + OpenP->StationAddress, + OpenP->Media->AddressLen) == OpenP->Media->AddressLen )) + { + + // + // Or this packet was sent by us, not another protocol + // on another machine, must have the packet filter set + // to promiscuous mode, ignore this packet also. + // + + NdisReleaseSpinLock( &OpenP->Pause->SpinLock ); + } + else + { + OpenP->Pause->GoReceived = TRUE; + + switch ( OpenP->Media->MediumType ) + { + case NdisMediumArcnet878_2: + case NdisMediumFddi : + case NdisMediumDix : + case NdisMedium802_3 : + case NdisMedium802_5 : + for ( i=0 ; i < OpenP->Media->AddressLen; i++ ) + { + OpenP->Pause->RemoteAddress[i] = (CHAR)&SrcAddr[i]; + } + break; + + default: + IF_TPDBG ( TP_DEBUG_RESOURCES ) + { + TpPrint0("TpFuncReceive: Unsupported MAC Media Type\n"); + } + } + + OpenP->Pause->TestSignature = GoPacketInfo->TestSignature; + OpenP->Pause->UniqueSignature = GoPacketInfo->UniqueSignature; + OpenP->Pause->PacketType = GoPacketInfo->PacketType; + + NdisReleaseSpinLock( &OpenP->Pause->SpinLock ); + } + } + } + else + { +// TEMP -- Find out WHY we got here... + +// this one is valid--can get it during abort of performance test +// if ( OpenP->Receive->Receiving != TRUE ) +// { +// TpPrint0("Rcv--receiving == FALSE\n"); +// } + + if ( PacketSize >= sizeof( PACKET_INFO )) + { + TpPrint1("Rcv--Psize >= PACKET_INFO, signature = %x\n", PacketInfo->Signature); + } + else if ( PacketSize >= sizeof( GO_PACKET_INFO )) + { + TpPrint1("Rcv--Psize >= GO_PACKET_INFO, signature = %x\n", PacketInfo->Signature); + } + else + { + TpPrint0("Rcv--Psize < GO_PACKET_INFO\n"); + } +// TpBreakPoint(); + +// + // + // We are not expecting to receive packets, or this packet is not + // large enough to be a functional packet, or we are not expecting + // to receive this packet. so stick it on the Event Queue. + // + + NdisAcquireSpinLock( &OpenP->EventQueue->SpinLock ); + + NextEvent = OpenP->EventQueue->Head + 1; + + if ( NextEvent == MAX_EVENT ) + { + NextEvent = 0; + } + + if ( NextEvent != OpenP->EventQueue->Tail ) + { + // + // There is room to add another event to the event queue. + // + + OpenP->EventQueue->Events[NextEvent].TpEventType = IndicateReceive; + OpenP->EventQueue->Head = NextEvent; + + // + // XXX: At this point we could stick the first X bytes (header) + // into the Events[head].EventInfo using xferdata. + // + + } + else + { + // + // The event queue is full, and this would have overflowed it, so + // mark the Head event overflow flag to show this. + // + + OpenP->EventQueue->Events[OpenP->EventQueue->Head].Overflow = TRUE; + } + + ++OpenP->EventQueue->ReceiveIndicationCount; + OpenP->EventQueue->ExpectReceiveComplete = TRUE; + + NdisReleaseSpinLock( &OpenP->EventQueue->SpinLock ); + + Status = NDIS_STATUS_NOT_RECOGNIZED; + + } + + return Status; +} + + + +VOID +TpFuncReceiveComplete( + IN NDIS_HANDLE ProtocolBindingContext + ) + +// ------- +// +// Routine Description: +// +// Arguments: +// +// Return Value: +// +// ----- + +{ + POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext); + + if ( OpenP->Receive->Receiving == TRUE ) + { + ++OpenP->Receive->Counters->ReceiveComps; + } + else + { + // + // We are not expecting this completion, so stick the + // info on the event queue. + // + + NdisAcquireSpinLock( &OpenP->EventQueue->SpinLock ); + + //**************************************************************** + // + // NOTE: Due to the fact that a MAC will complete all receive + // indications to EVERY transport that has it opened this + // completion is not entirely unexpected, and therefore will + // not be added to the Event Queue. + // + //**************************************************************** + +#if 0 + // + // We have received an unexpected Status Indication, so + // we are expecting (???) to receive the completion. + // + + NextEvent = OpenP->EventQueue->Head + 1; + + if ( NextEvent == MAX_EVENT ) + { + NextEvent = 0; + } + + if ( NextEvent != OpenP->EventQueue->Tail ) + { + // + // There is room to add another event to the event queue. + // + + OpenP->EventQueue->Events[NextEvent].TpEventType = IndicateReceiveComplete; + OpenP->EventQueue->Head = NextEvent; + + // XXX: Was it expected ??? + } + else + { + // + // The event queue is full, and this would overflow it. + // + OpenP->EventQueue->Events[OpenP->EventQueue->Head].Overflow = TRUE; + } +#endif + + // + // Reset the status indication counter to zero, and set the + // status completion expected flag to show that no completion + // routine is expected. + // + + OpenP->EventQueue->ReceiveIndicationCount = 0; + OpenP->EventQueue->ExpectReceiveComplete = FALSE; + + NdisReleaseSpinLock( &OpenP->EventQueue->SpinLock ); + } +} + + + +VOID +TpFuncTransferDataComplete( + IN NDIS_HANDLE ProtocolBindingContext, + IN PNDIS_PACKET Packet, + IN NDIS_STATUS Status, + IN UINT BytesTransferred + ) + +// ---------- +// +// Routine Description: +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +// --------- + +{ + POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext); + PNDIS_BUFFER Buffer; + PPROTOCOL_RESERVED ProtRes; + PTP_REQUEST_HANDLE XferReqHndl; + PTP_REQUEST_HANDLE SendReqHndl; + PTP_PACKET TpPacket; + PUCHAR BufMem; +// NDIS_STATUS SendStatus; + ULONG NextEvent; + ULONG i; + LARGE_INTEGER DueTime; + + + TP_ASSERT( Packet != NULL ); + + ProtRes = PROT_RES( Packet ); + XferReqHndl = ProtRes->RequestHandle; + + TP_ASSERT( Status == NDIS_STATUS_SUCCESS ); + TP_ASSERT( Packet == XferReqHndl->u.TRANS_REQ.Packet ); + + // + // Are we expecting to complete a Transfer Data at this time? + // First determine if we are running a RECEIVE test. If so, + // determine whether this is a legitimate completion, or a + // bug. + // + + TP_ASSERT( OpenP != NULL ); + + if (( OpenP->Receive->StopReceiving == FALSE ) && + (( XferReqHndl->Signature == FUNC_REQUEST_HANDLE_SIGNATURE ) && + ( XferReqHndl->Open == (POPEN_BLOCK)ProtocolBindingContext ))) + { + // + // If so then verfiy the PROTOCOL RESERVED section of the + // packet was not touched. + // + + if ( !TpCheckSum( (PUCHAR)ProtRes, + sizeof( PROTOCOL_RESERVED ) - sizeof( ULONG ), + &ProtRes->CheckSum )) + { + ++OpenP->Receive->Counters->XferDataFails; + return; + } + + // + // and then grab the pointer to the newly transferred packet, + // and the data stored in it. + // + + NdisQueryPacket( Packet,NULL,NULL,&Buffer,NULL ); + + TpPacket = (PTP_PACKET)MmGetMdlVirtualAddress( Buffer ); + + TP_ASSERT( BytesTransferred == XferReqHndl->u.TRANS_REQ.DataSize ); + + // + // We are expecting it, so if the request truly pended, then + // count the completion now. + // + + if ( XferReqHndl->RequestPended == TRUE ) + { + ++OpenP->Receive->Counters->XferDataComps; + } + + // + // We have a Func Packet, is it a resend packet or not? + // + + if (( TpPacket->u.F1.info.Signature == FUNC2_PACKET_SIGNATURE ) && + ( TpPacket->u.F1.info.PacketType == (UCHAR)FUNC2_PACKET_TYPE )) + { + if ( Status == NDIS_STATUS_SUCCESS ) + { + // + // It is a resend packet, we need to resend it. first check + // the header and the data in the pacekt. + // + + if ( !TpCheckSum( (PUCHAR)&TpPacket->u.F1.info, + sizeof( PACKET_INFO ) - sizeof( ULONG ), + (PULONG)&TpPacket->u.F1.info.CheckSum )) + { + ++OpenP->Receive->Counters->CorruptRecs; + } + + // XXX: function for this + BufMem = (PUCHAR)((PUCHAR)TpPacket + (UCHAR)sizeof( FUNC1_PACKET )); + + for ( i = 0 ; i < ( BytesTransferred - sizeof( FUNC1_PACKET )) ; i++ ) + { + if ( BufMem[i] != (UCHAR)( i % 256 )) + { + IF_TPDBG( TP_DEBUG_DATA ) + { + TpPrint1( + "TpFuncTransferDataComplete: Data Corruption in packet 0x%lX at\n", + Packet); + TpPrint3( + " offset %d into data. Expected 0x%X, found 0x%X.\n\n", + i,(i % 256),BufMem[i]); + } + ++OpenP->Receive->Counters->CorruptRecs; + + IF_TPDBG( TP_DEBUG_BREAKPOINT ) + { + TpBreakPoint(); + } + break; + } + } + + // + // Then copy the local adapter address into the source + // address in the packet header. + // + + // + // STARTCHANGE + // + if ( NdisMediumArray[OpenP->MediumIndex] == NdisMedium802_5 ) // Tokenring + { + for ( i = 0 ; i < OpenP->Media->AddressLen ; i++ ) + { + TpPacket->u.F1.media.tr.SrcAddress[i] = OpenP->StationAddress[i]; + } + } + else if ( NdisMediumArray[OpenP->MediumIndex] == NdisMediumFddi ) // Fddi + { + for ( i = 0 ; i < OpenP->Media->AddressLen ; i++ ) + { + TpPacket->u.F1.media.fddi.SrcAddress[i] = OpenP->StationAddress[i]; + } + } + else if ( NdisMediumArray[OpenP->MediumIndex] == NdisMedium802_3 ) // Ethernet + { + for ( i = 0 ; i < OpenP->Media->AddressLen ; i++ ) + { + TpPacket->u.F1.media.e.SrcAddress[i] = OpenP->StationAddress[i]; + } + } + else if ( NdisMediumArray[OpenP->MediumIndex] == NdisMediumArcnet878_2 ) // Arcnet + { + for ( i = 0 ; i < OpenP->Media->AddressLen ; i++ ) + { + TpPacket->u.F1.media.a.SrcAddress[i] = OpenP->StationAddress[i]; + } + } + // + // STOPCHANGE + // + + // + // if the NdisTransferData call completed successfully, + // then we can resend the packet now. Allocate the + // request handle and set it up as if the request + // pended. If it does not pend we will reset the + // flags later before calling the completion routine. + // + + Status = NdisAllocateMemory((PVOID *)&SendReqHndl, + sizeof( TP_REQUEST_HANDLE ), + 0, + HighestAddress ); + + if ( Status != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG( TP_DEBUG_RESOURCES ) + { + TpPrint0( + "TpFuncTransferDataComplete: unable to allocated request handle\n"); + } + return; + } + else + { + NdisZeroMemory( SendReqHndl,sizeof( TP_REQUEST_HANDLE )); + } + + SendReqHndl->Signature = SEND_REQUEST_HANDLE_SIGNATURE; + SendReqHndl->Open = OpenP; + SendReqHndl->RequestPended = TRUE; + SendReqHndl->u.SEND_REQ.Packet = Packet; + + // + // STARTCHANGE + // + SendReqHndl->u.SEND_REQ.PacketSize = BytesTransferred + sizeof( MEDIA_HEADER ); + // + // STOPCHANGE + // + + SendReqHndl->u.SEND_REQ.SendPacket = FALSE; + + // + // Now reset the packet to a FUNC1 packet type, and + // calculate the new checksum. + // + + TpPacket->u.F1.info.PacketType = FUNC1_PACKET_TYPE; + TpPacket->u.F1.info.Signature = FUNC1_PACKET_SIGNATURE; + + TpPacket->u.F1.info.CheckSum = + TpSetCheckSum( (PUCHAR)&TpPacket->u.F1.info, + sizeof( PACKET_INFO ) - sizeof( ULONG ) ); + + // + // Reference the new request handle off the reserved area. + // + + ProtRes->RequestHandle = SendReqHndl; + // + // 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 ) ); + + if (OpenP->Receive->ResendReq == NULL) + { + OpenP->Receive->ResendReq = SendReqHndl; + + DueTime.HighPart = -1; // So it will be relative. + if (OpenP->Receive->ResendType) + { + DueTime.LowPart = (ULONG)(-2 * (ONE_HUNDREDTH_SECOND)); + } + else + { + DueTime.LowPart = (ULONG)(-(ONE_HUNDREDTH_SECOND)); + } + + if ( KeSetTimer(&OpenP->Receive->ResendTimer, + DueTime, + &OpenP->Receive->ResendDpc )) + { + IF_TPDBG ( TP_DEBUG_DPC ) + { + TpPrint0("TpFuncTransferDataComplete set SendTimer while timer existed.\n"); + } + } + } + else + { + TpFuncResend(OpenP, SendReqHndl); + } + } + else // ( Status == Some Type Failure ) + { + // + // The transfer data call failed, increment the counter, + // and deallocate the resources. + // + + IF_TPDBG( TP_DEBUG_NDIS_CALLS ) + { + TpPrint1("TpFuncTransferDataComplete: NdisTransferData failed: returned %s\n", + TpGetStatus(Status)); + } + ++OpenP->Receive->Counters->XferDataFails; + + // + // Now free up the transfer packet resources. + // + + NdisUnchainBufferAtFront( Packet,&Buffer ); + NdisFreeMemory( MmGetMdlVirtualAddress( Buffer ),0,0 ); + TpFreeBuffer( Buffer ); + NdisFreePacket( Packet ); + } + } + else + { + // + // This is just a packet we should receive, count, and drop. + // + + BufMem = (PUCHAR)TpPacket; + + for ( i = 0 ; i < BytesTransferred ; i++ ) + { + if ( BufMem[i] != (UCHAR)( i % 256 )) + { + IF_TPDBG( TP_DEBUG_DATA ) + { + TpPrint1("TpFuncTransferDataComplete: Data Corruption in packet 0x%lX at\n", + Packet); + TpPrint3( + " offset %d into data. Expected 0x%X found 0x%X.\n", + i,(i % 256),BufMem[i]); + } + ++OpenP->Receive->Counters->CorruptRecs; + + IF_TPDBG( TP_DEBUG_BREAKPOINT ) + { + TpBreakPoint(); + } + break; + } + } + + if ( Status != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG( TP_DEBUG_NDIS_CALLS ) + { + TpPrint1("TpFuncReceive: NdisTransferData failed: returned %s\n", + TpGetStatus(Status)); + } + ++OpenP->Receive->Counters->XferDataFails; + } + + // + // Now free up the transfer packet resources. + // + + NdisUnchainBufferAtFront( Packet,&Buffer ); + NdisFreeMemory( MmGetMdlVirtualAddress( Buffer ),0,0 ); + TpFreeBuffer( Buffer ); + NdisFreePacket( Packet ); + } + + // + // And finally free up the Request Handle that was allocated + // in the Receive routine for the call to NdisTransferData. + // + + NdisFreeMemory( XferReqHndl,0,0 ); + } + else + { + // + // We are not expecting a transfer data to complete at this + // point, so stick this on the Event Queue. + // + + NdisAcquireSpinLock( &OpenP->EventQueue->SpinLock ); + + NextEvent = OpenP->EventQueue->Head + 1; + + if ( NextEvent == MAX_EVENT ) + { + NextEvent = 0; + } + + if ( NextEvent != OpenP->EventQueue->Tail ) + { + // + // There is room to add another event to the event queue. + // + + OpenP->EventQueue->Events[NextEvent].TpEventType = CompleteTransferData; + OpenP->EventQueue->Head = NextEvent; + } + else + { + // + // The event queue is full, and this would have overflowed it, so + // mark the Head event overflow flag to show this. + // + OpenP->EventQueue->Events[OpenP->EventQueue->Head].Overflow = TRUE; + } + + // + // We have a resource, the packet, should we free it? to where? + // who really owns it? + // + NdisReleaseSpinLock( &OpenP->EventQueue->SpinLock ); + } + return; +} + +VOID +TpFuncResend(POPEN_BLOCK OpenP, + PTP_REQUEST_HANDLE SendReqHndl) +{ + NDIS_STATUS Status; + PNDIS_PACKET Packet = SendReqHndl->u.SEND_REQ.Packet; + + // + // Increment the send pending packet counter, + // + + ++OpenP->Receive->PacketsPending; + + // + // and the number of packets sent, + // + + ++OpenP->Receive->Counters->Sends; + + // + // and send it... + // + + NdisSend( &Status, + OpenP->NdisBindingHandle, + Packet ); + + if ( Status != NDIS_STATUS_PENDING ) + { + --OpenP->Receive->PacketsPending; + + if ( Status != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG( TP_DEBUG_NDIS_CALLS ) + { + TpPrint1("TpFuncResendDpc: NdisSend failed: returned %s\n", TpGetStatus(Status)); + } + // + // If we are running on TokenRing the following to "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. + // + 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 )) + { + ++OpenP->Send->Counters->SendFails; + } + } + else + { + ++OpenP->Send->Counters->SendFails; + } + } + SendReqHndl->RequestPended = FALSE; + TpFuncSendComplete( OpenP,Packet,Status ); + } + else + { + ++OpenP->Receive->Counters->SendPends; + } + +} + + +VOID +TpFuncResendDpc( + IN PKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SysArg1, + IN PVOID SysArg2 + ) +{ + POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext); + PTP_REQUEST_HANDLE SendReqHndl = OpenP->Receive->ResendReq; + + + UNREFERENCED_PARAMETER( Dpc ); + UNREFERENCED_PARAMETER( SysArg1 ); + UNREFERENCED_PARAMETER( SysArg2 ); + + TpFuncResend(OpenP, SendReqHndl); + + OpenP->Receive->ResendReq = NULL; +} + + + +VOID +TpFuncReceiveDpc( + IN PKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SysArg1, + IN PVOID SysArg2 + ) + +// -------- +// +// Routine Description: +// +// Arguments: +// +// Return Value: +// +// ------- + +{ + POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext); + LARGE_INTEGER DueTime; + + UNREFERENCED_PARAMETER( Dpc ); + UNREFERENCED_PARAMETER( SysArg1 ); + UNREFERENCED_PARAMETER( SysArg2 ); + + DueTime.HighPart = -1; // So it will be relative. + DueTime.LowPart = (ULONG)(-(ONE_SECOND)); + + // + // If the Irp has been cancelled or the Stop Receive + // flag has been set then end the test. + // + + NdisAcquireSpinLock( &OpenP->SpinLock ); + + if ((( OpenP->Receive->ReceiveIrp == NULL ) || + ( OpenP->Receive->ReceiveIrp->Cancel == TRUE )) || + (( OpenP->Receive->Receiving == TRUE ) && + ( OpenP->Receive->StopReceiving == TRUE ))) + { + NdisReleaseSpinLock( &OpenP->SpinLock ); + + // + // The receive test should now stop, so queue the Receive + // End dpc routine. + // + + if ( KeSetTimer(&OpenP->Receive->ReceiveTimer, + DueTime, + &OpenP->Receive->ReceiveEndDpc )) + { + IF_TPDBG ( TP_DEBUG_DPC ) + { + TpPrint0("TpFuncReceiveDpc set StressEnd timer while timer existed.\n"); + } + } + } + else + { + NdisReleaseSpinLock( &OpenP->SpinLock ); + + // + // Otherwise the test should continue, so insert the next instance + // of the Receive Dpc in the timer queue and exit. This will queue + // the next instance of the TpFuncReceiveDpc routine when the + // timer goes off. + // + + if ( KeSetTimer(&OpenP->Receive->ReceiveTimer, + DueTime, + &OpenP->Receive->ReceiveDpc )) + { + IF_TPDBG ( TP_DEBUG_DPC ) + { + TpPrint0("TpFuncReceiveDpc set Receive timer while timer existed.\n"); + } + } + } +} + + + +VOID +TpFuncReceiveEndDpc( + IN PKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SysArg1, + IN PVOID SysArg2 + ) + +// ---------- +// +// Routine Description: +// +// +// Arguments: +// +// +// Return Value: +// +// +// -------- + +{ + POPEN_BLOCK OpenP = ((POPEN_BLOCK)DeferredContext); + LARGE_INTEGER DueTime; + + UNREFERENCED_PARAMETER( Dpc ); + UNREFERENCED_PARAMETER( SysArg1 ); + UNREFERENCED_PARAMETER( SysArg2 ); + + // + // 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 requeues the packet(s) has still no completed + // we assume it will never complete and return the results and finish. + // + + NdisAcquireSpinLock( &OpenP->SpinLock ); + + if (((( OpenP->Receive->ReceiveIrp != NULL ) && + ( OpenP->Receive->ReceiveIrp->Cancel == FALSE )) && + ( OpenP->Receive->PacketsPending != 0 )) && + ( OpenP->Receive->ReceiveEndDpcCount++ < 10 )) + { + NdisReleaseSpinLock( &OpenP->SpinLock ); + + DueTime.HighPart = -1; // So it will be relative. + DueTime.LowPart = (ULONG)(-(ONE_SECOND)); + + if ( KeSetTimer(&OpenP->Receive->ReceiveTimer, + DueTime, + &OpenP->Receive->ReceiveEndDpc )) + { + IF_TPDBG ( TP_DEBUG_DPC ) + { + TpPrint0("TpFuncReceiveEndDpc set ReceiveTimer while timer existed.\n"); + } + } + return; + } + + // + // If the status has not been reset, then set it to success now. + // + + if ( OpenP->Receive->ReceiveIrp->IoStatus.Status == NDIS_STATUS_PENDING ) + { + OpenP->Receive->ReceiveIrp->IoStatus.Status = NDIS_STATUS_SUCCESS; + } + + // + // Now write the RECEIVE results to the output buffer. + // + + TpWriteSendReceiveResults( OpenP->Receive->Counters, + OpenP->Receive->ReceiveIrp ); + + NdisReleaseSpinLock( &OpenP->SpinLock ); + + // + // Now set the receiving flag to indicate that we are no longer + // RECEIVEing packets. + // + + OpenP->Receive->Receiving = 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. + // + + TpRemoveReference( OpenP ); + + IoMarkIrpPending( OpenP->Receive->ReceiveIrp ); + + IoAcquireCancelSpinLock( &OpenP->Receive->ReceiveIrp->CancelIrql ); + IoSetCancelRoutine( OpenP->Receive->ReceiveIrp,NULL ); + IoReleaseCancelSpinLock( OpenP->Receive->ReceiveIrp->CancelIrql ); + + IoCompleteRequest( OpenP->Receive->ReceiveIrp,IO_NETWORK_INCREMENT ); + + OpenP->Receive->ReceiveIrp = NULL; + + return; +} + + + +NDIS_STATUS +TpFuncGetEvent( + IN POPEN_BLOCK OpenP + ) + +// ---- +// +// Routine Description: +// +// +// Arguments: +// +// +// Return Value: +// +// Status - +// +// ----- + +{ + PEVENT_RESULTS OutputBuffer; + ULONG NextEvent; + + OutputBuffer = MmGetSystemAddressForMdl( OpenP->Irp->MdlAddress ); + + OutputBuffer->Signature = EVENT_RESULTS_SIGNATURE; + + NdisAcquireSpinLock( &OpenP->EventQueue->SpinLock ); + + if ( OpenP->EventQueue->Head == OpenP->EventQueue->Tail ) + { + // + // There is nothing in the Event Queue. + // + + OpenP->Irp->IoStatus.Status = TP_STATUS_NO_EVENTS; + } + else + { + if (( NextEvent = ++OpenP->EventQueue->Tail ) == MAX_EVENT ) + { + NextEvent = OpenP->EventQueue->Tail = 0; + } + + OutputBuffer->TpEventType = OpenP->EventQueue->Events[NextEvent].TpEventType; + OutputBuffer->QueueOverFlowed = OpenP->EventQueue->Events[NextEvent].Overflow; + + OpenP->EventQueue->Events[NextEvent].TpEventType = Unknown; + OpenP->EventQueue->Events[NextEvent].EventInfo = NULL; + OpenP->EventQueue->Events[NextEvent].Overflow = FALSE; + + OpenP->Irp->IoStatus.Status = STATUS_SUCCESS; + } + + NdisReleaseSpinLock( &OpenP->EventQueue->SpinLock ); + + return OpenP->Irp->IoStatus.Status; +} + + + +VOID +TpFuncStatus( + IN NDIS_HANDLE ProtocolBindingContext, + IN NDIS_STATUS GeneralStatus, + IN PVOID StatusBuffer, + IN UINT StatusBufferSize + ) +{ + POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext); + ULONG NextEvent; + + // + // We have receive a Status indication, stick it on the + // Event Queue. + // + + NdisAcquireSpinLock( &OpenP->EventQueue->SpinLock ); + + NextEvent = OpenP->EventQueue->Head + 1; + + if ( NextEvent == MAX_EVENT ) + { + NextEvent = 0; + } + + if ( NextEvent != OpenP->EventQueue->Tail ) + { + // + // There is room to add another event to the event queue. + // + + OpenP->EventQueue->Events[NextEvent].TpEventType = IndicateStatus; + OpenP->EventQueue->Head = NextEvent; + + // + // At this point we could stick the General Status + // into the EventInfo buffer. + // + + } + else + { + // + // The event queue is full, and this would overflow it. + // + OpenP->EventQueue->Events[OpenP->EventQueue->Head].Overflow = TRUE; + } + + // + // Increment the Status Indication counter and set the status + // completion flag to true to show that a completion is expected. + // + + ++OpenP->EventQueue->StatusIndicationCount; + + OpenP->EventQueue->ExpectStatusComplete = TRUE; + + NdisReleaseSpinLock( &OpenP->EventQueue->SpinLock ); +} + + + +VOID +TpFuncStatusComplete( + IN NDIS_HANDLE ProtocolBindingContext + ) + +// ---------- +// +// Routine Description: +// +// Print out the help message to the debugger screen. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +// --------- + +{ + POPEN_BLOCK OpenP = ((POPEN_BLOCK)ProtocolBindingContext); + ULONG NextEvent; + + NdisAcquireSpinLock( &OpenP->EventQueue->SpinLock ); + + // + // We have received an unexpected Status Completion, so + // we are expecting (???) to receive the completion. + // + + NextEvent = OpenP->EventQueue->Head + 1; + + if ( NextEvent == MAX_EVENT ) + { + NextEvent = 0; + } + + if ( NextEvent != OpenP->EventQueue->Tail ) + { + // + // There is room to add another event to the event queue. + // + + OpenP->EventQueue->Events[NextEvent].TpEventType = IndicateStatusComplete; + OpenP->EventQueue->Head = NextEvent; + } + else + { + // + // The event queue is full, and this would overflow it. + // + + OpenP->EventQueue->Events[OpenP->EventQueue->Head].Overflow = TRUE; + } + + // + // Reset the status indication counter to zero, and set the + // status completion expected flag to show that no completion + // routine is expected. + // + + OpenP->EventQueue->StatusIndicationCount = 0; + OpenP->EventQueue->ExpectStatusComplete = FALSE; + + NdisReleaseSpinLock( &OpenP->EventQueue->SpinLock ); +} + + + +NDIS_STATUS +TpFuncSendGo( + IN POPEN_BLOCK OpenP, + IN PCMD_ARGS CmdArgs, + IN UCHAR PacketType + ) + +// ----- +// +// Routine Description: +// +// Arguments: +// +// Return Value: +// +// ---- + +{ + NDIS_STATUS Status; + PTP_REQUEST_HANDLE RequestHandle; + PGO_PACKET GoPacket; + PUCHAR p, q; + USHORT DataSizeShort; + PNDIS_BUFFER Buffer; + PNDIS_PACKET Packet; + PPROTOCOL_RESERVED ProtRes; + PREQUEST_RESULTS OutputBuffer; + ULONG i; + + OutputBuffer = MmGetSystemAddressForMdl( OpenP->Irp->MdlAddress ); + + // + // Allocate the request handle, and init the relevant fields + // + + Status = NdisAllocateMemory((PVOID *)&RequestHandle, + sizeof( TP_REQUEST_HANDLE ), + 0, + HighestAddress ); + + if ( Status != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG( TP_DEBUG_RESOURCES ) + { + TpPrint0("TpFuncSendGo: unable to allocated request handle.\n"); + } + OpenP->Irp->IoStatus.Status = NDIS_STATUS_RESOURCES; + return NDIS_STATUS_RESOURCES; + } + else + { + NdisZeroMemory( RequestHandle,sizeof( TP_REQUEST_HANDLE )); + } + + RequestHandle->Signature = GO_REQUEST_HANDLE_SIGNATURE; + RequestHandle->Open = OpenP; + + // + // Now allocate the GoPacket to copy the packet data into. + // + + Status = NdisAllocateMemory((PVOID *)&GoPacket, + sizeof( GO_PACKET ), + 0, + HighestAddress ); + + if ( Status != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG(TP_DEBUG_RESOURCES) + { + TpPrint0("TpFuncSendGo: unable to allocate buffer memory.\n"); + } + OpenP->Irp->IoStatus.Status = NDIS_STATUS_RESOURCES; + return NDIS_STATUS_RESOURCES; + } + else + { + NdisZeroMemory( (PUCHAR)GoPacket,sizeof( GO_PACKET )); + } + + switch ( OpenP->Media->MediumType ) + { + case NdisMedium802_5: + GoPacket->go_media.tr.AC = 0x10; + GoPacket->go_media.tr.FC = 0x40; + + p = (PUCHAR)&GoPacket->go_media.tr.DestAddress[0]; + q = (PUCHAR)&GoPacket->go_media.tr.SrcAddress[0]; + + for ( i=0;i<OpenP->Media->AddressLen;i++ ) + { + *p++ = CmdArgs->ARGS.PAUSE_GO.RemoteAddress[i]; + *q++ = OpenP->StationAddress[i]; + } + break; + + case NdisMediumDix: + case NdisMedium802_3: + + p = (PUCHAR)&GoPacket->go_media.e.DestAddress[0]; + q = (PUCHAR)&GoPacket->go_media.e.SrcAddress[0]; + + for ( i=0;i<OpenP->Media->AddressLen;i++ ) + { + *p++ = CmdArgs->ARGS.PAUSE_GO.RemoteAddress[i]; + *q++ = OpenP->StationAddress[i]; + } + + DataSizeShort = (USHORT)( sizeof( GO_PACKET ) - OpenP->Media->HeaderSize ); + + GoPacket->go_media.e.PacketSize_Hi = (UCHAR)(DataSizeShort >> 8 ); + GoPacket->go_media.e.PacketSize_Lo = (UCHAR)DataSizeShort; + break; + + case NdisMediumFddi: + GoPacket->go_media.fddi.FC = 0x57; + + p = (PUCHAR)&GoPacket->go_media.fddi.DestAddress[0]; + q = (PUCHAR)&GoPacket->go_media.fddi.SrcAddress[0]; + + for ( i=0;i<OpenP->Media->AddressLen;i++ ) + { + *p++ = CmdArgs->ARGS.PAUSE_GO.RemoteAddress[i]; + *q++ = OpenP->StationAddress[i]; + } + break; + + // + // STARTCHANGE + // + case NdisMediumArcnet878_2: + GoPacket->go_media.a.ProtocolID = ARCNET_DEFAULT_PROTOCOLID; + + p = (PUCHAR)&GoPacket->go_media.a.DestAddress[0]; + q = (PUCHAR)&GoPacket->go_media.a.SrcAddress[0]; + + for ( i=0;i<OpenP->Media->AddressLen;i++ ) + { + *p++ = CmdArgs->ARGS.PAUSE_GO.RemoteAddress[i]; + *q++ = OpenP->StationAddress[i]; + } + break; + // + // STOPCHANGE + // + + default: + IF_TPDBG ( TP_DEBUG_RESOURCES ) + { + TpPrint0("TpFuncSendGo: Unsupported MAC Type\n"); + } + + OpenP->Irp->IoStatus.Status = NDIS_STATUS_RESOURCES; + return NDIS_STATUS_RESOURCES; + } + + GoPacket->info.Signature = GO_PACKET_SIGNATURE; + GoPacket->info.TestSignature = CmdArgs->ARGS.PAUSE_GO.TestSignature; + GoPacket->info.UniqueSignature = OpenP->Pause->UniqueSignature; + GoPacket->info.PacketType = PacketType; + + GoPacket->info.CheckSum = TpSetCheckSum((PUCHAR)&GoPacket->info, + sizeof( GO_PACKET_INFO ) - sizeof( ULONG ) ); + + // + // Then allocate the buffer that will reference the memory, + // + + Buffer = IoAllocateMdl( (PVOID)GoPacket,sizeof( GO_PACKET ),TRUE,FALSE,NULL ); + + if ( Buffer == NULL ) + { + IF_TPDBG(TP_DEBUG_RESOURCES) + { + TpPrint0("TpFuncSendGo: unable to allocate mdl buffer\n"); + } + NdisFreeMemory( (PVOID)GoPacket,0,0 ); + OpenP->Irp->IoStatus.Status = NDIS_STATUS_RESOURCES; + return NDIS_STATUS_RESOURCES; + } + MmBuildMdlForNonPagedPool( (PMDL)Buffer ); + + // + // and finally the NDIS_PACKET to pass to the NdisTransferData call. + // + + NdisAllocatePacket( &Status, + &Packet, + OpenP->Pause->PacketHandle ); + + if ( Status != NDIS_STATUS_SUCCESS ) + { + IF_TPDBG(TP_DEBUG_RESOURCES) + { + TpPrint0("TpFuncReceive: unable to allocate resend packet\n"); + } + IoFreeMdl( Buffer ); + NdisFreeMemory( (PVOID)GoPacket,0,0 ); + OpenP->Irp->IoStatus.Status = Status; + return Status; + } + else + { + // + // Setup the protocol reserved portion of the packet so the + // completion routines know what and where to deallocate. + // + + ProtRes = PROT_RES( Packet ); + ProtRes->Pool.PacketHandle = OpenP->Pause->PacketHandle; + ProtRes->InstanceCounters = NULL; + ProtRes->RequestHandle = RequestHandle; + RequestHandle->u.SEND_REQ.Packet = Packet; + } + + // + // Now chain the buffer to the packet. + // + + NdisChainBufferAtFront( Packet,Buffer ); + + // + // 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 ) ); + // + // And send it. + // + + NdisSend( &Status,OpenP->NdisBindingHandle,Packet ); + + if ( Status != NDIS_STATUS_PENDING ) + { + TpFuncSendComplete( OpenP,Packet,Status ); + } + else + { + // NOTE: should we somehow handle sends failing , or will be catch + // that on the next iteration??? - this could cause us problems + // on the go response packet. + Status = NDIS_STATUS_SUCCESS; + } + + OutputBuffer->RequestStatus = Status; + OpenP->Irp->IoStatus.Status = Status; + return Status; +} + + + +NDIS_STATUS +TpFuncPause( + IN POPEN_BLOCK OpenP, + IN PCMD_ARGS CmdArgs, + IN UCHAR PacketType + ) + +// ---- +// +// Routine Description: +// +// Arguments: +// +// Return Value: +// +// ---- + +{ + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + LARGE_INTEGER TimeOut; + PREQUEST_RESULTS OutputBuffer; + + OpenP->Pause->TimeOut = 0; + + OutputBuffer = MmGetSystemAddressForMdl( OpenP->Irp->MdlAddress ); + OutputBuffer->RequestStatus = TP_STATUS_TIMEDOUT; + + TimeOut.HighPart = -1; // so it will be relative. + TimeOut.LowPart = (ULONG)(-(ONE_SECOND)); + + do + { + NdisAcquireSpinLock( &OpenP->Pause->SpinLock ); + + if ( OpenP->Pause->GoReceived == FALSE ) + { + NdisReleaseSpinLock( &OpenP->Pause->SpinLock ); + + // + // If the Go packet has not arrived stall for a moment + // waiting for it to arrive. + // + + Status = KeDelayExecutionThread( KernelMode,FALSE,&TimeOut ); + if ( Status != STATUS_SUCCESS ) + { + break; + } + else + { + ++OpenP->Pause->TimeOut; + } + } + else + { + // + // Otherwise we have received a go packet, see if it + // is the one we are waiting for. + // + + if (( CmdArgs->ARGS.PAUSE_GO.TestSignature == OpenP->Pause->TestSignature ) && + ( OpenP->Pause->PacketType == PacketType )) + { + // + // It is, get out of here. + // + OpenP->Pause->GoReceived = FALSE; + + NdisReleaseSpinLock( &OpenP->Pause->SpinLock ); + + OutputBuffer->RequestStatus = NDIS_STATUS_SUCCESS; + break; + } + else + { + // + // We received a GO packet with the wrong test signature. + // + + OpenP->Pause->GoReceived = FALSE; + NdisReleaseSpinLock( &OpenP->Pause->SpinLock ); + } + } + + } while (( OpenP->Pause->TimeOut < 10 ) && ( OpenP->IrpCancelled == FALSE )); + + OpenP->Irp->IoStatus.Status = Status; + return Status; +} + + + |