windows-nt/Source/XPSP1/NT/net/rras/ndis/rasl2tp/mp.c
2020-09-26 16:20:57 +08:00

1768 lines
55 KiB
C

// 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"
// 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* pfUpdatePeerAddress,
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 fUpdatePeerAddress;
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,
&fUpdatePeerAddress,
&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;
}
if (fUpdatePeerAddress)
{
pAdapter->ulFlags |= ACBF_UpdatePeerAddress;
}
// 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 ) );
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* pfUpdatePeerAddress,
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;
}
}
// (optional) The host name passed to peer and used as the base of the
// call serial number.
//
{
NDIS_STRING nstr = NDIS_STRING_CONST( "HostName" );
NdisReadConfiguration(
&status, &pncp, hCfg, &nstr, NdisParameterString );
if (status == NDIS_STATUS_SUCCESS)
{
*ppszHostName =
StrDupNdisStringToA( &pncp->ParameterData.StringData );
}
else
{
// No setting in registry, so use a default.
//
*ppszHostName = GetFullHostNameFromRegistry();
if (!*ppszHostName)
{
*ppszHostName = StrDup( "NONE" );
}
status = NDIS_STATUS_SUCCESS;
}
}
// (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 that changes in peer's source IP
// address and/or UDP port are to result in the destination
// of outbound packets changing accordingly.
//
{
NDIS_STRING nstr = NDIS_STRING_CONST( "UpdatePeerAddress" );
NdisReadConfiguration(
&status, &pncp, hCfg, &nstr, NdisParameterInteger );
if (status == NDIS_STATUS_SUCCESS)
{
*pfUpdatePeerAddress =
(BOOLEAN )!!(pncp->ParameterData.IntegerData);
}
else
{
// No value in registry. Set a default.
//
*pfUpdatePeerAddress = FALSE;
status = NDIS_STATUS_SUCCESS;
}
}
// (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 ua=%d",
*pulMaxSendTimeoutMs,
*pulInitialSendTimeoutMs,
*pulMaxRetransmits,
(UINT )*pusControlReceiveWindow,
(UINT )*pusPayloadReceiveWindow,
(UINT )*pulPayloadSendWindow,
(UINT )*pfIgnoreFramingMismatch,
(UINT )*pfExclusiveTunnels,
(UINT )*phre,
(UINT )*pfUpdatePeerAddress ) );
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;
}