/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Module Name: miniport.c Abstract: This module contains all the Miniport interface processing routines. Author: Hakan Berk - Microsoft, Inc. (hakanb@microsoft.com) Feb-2000 Environment: Windows 2000 kernel mode Miniport driver or equivalent. Revision History: ---------------------------------------------------------------------------*/ #include #include #include #include #include #include #include "debug.h" #include "timer.h" #include "bpool.h" #include "ppool.h" #include "util.h" #include "packet.h" #include "protocol.h" #include "miniport.h" #include "tapi.h" #include "fsm.h" // // This is our global adapter context // ADAPTER* gl_pAdapter = NULL; // // Lock that controls access to gl_pAdapter. // This lock is necesarry for requests submitted from the bindings as // they will not know if the adapter is halted or not. // NDIS_SPIN_LOCK gl_lockAdapter; // // We need a flag to indicate if lock is allocated or not // BOOLEAN gl_fLockAllocated = FALSE; // // The timer queue that handles the scheduled timer events. // TIMERQ gl_TimerQ; // // This is used to create a unique identifier in packets // ULONG gl_UniqueCounter = 0; VOID CreateUniqueValue( IN HDRV_CALL hdCall, OUT CHAR* pUniqueValue, OUT USHORT* pSize ) { CHAR* pBuf = pUniqueValue; ULONG usUniqueValue = InterlockedIncrement( &gl_UniqueCounter ); NdisMoveMemory( pBuf, (CHAR*) &hdCall, sizeof( HDRV_CALL ) ); pBuf += sizeof( HDRV_CALL ); NdisMoveMemory( pBuf, (CHAR*) &usUniqueValue, sizeof( ULONG ) ); *pSize = sizeof( HDRV_CALL ) + sizeof( ULONG ); } HDRV_CALL RetrieveHdCallFromUniqueValue( IN CHAR* pUniqueValue, IN USHORT Size ) { if ( Size != sizeof( HDRV_CALL ) + sizeof( ULONG ) ) return (HDRV_CALL) NULL; return ( * (UNALIGNED HDRV_CALL*) pUniqueValue ); } //////////////////////////////////// // // Local function prototypes // //////////////////////////////////// VOID ReferenceAdapter( IN ADAPTER* pAdapter, IN BOOLEAN fAcquireLock ); VOID DereferenceAdapter( IN ADAPTER* pAdapter ); ADAPTER* AllocAdapter(); VOID FreeAdapter( ADAPTER* pAdapter ); NDIS_STATUS MpInitialize( OUT PNDIS_STATUS OpenErrorStatus, OUT PUINT SelectedMediumIndex, IN PNDIS_MEDIUM MediumArray, IN UINT MediumArraySize, IN NDIS_HANDLE MiniportAdapterHandle, IN NDIS_HANDLE WrapperConfigurationContext ); VOID MpHalt( IN NDIS_HANDLE MiniportAdapterContext ); NDIS_STATUS MpReset( OUT PBOOLEAN AddressingReset, IN NDIS_HANDLE MiniportAdapterContext ); NDIS_STATUS MpWanSend( IN NDIS_HANDLE MiniportAdapterContext, IN NDIS_HANDLE NdisLinkHandle, IN PNDIS_WAN_PACKET WanPacket ); NDIS_STATUS MpQueryInformation( IN NDIS_HANDLE MiniportAdapterContext, IN NDIS_OID Oid, IN PVOID InformationBuffer, IN ULONG InformationBufferLength, OUT PULONG BytesWritten, OUT PULONG BytesNeeded ); NDIS_STATUS MpSetInformation( IN NDIS_HANDLE MiniportAdapterContext, IN NDIS_OID Oid, IN PVOID InformationBuffer, IN ULONG InformationBufferLength, OUT PULONG BytesWritten, OUT PULONG BytesNeeded ); //////////////////////////////////// // // Interface functions definitions // //////////////////////////////////// NDIS_STATUS MpRegisterMiniport( IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath, OUT NDIS_HANDLE* pNdisWrapperHandle ) /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Functional Description: This function will be called from DriverEntry() to register the miniport and create an instance of the adapter. Parameters: DriverObject _ Pointer to driver object created by the system. RegistryPath _ Pointer to registery path name used to read registry parameters. Return Values: NDIS_STATUS_SUCCESFUL: Miniport registered succesfully. NDIS_STATUS_FAILURE: Miniport failed to register succesfully. ---------------------------------------------------------------------------*/ { NDIS_HANDLE NdisWrapperHandle; NDIS_STATUS status; NDIS_MINIPORT_CHARACTERISTICS nmc; TRACE( TL_I, TM_Mp, ("+MpRegisterMiniport") ); NdisMInitializeWrapper( &NdisWrapperHandle, pDriverObject, pRegistryPath, NULL ); // // Fill in the miniport characteristics // NdisZeroMemory( &nmc, sizeof( NDIS_MINIPORT_CHARACTERISTICS ) ); nmc.MajorNdisVersion = MP_NDIS_MajorVersion; nmc.MinorNdisVersion = MP_NDIS_MinorVersion; nmc.Reserved = NDIS_USE_WAN_WRAPPER; nmc.InitializeHandler = MpInitialize; nmc.ResetHandler = MpReset; nmc.HaltHandler = MpHalt; nmc.QueryInformationHandler = MpQueryInformation; nmc.SetInformationHandler = MpSetInformation; nmc.WanSendHandler = MpWanSend; // no CheckForHangHandler // no DisableInterruptHandler // no EnableInterruptHandler // no HandleInterruptHandler // no ISRHandler // no SendHandler (see WanSendHandler) // no TransferDataHandler // no WanTransferDataHandler // no ReturnPacketHandler // no SendPacketsHandler (see WanSendHandler) // no AllocateCompleteHandler // no CoActivateVcHandler // no CoDeactivateVcHandler // no CoSendPacketsHandler // no CoRequestHandler // // Set the characteristics registering the miniport // status = NdisMRegisterMiniport( NdisWrapperHandle, &nmc, sizeof( NDIS_MINIPORT_CHARACTERISTICS ) ); // // If registeration of miniport was not successful, // undo the initialization of wrapper // if ( status != NDIS_STATUS_SUCCESS ) { NdisTerminateWrapper( NdisWrapperHandle, NULL ); } else { *pNdisWrapperHandle = NdisWrapperHandle; } TRACE( TL_I, TM_Mp, ("-MpRegisterMiniport=$%x",status) ); return status; } //////////////////////////////////// // // Local function definitions // //////////////////////////////////// VOID ReferenceAdapter( IN ADAPTER* pAdapter, IN BOOLEAN fAcquireLock ) /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Functional Description: This function will increment the reference count on the adapter object. CAUTION: If fAcquireLock is set, this function will acquire the lock for the call, otherwise it will assume the caller owns the lock. Parameters: pAdapter _ A pointer to our call information structure. fAcquireLock _ Indicates if the caller already has the lock or not. Caller must set this flag to FALSE if it has the lock, otherwise it must be supplied as TRUE. Return Values: None ---------------------------------------------------------------------------*/ { LONG lRef; ASSERT( VALIDATE_ADAPTER( pAdapter ) ); TRACE( TL_V, TM_Mp, ("+ReferenceAdapter") ); if ( fAcquireLock ) NdisAcquireSpinLock( &pAdapter->lockAdapter ); lRef = ++pAdapter->lRef; if ( fAcquireLock ) NdisReleaseSpinLock( &pAdapter->lockAdapter ); TRACE( TL_V, TM_Mp, ("-ReferenceAdapter=$%d",lRef) ); } VOID DereferenceAdapter( IN ADAPTER* pAdapter ) /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Functional Description: This function will decrement the reference count on the adapter object If the ref count drops to 0 (which means the adapter has been halted), it will set fire pAdapter->eventAdapterHalted. Parameters: pAdapter _ A pointer ot our call information structure. Return Values: None ---------------------------------------------------------------------------*/ { LONG lRef; BOOLEAN fSignalAdapterHaltedEvent = FALSE; ASSERT( VALIDATE_ADAPTER( pAdapter ) ); TRACE( TL_V, TM_Mp, ("+DereferenceAdapter") ); NdisAcquireSpinLock( &pAdapter->lockAdapter ); lRef = --pAdapter->lRef; if ( lRef == 0 ) { pAdapter->ulMpFlags &= ~MPBF_MiniportInitialized; pAdapter->ulMpFlags &= ~MPBF_MiniportHaltPending; pAdapter->ulMpFlags |= MPBF_MiniportHalted; fSignalAdapterHaltedEvent = TRUE; } NdisReleaseSpinLock( &pAdapter->lockAdapter ); // // Signal the halting of the adapter if we need to // if ( fSignalAdapterHaltedEvent ) NdisSetEvent( &pAdapter->eventAdapterHalted ); TRACE( TL_V, TM_Mp, ("-DereferenceAdapter=$%x",lRef) ); } ADAPTER* AllocAdapter() /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Functional Description: This function will allocate the resources for the adapter object and return a pointer to it. Parameters: None Return Values: pAdapter: A pointer to the newly allocated adapter object. NULL: Resources were not available to create the adapter. ---------------------------------------------------------------------------*/ { ADAPTER* pAdapter = NULL; TRACE( TL_N, TM_Mp, ("+AllocAdapter") ); if ( ALLOC_ADAPTER( &pAdapter ) != NDIS_STATUS_SUCCESS ) { TRACE( TL_A, TM_Mp, ("AllocAdapter: Could not allocate context") ); TRACE( TL_N, TM_Mp, ("-AllocAdapter") ); return NULL; } // // Clear the memory // NdisZeroMemory( pAdapter, sizeof( ADAPTER ) ); // // Initialize adapter tag // pAdapter->tagAdapter = MTAG_ADAPTER; // // Allocate the lock that controls access to the adapter // NdisAllocateSpinLock( &pAdapter->lockAdapter ); // // Initialize the state // pAdapter->ulMpFlags = MPBF_MiniportIdle; TRACE( TL_N, TM_Mp, ("-AllocAdapter") ); return pAdapter; } NDIS_STATUS ReadRegistrySettings( IN OUT ADAPTER* pAdapter, IN NDIS_HANDLE WrapperConfigurationContext ) { NDIS_STATUS status = NDIS_STATUS_FAILURE; NDIS_HANDLE hCfg = 0; NDIS_CONFIGURATION_PARAMETER* pncp = 0; BOOLEAN fMaxLinesDefinedInRegistry = FALSE; TRACE( TL_N, TM_Mp, ("+ReadRegistrySettings") ); do { // // Open the Ndis configuration, it will be closed at the end of the // while loop before we exit it. // NdisOpenConfiguration( &status, &hCfg, WrapperConfigurationContext ); if ( status != NDIS_STATUS_SUCCESS ) { TRACE( TL_A, TM_Mp, ("ReadRegistrySettings: NdisOpenConfiguration() failed") ); break; } // // Read fClientRole value from the registry only in the debug builds // { #if DBG NDIS_STRING nstr = NDIS_STRING_CONST( "fClientRole" ); NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterInteger ); if (status == NDIS_STATUS_SUCCESS) { TRACE( TL_N, TM_Mp, ("ReadRegistrySettings: Read fClientRole from registry") ); pAdapter->fClientRole = ( pncp->ParameterData.IntegerData > 0 ) ? TRUE : FALSE; } else #endif { TRACE( TL_N, TM_Mp, ("ReadRegistrySettings: Could not read fClientRole from registry, using default value") ); pAdapter->fClientRole = TRUE; status = NDIS_STATUS_SUCCESS; } } #if DBG // // Read ServiceName and ServiceNameLength values from the registry. // These are server side only values. // { NDIS_STRING nstr = NDIS_STRING_CONST( "ServiceName" ); NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterString ); if (status == NDIS_STATUS_SUCCESS) { ANSI_STRING AnsiString; NdisZeroMemory( &AnsiString, sizeof( ANSI_STRING ) ); status = RtlUnicodeStringToAnsiString( &AnsiString, &pncp->ParameterData.StringData, TRUE ); if ( status == STATUS_SUCCESS ) { TRACE( TL_N, TM_Mp, ("ReadRegistrySettings: Read ServiceName from registry") ); pAdapter->nServiceNameLength = ( MAX_SERVICE_NAME_LENGTH < AnsiString.Length ) ? MAX_SERVICE_NAME_LENGTH : AnsiString.Length; NdisMoveMemory( pAdapter->ServiceName, AnsiString.Buffer, pAdapter->nServiceNameLength ) ; RtlFreeAnsiString( &AnsiString ); } } if ( status != NDIS_STATUS_SUCCESS ) { PWSTR wszKeyName = L"ComputerName"; PWSTR wszPath = L"ComputerName\\ComputerName"; RTL_QUERY_REGISTRY_TABLE QueryTable[2]; UNICODE_STRING UnicodeStr; WCHAR wszName[ MAX_COMPUTERNAME_LENGTH + 1]; NdisZeroMemory( QueryTable, 2 * sizeof( RTL_QUERY_REGISTRY_TABLE ) ); QueryTable[0].QueryRoutine = NULL; QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT; QueryTable[0].Name = wszKeyName; QueryTable[0].EntryContext = (PVOID) &UnicodeStr; NdisZeroMemory( &UnicodeStr, sizeof( UNICODE_STRING ) ); UnicodeStr.Length = 0; UnicodeStr.MaximumLength = MAX_COMPUTERNAME_LENGTH + 1; UnicodeStr.Buffer = wszName; status = RtlQueryRegistryValues( RTL_REGISTRY_CONTROL, wszPath, QueryTable, NULL, NULL ); if ( status == STATUS_SUCCESS ) { ANSI_STRING AnsiString; NdisZeroMemory( &AnsiString, sizeof( ANSI_STRING ) ); status = RtlUnicodeStringToAnsiString( &AnsiString, &UnicodeStr, TRUE ); if ( status == STATUS_SUCCESS ) { TRACE( TL_N, TM_Mp, ("ReadRegistrySettings: Using Machine Name as ServiceName") ); NdisMoveMemory( pAdapter->ServiceName, AnsiString.Buffer, AnsiString.Length ); NdisMoveMemory( pAdapter->ServiceName + AnsiString.Length, SERVICE_NAME_EXTENSION, sizeof( SERVICE_NAME_EXTENSION ) ); // // -1 is to ignore the terminating NULL character // pAdapter->nServiceNameLength = AnsiString.Length + sizeof( SERVICE_NAME_EXTENSION ) - 1; RtlFreeAnsiString( &AnsiString ); status = NDIS_STATUS_SUCCESS; } } } if ( status != NDIS_STATUS_SUCCESS ) { TRACE( TL_N, TM_Mp, ("ReadRegistrySettings: Using default hardcoded service name") ); NdisMoveMemory( pAdapter->ServiceName, "MS-RAS PPPoE", sizeof( "MS-RAS PPPoE" ) ); pAdapter->nServiceNameLength = ( sizeof( "MS-RAS PPPoE" ) / sizeof( CHAR ) ) - 1; status = NDIS_STATUS_SUCCESS; } // // Future: Convert service name to UTF-8 // It turns out that we can not do this conversion from a kernel module, // so the value read from the registry must be in UTF-8 format itself. // } // // Read AC-Name and AC-NameLength values from the registry. // These are server side only values. // { NDIS_STRING nstr = NDIS_STRING_CONST( "ACName" ); NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterString ); if (status == NDIS_STATUS_SUCCESS) { ANSI_STRING AnsiString; NdisZeroMemory( &AnsiString, sizeof( ANSI_STRING ) ); status = RtlUnicodeStringToAnsiString( &AnsiString, &pncp->ParameterData.StringData, TRUE ); if ( status == STATUS_SUCCESS ) { TRACE( TL_N, TM_Mp, ("ReadRegistrySettings: Read AC-Name from registry") ); pAdapter->nACNameLength = ( MAX_AC_NAME_LENGTH < AnsiString.Length ) ? MAX_AC_NAME_LENGTH : AnsiString.Length; NdisMoveMemory( pAdapter->ACName, AnsiString.Buffer, pAdapter->nACNameLength ) ; RtlFreeAnsiString( &AnsiString ); } } if ( status != NDIS_STATUS_SUCCESS ) { PWSTR wszKeyName = L"ComputerName"; PWSTR wszPath = L"ComputerName\\ComputerName"; RTL_QUERY_REGISTRY_TABLE QueryTable[2]; UNICODE_STRING UnicodeStr; WCHAR wszName[ MAX_COMPUTERNAME_LENGTH + 1]; NdisZeroMemory( QueryTable, 2 * sizeof( RTL_QUERY_REGISTRY_TABLE ) ); QueryTable[0].QueryRoutine = NULL; QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT; QueryTable[0].Name = wszKeyName; QueryTable[0].EntryContext = (PVOID) &UnicodeStr; NdisZeroMemory( &UnicodeStr, sizeof( UNICODE_STRING ) ); UnicodeStr.Length = 0; UnicodeStr.MaximumLength = MAX_COMPUTERNAME_LENGTH + 1; UnicodeStr.Buffer = wszName; status = RtlQueryRegistryValues( RTL_REGISTRY_CONTROL, wszPath, QueryTable, NULL, NULL ); if ( status == STATUS_SUCCESS ) { ANSI_STRING AnsiString; NdisZeroMemory( &AnsiString, sizeof( ANSI_STRING ) ); status = RtlUnicodeStringToAnsiString( &AnsiString, &UnicodeStr, TRUE ); if ( status == STATUS_SUCCESS ) { TRACE( TL_N, TM_Mp, ("ReadRegistrySettings: Using Machine Name as AC-Name") ); NdisMoveMemory( pAdapter->ACName, AnsiString.Buffer, AnsiString.Length ); pAdapter->nACNameLength = AnsiString.Length; RtlFreeAnsiString( &AnsiString ); status = NDIS_STATUS_SUCCESS; } } } if ( status != NDIS_STATUS_SUCCESS ) { TRACE( TL_N, TM_Mp, ("ReadRegistrySettings: Using default hardcoded value for AC-Name") ); NdisMoveMemory( pAdapter->ACName, "MS-RAS Access Concentrator", sizeof( "MS-RAS Access Concentrator" ) ); pAdapter->nACNameLength = ( sizeof( "MS-RAS Access Concentrator" ) / sizeof( CHAR ) ) - 1; status = NDIS_STATUS_SUCCESS; } // // Future: Convert AC name to UTF-8 // It turns out that we can not do this conversion from a kernel module, // so the value read from the registry must be in UTF-8 format itself. // } // // Read nClientQuota value // These is a server side only value. // { NDIS_STRING nstr = NDIS_STRING_CONST( "ClientQuota" ); NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterInteger ); if (status == NDIS_STATUS_SUCCESS) { TRACE( TL_N, TM_Mp, ("ReadRegistrySettings: Read ClientQuota from registry") ); pAdapter->nClientQuota = (UINT) pncp->ParameterData.IntegerData; } else #endif { TRACE( TL_N, TM_Mp, ("ReadRegistrySettings: Could not read ClientQuota from registry, using default value") ); pAdapter->nClientQuota = 3; status = NDIS_STATUS_SUCCESS; } #if DBG } // // Read MaxLines value // { NDIS_STRING nstr = NDIS_STRING_CONST( "MaxLines" ); NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterInteger ); if (status == NDIS_STATUS_SUCCESS) { TRACE( TL_N, TM_Mp, ("ReadRegistrySettings: Read MaxLines from registry") ); pAdapter->nMaxLines = (UINT) pncp->ParameterData.IntegerData; fMaxLinesDefinedInRegistry = TRUE; } else #endif { TRACE( TL_N, TM_Mp, ("ReadRegistrySettings: Could not read MaxLines from registry, using default value") ); pAdapter->nMaxLines = 1; status = NDIS_STATUS_SUCCESS; } #if DBG } // // Read CallsPerLine value // { NDIS_STRING nstr = NDIS_STRING_CONST( "CallsPerLine" ); NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterInteger ); if (status == NDIS_STATUS_SUCCESS) { TRACE( TL_N, TM_Mp, ("ReadRegistrySettings: Read CallsPerLine from registry") ); pAdapter->nCallsPerLine = (UINT) pncp->ParameterData.IntegerData; } else #endif { TRACE( TL_N, TM_Mp, ("ReadRegistrySettings: Could not read CallsPerLine from registry, using default value") ); pAdapter->nCallsPerLine = 1; status = NDIS_STATUS_SUCCESS; } #if DBG } #endif // // Read WanEndPoints if MaxLines was not defined in registry // if ( !fMaxLinesDefinedInRegistry ) { NDIS_STRING nstr = NDIS_STRING_CONST( "WanEndPoints" ); NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterInteger ); if (status == NDIS_STATUS_SUCCESS) { TRACE( TL_N, TM_Mp, ("ReadRegistrySettings: Read WanEndPoints from registry") ); pAdapter->nMaxLines = 1; pAdapter->nCallsPerLine = (UINT) pncp->ParameterData.IntegerData; } status = NDIS_STATUS_SUCCESS; } // // Read MaxTimeouts value // { NDIS_STRING nstr = NDIS_STRING_CONST( "MaxTimeouts" ); NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterInteger ); if (status == NDIS_STATUS_SUCCESS) { TRACE( TL_N, TM_Mp, ("ReadRegistrySettings: Read MaxTimeouts from registry") ); pAdapter->nMaxTimeouts = (UINT) pncp->ParameterData.IntegerData; } else { TRACE( TL_N, TM_Mp, ("ReadRegistrySettings: Could not read MaxTimeouts from registry, using default value") ); pAdapter->nMaxTimeouts = 3; status = NDIS_STATUS_SUCCESS; } } // // Read SendTimeout value // { NDIS_STRING nstr = NDIS_STRING_CONST( "SendTimeout" ); NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterInteger ); if (status == NDIS_STATUS_SUCCESS) { TRACE( TL_N, TM_Mp, ("ReadRegistrySettings: Read SendTimeout from registry") ); pAdapter->ulSendTimeout = (ULONG) pncp->ParameterData.IntegerData; } else { TRACE( TL_N, TM_Mp, ("ReadRegistrySettings: Could not read SendTimeout from registry, using default value") ); pAdapter->ulSendTimeout = 5000; status = NDIS_STATUS_SUCCESS; } } // // Read RecvTimeout value // { NDIS_STRING nstr = NDIS_STRING_CONST( "RecvTimeout" ); NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterInteger ); if (status == NDIS_STATUS_SUCCESS) { TRACE( TL_N, TM_Mp, ("ReadRegistrySettings: Read RecvTimeout from registry") ); pAdapter->ulRecvTimeout = (ULONG) pncp->ParameterData.IntegerData; } else { TRACE( TL_N, TM_Mp, ("ReadRegistrySettings: Could not read RecvTimeout from registry, using default value") ); pAdapter->ulRecvTimeout = 5000; status = NDIS_STATUS_SUCCESS; } } // // Read fAcceptAnyService value from the registry // { NDIS_STRING nstr = NDIS_STRING_CONST( "fAcceptAnyService" ); NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterInteger ); if (status == NDIS_STATUS_SUCCESS) { TRACE( TL_N, TM_Mp, ("ReadRegistrySettings: Read fAcceptAnyService from registry") ); pAdapter->fAcceptAnyService = ( pncp->ParameterData.IntegerData > 0 ) ? TRUE : FALSE; } else { TRACE( TL_N, TM_Mp, ("ReadRegistrySettings: Could not read fAcceptAnyService from registry, using default value") ); pAdapter->fAcceptAnyService = TRUE; status = NDIS_STATUS_SUCCESS; } } // // Close the Ndis configuration // NdisCloseConfiguration( hCfg ); } while ( FALSE ); TRACE( TL_N, TM_Mp, ("-ReadRegistrySettings=$%x",status) ); return status; } NDIS_STATUS InitializeAdapter( IN ADAPTER* pAdapter, IN NDIS_HANDLE MiniportAdapterHandle, IN NDIS_HANDLE WrapperConfigurationContext ) /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Functional Description: This function will initialize the contents of the adapter object. It will be called from inside MpInitialize() and it will read the necesarry values from the registry to initialize the adapter context. Parameters: pAdapter _ A pointer to our adapter information structure. Return Values: None ---------------------------------------------------------------------------*/ { NDIS_STATUS status = NDIS_STATUS_SUCCESS; NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress = NDIS_PHYSICAL_ADDRESS_CONST(-1,-1); ASSERT( VALIDATE_ADAPTER( pAdapter ) ); TRACE( TL_N, TM_Mp, ("+InitializeAdapter") ); // // Initialize and reset the adapter halted event // NdisInitializeEvent( &pAdapter->eventAdapterHalted ); NdisResetEvent( &pAdapter->eventAdapterHalted ); // // Set the state // pAdapter->ulMpFlags = MPBF_MiniportInitialized; // // Set NDIS's corresponding handle // pAdapter->MiniportAdapterHandle = MiniportAdapterHandle; // // Read values from registry // status = ReadRegistrySettings( pAdapter, WrapperConfigurationContext ); pAdapter->nMaxSendPackets = 1; // // Initialize the NdisWanInfo structure // pAdapter->NdisWanInfo.MaxFrameSize = PACKET_PPP_PAYLOAD_MAX_LENGTH; pAdapter->NdisWanInfo.MaxTransmit = 1; pAdapter->NdisWanInfo.HeaderPadding = PPPOE_PACKET_HEADER_LENGTH; pAdapter->NdisWanInfo.TailPadding = 0; pAdapter->NdisWanInfo.Endpoints = pAdapter->nCallsPerLine * pAdapter->nMaxLines; pAdapter->NdisWanInfo.MemoryFlags = 0; pAdapter->NdisWanInfo.HighestAcceptableAddress = HighestAcceptableAddress; pAdapter->NdisWanInfo.FramingBits = PPP_FRAMING | // PPP_COMPRESS_ADDRESS_CONTROL | // PPP_COMPRESS_PROTOCOL_FIELD | TAPI_PROVIDER; pAdapter->NdisWanInfo.DesiredACCM = 0; TRACE( TL_N, TM_Mp, ("-InitializeAdapter=$%x",status) ); return status; } VOID FreeAdapter( ADAPTER* pAdapter ) /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Functional Description: This function will deallocate the resources for the adapter object. Parameters: pAdapter _ A pointer to our adapter information structure. Return Values: None ---------------------------------------------------------------------------*/ { ASSERT( VALIDATE_ADAPTER( pAdapter ) ); TRACE( TL_N, TM_Mp, ("+FreeAdapter") ); NdisFreeSpinLock( &pAdapter->lockAdapter ); FREE_ADAPTER( pAdapter ); TRACE( TL_N, TM_Mp, ("-FreeAdapter") ); } NDIS_STATUS MpInitialize( OUT PNDIS_STATUS OpenErrorStatus, OUT PUINT SelectedMediumIndex, IN PNDIS_MEDIUM MediumArray, IN UINT MediumArraySize, IN NDIS_HANDLE MiniportAdapterHandle, IN NDIS_HANDLE WrapperConfigurationContext ) /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Functional Description: The MiniportInitialize request is called to have the Miniport driver initialize the adapter. No other request will be outstanding on the Miniport when this routine is called. No other request will be submitted to the Miniport until the operation is completed. The wrapper will supply an array containing a list of the media types that it supports. The Miniport driver reads this array and returns the index of the media type that the wrapper should treat her as. If the Miniport driver is impersonating a media type that is different from the true media type, this must be done completely transparently to the wrapper. If the Miniport driver cannot find a media type supported by both it and the wrapper, it returns NDIS_STATUS_UNSUPPORTED_MEDIA. The status value NDIS_STATUS_OPEN_ERROR has a special meaning. It indicates that the OpenErrorStatus parameter has returned a valid status which the wrapper can examine to obtain more information about the error. This routine is called with interrupts enabled, and a call to MiniportISR will occur if the adapter generates any interrupts. During this routine MiniportDisableInterrupt and MiniportEnableInterrupt will not be called, so it is the responsibility of the Miniport driver to acknowledge and clear any interrupts generated. This routine will be called from the context of MpRegisterMiniport(). Parameters: OpenErrorStatus _ Returns more information about the reason for the failure. Currently, the only values defined match those specified as Open Error Codes in Appendix B of the IBM Local Area Network Technical Reference. SelectedMediumIndex _ Returns the index in MediumArray of the medium type that the Miniport driver wishes to be viewed as. Note that even though the NDIS interface may complete this request asynchronously, it must return this index on completion of this function. MediumArray _ An array of medium types which the wrapper supports. MediumArraySize _ The number of elements in MediumArray. MiniportAdapterHandle _ A handle identifying the Miniport. The Miniport driver must supply this handle in future requests that refer to the Miniport. WrapperConfigurationContext _ The handle used for calls to NdisOpenConfiguration. Return Values: NDIS_STATUS_ADAPTER_NOT_FOUND NDIS_STATUS_FAILURE NDIS_STATUS_NOT_ACCEPTED NDIS_STATUS_OPEN_ERROR NDIS_STATUS_RESOURCES NDIS_STATUS_SUCCESS NDIS_STATUS_UNSUPPORTED_MEDIA ---------------------------------------------------------------------------*/ { NDIS_STATUS status = NDIS_STATUS_SUCCESS; ADAPTER* pAdapter = NULL; UINT i; TRACE( TL_I, TM_Mp, ("+MpInitialize") ); do { // // Select the medium // for (i=0; ilockAdapter ); pAdapter->ulMpFlags |= MPBF_MiniportHaltPending; NdisReleaseSpinLock( &pAdapter->lockAdapter ); // // Shutdown the tapi provider // { NDIS_TAPI_PROVIDER_SHUTDOWN DummyRequest; NdisZeroMemory( &DummyRequest, sizeof( NDIS_TAPI_PROVIDER_SHUTDOWN ) ); TpProviderShutdown( pAdapter, &DummyRequest, FALSE); } // // Remove the reference added in MpInitialize() // DereferenceAdapter( pAdapter ); // // Wait for all references to be removed // NdisWaitEvent( &pAdapter->eventAdapterHalted, 0 ); // // All references have been removed, now wait for all packets owned by NDIS // to be returned. // // Note that no synchronization is necesarry for reading the value of NumPacketsOwnedByNdis // at this point since it can only be incremented when there is at least 1 reference on the // binding - at this point ref count is 0 -, and because it can not be incremented, it can // only reach 0 once. // while ( pAdapter->NumPacketsOwnedByNdiswan ) { NdisMSleep( 10000 ); } // // Do deallocation of global resources first // NdisAcquireSpinLock( &gl_lockAdapter ); gl_pAdapter = NULL; PacketPoolUninit(); NdisReleaseSpinLock( &gl_lockAdapter ); // // Now we can clean up the adapter context // FreeAdapter( pAdapter ); TRACE( TL_I, TM_Mp, ("-MpHalt") ); } NDIS_STATUS MpReset( OUT PBOOLEAN AddressingReset, IN NDIS_HANDLE MiniportAdapterContext ) /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Functional Description: The MiniportReset request instructs the Miniport driver to issue a hardware reset to the network adapter. The Miniport driver also resets its software state. The MiniportReset request may also reset the parameters of the adapter. If a hardware reset of the adapter resets the current station address to a value other than what it is currently configured to, the Miniport driver automatically restores the current station address following the reset. Any multicast or functional addressing masks reset by the hardware do not have to be reprogrammed by the Miniport. NOTE: This is change from the NDIS 3.0 driver specification. If the multicast or functional addressing information, the packet filter, the lookahead size, and so on, needs to be restored, the Miniport indicates this with setting the flag AddressingReset to TRUE. It is not necessary for the Miniport to complete all outstanding requests and no other requests will be submitted to the Miniport until the operation is completed. Also, the Miniport does not have to signal the beginning and ending of the reset with NdisMIndicateStatus. NOTE: These are different than the NDIS 3.0 driver specification. The Miniport driver must complete the original request, if the orginal call to MiniportReset return NDIS_STATUS_PENDING, by calling NdisMResetComplete. If the underlying hardware does not provide a reset function under software control, then this request completes abnormally with NDIS_STATUS_NOT_RESETTABLE. If the underlying hardware attempts a reset and finds recoverable errors, the request completes successfully with NDIS_STATUS_SOFT_ERRORS. If the underlying hardware resets and, in the process, finds nonrecoverable errors, the request completes successfully with the status NDIS_STATUS_HARD_ERRORS. If the underlying hardware reset is accomplished without any errors, the request completes successfully with the status NDIS_STATUS_SUCCESS. Interrupts are in any state during this call. Parameters: MiniportAdapterContext _ The adapter handle passed to NdisMSetAttributes during MiniportInitialize. AddressingReset _ The Miniport indicates if the wrapper needs to call MiniportSetInformation to restore the addressing information to the current values by setting this value to TRUE. Return Values: NDIS_STATUS_HARD_ERRORS NDIS_STATUS_NOT_ACCEPTED NDIS_STATUS_NOT_RESETTABLE NDIS_STATUS_PENDING NDIS_STATUS_SOFT_ERRORS NDIS_STATUS_SUCCESS ---------------------------------------------------------------------------*/ { TRACE( TL_I, TM_Mp, ("+MpReset") ); TRACE( TL_I, TM_Mp, ("-MpReset") ); return NDIS_STATUS_NOT_RESETTABLE; } NDIS_STATUS MpWanSend( IN NDIS_HANDLE MiniportAdapterContext, IN NDIS_HANDLE NdisLinkHandle, IN PNDIS_WAN_PACKET WanPacket ) /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Functional Description: The Ndis(M)WanSend instructs a WAN driver to transmit a packet through the adapter onto the medium. Ownership of both the packet descriptor and the packet data is transferred to the WAN driver until the request is completed, either synchronously or asynchronously. If the WAN driver returns a status other than NDIS_STATUS_PENDING, then the request is complete, and ownership of the packet immediately reverts to the protocol. If the WAN driver returns NDIS_STATUS_PENDING, then the WAN driver must later indicate completion of the request by calling Ndis(M)WanSendComplete. The WAN driver should NOT return a status of NDIS_STATUS_RESOURCES to indicate that there are not enough resources available to process the transmit. Instead, the miniport should queue the send for a later time or lower the MaxTransmits value. The WAN miniport can NOT call NdisMSendResourcesAvailable. The packet passed in Ndis(M)WanSend will contain simple HDLC PPP framing if PPP framing is set. For SLIP or RAS framing, the packet contains only the data portion with no framing whatsoever. A WAN driver must NOT provide software loopback or promiscuous mode loopback. Both of these are fully provided for in the WAN wrapper. NOTE: The MacReservedx section as well as the WanPacketQueue section of the NDIS_WAN_PACKET is fully available for use by the WAN driver. Interrupts are in any state during this routine. Parameters: MacBindingHandle _ The handle to be passed to NdisMWanSendComplete(). NdisLinkHandle _ The Miniport link handle passed to NDIS_LINE_UP WanPacket _ A pointer to the NDIS_WAN_PACKET strucutre. The structure contains a pointer to a contiguous buffer with guaranteed padding at the beginning and end. The driver may manipulate the buffer in any way. typedef struct _NDIS_WAN_PACKET { LIST_ENTRY WanPacketQueue; PUCHAR CurrentBuffer; ULONG CurrentLength; PUCHAR StartBuffer; PUCHAR EndBuffer; PVOID ProtocolReserved1; PVOID ProtocolReserved2; PVOID ProtocolReserved3; PVOID ProtocolReserved4; PVOID MacReserved1; // Link PVOID MacReserved2; // MacBindingHandle PVOID MacReserved3; PVOID MacReserved4; } NDIS_WAN_PACKET, *PNDIS_WAN_PACKET; The available header padding is simply CurrentBuffer-StartBuffer. The available tail padding is EndBuffer-(CurrentBuffer+CurrentLength). Return Values: NDIS_STATUS_INVALID_DATA NDIS_STATUS_INVALID_LENGTH NDIS_STATUS_INVALID_OID NDIS_STATUS_NOT_ACCEPTED NDIS_STATUS_NOT_SUPPORTED NDIS_STATUS_PENDING NDIS_STATUS_SUCCESS NDIS_STATUS_FAILURE ---------------------------------------------------------------------------*/ { ADAPTER* pAdapter = MiniportAdapterContext; NDIS_STATUS status = NDIS_STATUS_FAILURE; CALL* pCall = NULL; BINDING* pBinding = NULL; PPPOE_PACKET* pPacket = NULL; BOOLEAN fTapiProvReferenced = FALSE; TRACE( TL_V, TM_Mp, ("+MpWanSend($%x,$%x,$%x)",MiniportAdapterContext,NdisLinkHandle,WanPacket) ); do { // // Make sure adapter context is a valid one // if ( !VALIDATE_ADAPTER( pAdapter ) ) { TRACE( TL_A, TM_Tp, ("MpWanSend($%x,$%x,$%x): Invalid adapter handle supplied", MiniportAdapterContext, NdisLinkHandle, WanPacket) ); break; } NdisAcquireSpinLock( &pAdapter->lockAdapter ); // // Make sure the handle table will not be freed as long as we need it // in this function // if ( !( pAdapter->TapiProv.ulTpFlags & TPBF_TapiProvShutdownPending ) && ( pAdapter->TapiProv.ulTpFlags & TPBF_TapiProvInitialized ) ) { fTapiProvReferenced = TRUE; ReferenceTapiProv( pAdapter, FALSE ); } else { NdisReleaseSpinLock( &pAdapter->lockAdapter ); TRACE( TL_A, TM_Tp, ("MpWanSend($%x,$%x,$%x): Tapi provider not initialized, or shutting down", MiniportAdapterContext, NdisLinkHandle, WanPacket) ); break; } // // Map the handle to the pointer for the call context // pCall = RetrieveFromHandleTable( pAdapter->TapiProv.hCallTable, NdisLinkHandle ); if ( pCall == NULL ) { NdisReleaseSpinLock( &pAdapter->lockAdapter ); TRACE( TL_A, TM_Tp, ("MpWanSend($%x,$%x,$%x): Invalid call handle supplied", MiniportAdapterContext, NdisLinkHandle, WanPacket) ); break; } NdisAcquireSpinLock( &pCall->lockCall ); if ( pCall->pBinding == NULL ) { NdisReleaseSpinLock( &pCall->lockCall ); NdisReleaseSpinLock( &pAdapter->lockAdapter ); TRACE( TL_A, TM_Tp, ("MpWanSend($%x,$%x,$%x): Binding not found", MiniportAdapterContext, NdisLinkHandle, WanPacket) ); break; } status = PacketInitializePAYLOADToSend( &pPacket, pCall->SrcAddr, pCall->DestAddr, pCall->usSessionId, WanPacket, pCall->pLine->pAdapter ); if ( status != NDIS_STATUS_SUCCESS ) { NdisReleaseSpinLock( &pCall->lockCall ); NdisReleaseSpinLock( &pAdapter->lockAdapter ); TRACE( TL_N, TM_Tp, ("MpWanSend($%x,$%x,$%x): Could not init payload packet to send", MiniportAdapterContext, NdisLinkHandle, WanPacket) ); break; } pBinding = pCall->pBinding; ReferenceBinding( pBinding, TRUE ); // // Reference the packet so that if PrSend() pends, // packet still exists around // ReferencePacket( pPacket ); // // Release the locks to send the packet // NdisReleaseSpinLock( &pCall->lockCall ); NdisReleaseSpinLock( &pAdapter->lockAdapter ); // // Packet is ready, so send it // status = PrSend( pBinding, pPacket ); // // Since the result of send will always be completed by a call to NdisMWanSendComplete(), // we have to return NDIS_STATUS_PENDING from this function. // status = NDIS_STATUS_PENDING; // // We can free the packet as we have a reference on the packet // PacketFree( pPacket ); } while ( FALSE ); // // If a reference is added on the tapi provider, remove it // if ( fTapiProvReferenced ) { DereferenceTapiProv( pAdapter ); } TRACE( TL_V, TM_Mp, ("-MpWanSend($%x,$%x,$%x)=$%x",MiniportAdapterContext,NdisLinkHandle,WanPacket,status) ); return status; } typedef struct _SUPPORTED_OIDS { NDIS_OID ndisOid; CHAR szOidName[64]; } SUPPORTED_OIDS; SUPPORTED_OIDS SupportedOidsArray[] = { { OID_GEN_CURRENT_LOOKAHEAD, "OID_GEN_CURRENT_LOOKAHEAD" }, { OID_GEN_DRIVER_VERSION, "OID_GEN_DRIVER_VERSION" }, { OID_GEN_HARDWARE_STATUS, "OID_GEN_HARDWARE_STATUS" }, { OID_GEN_LINK_SPEED, "OID_GEN_LINK_SPEED" }, { OID_GEN_MAC_OPTIONS, "OID_GEN_MAC_OPTIONS" }, { OID_GEN_MAXIMUM_LOOKAHEAD, "OID_GEN_MAXIMUM_LOOKAHEAD" }, { OID_GEN_MAXIMUM_FRAME_SIZE, "OID_GEN_MAXIMUM_FRAME_SIZE" }, { OID_GEN_MAXIMUM_TOTAL_SIZE, "OID_GEN_MAXIMUM_TOTAL_SIZE" }, { OID_GEN_MEDIA_SUPPORTED, "OID_GEN_MEDIA_SUPPORTED" }, { OID_GEN_MEDIA_IN_USE, "OID_GEN_MEDIA_IN_USE" }, { OID_GEN_RCV_ERROR, "OID_GEN_RCV_ERROR" }, { OID_GEN_RCV_OK, "OID_GEN_RCV_OK" }, { OID_GEN_RECEIVE_BLOCK_SIZE, "OID_GEN_RECEIVE_BLOCK_SIZE" }, { OID_GEN_RECEIVE_BUFFER_SPACE, "OID_GEN_RECEIVE_BUFFER_SPACE" }, { OID_GEN_SUPPORTED_LIST, "OID_GEN_SUPPORTED_LIST" }, { OID_GEN_TRANSMIT_BLOCK_SIZE, "OID_GEN_TRANSMIT_BLOCK_SIZE" }, { OID_GEN_TRANSMIT_BUFFER_SPACE, "OID_GEN_TRANSMIT_BUFFER_SPACE" }, { OID_GEN_VENDOR_DESCRIPTION, "OID_GEN_VENDOR_DESCRIPTION" }, { OID_GEN_VENDOR_ID, "OID_GEN_VENDOR_ID" }, { OID_GEN_XMIT_ERROR, "OID_GEN_XMIT_ERROR" }, { OID_GEN_XMIT_OK, "OID_GEN_XMIT_OK" }, { OID_PNP_CAPABILITIES, "OID_PNP_CAPABILITIES" }, { OID_PNP_SET_POWER, "OID_PNP_SET_POWER" }, { OID_PNP_QUERY_POWER, "OID_PNP_QUERY_POWER" }, { OID_PNP_ENABLE_WAKE_UP, "OID_PNP_ENABLE_WAKE_UP" }, { OID_TAPI_CLOSE, "OID_TAPI_CLOSE" }, { OID_TAPI_DROP, "OID_TAPI_DROP" }, { OID_TAPI_GET_ADDRESS_CAPS, "OID_TAPI_GET_ADDRESS_CAPS" }, { OID_TAPI_GET_ADDRESS_STATUS, "OID_TAPI_GET_ADDRESS_STATUS" }, { OID_TAPI_GET_CALL_INFO, "OID_TAPI_GET_CALL_INFO" }, { OID_TAPI_GET_CALL_STATUS, "OID_TAPI_GET_CALL_STATUS" }, { OID_TAPI_GET_DEV_CAPS, "OID_TAPI_GET_DEV_CAPS" }, { OID_TAPI_GET_EXTENSION_ID, "OID_TAPI_GET_EXTENSION_ID" }, { OID_TAPI_MAKE_CALL, "OID_TAPI_MAKE_CALL" }, { OID_TAPI_CLOSE_CALL, "OID_TAPI_CLOSE_CALL" }, { OID_TAPI_NEGOTIATE_EXT_VERSION, "OID_TAPI_NEGOTIATE_EXT_VERSION"}, { OID_TAPI_OPEN, "OID_TAPI_OPEN" }, { OID_TAPI_ANSWER, "OID_TAPI_ANSWER" }, { OID_TAPI_PROVIDER_INITIALIZE, "OID_TAPI_PROVIDER_INITIALIZE" }, { OID_TAPI_PROVIDER_SHUTDOWN, "OID_TAPI_PROVIDER_SHUTDOWN" }, { OID_TAPI_SET_STATUS_MESSAGES, "OID_TAPI_SET_STATUS_MESSAGES" }, { OID_TAPI_SET_DEFAULT_MEDIA_DETECTION, "OID_TAPI_SET_DEFAULT_MEDIA_DETECTION" }, { OID_WAN_CURRENT_ADDRESS, "OID_WAN_CURRENT_ADDRESS" }, { OID_WAN_GET_BRIDGE_INFO, "OID_WAN_GET_BRIDGE_INFO" }, { OID_WAN_GET_COMP_INFO, "OID_WAN_GET_COMP_INFO" }, { OID_WAN_GET_INFO, "OID_WAN_GET_INFO" }, { OID_WAN_GET_LINK_INFO, "OID_WAN_GET_LINK_INFO" }, { OID_WAN_GET_STATS_INFO, "OID_WAN_GET_STATS_INFO" }, { OID_WAN_HEADER_FORMAT, "OID_WAN_HEADER_FORMAT" }, { OID_WAN_LINE_COUNT, "OID_WAN_LINE_COUNT" }, { OID_WAN_MEDIUM_SUBTYPE, "OID_WAN_MEDIUM_SUBTYPE" }, { OID_WAN_PERMANENT_ADDRESS, "OID_WAN_PERMANENT_ADDRESS" }, { OID_WAN_PROTOCOL_TYPE, "OID_WAN_PERMANENT_ADDRESS" }, { OID_WAN_QUALITY_OF_SERVICE, "OID_WAN_QUALITY_OF_SERVICE" }, { OID_WAN_SET_BRIDGE_INFO, "OID_WAN_SET_BRIDGE_INFO" }, { OID_WAN_SET_COMP_INFO, "OID_WAN_SET_COMP_INFO" }, { OID_WAN_SET_LINK_INFO, "OID_WAN_SET_LINK_INFO" }, { (NDIS_OID) 0, "UNKNOWN OID" } }; CHAR* GetOidName( NDIS_OID Oid ) { // // Calculate the number of oids we support. // (Subtract one for unknown oid) // UINT nNumOids = ( sizeof( SupportedOidsArray ) / sizeof( SUPPORTED_OIDS ) ) - 1; UINT i; for ( i = 0; i < nNumOids; i++ ) { if ( Oid == SupportedOidsArray[i].ndisOid ) break; } return SupportedOidsArray[i].szOidName; } #define ENFORCE_SAFE_TOTAL_SIZE(mainStruct, embeddedStruct) \ ((mainStruct*) InformationBuffer)->embeddedStruct.ulTotalSize = InformationBufferLength - FIELD_OFFSET(mainStruct, embeddedStruct) #define RETRIEVE_NEEDED_AND_USED_LENGTH(mainStruct, embeddedStruct) \ { \ NeededLength = ((mainStruct*) InformationBuffer)->embeddedStruct.ulNeededSize + FIELD_OFFSET(mainStruct, embeddedStruct); \ UsedLength = ((mainStruct*) InformationBuffer)->embeddedStruct.ulUsedSize + FIELD_OFFSET(mainStruct, embeddedStruct); \ } NDIS_STATUS MpQueryInformation( IN NDIS_HANDLE MiniportAdapterContext, IN NDIS_OID Oid, IN PVOID InformationBuffer, IN ULONG InformationBufferLength, OUT PULONG BytesWritten, OUT PULONG BytesNeeded ) /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Functional Description: The MiniportQueryInformation request allows the inspection of the Miniport driver's capabilities and current status. If the Miniport does not complete the call immediately (by returning NDIS_STATUS_PENDING), it must call NdisMQueryInformationComplete to complete the call. The Miniport controls the buffers pointed to by InformationBuffer, BytesWritten, and BytesNeeded until the request completes. No other requests of the following kind will be submitted to the Miniport driver until this request has been completed: 1. MiniportQueryInformation() 2. MiniportSetInformation() 3. MiniportHalt() Note that the wrapper will intercept all queries of the following OIDs: OID_GEN_CURRENT_PACKET_FILTER, OID_GEN_PROTOCOL_OPTIONS, OID_802_5_CURRENT_FUNCTIONAL, OID_802_3_MULTICAST_LIST, OID_FDDI_LONG_MULTICAST_LIST, OID_FDDI_SHORT_MULTICAST_LIST. Interrupts are in any state during this call. Parameters: MiniportAdapterContext _ The adapter handle passed to NdisMSetAttributes during MiniportInitialize. Oid _ The OID. (See section 7.4 of the NDIS 3.0 specification for a complete description of OIDs.) InformationBuffer _ The buffer that will receive the information. (See section 7.4 of the NDIS 3.0 specification for a description of the length required for each OID.) InformationBufferLength _ The length in bytes of InformationBuffer. BytesWritten _ Returns the number of bytes written into InformationBuffer. BytesNeeded _ This parameter returns the number of additional bytes needed to satisfy the OID. Return Values: NDIS_STATUS_INVALID_DATA NDIS_STATUS_INVALID_LENGTH NDIS_STATUS_INVALID_OID NDIS_STATUS_NOT_ACCEPTED NDIS_STATUS_NOT_SUPPORTED NDIS_STATUS_PENDING NDIS_STATUS_RESOURCES NDIS_STATUS_FAILURE NDIS_STATUS_SUCCESS ---------------------------------------------------------------------------*/ { ADAPTER* pAdapter = (ADAPTER*) MiniportAdapterContext; NDIS_STATUS status = NDIS_STATUS_FAILURE; ULONG GenericUlong; PVOID SourceBuffer = NULL; ULONG NeededLength = 0; ULONG UsedLength = 0; // // This can be any string that represents PPPoE as a MAC address, but // it must be up to 6 chars long. // UCHAR PPPoEWanAddress[6] = { '3', 'P', 'o', 'E', '0', '0' }; TRACE( TL_I, TM_Mp, ("+MpQueryInformation($%x):%s",(ULONG) Oid, GetOidName( Oid ) ) ); // // Make sure adapter context is a valid one // if ( !VALIDATE_ADAPTER( pAdapter ) ) return status; switch ( Oid ) { case OID_GEN_MAXIMUM_LOOKAHEAD: { NeededLength = sizeof( GenericUlong ); GenericUlong = pAdapter->NdisWanInfo.MaxFrameSize; SourceBuffer = &GenericUlong; status = NDIS_STATUS_SUCCESS; break; } case OID_GEN_MAC_OPTIONS: { NeededLength = sizeof( GenericUlong ); GenericUlong = NDIS_MAC_OPTION_TRANSFERS_NOT_PEND; SourceBuffer = &GenericUlong; status = NDIS_STATUS_SUCCESS; break; } case OID_GEN_SUPPORTED_LIST: { // // Calculate the number of oids we support. // (Subtract one for unknown oid) // UINT nNumOids = ( sizeof( SupportedOidsArray ) / sizeof( SUPPORTED_OIDS ) ) - 1; NeededLength = nNumOids * sizeof( NDIS_OID ); if ( InformationBufferLength >= NeededLength ) { NDIS_OID* NdisOidArray = (NDIS_OID*) InformationBuffer; UINT i; for ( i = 0; i < nNumOids; i++ ) { NdisOidArray[i] = SupportedOidsArray[i].ndisOid; } status = NDIS_STATUS_SUCCESS; } break; } case OID_GEN_RCV_ERROR: case OID_GEN_RCV_OK: case OID_GEN_XMIT_ERROR: case OID_GEN_XMIT_OK: case OID_GEN_CURRENT_LOOKAHEAD: case OID_GEN_DRIVER_VERSION: case OID_GEN_HARDWARE_STATUS: case OID_GEN_LINK_SPEED: case OID_GEN_MAXIMUM_FRAME_SIZE: case OID_GEN_MAXIMUM_TOTAL_SIZE: case OID_GEN_MEDIA_SUPPORTED: case OID_GEN_MEDIA_IN_USE: case OID_GEN_RECEIVE_BLOCK_SIZE: case OID_GEN_RECEIVE_BUFFER_SPACE: case OID_GEN_TRANSMIT_BLOCK_SIZE: case OID_GEN_TRANSMIT_BUFFER_SPACE: case OID_GEN_VENDOR_DESCRIPTION: case OID_GEN_VENDOR_ID: { status = NDIS_STATUS_NOT_SUPPORTED; break; } case OID_TAPI_GET_ADDRESS_CAPS: { NeededLength = sizeof( NDIS_TAPI_GET_ADDRESS_CAPS ); if ( InformationBufferLength < NeededLength ) { break; } ENFORCE_SAFE_TOTAL_SIZE( NDIS_TAPI_GET_ADDRESS_CAPS, LineAddressCaps ); status = TpGetAddressCaps( pAdapter, (PNDIS_TAPI_GET_ADDRESS_CAPS) InformationBuffer ); RETRIEVE_NEEDED_AND_USED_LENGTH( NDIS_TAPI_GET_ADDRESS_CAPS, LineAddressCaps ); break; } case OID_TAPI_GET_CALL_INFO: { NeededLength = sizeof( NDIS_TAPI_GET_CALL_INFO ); if ( InformationBufferLength < NeededLength ) { break; } ENFORCE_SAFE_TOTAL_SIZE( NDIS_TAPI_GET_CALL_INFO, LineCallInfo ); status = TpGetCallInfo( pAdapter, (PNDIS_TAPI_GET_CALL_INFO) InformationBuffer ); RETRIEVE_NEEDED_AND_USED_LENGTH( NDIS_TAPI_GET_CALL_INFO, LineCallInfo ); break; } case OID_TAPI_GET_CALL_STATUS: { NeededLength = sizeof( NDIS_TAPI_GET_CALL_STATUS ); if ( InformationBufferLength < NeededLength ) { break; } ENFORCE_SAFE_TOTAL_SIZE( NDIS_TAPI_GET_CALL_STATUS, LineCallStatus ); status = TpGetCallStatus( pAdapter, (PNDIS_TAPI_GET_CALL_STATUS) InformationBuffer ); RETRIEVE_NEEDED_AND_USED_LENGTH( NDIS_TAPI_GET_CALL_STATUS, LineCallStatus ); break; } case OID_TAPI_GET_DEV_CAPS: { NeededLength = sizeof( NDIS_TAPI_GET_DEV_CAPS ); if ( InformationBufferLength < NeededLength ) { break; } ENFORCE_SAFE_TOTAL_SIZE( NDIS_TAPI_GET_DEV_CAPS, LineDevCaps ); status = TpGetDevCaps( pAdapter, (PNDIS_TAPI_GET_DEV_CAPS) InformationBuffer ); RETRIEVE_NEEDED_AND_USED_LENGTH( NDIS_TAPI_GET_DEV_CAPS, LineDevCaps ); break; } case OID_TAPI_GET_ID: { NeededLength = sizeof( NDIS_TAPI_GET_ID ); if ( InformationBufferLength < NeededLength ) { break; } ENFORCE_SAFE_TOTAL_SIZE( NDIS_TAPI_GET_ID, DeviceID ); status = TpGetId( pAdapter, (PNDIS_TAPI_GET_ID) InformationBuffer, InformationBufferLength ); RETRIEVE_NEEDED_AND_USED_LENGTH( NDIS_TAPI_GET_ID, DeviceID ); break; } case OID_TAPI_GET_ADDRESS_STATUS: { NeededLength = sizeof( NDIS_TAPI_GET_ADDRESS_STATUS ); if ( InformationBufferLength < NeededLength ) { break; } ENFORCE_SAFE_TOTAL_SIZE( NDIS_TAPI_GET_ADDRESS_STATUS, LineAddressStatus ); status = TpGetAddressStatus( pAdapter, (PNDIS_TAPI_GET_ADDRESS_STATUS) InformationBuffer ); RETRIEVE_NEEDED_AND_USED_LENGTH( NDIS_TAPI_GET_ADDRESS_STATUS, LineAddressStatus ); break; } case OID_TAPI_GET_EXTENSION_ID: { NeededLength = sizeof( NDIS_TAPI_GET_EXTENSION_ID ); if ( InformationBufferLength < NeededLength ) { break; } status = TpGetExtensionId( pAdapter, (PNDIS_TAPI_GET_EXTENSION_ID) InformationBuffer ); break; } case OID_TAPI_MAKE_CALL: { NeededLength = sizeof( NDIS_TAPI_MAKE_CALL ); if ( InformationBufferLength < NeededLength ) { break; } ENFORCE_SAFE_TOTAL_SIZE( NDIS_TAPI_MAKE_CALL, LineCallParams ); status = TpMakeCall( pAdapter, (PNDIS_TAPI_MAKE_CALL) InformationBuffer, InformationBufferLength ); break; } case OID_TAPI_NEGOTIATE_EXT_VERSION: { NeededLength = sizeof( NDIS_TAPI_NEGOTIATE_EXT_VERSION ); if ( InformationBufferLength < NeededLength ) { break; } status = TpNegotiateExtVersion( pAdapter, (PNDIS_TAPI_NEGOTIATE_EXT_VERSION) InformationBuffer ); break; } case OID_TAPI_OPEN: { NeededLength = sizeof( NDIS_TAPI_OPEN ); if ( InformationBufferLength < NeededLength ) { break; } status = TpOpenLine( pAdapter, (PNDIS_TAPI_OPEN) InformationBuffer ); break; } case OID_TAPI_PROVIDER_INITIALIZE: { NeededLength = sizeof( NDIS_TAPI_PROVIDER_INITIALIZE ); if ( InformationBufferLength < NeededLength ) { break; } status = TpProviderInitialize( pAdapter, (PNDIS_TAPI_PROVIDER_INITIALIZE) InformationBuffer ); break; } case OID_WAN_GET_INFO: { NeededLength = sizeof( NDIS_WAN_INFO ); if ( InformationBufferLength < NeededLength ) { break; } status = MpWanGetInfo( pAdapter, (PNDIS_WAN_INFO) InformationBuffer ); break; } case OID_WAN_MEDIUM_SUBTYPE: { NeededLength = sizeof( GenericUlong ); GenericUlong = NdisWanMediumPppoe; SourceBuffer = &GenericUlong; status = NDIS_STATUS_SUCCESS; break; } case OID_WAN_CURRENT_ADDRESS: case OID_WAN_PERMANENT_ADDRESS: { NeededLength = sizeof( PPPoEWanAddress ); SourceBuffer = PPPoEWanAddress; status = NDIS_STATUS_SUCCESS; break; } case OID_WAN_GET_LINK_INFO: { NeededLength = sizeof( NDIS_WAN_GET_LINK_INFO ); if ( InformationBufferLength < NeededLength ) { break; } status = MpWanGetLinkInfo( pAdapter, (PNDIS_WAN_GET_LINK_INFO) InformationBuffer ); break; } case OID_WAN_GET_BRIDGE_INFO: case OID_WAN_GET_STATS_INFO: case OID_WAN_HEADER_FORMAT: case OID_WAN_LINE_COUNT: case OID_WAN_PROTOCOL_TYPE: case OID_WAN_QUALITY_OF_SERVICE: case OID_WAN_SET_BRIDGE_INFO: case OID_WAN_SET_COMP_INFO: case OID_WAN_SET_LINK_INFO: case OID_WAN_GET_COMP_INFO: { status = NDIS_STATUS_NOT_SUPPORTED; break; } case OID_PNP_CAPABILITIES: { NDIS_PNP_CAPABILITIES UNALIGNED * pPnpCaps = (NDIS_PNP_CAPABILITIES UNALIGNED *) InformationBuffer; NeededLength = sizeof( NDIS_PNP_CAPABILITIES ); if ( InformationBufferLength < NeededLength ) { break; } pPnpCaps->Flags = 0; pPnpCaps->WakeUpCapabilities.MinMagicPacketWakeUp = NdisDeviceStateUnspecified; pPnpCaps->WakeUpCapabilities.MinPatternWakeUp = NdisDeviceStateUnspecified; pPnpCaps->WakeUpCapabilities.MinLinkChangeWakeUp = NdisDeviceStateUnspecified; status = NDIS_STATUS_SUCCESS; break; } case OID_PNP_QUERY_POWER: case OID_PNP_ENABLE_WAKE_UP: { NeededLength = 0; status = NDIS_STATUS_SUCCESS; break; } default: { // // Unknown OID // status = NDIS_STATUS_INVALID_OID; break; } } if ( status != NDIS_STATUS_NOT_SUPPORTED && status != NDIS_STATUS_INVALID_OID ) { if ( InformationBufferLength >= NeededLength ) { if ( status == NDIS_STATUS_SUCCESS ) { if ( SourceBuffer ) { NdisMoveMemory( InformationBuffer, SourceBuffer, NeededLength ); } *BytesWritten = NeededLength; } else if ( status == NDIS_STATUS_INVALID_LENGTH ) { *BytesWritten = 0; *BytesNeeded = NeededLength; } } else { *BytesWritten = 0; *BytesNeeded = NeededLength; status = NDIS_STATUS_INVALID_LENGTH; } } TRACE( TL_I, TM_Mp, ("-MpQueryInformation()=$%x",status) ); return status; } NDIS_STATUS MpSetInformation( IN NDIS_HANDLE MiniportAdapterContext, IN NDIS_OID Oid, IN PVOID InformationBuffer, IN ULONG InformationBufferLength, OUT PULONG BytesWritten, OUT PULONG BytesNeeded ) /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Functional Description: The MiniportSetInformation request allows for control of the Miniport by changing information maintained by the Miniport driver. Any of the settable NDIS Global Oids may be used. (see section 7.4 of the NDIS 3.0 specification for a complete description of the NDIS Oids.) If the Miniport does not complete the call immediately (by returning NDIS_STATUS_PENDING), it must call NdisMSetInformationComplete to complete the call. The Miniport controls the buffers pointed to by InformationBuffer, BytesRead, and BytesNeeded until the request completes. Interrupts are in any state during the call, and no other requests will be submitted to the Miniport until this request is completed. Parameters: MiniportAdapterContext _ The adapter handle passed to NdisMSetAttributes during MiniportInitialize. Oid _ The OID. (See section 7.4 of the NDIS 3.0 specification for a complete description of OIDs.) InformationBuffer _ The buffer that will receive the information. (See section 7.4 of the NDIS 3.0 specification for a description of the length required for each OID.) InformationBufferLength _ The length in bytes of InformationBuffer. BytesRead_ Returns the number of bytes read from InformationBuffer. BytesNeeded _ This parameter returns the number of additional bytes expected to satisfy the OID. Return Values: NDIS_STATUS_INVALID_DATA NDIS_STATUS_INVALID_LENGTH NDIS_STATUS_INVALID_OID NDIS_STATUS_NOT_ACCEPTED NDIS_STATUS_NOT_SUPPORTED NDIS_STATUS_PENDING NDIS_STATUS_RESOURCES NDIS_STATUS_SUCCESS ---------------------------------------------------------------------------*/ { ADAPTER* pAdapter = MiniportAdapterContext; NDIS_STATUS status = NDIS_STATUS_FAILURE; PVOID SourceBuffer = NULL; ULONG NeededLength = 0; ULONG GenericUlong; TRACE( TL_I, TM_Mp, ("+MpSetInformation($%x):%s",(ULONG) Oid, GetOidName( Oid ) ) ); // // Make sure adapter context is a valid one // if ( !VALIDATE_ADAPTER( pAdapter ) ) return status; switch ( Oid ) { case OID_TAPI_ANSWER: { NeededLength = sizeof( NDIS_TAPI_ANSWER ); if ( InformationBufferLength < NeededLength ) { break; } status = TpAnswerCall( pAdapter, (PNDIS_TAPI_ANSWER) InformationBuffer ); break; } case OID_TAPI_CLOSE: { NeededLength = sizeof( NDIS_TAPI_CLOSE ); if ( InformationBufferLength < NeededLength ) { break; } status = TpCloseLine( pAdapter, (PNDIS_TAPI_CLOSE) InformationBuffer, TRUE); break; } case OID_TAPI_CLOSE_CALL: { NeededLength = sizeof( NDIS_TAPI_CLOSE_CALL ); if ( InformationBufferLength < NeededLength ) { break; } status = TpCloseCall( pAdapter, (PNDIS_TAPI_CLOSE_CALL) InformationBuffer, TRUE ); break; } case OID_TAPI_DROP: { NeededLength = sizeof( NDIS_TAPI_DROP ); if ( InformationBufferLength < NeededLength ) { break; } status = TpDropCall( pAdapter, (PNDIS_TAPI_DROP) InformationBuffer, 0 ); break; } case OID_TAPI_PROVIDER_SHUTDOWN: { NeededLength = sizeof( NDIS_TAPI_PROVIDER_SHUTDOWN ); if ( InformationBufferLength < NeededLength ) { break; } status = TpProviderShutdown( pAdapter, (PNDIS_TAPI_PROVIDER_SHUTDOWN) InformationBuffer, TRUE ); break; } case OID_TAPI_SET_DEFAULT_MEDIA_DETECTION: { NeededLength = sizeof( NDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION ); if ( InformationBufferLength < NeededLength ) { break; } status = TpSetDefaultMediaDetection( pAdapter, (PNDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION) InformationBuffer ); break; } case OID_TAPI_SET_STATUS_MESSAGES: { NeededLength = sizeof( NDIS_TAPI_SET_STATUS_MESSAGES ); if ( InformationBufferLength < NeededLength ) { break; } status = TpSetStatusMessages( pAdapter, (PNDIS_TAPI_SET_STATUS_MESSAGES) InformationBuffer ); break; } case OID_WAN_SET_LINK_INFO: { NeededLength = sizeof( NDIS_WAN_SET_LINK_INFO ); if ( InformationBufferLength < NeededLength ) { break; } status = MpWanSetLinkInfo( pAdapter, (PNDIS_WAN_SET_LINK_INFO) InformationBuffer ); break; } case OID_PNP_SET_POWER: case OID_PNP_ENABLE_WAKE_UP: { NeededLength = 0; status = NDIS_STATUS_SUCCESS; break; } default: { // // Unknown OID // status = NDIS_STATUS_INVALID_OID; break; } } if ( status != NDIS_STATUS_NOT_SUPPORTED && status != NDIS_STATUS_INVALID_OID ) { if ( InformationBufferLength >= NeededLength ) { if ( SourceBuffer ) NdisMoveMemory( InformationBuffer, SourceBuffer, NeededLength ); *BytesWritten = NeededLength; } else { *BytesWritten = 0; *BytesNeeded = NeededLength; status = NDIS_STATUS_INVALID_LENGTH; } } TRACE( TL_I, TM_Mp, ("-MpSetInformation()=$%x",status) ); return status; } VOID MpNotifyBindingRemoval( BINDING* pBinding ) /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Functional Description: This function will be called by the protocol module to notify the miniport about the removal of a binding. Miniport identifies and drops the calls over the binding.. Parameters: pBinding _ A pointer to our binding information structure. Return Values: None ---------------------------------------------------------------------------*/ { ADAPTER* pAdapter = NULL; ASSERT( VALIDATE_BINDING( pBinding ) ); TRACE( TL_N, TM_Mp, ("+MpNotifyBindingRemoval($%x)",pBinding) ); if ( !gl_fLockAllocated ) { TRACE( TL_A, TM_Mp, ("MpNotifyBindingRemoval($%x): Global lock not allocated yet",pBinding) ); TRACE( TL_N, TM_Mp, ("-MpNotifyBindingRemoval($%x)",pBinding) ); return; } NdisAcquireSpinLock( &gl_lockAdapter ); if ( gl_pAdapter && !( gl_pAdapter->ulMpFlags & MPBF_MiniportHaltPending ) && ( gl_pAdapter->ulMpFlags & MPBF_MiniportInitialized ) ) { pAdapter = gl_pAdapter; NdisAcquireSpinLock( &pAdapter->lockAdapter ); if ( !( pAdapter->TapiProv.ulTpFlags & TPBF_TapiProvShutdownPending ) && ( pAdapter->TapiProv.ulTpFlags & TPBF_TapiProvInitialized ) ) { ReferenceTapiProv( pAdapter, FALSE ); NdisReleaseSpinLock( &pAdapter->lockAdapter ); } else { NdisReleaseSpinLock( &pAdapter->lockAdapter ); pAdapter = NULL; } } NdisReleaseSpinLock( &gl_lockAdapter ); if ( pAdapter == NULL ) { TRACE( TL_A, TM_Mp, ("MpNotifyBindingRemoval($%x): Tapi provider not initialized or no adapters found",pBinding) ); TRACE( TL_N, TM_Mp, ("-MpNotifyBindingRemoval($%x)",pBinding) ); return; } // // Complete any queued received packets in case PrReceiveComplete() // is not called // PrReceiveComplete( pBinding ); NdisAcquireSpinLock( &pAdapter->lockAdapter ); do { HANDLE_TABLE hCallTable = NULL; UINT hCallTableSize = 0; UINT i = 0; CALL* pCall; HDRV_CALL hdCall; // // Traverse the call handle table and drop calls over // the removed binding // hCallTableSize = pAdapter->nMaxLines * pAdapter->nCallsPerLine; hCallTable = pAdapter->TapiProv.hCallTable; for ( i = 0; i < hCallTableSize; i++ ) { NDIS_TAPI_DROP DummyRequest; BOOLEAN fDropCall = FALSE; pCall = RetrieveFromHandleTableByIndex( hCallTable, (USHORT) i ); if ( pCall == NULL ) continue; NdisAcquireSpinLock( &pCall->lockCall ); if ( pCall->pBinding == pBinding ) { // // This call is over the removed binding, // so it should be dropped // ReferenceCall( pCall, FALSE ); fDropCall = TRUE; } NdisReleaseSpinLock( &pCall->lockCall ); if ( !fDropCall ) { pCall = NULL; continue; } NdisReleaseSpinLock( &pAdapter->lockAdapter ); // // Initialize the request, and drop the call // DummyRequest.hdCall = pCall->hdCall; TpDropCall( pAdapter, &DummyRequest, LINEDISCONNECTMODE_UNREACHABLE ); // // Remove the reference added above // DereferenceCall( pCall ); // // Re-acquire the adapter's lock // NdisAcquireSpinLock( &pAdapter->lockAdapter ); } } while ( FALSE ); NdisReleaseSpinLock( &pAdapter->lockAdapter ); // // Remove the reference added above // DereferenceTapiProv( pAdapter ); TRACE( TL_N, TM_Mp, ("-MpNotifyBindingRemoval($%x)",pBinding) ); } CALL* MpMapPacketWithSessionIdToCall( IN ADAPTER* pAdapter, IN PPPOE_PACKET* pPacket ) /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Functional Description: This function will be called to map an in session packet to a call in call handle table. If such a call is identified, it will be referenced and a pointer to it will be returned. It is the caller's responsibility to remove the added reference. Parameters: pAdapter _ A pointer to our adapter information structure. pPacket _ A PPPoE packet received over the wire. Return Values: A pointer to the call context that the packet must be dispatched to. NULL if no such calls could be identified. ---------------------------------------------------------------------------*/ { CALL* pCall = NULL; CALL* pReturnCall = NULL; TRACE( TL_V, TM_Mp, ("+MpMapPacketWithSessionIdToCall($%x)",pPacket) ); NdisAcquireSpinLock( &pAdapter->lockAdapter ); if ( pAdapter->fClientRole ) { HANDLE_TABLE hCallTable = NULL; UINT hCallTableSize = 0; UINT i = 0; CHAR* pSrcAddr = PacketGetSrcAddr( pPacket ); CHAR* pDestAddr = PacketGetDestAddr( pPacket ); USHORT usSessionId = PacketGetSessionId( pPacket ); // // Miniport acting as a client: // Our algorithm is to search for the call handle table // to find the matching call // hCallTableSize = pAdapter->nMaxLines * pAdapter->nCallsPerLine; hCallTable = pAdapter->TapiProv.hCallTable; for ( i = 0; i < hCallTableSize ; i++ ) { pCall = RetrieveFromHandleTableByIndex( hCallTable, (USHORT) i ); if ( pCall == NULL ) continue; if ( ( pCall->usSessionId == usSessionId ) && ( NdisEqualMemory( pCall->SrcAddr, pDestAddr, 6 * sizeof( CHAR ) ) ) && ( NdisEqualMemory( pCall->DestAddr, pSrcAddr, 6 * sizeof( CHAR ) ) ) ) { // // The packet is intended for this call // ReferenceCall( pCall, TRUE ); pReturnCall = pCall; break; } } } else { HANDLE_TABLE hCallTable = NULL; CHAR* pSrcAddr = PacketGetSrcAddr( pPacket ); CHAR* pDestAddr = PacketGetDestAddr( pPacket ); USHORT usSessionId = PacketGetSessionId( pPacket ); // // Miniport acting as a server: // Our algorithm is to use the session id directly as the index // to the call handle table // hCallTable = pAdapter->TapiProv.hCallTable; pCall = RetrieveFromHandleTableBySessionId( hCallTable, usSessionId ); if ( pCall ) { if ( ( pCall->usSessionId == usSessionId ) && ( NdisEqualMemory( pCall->SrcAddr, pDestAddr, 6 * sizeof( CHAR ) ) ) && ( NdisEqualMemory( pCall->DestAddr, pSrcAddr, 6 * sizeof( CHAR ) ) ) ) { ReferenceCall( pCall, TRUE ); pReturnCall = pCall; } } } NdisReleaseSpinLock( &pAdapter->lockAdapter ); TRACE( TL_V, TM_Mp, ("-MpMapPacketWithSessionIdToCall($%x)=$%x",pPacket,pReturnCall) ); return pReturnCall; } CALL* MpMapPacketWithoutSessionIdToCall( IN ADAPTER* pAdapter, IN PPPOE_PACKET* pPacket ) /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Functional Description: This function will be called to map an out of session packet to a call that is in connecting state. If such a call is identified, it will be referenced and a pointer to it will be returned. It is the caller's responsibility to remove the added reference. This function will only be called for PADO or PADS packets. We use the HostUnique tags to save the handle to the call, and use them to map the returned packet back to the related call. This provides a very efficient mapping for these control packets. Our HostUnique tags are prepared in this way. We append hdCall, which is unique for a call, to a uniquely generated ULONG value to come up with a longer unique value. And when we receive the packet we decode the unique value to reach hdCall and use that to retrieve the call pointer. Parameters: pAdapter _ A pointer to our adapter information structure. pPacket _ A PPPoE packet received over the wire. Return Values: A pointer to the call context that the packet must be dispatched to. NULL if no such calls could be identified. ---------------------------------------------------------------------------*/ { USHORT usCode = PacketGetCode( pPacket ); CHAR* pUniqueValue = NULL; USHORT UniqueValueSize = 0; HDRV_CALL hdCall = (HDRV_CALL) NULL; CALL* pCall = NULL; TRACE( TL_N, TM_Mp, ("+MpMapPacketWithoutSessionIdToCall($%x)",pPacket) ); PacketRetrieveHostUniqueTag( pPacket, &UniqueValueSize, &pUniqueValue ); if ( pUniqueValue == NULL ) { TRACE( TL_A, TM_Mp, ("MpMapPacketWithoutSessionIdToCall($%x): Could not retrieve HostUnique tag",pPacket) ); TRACE( TL_N, TM_Mp, ("-MpMapPacketWithoutSessionIdToCall($%x)",pPacket) ); return NULL; } // // Decode the unique value and retrieve the call handle // hdCall = RetrieveHdCallFromUniqueValue( pUniqueValue, UniqueValueSize ); if ( hdCall == (HDRV_CALL) NULL ) { TRACE( TL_A, TM_Mp, ("MpMapPacketWithoutSessionIdToCall($%x): Could not retrieve call handle from unique value",pPacket) ); TRACE( TL_N, TM_Mp, ("-MpMapPacketWithoutSessionIdToCall($%x)",pPacket) ); return NULL; } NdisAcquireSpinLock( &pAdapter->lockAdapter ); // // Retrieve the call pointer using the call handle // pCall = RetrieveFromHandleTable( pAdapter->TapiProv.hCallTable, (NDIS_HANDLE) hdCall ); if ( pCall ) { if ( !( pCall->ulClFlags & CLBF_CallDropped || pCall->ulClFlags & CLBF_CallClosePending ) ) { ReferenceCall( pCall, TRUE ); } else { pCall = NULL; } } NdisReleaseSpinLock( &pAdapter->lockAdapter ); TRACE( TL_N, TM_Mp, ("-MpMapPacketWithoutSessionIdToCall($%x)=$%x",pPacket,pCall) ); return pCall; } BOOLEAN MpVerifyServiceName( IN ADAPTER* pAdapter, IN PPPOE_PACKET* pPacket, IN BOOLEAN fAcceptEmptyServiceNameTag ) /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Functional Description: This function will be called to verify that a requested service name is supported by our server. CAUTION: Do not attempt to lock anything inside this function, and make sure not to call any function that may do it because it must be lock free (caller might be holding locks). Parameters: pAdapter _ Pointer to the adapter structure that received the packet. pPacket _ A PADI or PADR packet received. fAcceptEmptyServiceNameTag _ An empty service name tag is valid in a PADI packet but not in a PADR packet. This flag indicates this behavior. Return Values: None ---------------------------------------------------------------------------*/ { BOOLEAN fRet = FALSE; USHORT tagServiceNameLength = 0; CHAR* tagServiceNameValue = NULL; TRACE( TL_V, TM_Mp, ("+MpVerifyServiceName($%x)",pPacket) ); RetrieveTag( pPacket, tagServiceName, &tagServiceNameLength, &tagServiceNameValue, 0, NULL, FALSE ); do { if ( fAcceptEmptyServiceNameTag ) { if ( tagServiceNameLength == 0 && tagServiceNameValue != NULL ) { fRet = TRUE; break; } } if ( tagServiceNameLength == pAdapter->nServiceNameLength && NdisEqualMemory( tagServiceNameValue, pAdapter->ServiceName, tagServiceNameLength) ) { fRet = TRUE; } } while ( FALSE ); TRACE( TL_V, TM_Mp, ("-MpVerifyServiceName($%x)=$%x",pPacket,fRet) ); return fRet; } VOID MpReplyToPADI( IN ADAPTER* pAdapter, IN BINDING* pBinding, IN PPPOE_PACKET* pPADI ) /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Functional Description: This function will be called when a PADI packet is received. It will look at the services we offer and reply to the PADI packet with a PADO packet informing the client of our services. Parameters: pAdapter _ Pointer to the adapter structure that received the packet. pBinding _ Pointer to the binding that the packet is received over. pPacket _ A received PADI packet. Return Values: None ---------------------------------------------------------------------------*/ { TRACE( TL_N, TM_Mp, ("+MpReplyToPADI") ); // // Verify the requested service name and // if ( MpVerifyServiceName( pAdapter, pPADI, TRUE ) ) { NDIS_STATUS status; PPPOE_PACKET* pPADO = NULL; status = PacketInitializePADOToSend( pPADI, &pPADO, pBinding->LocalAddress, pAdapter->nServiceNameLength, pAdapter->ServiceName, pAdapter->nACNameLength, pAdapter->ACName, TRUE ); if ( status == NDIS_STATUS_SUCCESS ) { // // Insert the empty generic service name tag // status = PacketInsertTag( pPADO, tagServiceName, 0, NULL, NULL ); if ( status == NDIS_STATUS_SUCCESS ) { UINT i; ReferencePacket( pPADO ); ReferenceBinding( pBinding, TRUE ); PrSend( pBinding, pPADO ); PacketFree( pPADO ); } } } TRACE( TL_N, TM_Mp, ("-MpReplyToPADI") ); } BOOLEAN MpCheckClientQuota( IN ADAPTER* pAdapter, IN PPPOE_PACKET* pPacket ) { BOOLEAN fRet = FALSE; HANDLE_TABLE hCallTable = NULL; UINT hCallTableSize = 0; CALL* pCall; CHAR *pSrcAddr = NULL; UINT nNumCurrentConn = 0; UINT i; TRACE( TL_N, TM_Mp, ("+MpCheckClientQuota") ); pSrcAddr = PacketGetSrcAddr( pPacket ); NdisAcquireSpinLock( &pAdapter->lockAdapter ); hCallTableSize = pAdapter->nMaxLines * pAdapter->nCallsPerLine; hCallTable = pAdapter->TapiProv.hCallTable; for ( i = 0; i < hCallTableSize; i++ ) { pCall = RetrieveFromHandleTableByIndex( hCallTable, (USHORT) i ); if ( pCall == NULL ) continue; if ( NdisEqualMemory( pCall->DestAddr, pSrcAddr, 6 * sizeof( CHAR ) ) ) { nNumCurrentConn++; continue; } } NdisReleaseSpinLock( &pAdapter->lockAdapter ); if ( nNumCurrentConn < pAdapter->nClientQuota ) { fRet = TRUE; } TRACE( TL_N, TM_Mp, ("-MpCheckClientQuota=$%d",(UINT) fRet) ); return fRet; } VOID MpSendPADSWithError( IN BINDING* pBinding, IN PPPOE_PACKET* pPADR, IN ULONG ulErrorCode ) { NDIS_STATUS status; PPPOE_PACKET* pPADS = NULL; TRACE( TL_N, TM_Mp, ("+MpSendPADSWithError") ); status = PacketInitializePADSToSend( pPADR, &pPADS, (USHORT) 0 ); if ( status == NDIS_STATUS_SUCCESS ) { switch (ulErrorCode) { case PPPOE_ERROR_SERVICE_NOT_SUPPORTED: status = PacketInsertTag( pPADS, tagServiceNameError, PPPOE_ERROR_SERVICE_NOT_SUPPORTED_MSG_SIZE, PPPOE_ERROR_SERVICE_NOT_SUPPORTED_MSG, NULL ); break; case PPPOE_ERROR_INVALID_AC_COOKIE_TAG: status = PacketInsertTag( pPADS, tagGenericError, PPPOE_ERROR_INVALID_AC_COOKIE_TAG_MSG_SIZE, PPPOE_ERROR_INVALID_AC_COOKIE_TAG_MSG, NULL ); break; case PPPOE_ERROR_CLIENT_QUOTA_EXCEEDED: status = PacketInsertTag( pPADS, tagACSystemError, PPPOE_ERROR_CLIENT_QUOTA_EXCEEDED_MSG_SIZE, PPPOE_ERROR_CLIENT_QUOTA_EXCEEDED_MSG, NULL ); break; } } if ( status == NDIS_STATUS_SUCCESS ) { ReferencePacket( pPADS ); ReferenceBinding( pBinding, TRUE ); PrSend( pBinding, pPADS ); } if ( pPADS ) { PacketFree( pPADS ); } TRACE( TL_N, TM_Mp, ("-MpSendPADSWithError") ); } VOID MpRecvCtrlPacket( IN BINDING* pBinding, IN PPPOE_PACKET* pPacket ) /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Functional Description: This function will be called by MpRecvPacket() when the packet received is a control packet. Caller (MpRecPacket()) will make sure that in the context of this function gl_pAdapter, gl_pAdapter->TapiProv.hCallTable and gl_pAdapter->TapiProv.hLineTable are valid. It will also reference and dereference TapiProv correctly. This function will identify the call the packet is for and dispatch the packet to it. Parameters: pBinding _ Pointer to the binding structure that packet was received over. pPacket _ A PPPoE packet received over the wire. Return Values: None ---------------------------------------------------------------------------*/ { ADAPTER* pAdapter = NULL; BOOLEAN fIndicateReceive = FALSE; USHORT usCode; CALL* pCall = NULL; TRACE( TL_N, TM_Mp, ("+MpRecvCtrlPacket($%x)",pPacket) ); pAdapter = gl_pAdapter; usCode = PacketGetCode( pPacket ); switch( usCode ) { case PACKET_CODE_PADI: // // Ignore the received PADI packets unless we act as a server and we have open lines. // if ( !pAdapter->fClientRole && ( pAdapter->TapiProv.nActiveLines > 0 ) ) { TRACE( TL_N, TM_Mp, ("MpRecvCtrlPacket($%x): PADI received",pPacket) ); MpReplyToPADI( pAdapter, pBinding, pPacket ); } break; case PACKET_CODE_PADR: // // Ignore the received PADR packets unless we act as a server. // if ( !pAdapter->fClientRole ) { ULONG ulErrorCode = PPPOE_NO_ERROR; TRACE( TL_N, TM_Mp, ("MpRecvCtrlPacket($%x): PADR received",pPacket) ); // // Verify the requested service name and validate the AC Cookie // tag, and if they look OK, then start receiving the call. // if ( !MpVerifyServiceName( pAdapter, pPacket, TRUE ) ) { ulErrorCode = PPPOE_ERROR_SERVICE_NOT_SUPPORTED; } else if ( !PacketValidateACCookieTagInPADR( pPacket ) ) { ulErrorCode = PPPOE_ERROR_INVALID_AC_COOKIE_TAG; } else if ( !MpCheckClientQuota( pAdapter, pPacket ) ) { ulErrorCode = PPPOE_ERROR_CLIENT_QUOTA_EXCEEDED; } if ( ulErrorCode == PPPOE_NO_ERROR ) { TpReceiveCall( pAdapter, pBinding, pPacket ); } else { MpSendPADSWithError( pBinding, pPacket, ulErrorCode ); } } break; case PACKET_CODE_PADO: if ( pAdapter->fClientRole ) { TRACE( TL_N, TM_Mp, ("MpRecvCtrlPacket($%x): PADO received",pPacket) ); // // Retrieve the call handle from the PADO packet // pCall = MpMapPacketWithoutSessionIdToCall( pAdapter, pPacket ); if ( pCall ) { // // Dispatch the packet to related call // FsmRun( pCall, pBinding, pPacket, NULL ); // // Remove the reference added in MpMapPacketWithoutSessionIdToCall() // DereferenceCall( pCall ); } } break; case PACKET_CODE_PADS: if ( pAdapter->fClientRole ) { TRACE( TL_N, TM_Mp, ("MpRecvCtrlPacket($%x): PADS received",pPacket) ); // // Retrieve the call handle from the PADS packet // pCall = MpMapPacketWithoutSessionIdToCall( pAdapter, pPacket ); if ( pCall ) { // // For PADS packet, we must make sure that no other calls // between the same 2 machines already have the same session id. // { HANDLE_TABLE hCallTable = NULL; UINT hCallTableSize = 0; UINT i = 0; USHORT usSessionId = PacketGetSessionId( pPacket ); CHAR* pSrcAddr = PacketGetSrcAddr( pPacket ); CHAR* pDestAddr = PacketGetDestAddr( pPacket ); BOOLEAN fDuplicateFound = FALSE; CALL* pTempCall = NULL; TRACE( TL_N, TM_Mp, ("MpRecvCtrlPacket($%x): Checking for duplicate session",pPacket) ); NdisAcquireSpinLock( &pAdapter->lockAdapter ); hCallTableSize = pAdapter->nMaxLines * pAdapter->nCallsPerLine; hCallTable = pAdapter->TapiProv.hCallTable; for ( i = 0; i < hCallTableSize ; i++ ) { pTempCall = RetrieveFromHandleTableByIndex( hCallTable, (USHORT) i ); if ( pTempCall == NULL ) continue; if ( ( pTempCall->usSessionId == usSessionId ) && ( NdisEqualMemory( pTempCall->SrcAddr, pSrcAddr, 6 * sizeof( CHAR ) ) ) && ( NdisEqualMemory( pTempCall->DestAddr, pDestAddr, 6 * sizeof( CHAR ) ) ) ) { // // Another call has been detected between the 2 machines with the same // session id, so do not accept this session // fDuplicateFound = TRUE; break; } } NdisReleaseSpinLock( &pAdapter->lockAdapter ); if ( fDuplicateFound ) { // // We have found another session with the same machine that has the // same session id, so we can not accept this new session. // // Remove the reference added in MpMapPacketWithoutSessionId() and // drop the packet // TRACE( TL_A, TM_Mp, ("MpRecvCtrlPacket($%x): Packet dropped - Duplicate session found",pPacket) ); DereferenceCall( pCall ); break; } } TRACE( TL_N, TM_Mp, ("MpRecvCtrlPacket($%x): No duplicate sessions found",pPacket) ); // // Dispatch the packet to related call // FsmRun( pCall, pBinding, pPacket, NULL ); // // Remove the reference added in MpMapPacketWithoutSessionIdToCall() // DereferenceCall( pCall ); } // if ( pCall ) ... } // if ( fClientRole ) ... break; case PACKET_CODE_PADT: TRACE( TL_N, TM_Mp, ("MpRecvCtrlPacket($%x): PADT received",pPacket) ); // // PADT packet must have a session id. // Identify the session and drop the call. // pCall = MpMapPacketWithSessionIdToCall( pAdapter, pPacket ); if ( pCall ) { NDIS_TAPI_DROP DummyRequest; TRACE( TL_N, TM_Mp, ("MpRecvCtrlPacket($%x): Call being dropped - PADT received",pPacket) ); // // Initialize the request, and drop the call // DummyRequest.hdCall = pCall->hdCall; TpDropCall( pAdapter, &DummyRequest, LINEDISCONNECTMODE_NORMAL ); // // Remove the reference added in MpMapPacketWithSessionIdToCall() // DereferenceCall( pCall ); } break; default: break; } TRACE( TL_N, TM_Mp, ("-MpRecvCtrlPacket($%x)",pPacket) ); } VOID MpRecvPacket( IN BINDING* pBinding, IN PPPOE_PACKET* pPacket ) /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Functional Description: This function will be called by the protocol module to notify the miniport when a packet is received. If packet is a control packet, it will call MpRecvCtrlPacket(), otherwise it will identify the call and notify NDISWAN about the packet received. Parameters: pBinding _ Pointer to the binding structure that packet was received over. pPacket _ A PPPoE packet received over the wire. Return Values: None ---------------------------------------------------------------------------*/ { ADAPTER* pAdapter = NULL; CALL* pCall = NULL; TRACE( TL_V, TM_Mp, ("+MpReceivePacket($%x)",pPacket) ); if ( !gl_fLockAllocated ) { TRACE( TL_V, TM_Mp, ("-MpReceivePacket($%x): Lock not allocated",pPacket) ); return; } NdisAcquireSpinLock( &gl_lockAdapter ); if ( gl_pAdapter && !( gl_pAdapter->ulMpFlags & MPBF_MiniportHaltPending ) && ( gl_pAdapter->ulMpFlags & MPBF_MiniportInitialized ) ) { pAdapter = gl_pAdapter; NdisAcquireSpinLock( &pAdapter->lockAdapter ); if ( !( pAdapter->TapiProv.ulTpFlags & TPBF_TapiProvShutdownPending ) && ( pAdapter->TapiProv.ulTpFlags & TPBF_TapiProvInitialized ) ) { ReferenceTapiProv( pAdapter, FALSE ); NdisReleaseSpinLock( &pAdapter->lockAdapter ); } else { NdisReleaseSpinLock( &pAdapter->lockAdapter ); pAdapter = NULL; } } NdisReleaseSpinLock( &gl_lockAdapter ); if ( pAdapter == NULL ) { TRACE( TL_V, TM_Mp, ("-MpReceivePacket($%x): Adapter not found",pPacket) ); return; } if ( PacketGetCode( pPacket ) == PACKET_CODE_PAYLOAD ) { // // Payload packet is received // pCall = MpMapPacketWithSessionIdToCall( pAdapter, pPacket ); if ( pCall ) { NdisAcquireSpinLock( &pCall->lockCall ); // // Make sure call is not dropped, closed or closing, and receive window is still open // if ( !( pCall->ulClFlags & ( CLBF_CallDropped | CLBF_CallClosePending | CLBF_CallClosed ) ) && ( pCall->nReceivedPackets < MAX_RECEIVED_PACKETS ) ) { // // Reference the packet. It will be dereferenced when indicated to NDISWAN, or // when the queue is destroyed because the call is getting cleaned up. // ReferencePacket( pPacket ); // // Insert into the receive queue and bump up the received packet count // InsertTailList( &pCall->linkReceivedPackets, &pPacket->linkPackets ); pCall->nReceivedPackets++; // // Try to schedule an IndicateReceivedPackets handler // MpScheduleIndicateReceivedPacketsHandler( pCall ); } NdisReleaseSpinLock( &pCall->lockCall ); // // Remove the reference added by MpMapPacketWithSessionIdToCall() // DereferenceCall( pCall ); } } else { // // Control packet is received, process it // MpRecvCtrlPacket( pBinding, pPacket ); } // // Remove the reference added above // DereferenceTapiProv( pAdapter ); TRACE( TL_V, TM_Mp, ("-MpReceivePacket($%x)",pPacket) ); } VOID MpIndicateReceivedPackets( IN TIMERQITEM* pTqi, IN VOID* pContext, IN TIMERQEVENT event ) { ULONG ulPacketsToIndicate = MAX_INDICATE_RECEIVED_PACKETS; CALL* pCall = (CALL*) pContext; PPPOE_PACKET* pPacket = NULL; LIST_ENTRY* pLink = NULL; ASSERT( VALIDATE_CALL( pCall ) ); NdisAcquireSpinLock( &pCall->lockCall ); while ( ulPacketsToIndicate > 0 && pCall->stateCall == CL_stateSessionUp && pCall->nReceivedPackets > 0) { ulPacketsToIndicate--; pLink = RemoveHeadList( &pCall->linkReceivedPackets ); pCall->nReceivedPackets--; NdisReleaseSpinLock( &pCall->lockCall ); { NDIS_STATUS status; CHAR* pPayload = NULL; USHORT usSize = 0; pPacket = (PPPOE_PACKET*) CONTAINING_RECORD( pLink, PPPOE_PACKET, linkPackets ); PacketRetrievePayload( pPacket, &pPayload, &usSize ); // // Future: Make sure the size of the packet is less than the max of what NDISWAN expects // // if ( usSize > pCall->NdisWanLinkInfo.MaxRecvFrameSize ) // { // TRACE( TL_A, TM_Mp, ("MpReceivePacket($%x): PAYLOAD too large to be indicated to NDISWAN",pPacket) ); // } // else TRACE( TL_V, TM_Mp, ("MpReceivePacket($%x): PAYLOAD is being indicated to NDISWAN",pPacket) ); NdisMWanIndicateReceive( &status, pCall->pLine->pAdapter->MiniportAdapterHandle, pCall->NdisLinkContext, pPayload, (UINT) usSize ); DereferencePacket( pPacket ); } NdisAcquireSpinLock( &pCall->lockCall ); } // // Check if there are more packets to indicate // if ( pCall->stateCall == CL_stateSessionUp && pCall->nReceivedPackets > 0) { // // More packets to indicate, so schedule another timer manually. // We can not use MpScheduleIndicateReceivedPacketsHandler() function here // because of performance reasons, so we do it manually. // // Since we are scheduling another handler, we do not dereference and reference // the call context. // TimerQInitializeItem( &pCall->timerReceivedPackets ); TimerQScheduleItem( &gl_TimerQ, &pCall->timerReceivedPackets, (ULONG) RECEIVED_PACKETS_TIMEOUT, MpIndicateReceivedPackets, (PVOID) pCall ); NdisReleaseSpinLock( &pCall->lockCall ); } else { // // We are done, so let's remove the reference on the call context, and // reset the CLBF_CallReceivePacketHandlerScheduled flag // pCall->ulClFlags &= ~CLBF_CallReceivePacketHandlerScheduled; NdisReleaseSpinLock( &pCall->lockCall ); DereferenceCall( pCall ); } } VOID MpScheduleIndicateReceivedPacketsHandler( CALL* pCall ) /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Functional Description: This function will be called to schedule MpIndicateReceivedPackets() handler. It will check if we are allowed to schedule it first, and if we are, then it will schedule it and reference the call context. CAUTION :Caller MUST be holding pCall->lockCall. Parameters: pCall _ Pointer to our call context. Return Values: NONE ---------------------------------------------------------------------------*/ { if ( !( pCall->ulClFlags & CLBF_CallReceivePacketHandlerScheduled ) && pCall->stateCall == CL_stateSessionUp && pCall->nReceivedPackets > 0 ) { pCall->ulClFlags |= CLBF_CallReceivePacketHandlerScheduled; TimerQInitializeItem( &pCall->timerReceivedPackets ); TimerQScheduleItem( &gl_TimerQ, &pCall->timerReceivedPackets, (ULONG) RECEIVED_PACKETS_TIMEOUT, MpIndicateReceivedPackets, (PVOID) pCall ); ReferenceCall( pCall, FALSE ); } } NDIS_STATUS MpWanGetInfo( IN ADAPTER* pAdapter, IN PNDIS_WAN_INFO pWanInfo ) /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Functional Description: This function will be called when miniport receives an OID_WAN_GET_INFO query from NDISWAN. It will acquire the necesarry information and return it back to NDISWAN. All the info is initialized when the adapter is initialized except for MaxFrameSize which depends on the active bindings. That's why we query the protocol to get the current MaxFrameSize, and pass it back. Parameters: pAdapter _ Pointer to our adapter context. pWanInfo _ Pointer to the NDIS_WAN_INFO structure to be filled in. Return Values: NDIS_STATUS_SUCCESS ---------------------------------------------------------------------------*/ { NDIS_STATUS status = NDIS_STATUS_SUCCESS; TRACE( TL_N, TM_Mp, ("+MpWanGetInfo") ); // // Retrieve the current MaxFrameSize from protocol // pAdapter->NdisWanInfo.MaxFrameSize = PrQueryMaxFrameSize(); // // Pass data back to NDISWAN // *pWanInfo = pAdapter->NdisWanInfo; TRACE( TL_N, TM_Mp, ("-MpWanGetInfo()=$%x",status) ); return status; } NDIS_STATUS MpWanGetLinkInfo( IN ADAPTER* pAdapter, IN PNDIS_WAN_GET_LINK_INFO pWanLinkInfo ) /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Functional Description: This function will be called when miniport receives an OID_WAN_GET_LINK_INFO query from NDISWAN. It will acquire the necesarry information and return it back to NDISWAN. All the info is initialized in TpCallStateChangeHandler() when TAPI is signaled to LINECALLSTATE_CONNECTED state. Parameters: pAdapter _ Pointer to our adapter context. pWanLinkInfo _ Pointer to the NDIS_WAN_GET_LINK_INFO structure to be filled in. Return Values: NDIS_STATUS_FAILURE NDIS_STATUS_SUCCESS ---------------------------------------------------------------------------*/ { NDIS_STATUS status = NDIS_STATUS_FAILURE; CALL* pCall = NULL; TRACE( TL_N, TM_Mp, ("+MpWanGetLinkInfo") ); pCall = RetrieveFromHandleTable( pAdapter->TapiProv.hCallTable, pWanLinkInfo->NdisLinkHandle ); if ( pCall ) { *pWanLinkInfo = pCall->NdisWanLinkInfo; status = NDIS_STATUS_SUCCESS; } TRACE( TL_N, TM_Mp, ("-MpWanGetLinkInfo()=$%x",status) ); return status; } NDIS_STATUS MpWanSetLinkInfo( IN ADAPTER* pAdapter, IN PNDIS_WAN_SET_LINK_INFO pWanLinkInfo ) /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Functional Description: This function will be called when miniport receives an OID_WAN_SET_LINK_INFO request from NDISWAN. It will do some checks on the passed in params, and if the values are acceptiable it will copy them onto the call context. Parameters: pAdapter _ Pointer to our adapter context. pWanLinkInfo _ Pointer to the NDIS_WAN_SET_LINK_INFO structure. Return Values: NDIS_STATUS_FAILURE NDIS_STATUS_SUCCESS ---------------------------------------------------------------------------*/ { NDIS_STATUS status = NDIS_STATUS_FAILURE; CALL* pCall = NULL; TRACE( TL_N, TM_Mp, ("+MpWanSetLinkInfo") ); pCall = RetrieveFromHandleTable( pAdapter->TapiProv.hCallTable, pWanLinkInfo->NdisLinkHandle ); if ( pCall ) { do { if ( pWanLinkInfo->MaxSendFrameSize > pCall->ulMaxFrameSize ) { TRACE( TL_A, TM_Mp, ("MpWanSetLinkInfo: Requested MaxSendFrameSize is larger than NIC's") ); } if ( pWanLinkInfo->MaxRecvFrameSize < pCall->ulMaxFrameSize ) { TRACE( TL_A, TM_Mp, ("MpWanSetLinkInfo: Requested MaxRecvFrameSize is smaller than NIC's") ); } if ( pWanLinkInfo->HeaderPadding != pAdapter->NdisWanInfo.HeaderPadding ) { TRACE( TL_A, TM_Mp, ("MpWanSetLinkInfo: Requested HeaderPadding is different than what we asked for") ); } if ( pWanLinkInfo->SendFramingBits & ~pAdapter->NdisWanInfo.FramingBits ) { TRACE( TL_A, TM_Mp, ("MpWanSetLinkInfo: Unknown send framing bits requested") ); break; } if ( pWanLinkInfo->RecvFramingBits & ~pAdapter->NdisWanInfo.FramingBits ) { TRACE( TL_A, TM_Mp, ("MpWanSetLinkInfo: Unknown recv framing bits requested") ); break; } // // Ignore FrameSize if the values are 0. // if(pWanLinkInfo->MaxSendFrameSize != 0) { pCall->NdisWanLinkInfo.MaxSendFrameSize = pWanLinkInfo->MaxSendFrameSize; } if(pWanLinkInfo->MaxRecvFrameSize != 0) { pCall->NdisWanLinkInfo.MaxRecvFrameSize = pWanLinkInfo->MaxRecvFrameSize; } RtlCopyMemory(&pCall->NdisWanLinkInfo.HeaderPadding, &pWanLinkInfo->HeaderPadding, sizeof(NDIS_WAN_GET_LINK_INFO) - FIELD_OFFSET(NDIS_WAN_GET_LINK_INFO, HeaderPadding)); // pCall->NdisWanLinkInfo = * ( (PNDIS_WAN_GET_LINK_INFO) pWanLinkInfo ); status = NDIS_STATUS_SUCCESS; } while ( FALSE ); } TRACE( TL_N, TM_Mp, ("-MpWanSetLinkInfo()=$%x",status) ); return status; }