1768 lines
55 KiB
C
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;
|
|
}
|