|
|
// Copyright (c) 1997, Microsoft Corporation, all rights reserved
//
// mp.c
// RAS L2TP WAN mini-port/call-manager driver
// Mini-port routines
//
// 01/07/97 Steve Cobb
#include "l2tpp.h"
#include "mp.tmh"
// The adapter control block address is recorded in this global as a debugging
// aid. This global must not be read by any code.
//
ADAPTERCB* g_pDebugAdapter;
// The number of packets indicated up to and returned from the driver above.
//
LONG g_lPacketsIndicated = 0; LONG g_lPacketsReturned = 0;
// Call statistics totals for all calls since loading, calls and the lock
// protecting access to them. For this global only, the 'ullCallUp' field is
// the number of calls recorded, rather than a time.
//
CALLSTATS g_stats; NDIS_SPIN_LOCK g_lockStats;
// Default settings for the NDIS_WAN_CO_INFO capabilities of an adapter.
//
static NDIS_WAN_CO_INFO g_infoDefaults = { L2TP_MaxFrameSize, // MaxFrameSize
0, // MaxSendWindow (placeholder)
PPP_FRAMING // FramingBits
| PPP_COMPRESS_ADDRESS_CONTROL | PPP_COMPRESS_PROTOCOL_FIELD, 0, // DesiredACCM
};
//-----------------------------------------------------------------------------
// Local prototypes (alphabetically)
//-----------------------------------------------------------------------------
VOID FreeAdapter( IN ADAPTERCB* pAdapter );
NDIS_STATUS GetRegistrySettings( IN NDIS_HANDLE WrapperConfigurationContext, OUT USHORT* pusMaxVcs, OUT TDIXMEDIATYPE* pMediaType, OUT L2TPROLE* pOutgoingRole, OUT ULONG* pulMaxSendTimeoutMs, OUT ULONG* pulInitialSendTimeoutMs, OUT ULONG* pulMaxRetransmits, OUT ULONG* pulHelloMs, OUT ULONG* pulMaxAckDelayMs, OUT SHORT* psMaxOutOfOrder, OUT USHORT* pusControlReceiveWindow, OUT USHORT* pusPayloadReceiveWindow, OUT ULONG* pulPayloadSendWindow, OUT USHORT* pusLlistDepth, OUT CHAR** ppszHostName, OUT CHAR** ppszPassword, OUT BOOLEAN* pfIgnoreFramingMismatch, OUT BOOLEAN* pfExclusiveTunnels, OUT HOSTROUTEEXISTS* phre, OUT BOOLEAN* pfDisableUdpXsums, OUT WCHAR** ppszDriverDesc );
NDIS_STATUS QueryInformation( IN ADAPTERCB* pAdapter, IN VCCB* pLink, IN NDIS_OID Oid, IN PVOID InformationBuffer, IN ULONG InformationBufferLength, OUT PULONG BytesWritten, OUT PULONG BytesNeeded );
NDIS_STATUS SetInformation( IN ADAPTERCB* pAdapter, IN VCCB* pLink, IN NDIS_OID Oid, IN PVOID InformationBuffer, IN ULONG InformationBufferLength, OUT PULONG BytesRead, OUT PULONG BytesNeeded );
//-----------------------------------------------------------------------------
// Mini-port handlers
//-----------------------------------------------------------------------------
NDIS_STATUS LmpInitialize( OUT PNDIS_STATUS OpenErrorStatus, OUT PUINT SelectedMediumIndex, IN PNDIS_MEDIUM MediumArray, IN UINT MediumArraySize, IN NDIS_HANDLE MiniportAdapterHandle, IN NDIS_HANDLE WrapperConfigurationContext )
// Standard 'MiniportInitialize' routine called by NDIS to initialize a
// new WAN adapter. See DDK doc. The driver will receive no requests
// until this initialization has completed.
//
{ NDIS_STATUS status; ADAPTERCB* pAdapter;
TRACE( TL_I, TM_Init, ( "LmpInit" ) );
status = *OpenErrorStatus = NDIS_STATUS_SUCCESS;
// Find the medium index in the array of media, looking for the only one
// we support, 'NdisMediumCoWan'.
//
{ UINT i;
for (i = 0; i < MediumArraySize; ++i) { if (MediumArray[ i ] == NdisMediumCoWan) { break; } }
if (i >= MediumArraySize) { TRACE( TL_A, TM_Init, ( "medium?" ) ); return NDIS_STATUS_FAILURE; }
*SelectedMediumIndex = i; }
// Allocate and zero a control block for the new adapter.
//
pAdapter = ALLOC_NONPAGED( sizeof(*pAdapter), MTAG_ADAPTERCB ); TRACE( TL_N, TM_Init, ( "Acb=$%p", pAdapter ) ); if (!pAdapter) { return NDIS_STATUS_RESOURCES; } NdisZeroMemory( pAdapter, sizeof(*pAdapter) );
// The adapter control block address is recorded in 'g_pDebugAdapter' as a
// debugging aid only. This global is not to be read by any code.
//
g_pDebugAdapter = pAdapter;
// Set a marker for easier memory dump browsing and future assertions.
//
pAdapter->ulTag = MTAG_ADAPTERCB;
// Save the NDIS handle associated with this adapter for use in future
// NdisXxx calls.
//
pAdapter->MiniportAdapterHandle = MiniportAdapterHandle;
// Initialize the list of active tunnels and it's lock.
//
InitializeListHead( &pAdapter->listTunnels ); NdisAllocateSpinLock( &pAdapter->lockTunnels );
// Copy default NDISWAN information. Some of these are updated below.
//
NdisMoveMemory( &pAdapter->info, &g_infoDefaults, sizeof(pAdapter->info) ); pAdapter->info.MaxFrameSize = 1400;
do { TDIXMEDIATYPE tmt; L2TPROLE role; USHORT usLlistDepth; BOOLEAN fIgnoreFramingMismatch; BOOLEAN fExclusiveTunnels; HOSTROUTEEXISTS hre; BOOLEAN fDisableUdpXsums;
// Read this adapter's registry settings.
//
status = GetRegistrySettings( WrapperConfigurationContext, &pAdapter->usMaxVcs, &tmt, &role, &pAdapter->ulMaxSendTimeoutMs, &pAdapter->ulInitialSendTimeoutMs, &pAdapter->ulMaxRetransmits, &pAdapter->ulHelloMs, &pAdapter->ulMaxAckDelayMs, &pAdapter->sMaxOutOfOrder, &pAdapter->usControlReceiveWindow, &pAdapter->usPayloadReceiveWindow, &pAdapter->info.MaxSendWindow, &usLlistDepth, &pAdapter->pszHostName, &pAdapter->pszPassword, &fIgnoreFramingMismatch, &fExclusiveTunnels, &hre, &fDisableUdpXsums, &pAdapter->pszDriverDesc );
if (status != NDIS_STATUS_SUCCESS) { // Set 'usMaxVcs' to 0 as an indication to FreeAdapter that the
// lookaside lists and pools were not initialized.
//
pAdapter->usMaxVcs = 0; break; }
// Convert the outgoing call role and mismatch flags to the equivalent
// control block flag settings.
//
if (role == LR_Lac) { pAdapter->ulFlags |= ACBF_OutgoingRoleLac; }
if (fIgnoreFramingMismatch) { pAdapter->ulFlags |= ACBF_IgnoreFramingMismatch; }
if (fExclusiveTunnels) { pAdapter->ulFlags |= ACBF_ExclusiveTunnels; }
// Initialize our framing and bearer capability bit masks. NDISWAN
// supports only synchronous framing. Until we add the full LAC
// support, we have no bearer capabilities for both the LAC and LNS
// roles.
//
pAdapter->ulFramingCaps = FBM_Sync; pAdapter->ulBearerCaps = 0;
// Initialize lookaside lists, buffer pools, and packet pool. On NT,
// lookaside depths are optimized by the system based on usage
// regardless of the depth set, but choose something reasonable
// anyway.
//
{ if (pAdapter->usMaxVcs < usLlistDepth) { usLlistDepth = pAdapter->usMaxVcs; }
NdisInitializeNPagedLookasideList( &pAdapter->llistWorkItems, NULL, NULL, 0, sizeof(NDIS_WORK_ITEM), MTAG_WORKITEM, usLlistDepth );
NdisInitializeNPagedLookasideList( &pAdapter->llistTimerQItems, NULL, NULL, 0, sizeof(TIMERQITEM), MTAG_TIMERQITEM, usLlistDepth );
NdisInitializeNPagedLookasideList( &pAdapter->llistControlSents, NULL, NULL, 0, sizeof(CONTROLSENT), MTAG_CTRLSENT, usLlistDepth );
NdisInitializeNPagedLookasideList( &pAdapter->llistPayloadSents, NULL, NULL, 0, sizeof(PAYLOADSENT), MTAG_PAYLSENT, usLlistDepth );
NdisInitializeNPagedLookasideList( &pAdapter->llistTunnelWorks, NULL, NULL, 0, sizeof(TUNNELWORK), MTAG_TUNNELWORK, usLlistDepth );
NdisInitializeNPagedLookasideList( &pAdapter->llistControlMsgInfos, NULL, NULL, 0, sizeof(CONTROLMSGINFO), MTAG_CTRLMSGINFO, usLlistDepth );
#if LLISTALL
NdisInitializeNPagedLookasideList( &pAdapter->llistTunnels, NULL, NULL, 0, sizeof(TUNNELCB), MTAG_TUNNELCB, usLlistDepth );
NdisInitializeNPagedLookasideList( &pAdapter->llistVcs, NULL, NULL, 0, sizeof(VCCB), MTAG_VCCB, usLlistDepth );
NdisInitializeNPagedLookasideList( &pAdapter->llistTimerQs, NULL, NULL, 0, sizeof(TIMERQ), MTAG_TIMERQ, usLlistDepth );
NdisInitializeNPagedLookasideList( &pAdapter->llistControlReceiveds, NULL, NULL, 0, sizeof(CONTROLRECEIVED), MTAG_CTRLRECD,, usLlistDepth );
NdisInitializeNPagedLookasideList( &pAdapter->llistPayloadReceiveds, NULL, NULL, 0, sizeof(PAYLOADRECEIVED), MTAG_PAYLRECD, usLlistDepth );
NdisInitializeNPagedLookasideList( &pAdapter->llistInCallSetups, NULL, NULL, 0, sizeof(INCALLSETUP), MTAG_INCALL, usLlistDepth ); #endif
InitBufferPool( &pAdapter->poolFrameBuffers, L2TP_FrameBufferSize + ((tmt == TMT_RawIp) ? IpFixedHeaderSize : 0), 0, 10, 0, TRUE, MTAG_FBUFPOOL );
InitBufferPool( &pAdapter->poolHeaderBuffers, L2TP_HeaderBufferSize, 0, 20, 0, TRUE, MTAG_HBUFPOOL );
InitPacketPool( &pAdapter->poolPackets, 0, 0, 30, 0, MTAG_PACKETPOOL ); }
// Initialize the TDI extension context.
//
TdixInitialize( tmt, hre, ((fDisableUdpXsums) ? TDIXF_DisableUdpXsums : 0), L2tpReceive, &pAdapter->poolFrameBuffers, &pAdapter->tdix );
// Allocate and zero the VC control block address array.
//
{ ULONG ulSize;
ulSize = pAdapter->usMaxVcs * sizeof(VCCB*); pAdapter->ppVcs = ALLOC_NONPAGED( ulSize, MTAG_VCTABLE ); TRACE( TL_V, TM_Init, ( "VcTable=$%p", pAdapter->ppVcs ) ); if (!pAdapter->ppVcs) { status = NDIS_STATUS_RESOURCES; break; }
NdisZeroMemory( pAdapter->ppVcs, ulSize );
// Allocate the lock that guards the table.
//
NdisAllocateSpinLock( &pAdapter->lockVcs );
// At this point, all VC slots in the table are available.
//
pAdapter->lAvailableVcSlots = (LONG )pAdapter->usMaxVcs;
// Set the initial value of the termination call ID counter. See
// GetNextTerminationCallId.
//
pAdapter->usNextTerminationCallId = pAdapter->usMaxVcs + 1;
}
// Inform NDIS of the attributes of our adapter. Set the
// 'MiniportAdapterContext' returned to us by NDIS when it calls our
// handlers to the address of our adapter control block. Turn off
// hardware oriented timeouts.
//
NdisMSetAttributesEx( MiniportAdapterHandle, (NDIS_HANDLE)pAdapter, (UINT)-1, NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT | NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT, NdisInterfaceInternal );
// Register the address family of our call manager with NDIS for the
// newly bound adapter. We use the mini-port form of
// RegisterAddressFamily instead of the protocol form, though that
// would also work. With the protocol form, our internal call manager
// would have to go thru NDIS to talk to the mini-port instead of just
// calling directly. Since the L2TP call manager is not likely to be
// useful with anything but the L2TP mini-port, this would be a waste.
// The mini-port form also causes the call manager VC context to
// automatically map to the mini-port VC context, which is exactly
// what we want.
//
// NDIS notifies all call manager clients of the new family we
// register. The TAPI proxy is the only client expected to be
// interested. NDISWAN will receive the notification, but ignore it
// and wait for the TAPI proxy to notify it of the proxied version.
//
{ NDIS_CALL_MANAGER_CHARACTERISTICS ncmc; CO_ADDRESS_FAMILY family;
NdisZeroMemory( &family, sizeof(family) ); family.MajorVersion = NDIS_MajorVersion; family.MinorVersion = NDIS_MinorVersion; family.AddressFamily = CO_ADDRESS_FAMILY_TAPI_PROXY;
NdisZeroMemory( &ncmc, sizeof(ncmc) ); ncmc.MajorVersion = NDIS_MajorVersion; ncmc.MinorVersion = NDIS_MinorVersion; ncmc.CmCreateVcHandler = LcmCmCreateVc; ncmc.CmDeleteVcHandler = LcmCmDeleteVc; ncmc.CmOpenAfHandler = LcmCmOpenAf; ncmc.CmCloseAfHandler = LcmCmCloseAf; ncmc.CmRegisterSapHandler = LcmCmRegisterSap; ncmc.CmDeregisterSapHandler = LcmCmDeregisterSap; ncmc.CmMakeCallHandler = LcmCmMakeCall; ncmc.CmCloseCallHandler = LcmCmCloseCall; ncmc.CmIncomingCallCompleteHandler = LcmCmIncomingCallComplete; // no CmAddPartyHandler
// no CmDropPartyHandler
ncmc.CmActivateVcCompleteHandler = LcmCmActivateVcComplete; ncmc.CmDeactivateVcCompleteHandler = LcmCmDeactivateVcComplete; ncmc.CmModifyCallQoSHandler = LcmCmModifyCallQoS; ncmc.CmRequestHandler = LcmCmRequest; // no CmRequestCompleteHandler
TRACE( TL_I, TM_Cm, ( "NdisMCmRegAf" ) ); status = NdisMCmRegisterAddressFamily( MiniportAdapterHandle, &family, &ncmc, sizeof(ncmc) ); TRACE( TL_I, TM_Cm, ( "NdisMCmRegAf=$%x", status ) ); } } while (FALSE);
if (status == NDIS_STATUS_SUCCESS) { // Add a reference that will eventually be removed by an NDIS call to
// the LmpHalt handler.
//
ReferenceAdapter( pAdapter ); } else { // Failed, so undo whatever portion succeeded.
//
if (pAdapter) { FreeAdapter( pAdapter ); } }
TRACE( TL_V, TM_Init, ( "LmpInit=$%08x", status ) ); return status; }
VOID LmpHalt( IN NDIS_HANDLE MiniportAdapterContext )
// Standard 'MiniportHalt' routine called by NDIS to deallocate all
// resources attached to the adapter. NDIS does not make any other calls
// for this mini-port adapter during or after this call. NDIS will not
// call this routine when packets indicated as received have not been
// returned, or when any VC is created and known to NDIS. Runs at PASSIVE
// IRQL.
//
{ ADAPTERCB* pAdapter;
TRACE( TL_I, TM_Mp, ( "LmpHalt" ) );
pAdapter = (ADAPTERCB* )MiniportAdapterContext; if (!pAdapter || pAdapter->ulTag != MTAG_ADAPTERCB) { ASSERT( !"Atag?" ); return; }
// Don't allow the halt to complete before all timers have completed as
// this can result in a 0xC7 bugcheck if the driver is immediately
// unloaded. All timers should be in the process of terminating before
// NDIS calls this handler, so this should occur very quickly.
//
while (pAdapter->ulTimers) { TRACE( TL_A, TM_Mp, ( "LmpHalt timers=%d", pAdapter->ulTimers ) ); WPLOG( LL_A, LM_Mp, ( "LmpHalt timers=%d", pAdapter->ulTimers ) ); NdisMSleep( 100000 ); }
DereferenceAdapter( pAdapter );
TRACE( TL_V, TM_Mp, ( "LmpHalt done" ) ); }
NDIS_STATUS LmpReset( OUT PBOOLEAN AddressingReset, IN NDIS_HANDLE MiniportAdapterContext )
// Standard 'MiniportReset' routine called by NDIS to reset the driver's
// software state.
//
{ TRACE( TL_I, TM_Mp, ( "LmpReset" ) );
return NDIS_STATUS_NOT_RESETTABLE; }
VOID LmpReturnPacket( IN NDIS_HANDLE MiniportAdapterContext, IN PNDIS_PACKET Packet )
// Standard 'MiniportReturnPacket' routine called by NDIS when a packet
// used to indicate a receive has been released by the driver above.
//
{ VCCB* pVc; CHAR* pBuffer; ADAPTERCB* pAdapter; NDIS_BUFFER* pTrimmedBuffer; PACKETHEAD* pHead; PACKETPOOL* pPool;
TRACE( TL_N, TM_Mp, ( "LmpReturnPacket" ) );
// Unpack the context information we stashed earlier.
//
pHead = *((PACKETHEAD** )(&Packet->MiniportReserved[ 0 ])); pBuffer = *((CHAR** )(&Packet->MiniportReserved[ sizeof(VOID*) ]));
// Find the adapter from the PACKETHEAD address.
//
pPool = PacketPoolFromPacketHead( pHead ); pAdapter = CONTAINING_RECORD( pPool, ADAPTERCB, poolPackets ); ASSERT( pAdapter->ulTag == MTAG_ADAPTERCB );
// Free the descriptor created by NdisCopyBuffer.
//
NdisUnchainBufferAtFront( Packet, &pTrimmedBuffer ); if (pTrimmedBuffer) { extern ULONG g_ulNdisFreeBuffers;
NdisFreeBuffer( pTrimmedBuffer ); NdisInterlockedIncrement( &g_ulNdisFreeBuffers ); }
// Free the buffer and packet back to the pools.
//
FreeBufferToPool( &pAdapter->poolFrameBuffers, pBuffer, TRUE ); FreePacketToPool( &pAdapter->poolPackets, pHead, TRUE );
NdisInterlockedIncrement( &g_lPacketsReturned );
TRACE( TL_V, TM_Mp, ( "LmpReturnPacket done" ) ); }
NDIS_STATUS LmpCoActivateVc( IN NDIS_HANDLE MiniportVcContext, IN OUT PCO_CALL_PARAMETERS CallParameters )
// Standard 'MiniportCoActivateVc' routine called by NDIS in response to a
// protocol's request to activate a virtual circuit.
//
{ ASSERT( !"LmpCoActVc?" ); return NDIS_STATUS_SUCCESS; }
NDIS_STATUS LmpCoDeactivateVc( IN NDIS_HANDLE MiniportVcContext )
// Standard 'MiniportCoDeactivateVc' routine called by NDIS in response to
// a protocol's request to de-activate a virtual circuit.
//
{ ASSERT( !"LmpCoDeactVc?" ); return NDIS_STATUS_SUCCESS; }
VOID LmpCoSendPackets( IN NDIS_HANDLE MiniportVcContext, IN PPNDIS_PACKET PacketArray, IN UINT NumberOfPackets )
// Standard 'MiniportCoDeactivateVc' routine called by NDIS in response to
// a protocol's request to send packets on a virtual circuit.
//
{ UINT i; NDIS_STATUS status; NDIS_PACKET** ppPacket; VCCB* pVc;
TRACE( TL_N, TM_Send, ( "LmpCoSendPackets(%d)", NumberOfPackets ) );
pVc = (VCCB* )MiniportVcContext; ASSERT( pVc->ulTag == MTAG_VCCB );
for (i = 0, ppPacket = PacketArray; i < NumberOfPackets; ++i, ++ppPacket) { NDIS_PACKET* pPacket = *ppPacket;
// SendPayload sends the packet and eventually calls
// NdisMCoSendComplete to notify caller of the result.
//
NDIS_SET_PACKET_STATUS( pPacket, NDIS_STATUS_PENDING ); SendPayload( pVc, pPacket ); }
TRACE( TL_V, TM_Send, ( "LmpCoSendPackets done" ) ); }
NDIS_STATUS LmpCoRequest( IN NDIS_HANDLE MiniportAdapterContext, IN NDIS_HANDLE MiniportVcContext, IN OUT PNDIS_REQUEST NdisRequest )
// Standard 'MiniportCoRequestHandler' routine called by NDIS in response
// to a protocol's request information from the mini-port. Unlike the
// Query/SetInformation handlers that this routine obsoletes, requests are
// not serialized.
//
{ ADAPTERCB* pAdapter; VCCB* pVc; NDIS_STATUS status;
TRACE( TL_N, TM_Mp, ( "LmpCoReq" ) );
pAdapter = (ADAPTERCB* )MiniportAdapterContext; if (pAdapter->ulTag != MTAG_ADAPTERCB) { ASSERT( !"Atag?" ); return NDIS_STATUS_INVALID_DATA; }
pVc = (VCCB* )MiniportVcContext; if (pVc && pVc->ulTag != MTAG_VCCB) { ASSERT( !"Vtag?" ); return NDIS_STATUS_INVALID_DATA; }
switch (NdisRequest->RequestType) { case NdisRequestQueryInformation: { status = QueryInformation( pAdapter, pVc, NdisRequest->DATA.QUERY_INFORMATION.Oid, NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer, NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength, &NdisRequest->DATA.QUERY_INFORMATION.BytesWritten, &NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded ); break; }
case NdisRequestSetInformation: { status = SetInformation( pAdapter, pVc, NdisRequest->DATA.SET_INFORMATION.Oid, NdisRequest->DATA.SET_INFORMATION.InformationBuffer, NdisRequest->DATA.SET_INFORMATION.InformationBufferLength, &NdisRequest->DATA.SET_INFORMATION.BytesRead, &NdisRequest->DATA.SET_INFORMATION.BytesNeeded ); break; }
default: { status = NDIS_STATUS_NOT_SUPPORTED; TRACE( TL_A, TM_Mp, ( "type=%d?", NdisRequest->RequestType ) ); break; } }
TRACE( TL_V, TM_Mp, ( "LmpCoReq=$%x", status ) ); return status; }
//-----------------------------------------------------------------------------
// Mini-port utility routines (alphabetically)
// Some are used externally
//-----------------------------------------------------------------------------
VOID DereferenceAdapter( IN ADAPTERCB* pAdapter )
// Removes a reference from the adapter control block 'pAdapter', and when
// frees the adapter resources when the last reference is removed.
//
{ LONG lRef;
lRef = NdisInterlockedDecrement( &pAdapter->lRef );
TRACE( TL_N, TM_Ref, ( "DerefA to %d", lRef ) ); ASSERT( lRef >= 0 );
if (lRef == 0) { FreeAdapter( pAdapter ); } }
VOID FreeAdapter( IN ADAPTERCB* pAdapter )
// Frees all resources allocated for adapter 'pAdapter', including
// 'pAdapter' itself.
//
{ BOOLEAN fSuccess;
ASSERT( IsListEmpty( &pAdapter->listTunnels ) );
if (pAdapter->ppVcs) { FREE_NONPAGED( pAdapter->ppVcs ); }
// Setting 'usMaxVcs' to 0 is LmpInitialize's way of telling us that the
// lookaside lists and pools were not initialized.
//
if (pAdapter->usMaxVcs) { NdisDeleteNPagedLookasideList( &pAdapter->llistWorkItems ); NdisDeleteNPagedLookasideList( &pAdapter->llistTimerQItems ); NdisDeleteNPagedLookasideList( &pAdapter->llistControlSents ); NdisDeleteNPagedLookasideList( &pAdapter->llistPayloadSents ); NdisDeleteNPagedLookasideList( &pAdapter->llistTunnelWorks ); NdisDeleteNPagedLookasideList( &pAdapter->llistControlMsgInfos );
#if LLISTALL
NdisDeleteNPagedLookasideList( &pAdapter->llistTunnels ); NdisDeleteNPagedLookasideList( &pAdapter->llistVcs ); NdisDeleteNPagedLookasideList( &pAdapter->llistTimerQs ); NdisDeleteNPagedLookasideList( &pAdapter->llistControlReceiveds ); NdisDeleteNPagedLookasideList( &pAdapter->llistPayloadReceiveds ); NdisDeleteNPagedLookasideList( &pAdapter->llistInCallSetups ); #endif
fSuccess = FreeBufferPool( &pAdapter->poolFrameBuffers ); ASSERT( fSuccess ); fSuccess = FreeBufferPool( &pAdapter->poolHeaderBuffers ); ASSERT( fSuccess ); fSuccess = FreePacketPool( &pAdapter->poolPackets ); ASSERT( fSuccess ); }
if (pAdapter->pszPassword) { FREE_NONPAGED( pAdapter->pszPassword ); }
if (pAdapter->pszDriverDesc) { FREE_NONPAGED( pAdapter->pszDriverDesc ); }
if (pAdapter->pszHostName) { FREE_NONPAGED( pAdapter->pszHostName ); }
pAdapter->ulTag = MTAG_FREED; FREE_NONPAGED( pAdapter ); }
NDIS_STATUS GetRegistrySettings( IN NDIS_HANDLE WrapperConfigurationContext, OUT USHORT* pusMaxVcs, OUT TDIXMEDIATYPE* pMediaType, OUT L2TPROLE* pOutgoingRole, OUT ULONG* pulMaxSendTimeoutMs, OUT ULONG* pulInitialSendTimeoutMs, OUT ULONG* pulMaxRetransmits, OUT ULONG* pulHelloMs, OUT ULONG* pulMaxAckDelayMs, OUT SHORT* psMaxOutOfOrder, OUT USHORT* pusControlReceiveWindow, OUT USHORT* pusPayloadReceiveWindow, OUT ULONG* pulPayloadSendWindow, OUT USHORT* pusLlistDepth, OUT CHAR** ppszHostName, OUT CHAR** ppszPassword, OUT BOOLEAN* pfIgnoreFramingMismatch, OUT BOOLEAN* pfExclusiveTunnels, OUT HOSTROUTEEXISTS* phre, OUT BOOLEAN* pfDisableUdpXsums, OUT WCHAR** ppszDriverDesc )
// Read this mini-port's registry settings into caller's output variables.
// 'WrapperConfigurationContext' is the handle to passed to
// MiniportInitialize.
//
{ NDIS_STATUS status; NDIS_HANDLE hCfg; NDIS_CONFIGURATION_PARAMETER* pncp;
NdisOpenConfiguration( &status, &hCfg, WrapperConfigurationContext ); if (status != NDIS_STATUS_SUCCESS) return status;
do { // (recommended) The number of VCs we must be able to provide.
//
{ NDIS_STRING nstr = NDIS_STRING_CONST( "MaxWanEndpoints" );
NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterInteger ); if (status == NDIS_STATUS_SUCCESS) { *pusMaxVcs = (USHORT )pncp->ParameterData.IntegerData;
// Make sure it's a valid value. The implicit upper bound
// imposed by the protocol's Tunnel-Id/Call-ID sizes is 65535.
// Settings above 1000 are not recommended, but will work if
// huge amounts of memory and bandwidth are available.
//
if (*pusMaxVcs < 1) { status = NDIS_STATUS_INVALID_DATA; break; } } else { *pusMaxVcs = 1000; status = NDIS_STATUS_SUCCESS; } }
// (recommended) The media type to run L2TP over.
//
{ NDIS_STRING nstr = NDIS_STRING_CONST( "VpnMediaType" );
NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterInteger ); if (status == NDIS_STATUS_SUCCESS) { *pMediaType = (TDIXMEDIATYPE )pncp->ParameterData.IntegerData;
// Make sure it's a valid type.
//
if (*pMediaType != TMT_Udp && *pMediaType != TMT_RawIp) { status = NDIS_STATUS_INVALID_DATA; break; } } else { // No media type in registry. Default to UDP.
//
*pMediaType = TMT_Udp; status = NDIS_STATUS_SUCCESS; } }
// (optional) The maximum send timeout in milliseconds.
//
{ NDIS_STRING nstr = NDIS_STRING_CONST( "MaxSendTimeoutMs" );
NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterInteger ); if (status == NDIS_STATUS_SUCCESS) { *pulMaxSendTimeoutMs = pncp->ParameterData.IntegerData;
// Make sure it's a valid value.
//
if (*pulMaxSendTimeoutMs == 0) { *pulMaxSendTimeoutMs = 0x7FFFFFFF; } } else { // No value in registry. Set a reasonable default.
//
*pulMaxSendTimeoutMs = L2TP_DefaultMaxSendTimeoutMs; status = NDIS_STATUS_SUCCESS; } }
// (optional) The initial send timeout in milliseconds.
//
{ NDIS_STRING nstr = NDIS_STRING_CONST( "InitialSendTimeoutMs" );
NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterInteger ); if (status == NDIS_STATUS_SUCCESS) { *pulInitialSendTimeoutMs = pncp->ParameterData.IntegerData;
// Make sure it's a valid value.
//
if (*pulInitialSendTimeoutMs == 0) { *pulInitialSendTimeoutMs = 0x7FFFFFFF; }
if (*pulInitialSendTimeoutMs > *pulMaxSendTimeoutMs) *pulInitialSendTimeoutMs = *pulMaxSendTimeoutMs; } else { // No value in registry. Set a reasonable default.
//
*pulInitialSendTimeoutMs = L2TP_DefaultSendTimeoutMs; status = NDIS_STATUS_SUCCESS; } }
// (optional) The maximum number of control message retransmissions
// before the tunnel is reset.
//
{ NDIS_STRING nstr = NDIS_STRING_CONST( "MaxRetransmits" );
NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterInteger ); if (status == NDIS_STATUS_SUCCESS) { *pulMaxRetransmits = pncp->ParameterData.IntegerData; } else { // No value in registry. Set a reasonable default.
//
*pulMaxRetransmits = L2TP_DefaultMaxRetransmits; status = NDIS_STATUS_SUCCESS; } }
// (optional) The control Hello timeout in milliseconds.
//
{ NDIS_STRING nstr = NDIS_STRING_CONST( "HelloMs" );
NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterInteger ); if (status == NDIS_STATUS_SUCCESS) { *pulHelloMs = pncp->ParameterData.IntegerData; } else { // No value in registry. Set a reasonable default.
//
*pulHelloMs = L2TP_HelloMs; status = STATUS_SUCCESS; } }
// (optional) The maximum piggyback delay in milliseconds before
// sending a zero payload acknowledgement.
//
{ NDIS_STRING nstr = NDIS_STRING_CONST( "MaxAckDelayMs" );
NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterInteger ); if (status == NDIS_STATUS_SUCCESS) { *pulMaxAckDelayMs = pncp->ParameterData.IntegerData; } else { // No value in registry. Set a reasonable default.
//
*pulMaxAckDelayMs = L2TP_MaxAckDelay; status = NDIS_STATUS_SUCCESS; } }
// (optional) The maximum number of out-of-order packets to queue.
//
{ NDIS_STRING nstr = NDIS_STRING_CONST( "MaxOutOfOrder" );
NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterInteger ); if (status == NDIS_STATUS_SUCCESS) { *psMaxOutOfOrder = (SHORT )pncp->ParameterData.IntegerData;
// Make sure it's not negative and within 1/4 of the possible
// sequence values to avoid aliasing. Zero effectively
// disables out of order handling.
//
if (*psMaxOutOfOrder < 0 || *psMaxOutOfOrder > 0x4000) { status = NDIS_STATUS_INVALID_DATA; break; } } else { // No value in registry. Set a reasonable default.
//
*psMaxOutOfOrder = 100; status = NDIS_STATUS_SUCCESS; } }
// (optional) The role (LNS or LAC) that the adapter will play in
// outgoing calls. The role played for incoming calls is
// determined by the role the peer plays in his call
// request.
//
{ NDIS_STRING nstr = NDIS_STRING_CONST( "OutgoingRole" );
NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterInteger ); if (status == NDIS_STATUS_SUCCESS) { *pOutgoingRole = (L2TPROLE )pncp->ParameterData.IntegerData;
// Make sure it's a valid role.
//
if (*pOutgoingRole != LR_Lac && *pOutgoingRole != LR_Lns) { status = NDIS_STATUS_INVALID_DATA; break; } } else { // No role in registry. Default to LAC.
//
*pOutgoingRole = LR_Lac; status = NDIS_STATUS_SUCCESS; } }
// (optional) The control receive window sent to peer to indicate how
// many sent control messages peer may have outstanding.
//
{ NDIS_STRING nstr = NDIS_STRING_CONST( "ControlReceiveWindow" );
NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterInteger ); if (status == NDIS_STATUS_SUCCESS) { *pusControlReceiveWindow = (USHORT )pncp->ParameterData.IntegerData; } else { // No setting in registry. Set a reasonable default.
//
*pusControlReceiveWindow = 8; status = NDIS_STATUS_SUCCESS; } }
// (optional) The payload receive window sent to peer to indicate how
// many send payloads peer may have outstanding on any one
// call. A value of 0 disables all Ns/Nr sequencing on the
// payload channel for locally requested calls.
//
{ NDIS_STRING nstr = NDIS_STRING_CONST( "PayloadReceiveWindow" );
NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterInteger ); if (status == NDIS_STATUS_SUCCESS) { *pusPayloadReceiveWindow = (USHORT )pncp->ParameterData.IntegerData; } else { // No setting in registry. Set a reasonable default.
//
// Note: Default changed to 0 (off) from 16 due to performance
// study that shows significantly better results without
// flow control, presumably due to interference with
// higher level timers.
//
*pusPayloadReceiveWindow = 0; status = NDIS_STATUS_SUCCESS; } }
// (optional) The maximum payload send window size reported to
// NDISWAN. Peer may set the actual send window higher or
// lower, but if higher this is the actual maximum.
//
{ NDIS_STRING nstr = NDIS_STRING_CONST( "PayloadSendWindow" );
NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterInteger ); if (status == NDIS_STATUS_SUCCESS) { *pulPayloadSendWindow = (ULONG )pncp->ParameterData.IntegerData; } else { // No setting in registry. Set a reasonable default.
//
*pulPayloadSendWindow = 16; status = NDIS_STATUS_SUCCESS; } }
// (optional) The lookaside list depth ceiling, where higher values
// allow this driver to consume more non-paged pool in
// return for performance gain at high volumes. Setting
// this value above 'MaxVcs' has no effect.
//
{ NDIS_STRING nstr = NDIS_STRING_CONST( "LookasideDepth" );
NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterInteger ); if (status == NDIS_STATUS_SUCCESS) { *pusLlistDepth = (USHORT )pncp->ParameterData.IntegerData; } else { // No setting in registry. Set a reasonable default.
//
*pusLlistDepth = 30; status = NDIS_STATUS_SUCCESS; } }
// The host name passed to peer and used as the base of the
// call serial number.
// Host name is required as this is used in hostname MUST AVP.
{ NDIS_STRING nstr = NDIS_STRING_CONST( "HostName" ); NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterString ); if (status == NDIS_STATUS_SUCCESS) { *ppszHostName = StrDupNdisStringToA( &pncp->ParameterData.StringData ); if(!*ppszHostName) { status = NDIS_STATUS_RESOURCES; } } else { // No setting in registry, so use a default.
//
*ppszHostName = GetFullHostNameFromRegistry(); if (!*ppszHostName) { *ppszHostName = StrDupSized("NONE", sizeof("NONE"), 0); }
if(*ppszHostName) { status = NDIS_STATUS_SUCCESS; } else { status = NDIS_STATUS_RESOURCES; } } if(status != NDIS_STATUS_SUCCESS) { break; } }
// (optional) The single password shared with peer for use in
// verifying peer's identity. If specified, authentication
// of peer is required, and if not, authentication is not
// provided.
//
{ NDIS_STRING nstr = NDIS_STRING_CONST( "Password" );
NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterString ); if (status == NDIS_STATUS_SUCCESS) { *ppszPassword = StrDupNdisStringToA( &pncp->ParameterData.StringData ); } else { // No setting in registry...and no default.
//
*ppszPassword = NULL; status = NDIS_STATUS_SUCCESS; } }
// (optional) Buggy peer hedge flag to ignore framing mismatches.
//
{ NDIS_STRING nstr = NDIS_STRING_CONST( "IgnoreFramingMismatch" );
NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterInteger ); if (status == NDIS_STATUS_SUCCESS) { *pfIgnoreFramingMismatch = (BOOLEAN )!!(pncp->ParameterData.IntegerData); } else { // No value in registry. Set a reasonable default.
//
*pfIgnoreFramingMismatch = TRUE; status = NDIS_STATUS_SUCCESS; } }
// (optional) Flag indicating whether, by default, separate tunnels
// are to be created for each outgoing call even if a
// tunnel already exists to the same peer. This setting
// can be overridden via L2TP-specific call parameters.
//
{ NDIS_STRING nstr = NDIS_STRING_CONST( "ExclusiveTunnels" );
NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterInteger ); if (status == NDIS_STATUS_SUCCESS) { *pfExclusiveTunnels = (BOOLEAN )!!(pncp->ParameterData.IntegerData); } else { // No value in registry. Set a default.
//
*pfExclusiveTunnels = FALSE; status = NDIS_STATUS_SUCCESS; } }
// (optional) Flag indicating whether routes created outside this
// driver may be used as L2TP host routes. If the flag is
// not set, the pre-existing host routes will cause the
// tunnel to close.
//
{ NDIS_STRING nstr = NDIS_STRING_CONST( "UseExistingRoutes" ); BOOLEAN fDefault;
fDefault = FALSE;
NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterInteger ); if (status == NDIS_STATUS_SUCCESS) { *phre = (HOSTROUTEEXISTS )pncp->ParameterData.IntegerData;
if (*phre != HRE_Use && *phre != HRE_Fail #if ROUTEWITHREF
&& *phre != HRE_Reference #endif
) { // Bad value in registry.
//
fDefault = TRUE; } } else { // No value in registry.
//
status = NDIS_STATUS_SUCCESS; fDefault = TRUE; }
if (fDefault) { #if ROUTEWITHREF
// Set default to "reference" as this allows simultaneous L2TP
// and PPTP connections between the same two peers without
// host route trashing.
//
*phre = HRE_Reference; #else
// Set default to "fail" to prevent L2TP from stomping on a
// PPTP host route.
//
*phre = HRE_Fail; #endif
} }
// (optional) Flag indicating whether UDP checksums should be disabled
// on L2TP payload traffic.
//
{ NDIS_STRING nstr = NDIS_STRING_CONST( "DisableUdpChecksums" );
NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterInteger ); if (status == NDIS_STATUS_SUCCESS) { *pfDisableUdpXsums = (BOOLEAN )!!(pncp->ParameterData.IntegerData); } else {
// No value in registry. Set a default. The L2TP draft says
// implementation MUST default to "enabled".
//
*pfDisableUdpXsums = TRUE; status = NDIS_STATUS_SUCCESS; } }
// (required) The driver description string, which is reported to TAPI
// as the L2TP line name.
//
{ NDIS_STRING nstr = NDIS_STRING_CONST( "DriverDesc" );
NdisReadConfiguration( &status, &pncp, hCfg, &nstr, NdisParameterString ); if (status == NDIS_STATUS_SUCCESS) { *ppszDriverDesc = StrDupNdisString( &pncp->ParameterData.StringData ); } else { // No setting in registry...and no default.
//
*ppszDriverDesc = NULL; status = NDIS_STATUS_SUCCESS; } } } while (FALSE);
NdisCloseConfiguration( hCfg );
TRACE( TL_N, TM_Init, ( "Reg: vcs=%d mt=%d or=%d lld=%d hto=%d ooo=%d mad=%d dx=%d", *pusMaxVcs, *pMediaType, *pOutgoingRole, (ULONG )*pusLlistDepth, *pulHelloMs, (INT )*psMaxOutOfOrder, *pulMaxAckDelayMs, (UINT )*pfDisableUdpXsums ) ); TRACE( TL_N, TM_Init, ( "Reg: mto=%d ito=%d mrt=%d crw=%d prw=%d psw=%d ifm=%d xt=%d xr=%d", *pulMaxSendTimeoutMs, *pulInitialSendTimeoutMs, *pulMaxRetransmits, (UINT )*pusControlReceiveWindow, (UINT )*pusPayloadReceiveWindow, (UINT )*pulPayloadSendWindow, (UINT )*pfIgnoreFramingMismatch, (UINT )*pfExclusiveTunnels, (UINT )*phre)); TRACE( TL_N, TM_Init, ( "Reg: hn=\"%s\" pw=\"%s\"", ((*ppszHostName) ? *ppszHostName : ""), ((*ppszPassword) ? *ppszPassword : "") ) );
return status; }
NDIS_STATUS QueryInformation( IN ADAPTERCB* pAdapter, IN VCCB* pVc, IN NDIS_OID Oid, IN PVOID InformationBuffer, IN ULONG InformationBufferLength, OUT PULONG BytesWritten, OUT PULONG BytesNeeded )
// Handle QueryInformation requests. Arguments are as for the standard
// NDIS 'MiniportQueryInformation' handler except this routine does not
// count on being serialized with respect to other requests.
//
{ NDIS_STATUS status; ULONG ulInfo; VOID* pInfo; ULONG ulInfoLen;
status = NDIS_STATUS_SUCCESS;
// The cases in this switch statement find or create a buffer containing
// the requested information and point 'pInfo' at it, noting it's length
// in 'ulInfoLen'. Since many of the OIDs return a ULONG, a 'ulInfo'
// buffer is set up as the default.
//
ulInfo = 0; pInfo = &ulInfo; ulInfoLen = sizeof(ulInfo);
switch (Oid) { case OID_GEN_MAXIMUM_LOOKAHEAD: { // Report the maximum number of bytes we can always provide as
// lookahead data on receive indications. We always indicate full
// packets so this is the same as the receive block size. And
// since we always allocate enough for a full packet, the receive
// block size is the same as the frame size.
//
TRACE( TL_N, TM_Mp, ( "QInfo(OID_GEN_MAXIMUM_LOOKAHEAD)" ) ); ulInfo = L2TP_MaxFrameSize; break; }
case OID_GEN_MAC_OPTIONS: { // Report a bitmask defining optional properties of the driver.
//
// NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA promises that our receive
// buffer is not on a device-specific card.
//
// NDIS_MAC_OPTION_TRANSFERS_NOT_PEND promises we won't return
// NDIS_STATUS_PENDING from our TransferData handler which is true
// since we don't have one.
//
TRACE( TL_N, TM_Mp, ( "QInfo(OID_GEN_MAC_OPTIONS)" ) ); ulInfo = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | NDIS_MAC_OPTION_TRANSFERS_NOT_PEND; break; }
case OID_WAN_MEDIUM_SUBTYPE: { // Report the media subtype we support. NDISWAN may use this in
// the future (doesn't now) to provide framing differences for
// different media.
//
TRACE( TL_N, TM_Mp, ( "QInfo(OID_WAN_MEDIUM_SUBTYPE)" ) ); ulInfo = NdisWanMediumL2TP; break; }
case OID_WAN_CO_GET_INFO: { // Report the capabilities of the adapter.
//
TRACE( TL_N, TM_Mp, ( "QInfo(OID_WAN_CO_GET_INFO)" ) ); pInfo = &pAdapter->info; ulInfoLen = sizeof(NDIS_WAN_CO_INFO); break; }
case OID_WAN_CO_GET_LINK_INFO: { // Report the current state of the link.
//
TRACE( TL_N, TM_Mp, ( "QInfo(OID_WAN_CO_GET_LINK_INFO)" ) );
if (!pVc) { return NDIS_STATUS_INVALID_DATA; }
pInfo = &pVc->linkinfo; ulInfoLen = sizeof(NDIS_WAN_CO_GET_LINK_INFO); break; }
case OID_WAN_CO_GET_COMP_INFO: { // Report the type of compression we provide, which is none.
//
TRACE( TL_N, TM_Mp, ( "QInfo(OID_WAN_CO_GET_COMP_INFO)" ) ); status = NDIS_STATUS_NOT_SUPPORTED; ulInfoLen = 0; break; }
case OID_WAN_CO_GET_STATS_INFO: { // Because L2TP doesn't do compression, NDISWAN will use it's own
// statistics and not query ours.
//
ASSERT( !"OID_WAN_CO_GET_STATS_INFO?" ); status = NDIS_STATUS_NOT_SUPPORTED; ulInfoLen = 0; break; }
case OID_GEN_SUPPORTED_LIST: { static ULONG aulSupportedOids[] = { OID_GEN_SUPPORTED_LIST, OID_GEN_MAXIMUM_LOOKAHEAD, OID_GEN_MAC_OPTIONS, OID_WAN_MEDIUM_SUBTYPE, OID_WAN_CO_GET_INFO, OID_WAN_CO_GET_LINK_INFO, OID_WAN_CO_SET_LINK_INFO, OID_CO_TAPI_CM_CAPS, OID_CO_TAPI_LINE_CAPS, OID_CO_TAPI_ADDRESS_CAPS, OID_CO_TAPI_GET_CALL_DIAGNOSTICS };
TRACE( TL_N, TM_Mp, ( "QInfo(OID_GEN_SUPPORTED_LIST)" ) ); pInfo = aulSupportedOids; ulInfoLen = sizeof(aulSupportedOids); break; }
#if 0
// These OIDs are mandatory according to current doc, but since
// NDISWAN never requests them they are omitted.
//
case OID_GEN_HARDWARE_STATUS: case OID_GEN_MEDIA_SUPPORTED: case OID_GEN_MEDIA_IN_USE: case OID_GEN_MEDIA_IN_USE: case OID_GEN_MAXIMUM_FRAME_SIZE: case OID_GEN_LINK_SPEED: case OID_GEN_TRANSMIT_BUFFER_SPACE: case OID_GEN_RECEIVE_BUFFER_SPACE: case OID_GEN_TRANSMIT_BLOCK_SIZE: case OID_GEN_RECEIVE_BLOCK_SIZE: case OID_GEN_VENDOR_ID: case OID_GEN_VENDOR_DESCRIPTION: case OID_GEN_VENDOR_DRIVER_VERSION: case OID_GEN_CURRENT_PACKET_FILTER: case OID_GEN_CURRENT_LOOKAHEAD: case OID_GEN_DRIVER_VERSION: case OID_GEN_MAXIMUM_TOTAL_SIZE: case OID_GEN_MAC_OPTIONS: case OID_GEN_MEDIA_CONNECT_STATUS: case OID_GEN_MAXIMUM_SEND_PACKETS: case OID_WAN_PERMANENT_ADDRESS: case OID_WAN_CURRENT_ADDRESS: case OID_WAN_QUALITY_OF_SERVICE: case OID_WAN_LINE_COUNT: #endif
default: { TRACE( TL_A, TM_Mp, ( "Q-OID=$%08x?", Oid ) ); status = NDIS_STATUS_NOT_SUPPORTED; ulInfoLen = 0; break; } }
if (ulInfoLen > InformationBufferLength) { // Caller's buffer is too small. Tell him what he needs.
//
*BytesNeeded = ulInfoLen; status = NDIS_STATUS_INVALID_LENGTH; } else { // Copy the found result to caller's buffer.
//
if (ulInfoLen > 0) { NdisMoveMemory( InformationBuffer, pInfo, ulInfoLen ); DUMPDW( TL_N, TM_Mp, pInfo, ulInfoLen ); }
*BytesNeeded = *BytesWritten = ulInfoLen; }
return status; }
VOID ReferenceAdapter( IN ADAPTERCB* pAdapter )
// Adds areference to the adapter block, 'pAdapter'.
//
{ LONG lRef;
lRef = NdisInterlockedIncrement( &pAdapter->lRef );
TRACE( TL_N, TM_Ref, ( "RefA to %d", lRef ) ); }
NDIS_STATUS SetInformation( IN ADAPTERCB* pAdapter, IN VCCB* pVc, IN NDIS_OID Oid, IN PVOID InformationBuffer, IN ULONG InformationBufferLength, OUT PULONG BytesRead, OUT PULONG BytesNeeded )
// Handle SetInformation requests. Arguments are as for the standard NDIS
// 'MiniportQueryInformation' handler except this routine does not count
// on being serialized with respect to other requests.
//
{ NDIS_STATUS status;
status = NDIS_STATUS_SUCCESS;
switch (Oid) { case OID_WAN_CO_SET_LINK_INFO: { // Read new link state settings.
//
TRACE( TL_N, TM_Mp, ( "SInfo(OID_WAN_CO_SET_LINK_INFO)" ) ); if (InformationBufferLength < sizeof(NDIS_WAN_CO_SET_LINK_INFO)) { status = NDIS_STATUS_INVALID_LENGTH; *BytesRead = 0; } else { if (!pVc) return NDIS_STATUS_INVALID_DATA;
ASSERT( sizeof(pVc->linkinfo) == sizeof(NDIS_WAN_CO_SET_LINK_INFO) );
NdisMoveMemory( &pVc->linkinfo, InformationBuffer, sizeof(pVc->linkinfo) ); DUMPB( TL_N, TM_Mp, &pVc->linkinfo, sizeof(pVc->linkinfo) );
*BytesRead = sizeof(NDIS_WAN_CO_SET_LINK_INFO); }
*BytesNeeded = sizeof(NDIS_WAN_CO_SET_LINK_INFO); } break;
case OID_WAN_CO_SET_COMP_INFO: { // L2TP doesn't provide compression.
//
TRACE( TL_N, TM_Mp, ( "SInfo(OID_WAN_CO_SET_COMP_INFO)" ) ); status = NDIS_STATUS_NOT_SUPPORTED; *BytesRead = *BytesNeeded = 0; break; }
#if 0
// These OIDs are mandatory according to current doc, but since
// NDISWAN never requests them they are omitted.
//
case OID_GEN_CURRENT_PACKET_FILTER: case OID_GEN_CURRENT_LOOKAHEAD: case OID_GEN_PROTOCOL_OPTIONS: case OID_WAN_PROTOCOL_TYPE: case OID_WAN_HEADER_FORMAT: #endif
default: { TRACE( TL_A, TM_Mp, ( "S-OID=$%08x?", Oid ) ); status = NDIS_STATUS_NOT_SUPPORTED; *BytesRead = *BytesNeeded = 0; break; } }
return status; }
|