windows-nt/Source/XPSP1/NT/net/rras/ip/wanarp2/adapter.c

4077 lines
93 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
ipinip\adapter.c
Abstract:
The file contains the section interface of WANARP to the TCP/IP stack
that is involved with Binding Notification and Querying/Setting
information for interfaces
Revision History:
AmritanR
--*/
#define __FILE_SIG__ ADAPTER_SIG
#include "inc.h"
#pragma hdrstop
NDIS_HANDLE g_nhUnbindContext;
NDIS_HANDLE g_nhBindContext;
NDIS_STATUS g_nsStatus = 0;
NDIS_STATUS g_nsError = 0;
BOOLEAN g_bRemovalInProgress;
WORK_QUEUE_ITEM g_wqiWorkItem;
WORK_QUEUE_ITEM g_wqiNdisWorkItem;
const GUID ServerInterfaceGuid = {0x6e06f030, 0x7526, 0x11d2, {0xba, 0xf4, 0x00, 0x60, 0x08, 0x15, 0xa4, 0xbd}};
extern
VOID
IPDelayedNdisReEnumerateBindings(
CTEEvent *Event,
PVOID Context
);
BOOLEAN
IsBindingPresent(
IN GUID *pGuid
);
VOID
WanNdisBindAdapter(
PNDIS_STATUS pnsRetStatus,
NDIS_HANDLE nhBindContext,
PNDIS_STRING nsAdapterName,
PVOID pvSystemSpecific1,
PVOID pvSystemSpecific2
)
{
RtAssert(FALSE);
}
INT
WanIpBindAdapter(
IN PNDIS_STATUS pnsRetStatus,
IN NDIS_HANDLE nhBindContext,
IN PNDIS_STRING pnsAdapterName,
IN PVOID pvSS1,
IN PVOID pvSS2
)
/*++
Routine Description:
Called by IP to bind an adapter. We open the binding and then do
all the other work in complete handler
Locks:
The routine acquires the global adapter list lock, so it is not
PAGEABLE.
Arguments:
Return Value:
--*/
{
NDIS_STATUS nsStatus;
KIRQL kiIrql;
LONG lResult;
#if DBG
ANSI_STRING asTempAnsiString;
#endif
TraceEnter(ADPT, "WanIpBindAdapter");
//
// Serialize Bind, Unbind code
//
WanpAcquireResource(&g_wrBindMutex);
RtAcquireSpinLock(&g_rlStateLock,
&kiIrql);
//
// See if we have already received a BIND call or are in the process
// of servicing a bind
//
if(g_lBindRcvd isnot 0)
{
//
// We have already received a bind call
//
RtAssert(g_lBindRcvd is 1);
RtReleaseSpinLock(&g_rlStateLock,
kiIrql);
WanpReleaseResource(&g_wrBindMutex);
Trace(ADPT,ERROR,
("WanIpBindAdapter: Duplicate bind call\n"));
*pnsRetStatus = NDIS_STATUS_SUCCESS;
TraceLeave(ADPT, "WanIpBindAdapter");
return FALSE;
}
//
// Set BindRcvd to 1 so that we dont service any binds till we
// get done
//
g_lBindRcvd = 1;
RtReleaseSpinLock(&g_rlStateLock,
kiIrql);
Trace(ADPT, INFO,
("WanIpBindAdapter: IP called to bind to adapter %S\n",
pnsAdapterName->Buffer));
//
// We need to open this adapter as our NDISWAN binding
//
g_nhBindContext = nhBindContext;
nsStatus = WanpOpenNdisWan(pnsAdapterName,
(PNDIS_STRING)pvSS1);
if((nsStatus isnot NDIS_STATUS_SUCCESS) and
(nsStatus isnot NDIS_STATUS_PENDING))
{
RtAcquireSpinLock(&g_rlStateLock,
&kiIrql);
g_lBindRcvd = 0;
RtReleaseSpinLock(&g_rlStateLock,
kiIrql);
Trace(ADPT, ERROR,
("WanIpBindAdapter: Error %x opening NDISWAN on %S\n",
nsStatus,
pnsAdapterName->Buffer));
}
*pnsRetStatus = nsStatus;
//
// At this point we are done. If the operation finished synchronously
// then our OpenAdapterComplete handler has already been called
// Otherwise stuff will happen later
//
TraceLeave(ADPT, "WanIpBindAdapter");
return TRUE;
}
#pragma alloc_text(PAGE, WanpOpenNdisWan)
NDIS_STATUS
WanpOpenNdisWan(
PNDIS_STRING pnsAdapterName,
PNDIS_STRING pnsSystemSpecific1
)
/*++
Routine Description:
This routine opens the ndiswan adapter. It also stores the SS1 string
in a global for use by the completion routine
Locks:
Called with the g_wrBindMutex held exclusively
Arguments:
pusBindName Name of the bindings
pnsSystemSpecific1 The SS1 passed in the bind call from IP
Return Value:
--*/
{
NDIS_STATUS nsStatus, nsError;
UINT i;
NDIS_MEDIUM MediaArray[] = {NdisMediumWan};
PWCHAR pwcNameBuffer, pwcStringBuffer;
PBYTE pbyBuffer;
PAGED_CODE();
TraceEnter(ADPT,"OpenNdiswan");
//
// Save a copy of the NDIS binding name
// Increase the length by 1 so that we can NULL terminate it for
// easy printing
//
pnsAdapterName->Length += sizeof(WCHAR);
g_usNdiswanBindName.Buffer = RtAllocate(NonPagedPool,
pnsAdapterName->Length,
WAN_STRING_TAG);
if(g_usNdiswanBindName.Buffer is NULL)
{
Trace(GLOBAL, ERROR,
("OpenNdiswan: Unable to allocate %d bytes\n",
pnsAdapterName->Length));
g_nhBindContext = NULL;
WanpReleaseResource(&g_wrBindMutex);
return STATUS_INSUFFICIENT_RESOURCES;
}
g_usNdiswanBindName.MaximumLength = pnsAdapterName->Length;
RtlUpcaseUnicodeString(&g_usNdiswanBindName,
pnsAdapterName,
FALSE);
pnsAdapterName->Length -= sizeof(WCHAR);
g_usNdiswanBindName.Length -= sizeof(WCHAR);
//
// NULL terminate
//
g_usNdiswanBindName.Buffer[g_usNdiswanBindName.MaximumLength/sizeof(WCHAR) - 1] = UNICODE_NULL;
//
// Save a copy of SS1
//
pwcStringBuffer = RtAllocate(NonPagedPool,
pnsSystemSpecific1->MaximumLength,
WAN_STRING_TAG);
if(pwcStringBuffer is NULL)
{
RtFree(g_usNdiswanBindName.Buffer);
g_usNdiswanBindName.Buffer = NULL;
g_usNdiswanBindName.MaximumLength = 0;
g_usNdiswanBindName.Length = 0;
g_nhBindContext = NULL;
WanpReleaseResource(&g_wrBindMutex);
return NDIS_STATUS_RESOURCES;
}
RtlZeroMemory(pwcStringBuffer,
pnsSystemSpecific1->MaximumLength);
//
// Save a copy of the SS1 string
//
g_nsSystemSpecific1.MaximumLength = pnsSystemSpecific1->MaximumLength;
g_nsSystemSpecific1.Length = pnsSystemSpecific1->Length;
g_nsSystemSpecific1.Buffer = pwcStringBuffer;
RtlCopyMemory(g_nsSystemSpecific1.Buffer,
pnsSystemSpecific1->Buffer,
pnsSystemSpecific1->Length);
//
// Open the NDIS adapter.
//
Trace(ADPT, INFO,
("OpenNdiswan: Opening %S\n", g_usNdiswanBindName.Buffer));
//
// Medium index
//
i = 0;
#define MAX_MEDIA 1
NdisOpenAdapter(&nsStatus,
&nsError,
&g_nhNdiswanBinding,
&i,
MediaArray,
MAX_MEDIA,
g_nhWanarpProtoHandle,
(NDIS_HANDLE)0x0CABB1E5,
pnsAdapterName,
0,
NULL);
#undef MAX_MEDIA
if(nsStatus isnot NDIS_STATUS_PENDING)
{
//
// we always return PENDING to NDIS because we need to
// do a switch to system thread when we are done setting OIDS to
// NDISWAN. So call out completion routine here
//
WanNdisOpenAdapterComplete((NDIS_HANDLE)0x0CABB1E5,
nsStatus,
nsError);
nsStatus = NDIS_STATUS_PENDING;
}
TraceLeave(ADPT, "OpenNdiswan");
return nsStatus;
}
#pragma alloc_text (PAGE, WanNdisOpenAdapterComplete)
VOID
WanNdisOpenAdapterComplete(
NDIS_HANDLE nhHandle,
NDIS_STATUS nsStatus,
NDIS_STATUS nsError
)
/*++
Routine Description:
Completion routine called by NDIS when it is done opening the NDISWAN
binding
If the open was successful, we start the train of requests
Locks:
Called either synchronously or off a worker thread with the g_wrBindMutex
This routine needs to release the resource and set g_lBindRcvd
Arguments:
nhHandle
nsStatus
nsError
Return Value:
None
--*/
{
NDIS_STATUS nsResult;
BYTE rgbyProtocolId[ARP_802_ADDR_LENGTH] = {0x80,
0x00,
0x00,
0x00,
0x08,
0x00};
PWANARP_NDIS_REQUEST_CONTEXT pRequestContext;
TraceEnter(ADPT,"NdisOpenAdapterComplete");
PAGED_CODE();
RtAssert(nhHandle is (NDIS_HANDLE)0x0CABB1E5);
//
// If we couldnt open the NDIS wan binding, free all the resources
// and return
//
if(nsStatus isnot NDIS_STATUS_SUCCESS)
{
Trace(ADPT, ERROR,
("OpenAdapterComplete: Status %x\n", nsStatus));
RtAssert(g_nhBindContext isnot NULL);
NdisCompleteBindAdapter(g_nhBindContext,
nsStatus,
nsError);
g_nhBindContext = NULL;
WanpFreeBindResourcesAndReleaseLock();
return;
}
//
// From here on, the NDISWAN adapter is opened, so to cleanup resources
// we must call CloseNdisWan()
//
pRequestContext = RtAllocate(NonPagedPool,
sizeof(WANARP_NDIS_REQUEST_CONTEXT),
WAN_REQUEST_TAG);
if(pRequestContext is NULL)
{
RtAssert(g_nhBindContext isnot NULL);
#if 0
NdisCompleteBindAdapter(g_nhBindContext,
nsStatus,
nsError);
g_nhBindContext = NULL;
#endif
g_nsStatus = g_nsError = NDIS_STATUS_RESOURCES;
ExInitializeWorkItem(&g_wqiNdisWorkItem,
WanpCloseNdisWan,
NULL);
ExQueueWorkItem(&g_wqiNdisWorkItem,
DelayedWorkQueue);
// WanpCloseNdisWan(NULL);
Trace(ADPT, ERROR,
("NdisOpenAdapterComplete: Couldnt allocate memory for request context\n"));
return;
}
//
// Set protocol type
//
RtlCopyMemory(pRequestContext->rgbyProtocolId,
rgbyProtocolId,
sizeof(rgbyProtocolId));
nsResult = WanpDoNdisRequest(NdisRequestSetInformation,
OID_WAN_PROTOCOL_TYPE,
pRequestContext->rgbyProtocolId,
sizeof(pRequestContext->rgbyProtocolId),
pRequestContext,
WanpSetProtocolTypeComplete);
if(nsResult isnot NDIS_STATUS_PENDING)
{
//
// No need to call the completion routine, since DoNdisRequest
// always calls it
//
Trace(ADPT, ERROR,
("NdisOpenAdapterComplete: %x from OID_WAN_PROTOCOL_TYPE\n",
nsResult));
}
TraceLeave(ADPT,"NdisOpenAdapterComplete");
}
VOID
WanpSetProtocolTypeComplete(
NDIS_HANDLE nhHandle,
struct _WANARP_NDIS_REQUEST_CONTEXT *pRequestContext,
NDIS_STATUS nsStatus
)
/*++
Routine Description:
Completion handler called when we are done with setting
OID_WAN_PROTOCOL_TYPE
Locks:
None
Arguments:
nhHandle Binding for the adapter to which the request was sent
pRequestContext Pointer to the request context
nsStatus Result of the request
Return Value:
None
--*/
{
NDIS_STATUS nsResult;
TraceEnter(ADPT,"SetProtocolTypeComplete");
if(nsStatus isnot NDIS_STATUS_SUCCESS)
{
Trace(ADPT, ERROR,
("SetProtocolTypeComplete: Status %x\n", nsStatus));
WanpLastOidComplete(nhHandle,
pRequestContext,
nsStatus);
return;
}
//
// Set lookahead size
//
pRequestContext->ulLookahead = WANARP_LOOKAHEAD_SIZE;
nsResult = WanpDoNdisRequest(NdisRequestSetInformation,
OID_GEN_CURRENT_LOOKAHEAD,
&(pRequestContext->ulLookahead),
sizeof(pRequestContext->ulLookahead),
pRequestContext,
WanpSetLookaheadComplete);
if(nsResult isnot NDIS_STATUS_PENDING)
{
Trace(ADPT, ERROR,
("SetProtocolTypeComplete: %x from OID_GEN_CURRENT_LOOKAHEAD\n",
nsResult));
}
TraceLeave(ADPT,"SetProtocolTypeComplete");
}
VOID
WanpSetLookaheadComplete(
NDIS_HANDLE nhHandle,
struct _WANARP_NDIS_REQUEST_CONTEXT *pRequestContext,
NDIS_STATUS nsStatus
)
/*++
Routine Description:
Completion handler called when we are done with setting
OID_GEN_CURRENT_LOOKAHEAD
Locks:
None
Arguments:
nhHandle Binding for the adapter to which the request was sent
pRequestContext Pointer to the request context
nsStatus Result of the request
Return Value:
None
--*/
{
NDIS_STATUS nsResult;
TraceEnter(ADPT,"SetLookaheadComplete");
if(nsStatus isnot NDIS_STATUS_SUCCESS)
{
Trace(ADPT, ERROR,
("SetLookaheadComplete: Status %x\n", nsStatus));
WanpLastOidComplete(nhHandle,
pRequestContext,
nsStatus);
return;
}
//
// Set packet filters
//
pRequestContext->ulPacketFilter =
NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_DIRECTED;
nsResult = WanpDoNdisRequest(NdisRequestSetInformation,
OID_GEN_CURRENT_PACKET_FILTER,
&(pRequestContext->ulPacketFilter),
sizeof(pRequestContext->ulPacketFilter),
pRequestContext,
WanpSetPacketFilterComplete);
if(nsResult isnot NDIS_STATUS_PENDING)
{
Trace(ADPT, ERROR,
("SetLookaheadComplete: %x from OID_GEN_CURRENT_PACKET_FILTER\n",
nsResult));
}
TraceLeave(ADPT,"SetLookaheadComplete");
}
VOID
WanpSetPacketFilterComplete(
NDIS_HANDLE nhHandle,
struct _WANARP_NDIS_REQUEST_CONTEXT *pRequestContext,
NDIS_STATUS nsStatus
)
/*++
Routine Description:
Completion handler called when we are done with setting
OID_GEN_CURRENT_PACKET_FILTER
Locks:
None
Arguments:
nhHandle Binding for the adapter to which the request was sent
pRequestContext Pointer to the request context
nsStatus Result of the request
Return Value:
None
--*/
{
NDIS_STATUS nsResult;
BYTE byHeaderSize;
TraceEnter(ADPT,"SetPacketFilterComplete");
if(nsStatus isnot NDIS_STATUS_SUCCESS)
{
Trace(ADPT, ERROR,
("SetPacketFilterComplete: Status %x\n", nsStatus));
WanpLastOidComplete(nhHandle,
pRequestContext,
nsStatus);
return;
}
//
// Set packet filters
//
pRequestContext->TransportHeaderOffset.ProtocolType =
NDIS_PROTOCOL_ID_TCP_IP;
pRequestContext->TransportHeaderOffset.HeaderOffset =
(USHORT)sizeof(ETH_HEADER);
nsResult = WanpDoNdisRequest(NdisRequestSetInformation,
OID_GEN_TRANSPORT_HEADER_OFFSET,
&(pRequestContext->TransportHeaderOffset),
sizeof(pRequestContext->TransportHeaderOffset),
pRequestContext,
WanpLastOidComplete);
if(nsResult isnot NDIS_STATUS_PENDING)
{
Trace(ADPT, ERROR,
("SetPacketFilterComplete: %x from OID_GEN_TRANSPORT_HEADER_OFFSET\n",
nsResult));
}
TraceLeave(ADPT,"SetPacketFilterComplete");
}
VOID
WanpLastOidComplete(
NDIS_HANDLE nhHandle,
struct _WANARP_NDIS_REQUEST_CONTEXT *pRequestContext,
NDIS_STATUS nsStatus
)
/*++
Routine Description:
Completion handler called when we are done with setting the last OID
Currently that is OID_GEN_TRANSPORT_HEADER_OFFSET,
If everything went, well we initialize our adapters
Locks:
None
Arguments:
nhHandle Binding for the adapter to which the request was sent
pRequestContext Pointer to the request context
nsStatus Result of the request
Return Value:
None
--*/
{
NDIS_STATUS nsResult;
TraceEnter(ADPT,"LastOidComplete");
RtFree(pRequestContext);
RtAssert(g_wrBindMutex.lWaitCount >= 1);
if(nsStatus isnot STATUS_SUCCESS)
{
RtAssert(g_nhBindContext isnot NULL);
#if 0
//
// BindContext being NON-NULL means we are being called
// asynchronously, hence call NdisCompleteBindAdapter
//
NdisCompleteBindAdapter(g_nhBindContext,
nsStatus,
nsStatus);
g_nhBindContext = NULL;
#endif
Trace(ADPT, ERROR,
("LastOidComplete: Status %x\n", nsStatus));
g_nsStatus = g_nsError = nsStatus;
ExInitializeWorkItem(&g_wqiNdisWorkItem,
WanpCloseNdisWan,
NULL);
ExQueueWorkItem(&g_wqiNdisWorkItem,
DelayedWorkQueue);
// WanpCloseNdisWan(NULL);
return;
}
//
// This needs to be put in when the multiple adapters stuff is done
//
//
// The OpenNdiswan call would have setup the system specific
// Since the WanpInitializeAdapters must be called at PASSIVE, we
// fire of a work item here to call the function.
//
ExInitializeWorkItem(&g_wqiWorkItem,
WanpInitializeAdapters,
NULL);
ExQueueWorkItem(&g_wqiWorkItem,
DelayedWorkQueue);
//
// Dont release the mutex here
//
TraceLeave(ADPT,"LastOidComplete");
}
//
// When this is used, remember NOT to use NdisUnbindAdapter as a clean
// up routine because of the way the resource is held
//
#pragma alloc_text(PAGE, WanpInitializeAdapters)
NTSTATUS
WanpInitializeAdapters(
PVOID pvContext
)
/*++
Routine Description:
This routine uses the stored SS1 and opens the IP config for the
binding. It then loops through the multi_sz and creates one adapter
for every sz.
Locks:
Called with the bind mutex held.
This function releases the mutex
Arguments:
None
Return Value:
--*/
{
NDIS_STRING IPConfigName = NDIS_STRING_CONST("IPConfig");
NDIS_STATUS nsStatus;
NDIS_HANDLE nhConfigHandle;
USHORT i;
PADAPTER pNewAdapter;
NTSTATUS nStatus, nReturnStatus;
PWCHAR pwszDeviceBuffer;
PNDIS_CONFIGURATION_PARAMETER pParam;
TraceEnter(ADPT, "InitializeAdapters");
PAGED_CODE();
UNREFERENCED_PARAMETER(pvContext);
RtAssert(g_nhBindContext isnot NULL);
do
{
//
// Open the key for this "adapter"
//
NdisOpenProtocolConfiguration(&nsStatus,
&nhConfigHandle,
&g_nsSystemSpecific1);
if(nsStatus isnot NDIS_STATUS_SUCCESS)
{
Trace(ADPT, ERROR,
("InitializeAdapters: Unable to Open Protocol Config %x\n",
nsStatus));
break;
}
//
// Read in the IPConfig string. If this is not present,
// fail this call.
//
NdisReadConfiguration(&nsStatus,
&pParam,
nhConfigHandle,
&IPConfigName,
NdisParameterMultiString);
if((nsStatus isnot NDIS_STATUS_SUCCESS) or
(pParam->ParameterType isnot NdisParameterMultiString))
{
Trace(ADPT, ERROR,
("InitializeAdapters: Unable to read IPConfig. Status %x \n",
nsStatus));
NdisCloseConfiguration(nhConfigHandle);
nsStatus = STATUS_UNSUCCESSFUL;
break;
}
//
// Allocate memory for the max length device name - used later
//
pwszDeviceBuffer =
RtAllocate(NonPagedPool,
(WANARP_MAX_DEVICE_NAME_LEN + 1) * sizeof(WCHAR),
WAN_STRING_TAG);
if(pwszDeviceBuffer is NULL)
{
NdisCloseConfiguration(nhConfigHandle);
Trace(ADPT, ERROR,
("InitializeAdapters: Couldnt alloc %d bytes for dev name\n",
(WANARP_MAX_DEVICE_NAME_LEN + 1) * sizeof(WCHAR)));
nsStatus = STATUS_INSUFFICIENT_RESOURCES;
break;
}
}while(FALSE);
if(nsStatus isnot STATUS_SUCCESS)
{
//
// Tell NDIS that the bind is done but it failed
//
g_nsStatus = g_nsError = nsStatus;
#if 0
NdisCompleteBindAdapter(g_nhBindContext,
nsStatus,
nsStatus);
g_nhBindContext = NULL;
#endif
WanpCloseNdisWan(NULL);
TraceLeave(ADPT, "InitializeAdapters");
return nsStatus;
}
//
// Now walk through the each of the string
// Since the string must end with two \0's we only walk Len/2 - 1
//
i = 0;
nReturnStatus = STATUS_UNSUCCESSFUL;
RtAssert((pParam->ParameterData.StringData.Length % sizeof(WCHAR)) is 0);
//
// The IPConfigString is a MULTI_SZ with each SZ being the relative key
// for an interfaces IP configuration. It is thus something like
// TCPIP\PARAMETERS\INTERFACES\<device_name>
// Being a MULTI_SZ it is terminated by 2 NULL characters. So we
// walk till the last but one character while parsing out the SZ from
// the multi_sz
//
while(i < (pParam->ParameterData.StringData.Length/sizeof(WCHAR)) - 1)
{
USHORT j, usConfigLen, usDevLen;
UNICODE_STRING usTempString, usUpcaseString, usDevString;
PADAPTER pNewAdapter;
GUID Guid;
if(pParam->ParameterData.StringData.Buffer[i] is UNICODE_NULL)
{
if(pParam->ParameterData.StringData.Buffer[i + 1] is UNICODE_NULL)
{
//
// Two nulls - end of string
//
break;
}
//
// only one null, just move on to the next character
//
i++;
continue;
}
RtAssert(pParam->ParameterData.StringData.Buffer[i] isnot UNICODE_NULL);
//
// Now i points to the start of an SZ. Figure out the length of this
//
usConfigLen =
(USHORT)wcslen(&(pParam->ParameterData.StringData.Buffer[i]));
//
// Make usTempString point to this config. Also increase
// the size by one so one can print this nicely
//
usTempString.MaximumLength = (usConfigLen + 1) * sizeof(WCHAR);
usTempString.Length = (usConfigLen + 1) * sizeof(WCHAR);
usTempString.Buffer = &(pParam->ParameterData.StringData.Buffer[i]);
usUpcaseString.Buffer = RtAllocate(NonPagedPool,
usTempString.MaximumLength,
WAN_STRING_TAG);
if(usUpcaseString.Buffer is NULL)
{
Trace(ADPT, ERROR,
("InitializeAdapters: Unable to allocate %d bytes\n",
usTempString.MaximumLength));
usUpcaseString.MaximumLength = 0;
usUpcaseString.Length = 0;
i += usConfigLen;
continue;
}
usUpcaseString.MaximumLength = usTempString.MaximumLength;
RtlUpcaseUnicodeString(&usUpcaseString,
&usTempString,
FALSE);
//
// Set the last wchar to null
//
usUpcaseString.Buffer[usConfigLen] = UNICODE_NULL;
//
// Set the length back to what it was
//
usUpcaseString.Length -= sizeof(WCHAR);
RtAssert((usUpcaseString.Length % sizeof(WCHAR)) is 0);
//
// The device name is the last thing in the '\' separated path.
// So walk the SZ backwards looking for '\'
// NOTE one could use wcsrchr, but it would be inefficient since
// it doesnt know the end of the buffer
//
for(j = usUpcaseString.Length/sizeof(WCHAR) - 1;
j >= 0;
j--)
{
if(usUpcaseString.Buffer[j] is L'\\')
{
break;
}
}
//
// So at this point j is the index to the last '\'
//
//
// First off, make this a GUID
//
nStatus = ConvertStringToGuid(&(usUpcaseString.Buffer[j + 1]),
wcslen(&(usUpcaseString.Buffer[j + 1])) * sizeof(WCHAR),
&Guid);
if(nStatus isnot STATUS_SUCCESS)
{
//
// Hmm - not a GUID?
//
Trace(ADPT, ERROR,
("InitializeAdapters: String %S is not a GUID\n",
&(usUpcaseString.Buffer[j + 1])));
//
// Free the upcase string and move to the next SZ in IPConfig
//
RtFree(usUpcaseString.Buffer);
usUpcaseString.Buffer = NULL;
usUpcaseString.MaximumLength = 0;
usUpcaseString.Length = 0;
i += usConfigLen;
continue;
}
//
// Make sure this binding is not present
//
if(IsBindingPresent(&Guid))
{
Trace(ADPT, WARN,
("InitializeAdapters: %S already present\n",
&(usUpcaseString.Buffer[j + 1])));
//
// Free the upcase string and move to the next SZ in IPConfig
//
RtFree(usUpcaseString.Buffer);
usUpcaseString.Buffer = NULL;
usUpcaseString.MaximumLength = 0;
usUpcaseString.Length = 0;
i += usConfigLen;
continue;
}
//
// We need to tack on a \DEVICE in front of Guid string
//
usDevLen = wcslen(TCPIP_IF_PREFIX) +
wcslen(&(usUpcaseString.Buffer[j]));
//
// make sure we can fit in the space we have allocated
//
RtAssert(usDevLen <= WANARP_MAX_DEVICE_NAME_LEN);
pwszDeviceBuffer[usDevLen] = UNICODE_NULL;
usDevString.MaximumLength = usDevLen * sizeof(WCHAR);
usDevString.Length = usDevLen * sizeof(WCHAR);
usDevString.Buffer = pwszDeviceBuffer;
//
// Copy over the \Device part
//
RtlCopyMemory(pwszDeviceBuffer,
TCPIP_IF_PREFIX,
wcslen(TCPIP_IF_PREFIX) * sizeof(WCHAR));
//
// Cat the \<Name> part
//
RtlCopyMemory(&(pwszDeviceBuffer[wcslen(TCPIP_IF_PREFIX)]),
&usUpcaseString.Buffer[j],
wcslen(&(usUpcaseString.Buffer[j])) * sizeof(WCHAR));
//
// Create an adapter with this name and config
//
pNewAdapter = NULL;
Trace(ADPT, INFO,
("InitializeAdapters: Calling create adapter for %S %S\n",
usUpcaseString.Buffer,
usDevString.Buffer));
nStatus = WanpCreateAdapter(&Guid,
&usUpcaseString,
&usDevString,
&pNewAdapter);
if(nStatus isnot STATUS_SUCCESS)
{
Trace(ADPT, ERROR,
("InitializeAdapters: Err %x creating adapter for %S (%S)\n",
nStatus,
usUpcaseString.Buffer,
pwszDeviceBuffer));
}
else
{
//
// If even one succeeds, we return success
//
nReturnStatus = STATUS_SUCCESS;
}
//
// Done with the upcased string
//
RtFree(usUpcaseString.Buffer);
usUpcaseString.Buffer = NULL;
usUpcaseString.MaximumLength = 0;
usUpcaseString.Length = 0;
//
// Go to the next SZ in the MULTI_SZ
//
i += usConfigLen;
}
NdisCloseConfiguration(nhConfigHandle);
RtFree(pwszDeviceBuffer);
NdisCompleteBindAdapter(g_nhBindContext,
nReturnStatus,
nReturnStatus);
g_nhBindContext = NULL;
if(nReturnStatus isnot STATUS_SUCCESS)
{
WanpCloseNdisWan(NULL);
}
else
{
g_lBindRcvd = 1;
WanpReleaseResource(&g_wrBindMutex);
}
TraceLeave(ADPT, "InitializeAdapters");
return nReturnStatus;
}
NTSTATUS
WanpCreateAdapter(
IN GUID *pAdapterGuid,
IN PUNICODE_STRING pusConfigName,
IN PUNICODE_STRING pusDeviceName,
OUT ADAPTER **ppNewAdapter
)
/*++
Routine Description:
Creates and initializes an ADAPTER structure
If this is the first adapter, it is used as the server adapter.
For that case, it also creates and initializes the server interface.
The server adapter is added to IP
Locks:
Called at passive, however it acquires the adapter list lock since it
sets g_pServerAdapter/Interface
Arguments:
pusConfigName Name of config key
pusDeviceName The device name for the adapter
ppNewAdapter Pointer to storage for the pointer to newly created adapter
Return Value:
STATUS_SUCCESS
STATUS_INSUFFICIENT_RESOURCES
--*/
{
ULONG ulSize;
PVOID pvBuffer;
PADAPTER pAdapter;
USHORT i;
NTSTATUS nStatus;
KIRQL kiIrql;
PASSIVE_ENTRY();
TraceEnter(ADPT, "CreateAdapter");
Trace(ADPT, TRACE,
("CreateAdapter: \n\t%S\n\t%S\n",
pusConfigName->Buffer,
pusDeviceName->Buffer));
*ppNewAdapter = NULL;
//
// The size that one needs is the size of the adapter + the length of the
// name. Add a WCHAR to get a easily printtable string.
// Align everything on a 4 byte boundary
//
ulSize = ALIGN_UP(sizeof(ADAPTER), ULONG) +
ALIGN_UP((pusConfigName->Length + sizeof(WCHAR)), ULONG) +
ALIGN_UP((pusDeviceName->Length + sizeof(WCHAR)), ULONG);
#if DBG
//
// For debug code we also store the adapter name in ANSI
// We use 2 * sizeof(CHAR) because RtlUnicodeToAnsiString needs
// MaximumLength + 1
//
ulSize += pusDeviceName->Length/sizeof(WCHAR) + (2 * sizeof(CHAR));
#endif
pAdapter = RtAllocate(NonPagedPool,
ulSize,
WAN_ADAPTER_TAG);
if(pAdapter is NULL)
{
Trace(ADPT, ERROR,
("CreateAdapter: Failed to allocate memory\n"));
TraceLeave(ADPT, "CreateAdapter");
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Clear all the fields out
//
RtlZeroMemory(pAdapter,
ulSize);
//
// The config name buffer starts at the end of the adapter structure.
//
pvBuffer = (PVOID)((ULONG_PTR)pAdapter + sizeof(ADAPTER));
//
// We DWORD align it for better compare/copy
//
pvBuffer = ALIGN_UP_POINTER(pvBuffer, ULONG);
pAdapter->usConfigKey.Length = pusConfigName->Length;
pAdapter->usConfigKey.MaximumLength = pusConfigName->Length;
pAdapter->usConfigKey.Buffer = (PWCHAR)pvBuffer;
RtlCopyMemory(pAdapter->usConfigKey.Buffer,
pusConfigName->Buffer,
pusConfigName->Length);
//
// The device name comes after this
//
pvBuffer = (PVOID)((ULONG_PTR)pvBuffer +
pusConfigName->Length +
sizeof(WCHAR));
pvBuffer = ALIGN_UP_POINTER(pvBuffer, ULONG);
pAdapter->usDeviceNameW.Length = pusDeviceName->Length;
pAdapter->usDeviceNameW.MaximumLength = pusDeviceName->Length;
pAdapter->usDeviceNameW.Buffer = (PWCHAR)pvBuffer;
RtlCopyMemory(pAdapter->usDeviceNameW.Buffer,
pusDeviceName->Buffer,
pusDeviceName->Length);
#if DBG
//
// The debug string comes after the UNICODE device name buffer
//
pvBuffer = (PVOID)((ULONG_PTR)pvBuffer +
pusDeviceName->Length +
sizeof(WCHAR));
pvBuffer = ALIGN_UP_POINTER(pvBuffer, ULONG);
pAdapter->asDeviceNameA.Buffer = (PCHAR)pvBuffer;
//
// Apparently, the unicode to ansi function wants length + 1
//
pAdapter->asDeviceNameA.MaximumLength = pusDeviceName->Length/sizeof(WCHAR) + 1;
RtlUnicodeStringToAnsiString(&pAdapter->asDeviceNameA,
&pAdapter->usDeviceNameW,
FALSE);
#endif // DBG
//
// Structure copy
//
pAdapter->Guid = *pAdapterGuid;
//
// Must be set to INVALID so that GetEntityList can work
//
pAdapter->dwATInstance = INVALID_ENTITY_INSTANCE;
pAdapter->dwIfInstance = INVALID_ENTITY_INSTANCE;
//
// Set the state
//
pAdapter->byState = AS_FREE;
//
// This hardware index is needed to generate the Unique ID that
// DHCP uses.
// NOTE - we dont have an index so all hardware addrs will be the same
//
BuildHardwareAddrFromIndex(pAdapter->rgbyHardwareAddr,
pAdapter->dwAdapterIndex);
//
// Initialize the lock for the adapter
//
RtInitializeSpinLock(&(pAdapter->rlLock));
InitializeListHead(&(pAdapter->lePendingPktList));
InitializeListHead(&(pAdapter->lePendingHdrList));
InitializeListHead(&(pAdapter->leEventList));
//
// Set the Refcount to 1 because it will either lie on some list
// or be pointed to by g_pServerAdapter
//
InitAdapterRefCount(pAdapter);
if(g_pServerAdapter is NULL)
{
PUMODE_INTERFACE pInterface;
//
// We use the first adapter adapter as the server adapter
// We also create the server interface right here
//
RtAssert(g_pServerInterface is NULL);
pInterface = RtAllocate(NonPagedPool,
sizeof(UMODE_INTERFACE),
WAN_INTERFACE_TAG);
if(pInterface is NULL)
{
Trace(ADPT, ERROR,
("CreateAdapter: Couldnt allocate %d bytes for server i/f\n",
sizeof(UMODE_INTERFACE)));
RtFree(pAdapter);
*ppNewAdapter = NULL;
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(pInterface,
sizeof(UMODE_INTERFACE));
//
// Get an index from IP
// If this fails, it sets the value to INVALID_IF_INDEX
//
nStatus = WanpGetNewIndex(&(pInterface->dwRsvdAdapterIndex));
if(nStatus isnot STATUS_SUCCESS)
{
Trace(ADPT, ERROR,
("CreateAdapter: Couldnt get index for server interface\n"));
RtFree(pAdapter);
RtFree(pInterface);
*ppNewAdapter = NULL;
return STATUS_INSUFFICIENT_RESOURCES;
}
Trace(ADPT, TRACE,
("CreateAdapter: Server Index is %d\n",
pInterface->dwRsvdAdapterIndex));
RtInitializeSpinLock(&(pInterface->rlLock));
InitInterfaceRefCount(pInterface);
pInterface->dwIfIndex = INVALID_IF_INDEX;
pInterface->dwAdminState = IF_ADMIN_STATUS_UP;
pInterface->duUsage = DU_CALLIN;
//
// Structure copy
//
pInterface->Guid = ServerInterfaceGuid;
EnterWriter(&g_rwlAdapterLock,
&kiIrql);
pAdapter->byState = AS_FREE;
pInterface->dwOperState = IF_OPER_STATUS_DISCONNECTED;
pInterface->dwLastChange = GetTimeTicks();
//
// We dont cross ref the structures here. That is done
// we have added the server interface to IP.
//
g_pServerAdapter = pAdapter;
g_pServerInterface = pInterface;
ExitWriter(&g_rwlAdapterLock,
kiIrql);
Trace(ADPT, INFO,
("CreateAdapter: %S is server adapter\n",
pAdapter->usDeviceNameW.Buffer));
}
else
{
EnterWriter(&g_rwlAdapterLock,
&kiIrql);
InsertHeadList(&g_leFreeAdapterList,
&(pAdapter->leAdapterLink));
g_ulNumFreeAdapters++;
ExitWriter(&g_rwlAdapterLock,
kiIrql);
}
InterlockedIncrement(&g_ulNumAdapters);
*ppNewAdapter = pAdapter;
TraceLeave(ADPT, "CreateAdapter");
return STATUS_SUCCESS;
}
#pragma alloc_text(PAGE, WanNdisUnbindAdapter)
VOID
WanNdisUnbindAdapter(
PNDIS_STATUS pnsRetStatus,
NDIS_HANDLE nhProtocolContext,
NDIS_HANDLE nhUnbindContext
)
/*++
Routine Description:
Called by NDIS to unbind an open adapter. Since we only open one adapter
we get this only once.
Locks:
The function acquires the g_wrBindMutex. This is released in
WanpFreeBindResourcesAndReleaseLock
Arguments:
pnsRetStatus
nhProtocolContext
nhUnbindContext
Return Value:
NDIS_STATUS_PENDING
--*/
{
NDIS_STATUS nsStatus;
TraceEnter(ADPT,"NdisUnbindAdapter");
PAGED_CODE();
RtAssert(nhProtocolContext is (NDIS_HANDLE)0x0CABB1E5);
//
// Get into the critical section
//
WanpAcquireResource(&g_wrBindMutex);
//
// Mark all the adapters as down so that we dont process anything
// from IP on them
//
//
// Close the adapter if we havent already done so.
// This will stop us getting stuff from NDISWAN
//
if(g_nhNdiswanBinding isnot NULL)
{
g_nhUnbindContext = nhUnbindContext;
WanpCloseNdisWan(NULL);
//
// If we call CloseNdisWan then we DONT release the resource here.
// It is released by CloseAdapterComplete
//
*pnsRetStatus = NDIS_STATUS_PENDING;
}
else
{
WanpReleaseResource(&g_wrBindMutex);
*pnsRetStatus = NDIS_STATUS_SUCCESS;
}
TraceLeave(ADPT, "NdisUnbindAdapter");
}
VOID
WanpCloseNdisWan(
PVOID pvContext
)
/*++
Routine Description:
This function cleans all the resources of an open adapter
Locks:
The function is called with the g_wrBindMutex held.
Arguments:
None
Return Value:
None
--*/
{
NDIS_STATUS nsStatus;
TraceEnter(ADPT, "WanpCloseNdisWan");
RtAssert(g_nhNdiswanBinding isnot NULL);
RtAssert(g_wrBindMutex.lWaitCount >= 1);
NdisCloseAdapter(&nsStatus,
g_nhNdiswanBinding);
g_nhNdiswanBinding = NULL;
//
// If our completion routine will not be called, do it here
//
if(nsStatus isnot NDIS_STATUS_PENDING)
{
WanNdisCloseAdapterComplete((NDIS_HANDLE)0x0CABB1E5,
nsStatus);
}
//
// We DONT release the resource here. It is released by
// CloseAdapterComplete
//
TraceLeave(ADPT, "WanpCloseNdisWan");
return;
}
#pragma alloc_text(PAGE, WanNdisCloseAdapterComplete)
VOID
WanNdisCloseAdapterComplete(
NDIS_HANDLE nhBindHandle,
NDIS_STATUS nsStatus
)
/*++
Routine Description:
Called by NDIS when it is done closing the NDISWAN adapter
The close adapter can be done either because we failed somewhere (after
successfully opening our adapter) and in the process of cleanup are
closing our adapter (in which case the unbind context will be null) or
because we got an unbind and were cleaning up all adapter related stuff
Locks:
Called the g_wrBindMutex held.
The resource was acquired either in the Unbind handler or was acquired
before the failure code was called
Arguments:
nhBindHandle
nsStatus
Return Value:
None
--*/
{
KIRQL kiIrql;
NDIS_HANDLE nhUnbind;
NDIS_HANDLE nhBind;
NDIS_STATUS tnsStatus, tnsError;
TraceEnter(ADPT, "NdisCloseAdapterComplete");
PAGED_CODE();
nhUnbind = g_nhUnbindContext;
nhBind = g_nhBindContext;
tnsStatus = g_nsStatus;
tnsError = g_nsError;
RtAssert(g_wrBindMutex.lWaitCount >= 1);
g_nhUnbindContext = NULL;
g_nhBindContext = NULL;
WanpFreeBindResourcesAndReleaseLock();
if(nhBind isnot NULL)
{
RtAssert(nhUnbind == NULL);
//
// Tell NDIS that the bind is done but it failed
//
NdisCompleteBindAdapter(nhBind,
tnsStatus,
tnsError);
}
//
// If this is being triggered from an unbind..
//
if(nhUnbind isnot NULL)
{
RtAssert(nhBind == NULL);
NdisCompleteUnbindAdapter(nhUnbind,
NDIS_STATUS_SUCCESS);
}
}
VOID
WanpFreeBindResourcesAndReleaseLock(
VOID
)
{
RtAssert(g_wrBindMutex.lWaitCount >= 1);
RtFree(g_usNdiswanBindName.Buffer);
g_usNdiswanBindName.Buffer = NULL;
RtFree(g_nsSystemSpecific1.Buffer);
g_nsSystemSpecific1.Buffer = NULL;
WanpRemoveAllAdapters();
//
// There could be turds in the connection table if this was not
// a clean shutdown
//
WanpRemoveAllConnections();
//
// Done, set the global event
//
KeSetEvent(&g_keCloseEvent,
0,
FALSE);
//
// Finally done, set g_lBindRcvd and release the resource
//
g_lBindRcvd = 0;
WanpReleaseResource(&g_wrBindMutex);
PASSIVE_EXIT();
}
PADAPTER
WanpFindAdapterToMap(
IN DIAL_USAGE duUsage,
OUT PKIRQL pkiIrql,
IN DWORD dwAdapterIndex,
IN PUNICODE_STRING pusNewIfName
)
/*++
Routine Description:
Finds a free adapter to map to an interface.
The adapter, if found is locked and referenced. Its state is set to
AS_MAPPING and it is put on the mapped list.
Locks:
Must be called at PASSIVE
Acquires g_rwlAdapterLock as WRITER
If it returns a mapped adapter, then the function returns at DPC and
the original IRQL is in pkiIrql
Arguments:
duUsage The usage for which the adapter needs to be found
pkiIrql
dwAdapterIndex
pusNewIfName
Return Value:
Pointer to adapter if successful
--*/
{
PADAPTER pAdapter;
KIRQL kiIrql;
PLIST_ENTRY pleNode;
NTSTATUS nStatus;
KEVENT keChangeEvent;
WAN_EVENT_NODE TempEvent;
//
// Find a free adapter
//
EnterWriter(&g_rwlAdapterLock,
&kiIrql);
if(duUsage is DU_CALLIN)
{
if(g_pServerAdapter is NULL)
{
Trace(CONN, ERROR,
("FindAdapterToMap: No server adapter\n"));
ExitWriter(&g_rwlAdapterLock,
kiIrql);
return NULL;
}
RtAssert(g_pServerInterface);
//
// Lock out the adapter
//
RtAcquireSpinLockAtDpcLevel(&(g_pServerAdapter->rlLock));
//
// Reference it because we are going to return it. Also we need the
// reference when we let go of the lock if we need to wait
//
ReferenceAdapter(g_pServerAdapter);
//
// See if the adapter has been added to IP
// rasiphlp has to call us to map the server adapter before
// doing a line up
//
if(g_pServerAdapter->byState isnot AS_MAPPED)
{
RtAssert(g_pServerAdapter->byState is AS_ADDING);
if(g_pServerAdapter->byState is AS_ADDING)
{
KeInitializeEvent(&(TempEvent.keEvent),
SynchronizationEvent,
FALSE);
InsertTailList(&(g_pServerAdapter->leEventList),
&(TempEvent.leEventLink));
//
// Let go of the lock and wait on the event
//
RtReleaseSpinLockFromDpcLevel(&(g_pServerAdapter->rlLock));
ExitWriter(&g_rwlAdapterLock,
kiIrql);
nStatus = KeWaitForSingleObject(&(TempEvent.keEvent),
Executive,
KernelMode,
FALSE,
NULL);
RtAssert(nStatus is STATUS_SUCCESS);
EnterWriter(&g_rwlAdapterLock,
&kiIrql);
RtAcquireSpinLockAtDpcLevel(&(g_pServerAdapter->rlLock));
RemoveEntryList(&(TempEvent.leEventLink));
}
}
if(g_pServerAdapter->byState isnot AS_MAPPED)
{
PADAPTER pTempAdapter;
//
// Couldnt add the adapter because of some reason,
//
pTempAdapter = g_pServerAdapter;
Trace(CONN, ERROR,
("FindAdapterToMap: Unable to get mapped server adapter\n"));
RtReleaseSpinLockFromDpcLevel(&(g_pServerAdapter->rlLock));
ExitWriter(&g_rwlAdapterLock,
kiIrql);
DereferenceAdapter(pTempAdapter);
return NULL;
}
RtAssert(g_pServerAdapter->byState is AS_MAPPED);
ExitWriterFromDpcLevel(&g_rwlAdapterLock);
*pkiIrql = kiIrql;
return g_pServerAdapter;
}
//
// Non dial in case. First try and see if there is an adapter with the
// index we want already added to IP
//
pAdapter = NULL;
for(pleNode = g_leAddedAdapterList.Flink;
pleNode isnot &g_leAddedAdapterList;
pleNode = pleNode->Flink)
{
PADAPTER pTempAdapter;
pTempAdapter = CONTAINING_RECORD(pleNode,
ADAPTER,
leAdapterLink);
RtAssert(pTempAdapter->byState is AS_ADDED);
if(pTempAdapter->dwAdapterIndex is dwAdapterIndex)
{
RemoveEntryList(&(pTempAdapter->leAdapterLink));
g_ulNumAddedAdapters--;
pAdapter = pTempAdapter;
break;
}
}
if(pAdapter isnot NULL)
{
//
// So we found an added adapter (it has been removed from the
// added adapter list). Add it to the mapped list
//
InsertTailList(&g_leMappedAdapterList,
&(pAdapter->leAdapterLink));
g_ulNumMappedAdapters++;
RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
ExitWriterFromDpcLevel(&g_rwlAdapterLock);
ReferenceAdapter(pAdapter);
pAdapter->byState = AS_MAPPING;
*pkiIrql = kiIrql;
#if DBG
Trace(CONN, INFO,
("FindAdapterToMap: Found %s already added\n",
pAdapter->asDeviceNameA.Buffer));
#endif
return pAdapter;
}
//
// Didnt find an added adapter
// See if the adapter is on the change list. We want to wait for this
// because IP doesnt like to have to interfaces with the same index, even
// if one is in the process of being removed
//
for(pleNode = g_leChangeAdapterList.Flink;
pleNode isnot &g_leChangeAdapterList;
pleNode = pleNode->Flink)
{
PADAPTER pTempAdapter;
pTempAdapter = CONTAINING_RECORD(pleNode,
ADAPTER,
leAdapterLink);
if(pTempAdapter->dwAdapterIndex is dwAdapterIndex)
{
//
// Wait for the change to complete
//
KeInitializeEvent(&(TempEvent.keEvent),
SynchronizationEvent,
FALSE);
RtAcquireSpinLockAtDpcLevel(&(pTempAdapter->rlLock));
InsertTailList(&(pTempAdapter->leEventList),
&(TempEvent.leEventLink));
//
// Reference the adapter, let go of the lock and wait on the event
//
ReferenceAdapter(pTempAdapter);
RtReleaseSpinLockFromDpcLevel(&(pTempAdapter->rlLock));
ExitWriter(&g_rwlAdapterLock,
kiIrql);
nStatus = KeWaitForSingleObject(&(TempEvent.keEvent),
Executive,
KernelMode,
FALSE,
NULL);
RtAssert(nStatus is STATUS_SUCCESS);
EnterWriter(&g_rwlAdapterLock,
&kiIrql);
RtAcquireSpinLockAtDpcLevel(&(pTempAdapter->rlLock));
RemoveEntryList(&(TempEvent.leEventLink));
RtReleaseSpinLockFromDpcLevel(&(pTempAdapter->rlLock));
DereferenceAdapter(pTempAdapter);
break;
}
}
if(!IsListEmpty(&g_leFreeAdapterList))
{
pleNode = RemoveHeadList(&g_leFreeAdapterList);
pAdapter = CONTAINING_RECORD(pleNode,
ADAPTER,
leAdapterLink);
g_ulNumFreeAdapters--;
#if DBG
Trace(CONN, INFO,
("FindAdapterToMap: Found free adapter %s\n",
pAdapter->asDeviceNameA.Buffer));
#endif // DBG
}
else
{
//
// Couldnt find an adapter. That is bad
// TODO - if the added adapter list is not empty, we could call
// RemoveSomeAddedAdapter... at this point
//
Trace(ADPT, ERROR,
("FindAdapterToMap: Couldnt find free adapter\n"));
ExitWriter(&g_rwlAdapterLock,
kiIrql);
return NULL;
}
//
// Lock and refcount the adapter.
//
RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
ReferenceAdapter(pAdapter);
//
// The adapter better not be mapped
//
RtAssert(pAdapter->pInterface is NULL);
RtAssert(pAdapter->byState is AS_FREE);
//
// Set the state to ADDING
//
pAdapter->byState = AS_ADDING;
//
// Since we are changing the state, no one else should be also
// changing the state
//
RtAssert(pAdapter->pkeChangeEvent is NULL);
KeInitializeEvent(&keChangeEvent,
SynchronizationEvent,
FALSE);
pAdapter->pkeChangeEvent = &keChangeEvent;
//
// Insert into the change list
//
InsertTailList(&g_leChangeAdapterList,
&(pAdapter->leAdapterLink));
RtReleaseSpinLockFromDpcLevel(&(pAdapter->rlLock));
ExitWriter(&g_rwlAdapterLock,
kiIrql);
//
// Add the adapter to IP
//
nStatus = WanpAddAdapterToIp(pAdapter,
FALSE,
dwAdapterIndex,
pusNewIfName,
IF_TYPE_PPP,
IF_ACCESS_POINTTOPOINT,
IF_CONNECTION_DEMAND);
if(nStatus isnot STATUS_SUCCESS)
{
Trace(ADPT, ERROR,
("FindAdapterToMap: %x adding %x to IP\n",
nStatus, pAdapter));
EnterWriter(&g_rwlAdapterLock,
&kiIrql);
RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
#if DBG
RtAssert(IsEntryOnList(&g_leChangeAdapterList,
&(pAdapter->leAdapterLink)));
#endif
pAdapter->pkeChangeEvent = NULL;
RemoveEntryList(&(pAdapter->leAdapterLink));
pAdapter->byState = AS_FREE;
InsertTailList(&g_leFreeAdapterList,
&(pAdapter->leAdapterLink));
g_ulNumFreeAdapters++;
//
// If anyone is waiting on a state change, notify them
//
for(pleNode = pAdapter->leEventList.Flink;
pleNode isnot &(pAdapter->leEventList);
pleNode = pleNode->Flink)
{
PWAN_EVENT_NODE pTempEvent;
pTempEvent = CONTAINING_RECORD(pleNode,
WAN_EVENT_NODE,
leEventLink);
KeSetEvent(&(pTempEvent->keEvent),
0,
FALSE);
}
RtReleaseSpinLockFromDpcLevel(&(pAdapter->rlLock));
ExitWriter(&g_rwlAdapterLock,
kiIrql);
DereferenceAdapter(pAdapter);
return NULL;
}
//
// Wait till the OpenAdapter is called
//
nStatus = KeWaitForSingleObject(&keChangeEvent,
Executive,
KernelMode,
FALSE,
NULL);
RtAssert(nStatus is STATUS_SUCCESS);
Trace(ADPT, TRACE,
("FindAdapterToMap: IPAddInterface succeeded for adapter %w\n",
pAdapter->usDeviceNameW.Buffer));
//
// Lock the adapter, insert into the added list
//
EnterWriter(&g_rwlAdapterLock,
&kiIrql);
RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
#if DBG
RtAssert(IsEntryOnList(&g_leChangeAdapterList,
&(pAdapter->leAdapterLink)));
#endif
RemoveEntryList(&(pAdapter->leAdapterLink));
pAdapter->pkeChangeEvent = NULL;
InsertHeadList(&g_leMappedAdapterList,
&(pAdapter->leAdapterLink));
g_ulNumMappedAdapters++;
//
// If anyone is waiting on a state change, notify them
//
for(pleNode = pAdapter->leEventList.Flink;
pleNode isnot &(pAdapter->leEventList);
pleNode = pleNode->Flink)
{
PWAN_EVENT_NODE pTempEvent;
pTempEvent = CONTAINING_RECORD(pleNode,
WAN_EVENT_NODE,
leEventLink);
KeSetEvent(&(pTempEvent->keEvent),
0,
FALSE);
}
ExitWriterFromDpcLevel(&g_rwlAdapterLock);
*pkiIrql = kiIrql;
return pAdapter;
}
NTSTATUS
WanpAddAdapterToIp(
IN PADAPTER pAdapter,
IN BOOLEAN bServerAdapter,
IN DWORD dwAdapterIndex, OPTIONAL
IN PUNICODE_STRING pusNewIfName, OPTIONAL
IN DWORD dwMediaType,
IN BYTE byAccessType,
IN BYTE byConnectionType
)
/*++
Routine Description:
This routine adds the interface to IP
Locks:
MUST BE CALLED AT PASSIVE, but acquires a spinlock so cant be paged out
Arguments:
pAdapter The adapter to add
bServerAdapter Set to TRUE if this is a server adapter
dwAdapterIndex
pusNewIfName
Return Value:
STATUS_SUCCESS
--*/
{
LLIPBindInfo BindInfo;
IP_STATUS IPStatus;
UNICODE_STRING usName;
NTSTATUS nStatus;
KIRQL kiIrql;
PASSIVE_ENTRY();
TraceEnter(ADPT, "AddAdapterToIp");
RtlZeroMemory(&BindInfo, sizeof(LLIPBindInfo));
BindInfo.lip_context = pAdapter;
BindInfo.lip_mss = WANARP_DEFAULT_MTU;
BindInfo.lip_speed = WANARP_DEFAULT_SPEED;
BindInfo.lip_txspace = sizeof(ETH_HEADER);
BindInfo.lip_transmit = WanIpTransmit;
BindInfo.lip_transfer = WanIpTransferData;
BindInfo.lip_returnPkt = WanIpReturnPacket;
BindInfo.lip_close = WanIpCloseAdapter;
BindInfo.lip_addaddr = WanIpAddAddress;
BindInfo.lip_deladdr = WanIpDeleteAddress;
BindInfo.lip_invalidate = WanIpInvalidateRce;
BindInfo.lip_open = WanIpOpenAdapter;
BindInfo.lip_qinfo = WanIpQueryInfo;
BindInfo.lip_setinfo = WanIpSetInfo;
BindInfo.lip_getelist = WanIpGetEntityList;
BindInfo.lip_flags = LIP_COPY_FLAG;
if(bServerAdapter)
{
BindInfo.lip_flags |= (LIP_P2MP_FLAG | LIP_NOLINKBCST_FLAG);
BindInfo.lip_closelink = WanIpCloseLink;
}
else
{
BindInfo.lip_flags |= (LIP_P2P_FLAG | LIP_NOIPADDR_FLAG);
}
BindInfo.lip_addrlen = ARP_802_ADDR_LENGTH;
BindInfo.lip_addr = pAdapter->rgbyHardwareAddr;
BindInfo.lip_OffloadFlags = 0;
BindInfo.lip_dowakeupptrn = NULL;
BindInfo.lip_pnpcomplete = NULL;
BindInfo.lip_arpflushate = NULL;
BindInfo.lip_arpflushallate = NULL;
BindInfo.lip_setndisrequest = WanIpSetRequest;
RtlInitUnicodeString(&usName,
pAdapter->usConfigKey.Buffer);
#if DBG
//
// Only set while adding or deleting the interface, which is serialized
//
pAdapter->dwRequestedIndex = dwAdapterIndex;
#endif
IPStatus = g_pfnIpAddInterface(&(pAdapter->usDeviceNameW),
pusNewIfName,
&(pAdapter->usConfigKey),
NULL,
pAdapter,
WanIpDynamicRegister,
&BindInfo,
dwAdapterIndex,
dwMediaType,
byAccessType,
byConnectionType);
if(IPStatus isnot IP_SUCCESS)
{
Trace(ADPT, ERROR,
("AddAdapterToIp: IPAddInterface failed for adapter %w\n",
pAdapter->usDeviceNameW.Buffer));
TraceLeave(ADPT, "AddAdapterToIp");
return STATUS_UNSUCCESSFUL;
}
TraceLeave(ADPT, "AddAdapterToIp");
return STATUS_SUCCESS;
}
VOID
WanIpOpenAdapter(
IN PVOID pvContext
)
/*++
Routine Description:
Called by IP when the adapter from its IPAddInterface() call
Locks:
Arguments:
pvContext Pointer to the ADAPTER structure
Return Value:
None
--*/
{
PADAPTER pAdapter;
KIRQL kiIrql;
PLIST_ENTRY pleNode;
TraceEnter(ADPT, "WanOpenAdapter");
pAdapter = (PADAPTER)pvContext;
RtAcquireSpinLock(&(pAdapter->rlLock),
&kiIrql);
//
// Set the state to added
//
pAdapter->byState = AS_ADDED;
//
// One reference for the fact that we added the adapter to IP
//
ReferenceAdapter(pAdapter);
//
// Wake up the thread that caused this
//
RtAssert(pAdapter->pkeChangeEvent);
KeSetEvent(pAdapter->pkeChangeEvent,
0,
FALSE);
RtReleaseSpinLock(&(pAdapter->rlLock),
kiIrql);
TraceLeave(ADPT, "WanOpenAdapter");
}
VOID
WanpUnmapAdapter(
PADAPTER pAdapter
)
/*++
Routine Description:
This function moves an adapter from the mapped list and puts it on
the free list
Locks:
Called with no locks held, but not necessarily at PASSIVE.
The adapter and adapter list locks are acquired
Arguments:
pAdapter
Return Value:
None
--*/
{
KIRQL kiIrql;
#if DBG
//
// Make sure the adapter is on the mapped list
//
RtAssert(IsEntryOnList(&g_leMappedAdapterList,
&(pAdapter->leAdapterLink)));
#endif
EnterWriter(&g_rwlAdapterLock,
&kiIrql);
RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
RemoveEntryList(&(pAdapter->leAdapterLink));
g_ulNumMappedAdapters--;
InsertHeadList(&g_leAddedAdapterList,
&(pAdapter->leAdapterLink));
g_ulNumAddedAdapters++;
pAdapter->byState = AS_ADDED;
pAdapter->pInterface = NULL;
RtReleaseSpinLockFromDpcLevel(&(pAdapter->rlLock));
//
// Queue a work item if there is none queued, and we are not
// shutting down
//
RtAcquireSpinLockAtDpcLevel(&g_rlStateLock);
if((g_bRemovalInProgress isnot TRUE) and
(g_dwDriverState is DRIVER_STARTED))
{
g_bRemovalInProgress = TRUE;
ExInitializeWorkItem(&g_wqiWorkItem,
WanpRemoveSomeAddedAdaptersFromIp,
(PVOID)FALSE);
ExQueueWorkItem(&g_wqiWorkItem,
DelayedWorkQueue);
}
RtReleaseSpinLockFromDpcLevel(&g_rlStateLock);
ExitWriter(&g_rwlAdapterLock,
kiIrql);
return;
}
VOID
WanpRemoveSomeAddedAdaptersFromIp(
PVOID pvContext
)
/*++
Routine Description:
We queue this function to a work item to delete adapter(s) from IP when
the connection is torn down. Unlike the next function, this
(i) only removes added (but unmapped) adapters and
(ii) removes the adapters one at a time.
This allows another connection to move an adapter from the added list
to the free list while we are deleting another adapter from IP
Locks:
Must be called at passive
Acquires the adapter list lock as WRITER and the lock for each adapter
Arguments:
pvContext
Return Value:
None
--*/
{
PADAPTER pAdapter;
KIRQL kiIrql;
PLIST_ENTRY pleNode;
NTSTATUS nStatus;
KEVENT keChangeEvent;
PASSIVE_ENTRY();
UNREFERENCED_PARAMETER(pvContext);
KeInitializeEvent(&keChangeEvent,
SynchronizationEvent,
FALSE);
EnterWriter(&g_rwlAdapterLock,
&kiIrql);
while(!IsListEmpty(&g_leAddedAdapterList))
{
pleNode = RemoveHeadList(&g_leAddedAdapterList);
g_ulNumAddedAdapters--;
pAdapter = CONTAINING_RECORD(pleNode,
ADAPTER,
leAdapterLink);
RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
pAdapter->byState = AS_REMOVING;
//
// Since we are changing the state, no one else should be also
// changing the state
//
RtAssert(pAdapter->pkeChangeEvent is NULL);
pAdapter->pkeChangeEvent = &keChangeEvent;
//
// Insert it into the change list
//
InsertHeadList(&g_leChangeAdapterList,
&(pAdapter->leAdapterLink));
RtReleaseSpinLockFromDpcLevel(&(pAdapter->rlLock));
ExitWriter(&g_rwlAdapterLock,
kiIrql);
//
// Delete from IP but dont clear the index
//
g_pfnIpDeleteInterface(pAdapter->pvIpContext,
FALSE);
//
// Wait till the CloseAdapter completes
//
nStatus = KeWaitForSingleObject(&keChangeEvent,
Executive,
KernelMode,
FALSE,
NULL);
RtAssert(nStatus is STATUS_SUCCESS);
Trace(ADPT, INFO,
("RemoveSomeAddedAdaptersFromIp: Removed %S from Ip\n",
pAdapter->usDeviceNameW.Buffer));
//
// Remove from the change list and put on the free list
//
EnterWriter(&g_rwlAdapterLock,
&kiIrql);
RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
#if DBG
RtAssert(IsEntryOnList(&g_leChangeAdapterList,
&(pAdapter->leAdapterLink)));
#endif
RemoveEntryList(&(pAdapter->leAdapterLink));
pAdapter->byState = AS_FREE;
pAdapter->pkeChangeEvent = NULL;
InsertHeadList(&g_leFreeAdapterList,
&(pAdapter->leAdapterLink));
g_ulNumFreeAdapters++;
//
// If anyone is waiting on a state change, notify them
//
for(pleNode = pAdapter->leEventList.Flink;
pleNode isnot &(pAdapter->leEventList);
pleNode = pleNode->Flink)
{
PWAN_EVENT_NODE pTempEvent;
pTempEvent = CONTAINING_RECORD(pleNode,
WAN_EVENT_NODE,
leEventLink);
KeSetEvent(&(pTempEvent->keEvent),
0,
FALSE);
}
RtReleaseSpinLockFromDpcLevel(&(pAdapter->rlLock));
}
//
// We are done with the APC
//
g_bRemovalInProgress = FALSE;
ExitWriter(&g_rwlAdapterLock,
kiIrql);
return;
}
VOID
WanpRemoveAllAdaptersFromIp(
VOID
)
/*++
Routine Description:
This is a cleanup function called to remove all adapters (added and
mapped) from IP.
Locks:
Acquired the g_rwlAdapterLock as WRITER
Also acquire each adapter's lock when changing state
Arguments:
None
Return Value:
None
--*/
{
PADAPTER pAdapter;
KIRQL kiIrql;
LIST_ENTRY leTempHead, *pleNode;
NTSTATUS nStatus;
KEVENT keChangeEvent;
WAN_EVENT_NODE TempEvent;
PASSIVE_ENTRY();
KeInitializeEvent(&keChangeEvent,
SynchronizationEvent,
FALSE);
KeInitializeEvent(&(TempEvent.keEvent),
SynchronizationEvent,
FALSE);
InitializeListHead(&leTempHead);
EnterWriter(&g_rwlAdapterLock,
&kiIrql);
//
// First wait on any adapter in the change list to get out
// of the change state. Once that is done it is either added to ip
// or not, and we can deal with those two cases. This is to handle
// the case where we get an unbind in the middle of a status indication
//
while(!IsListEmpty(&g_leChangeAdapterList))
{
pleNode = g_leChangeAdapterList.Flink;
pAdapter = CONTAINING_RECORD(pleNode,
ADAPTER,
leAdapterLink);
RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
InsertTailList(&(pAdapter->leEventList),
&(TempEvent.leEventLink));
ReferenceAdapter(pAdapter);
RtReleaseSpinLockFromDpcLevel(&(pAdapter->rlLock));
ExitWriter(&g_rwlAdapterLock,
kiIrql);
nStatus = KeWaitForSingleObject(&(TempEvent.keEvent),
Executive,
KernelMode,
FALSE,
NULL);
RtAssert(nStatus is STATUS_SUCCESS);
EnterWriter(&g_rwlAdapterLock,
&kiIrql);
#if DBG
RtAssert(!IsEntryOnList(&g_leChangeAdapterList,
&(pAdapter->leAdapterLink)));
#endif
RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
RemoveEntryList(&(TempEvent.leEventLink));
DereferenceAdapter(pAdapter);
RtReleaseSpinLockFromDpcLevel(&(pAdapter->rlLock));
}
//
// Set the state of all the adapters to removing...
//
while(!IsListEmpty(&g_leMappedAdapterList))
{
pleNode = RemoveHeadList(&g_leMappedAdapterList);
g_ulNumMappedAdapters--;
pAdapter = CONTAINING_RECORD(pleNode,
ADAPTER,
leAdapterLink);
RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
pAdapter->byState = AS_REMOVING;
InsertHeadList(&leTempHead,
pleNode);
RtReleaseSpinLockFromDpcLevel(&(pAdapter->rlLock));
}
RtAssert(IsListEmpty(&g_leMappedAdapterList));
while(!IsListEmpty(&g_leAddedAdapterList))
{
pleNode = RemoveHeadList(&g_leAddedAdapterList);
g_ulNumAddedAdapters--;
pAdapter = CONTAINING_RECORD(pleNode,
ADAPTER,
leAdapterLink);
RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
pAdapter->byState = AS_REMOVING;
InsertHeadList(&leTempHead,
pleNode);
RtReleaseSpinLockFromDpcLevel(&(pAdapter->rlLock));
}
RtAssert(IsListEmpty(&g_leAddedAdapterList));
ExitWriter(&g_rwlAdapterLock,
kiIrql);
//
// No go through the list of adapters to remove from IP
//
while(!IsListEmpty(&leTempHead))
{
pleNode = RemoveHeadList(&leTempHead);
pAdapter = CONTAINING_RECORD(pleNode,
ADAPTER,
leAdapterLink);
EnterWriter(&g_rwlAdapterLock,
&kiIrql);
RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
//
// Since we are changing the state, no one else should be also
// changing the state
//
RtAssert(pAdapter->pkeChangeEvent is NULL);
pAdapter->pkeChangeEvent = &keChangeEvent;
//
// Insert it into the change list
//
InsertHeadList(&g_leChangeAdapterList,
&(pAdapter->leAdapterLink));
RtReleaseSpinLockFromDpcLevel(&(pAdapter->rlLock));
ExitWriter(&g_rwlAdapterLock,
kiIrql);
//
// Delete from IP but dont clear the index
//
g_pfnIpDeleteInterface(pAdapter->pvIpContext,
FALSE);
//
// Wait till the CloseAdapter completes
//
nStatus = KeWaitForSingleObject(&keChangeEvent,
Executive,
KernelMode,
FALSE,
NULL);
RtAssert(nStatus is STATUS_SUCCESS);
Trace(ADPT, INFO,
("RemoveAllAdaptersFromIp: Removed %S from Ip\n",
pAdapter->usDeviceNameW.Buffer));
//
// Remove from the change list and put on the free list
//
EnterWriter(&g_rwlAdapterLock,
&kiIrql);
#if DBG
RtAssert(IsEntryOnList(&g_leChangeAdapterList,
&(pAdapter->leAdapterLink)));
#endif
RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
RemoveEntryList(&(pAdapter->leAdapterLink));
pAdapter->byState = AS_FREE;
pAdapter->pkeChangeEvent = NULL;
InsertHeadList(&g_leFreeAdapterList,
&(pAdapter->leAdapterLink));
g_ulNumFreeAdapters++;
//
// If anyone is waiting on a state change, notify them
//
for(pleNode = pAdapter->leEventList.Flink;
pleNode isnot &(pAdapter->leEventList);
pleNode = pleNode->Flink)
{
PWAN_EVENT_NODE pTempEvent;
pTempEvent = CONTAINING_RECORD(pleNode,
WAN_EVENT_NODE,
leEventLink);
KeSetEvent(&(pTempEvent->keEvent),
0,
FALSE);
}
RtReleaseSpinLockFromDpcLevel(&(pAdapter->rlLock));
ExitWriter(&g_rwlAdapterLock,
kiIrql);
}
//
// The write is atomic so we dont need to
// acquire a lock
//
g_bRemovalInProgress = FALSE;
return;
}
VOID
WanIpCloseAdapter(
IN PVOID pvContext
)
/*++
Routine Description:
Called by IP when it wants to close an adapter. Currently this is done
from CloseNets() and IPDelInterface().
Locks:
Acquires the adapter lock
Arguments:
pvContext Pointer to the ADAPTER
Return Value:
None
--*/
{
PADAPTER pAdapter;
KIRQL kiIrql;
PLIST_ENTRY pleNode;
TraceEnter(ADPT, "IpCloseAdapter");
pAdapter = (PADAPTER)pvContext;
RtAcquireSpinLock(&(pAdapter->rlLock),
&kiIrql);
pAdapter->pvIpContext = NULL;
//
// Wake up the thread that caused this
//
RtAssert(pAdapter->pkeChangeEvent);
KeSetEvent(pAdapter->pkeChangeEvent,
0,
FALSE);
RtReleaseSpinLock(&(pAdapter->rlLock),
kiIrql);
DereferenceAdapter(pAdapter);
TraceLeave(ADPT, "IpCloseAdapter");
}
VOID
WanpRemoveAllAdapters(
VOID
)
/*++
Routine Description:
Locks:
Arguments:
Return Value:
--*/
{
LIST_ENTRY leTempHead, *pleNode;
KIRQL kiIrql;
NTSTATUS nStatus;
TraceEnter(ADPT, "RemoveAllAdapters");
//
// We can have mapped adapters.
//
//RtAssert(IsListEmpty(&g_leMappedAdapterList));
//
// Just call RemoveAllAdaptersFromIp()
//
WanpRemoveAllAdaptersFromIp();
//
// At this point the movement from one list to another is frozen
// because we dont accept LinkUp's from Ndiswan
//
RtAssert(IsListEmpty(&g_leAddedAdapterList));
//RtAssert(IsListEmpty(&g_leMappedAdapterList));
//RtAssert(IsListEmpty(&g_leChangeAdapterList));
EnterWriter(&g_rwlAdapterLock,
&kiIrql);
//
// First clean out the free adapters
//
while(!IsListEmpty(&g_leFreeAdapterList))
{
PLIST_ENTRY pleNode;
PADAPTER pAdapter;
pleNode = RemoveHeadList(&g_leFreeAdapterList);
g_ulNumFreeAdapters--;
pAdapter = CONTAINING_RECORD(pleNode,
ADAPTER,
leAdapterLink);
RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
RtAssert(pAdapter->byState is AS_FREE);
pAdapter->byState = 0xFF;
RtReleaseSpinLockFromDpcLevel(&(pAdapter->rlLock));
DereferenceAdapter(pAdapter);
}
//
// At the end of this, also remove the server adapter
//
if(g_pServerAdapter)
{
PADAPTER pAdapter;
PUMODE_INTERFACE pInterface;
BOOLEAN bCrossRefed;
RtAcquireSpinLockAtDpcLevel(&(g_pServerAdapter->rlLock));
RtAcquireSpinLockAtDpcLevel(&(g_pServerInterface->rlLock));
pAdapter = g_pServerAdapter;
pInterface = g_pServerInterface;
if(g_pServerAdapter->byState is AS_MAPPED)
{
RtAssert(g_pServerAdapter->pInterface is g_pServerInterface);
RtAssert(g_pServerInterface->pAdapter is g_pServerAdapter);
bCrossRefed = TRUE;
}
else
{
RtAssert(g_pServerAdapter->pInterface is NULL);
RtAssert(g_pServerInterface->pAdapter is NULL);
RtAssert(g_pServerAdapter->byState is AS_FREE);
bCrossRefed = FALSE;
}
//
// Remove the global pointers
//
g_pServerInterface = NULL;
g_pServerAdapter = NULL;
//
// Remove the mapping from interface
//
pInterface->pAdapter = NULL;
pAdapter->pInterface = NULL;
pAdapter->byState = AS_REMOVING;
RtReleaseSpinLockFromDpcLevel(&(pInterface->rlLock));
if(bCrossRefed)
{
//
// Deref because the cross mapping is removed
//
DereferenceAdapter(pAdapter);
DereferenceInterface(pInterface);
}
if(pAdapter->pvIpContext)
{
KEVENT keChangeEvent;
KeInitializeEvent(&keChangeEvent,
SynchronizationEvent,
FALSE);
//
// Since we are changing the state, no one else should be also
// changing the state
//
RtAssert(pAdapter->pkeChangeEvent is NULL);
pAdapter->pkeChangeEvent = &keChangeEvent;
RtReleaseSpinLockFromDpcLevel(&(pAdapter->rlLock));
ExitWriter(&g_rwlAdapterLock,
kiIrql);
//
// Delete from IP, but dont clear the index
//
g_pfnIpDeleteInterface(pAdapter->pvIpContext,
FALSE);
nStatus = KeWaitForSingleObject(&keChangeEvent,
Executive,
KernelMode,
FALSE,
NULL);
RtAssert(nStatus is STATUS_SUCCESS);
Trace(ADPT, INFO,
("RemoveAllAdapters: Removed %S (server adapter) from Ip\n",
pAdapter->usDeviceNameW.Buffer));
EnterWriter(&g_rwlAdapterLock,
&kiIrql);
RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
pAdapter->byState = AS_FREE;
pAdapter->pkeChangeEvent = NULL;
//
// If anyone is waiting on a state change, notify them
//
for(pleNode = pAdapter->leEventList.Flink;
pleNode isnot &(pAdapter->leEventList);
pleNode = pleNode->Flink)
{
PWAN_EVENT_NODE pTempEvent;
pTempEvent = CONTAINING_RECORD(pleNode,
WAN_EVENT_NODE,
leEventLink);
KeSetEvent(&(pTempEvent->keEvent),
0,
FALSE);
}
RtReleaseSpinLockFromDpcLevel(&(pAdapter->rlLock));
} else {
RtReleaseSpinLockFromDpcLevel(&(pAdapter->rlLock));
}
//
// Deref because the global pointers are null
//
DereferenceAdapter(pAdapter);
DereferenceInterface(pInterface);
}
ExitWriter(&g_rwlAdapterLock,
kiIrql);
TraceLeave(ADPT, "RemoveAllAdapters");
}
INT
WanIpDynamicRegister(
IN PNDIS_STRING InterfaceName,
IN PVOID pvIpInterfaceContext,
IN struct _IP_HANDLERS * IpHandlers,
IN struct LLIPBindInfo * ARPBindInfo,
IN UINT uiInterfaceNumber
)
{
PADAPTER pAdapter;
KIRQL irql;
TraceEnter(ADPT, "IpDynamicRegister");
pAdapter = (PADAPTER)(ARPBindInfo->lip_context);
RtAcquireSpinLock(&(pAdapter->rlLock),
&irql);
#if DBG
Trace(ADPT, INFO,
("IpDynamicRegister: IP called out to dynamically register %s\n",
pAdapter->asDeviceNameA.Buffer));
#endif
pAdapter->pvIpContext = pvIpInterfaceContext;
pAdapter->dwAdapterIndex = uiInterfaceNumber;
#if DBG
RtAssert(pAdapter->dwAdapterIndex is pAdapter->dwRequestedIndex);
#endif
if(g_pfnIpRcv is NULL)
{
g_pfnIpRcv = IpHandlers->IpRcvHandler;
g_pfnIpRcvComplete = IpHandlers->IpRcvCompleteHandler;
g_pfnIpSendComplete = IpHandlers->IpTxCompleteHandler;
g_pfnIpTDComplete = IpHandlers->IpTransferCompleteHandler;
g_pfnIpStatus = IpHandlers->IpStatusHandler;
g_pfnIpRcvPkt = IpHandlers->IpRcvPktHandler;
g_pfnIpPnp = IpHandlers->IpPnPHandler;
}
RtReleaseSpinLock(&(pAdapter->rlLock),
irql);
TraceLeave(ADPT, "IpDynamicRegister");
return TRUE;
}
NDIS_STATUS
WanpDoNdisRequest(
IN NDIS_REQUEST_TYPE RequestType,
IN NDIS_OID Oid,
IN PVOID pvInfo,
IN UINT uiInBufferLen,
IN PWANARP_NDIS_REQUEST_CONTEXT pRequestContext,
IN PFNWANARP_REQUEST_COMPLETION_HANDLER pfnCompletionHandler OPTIONAL
)
/*++
Routine Description:
Wrapper for the NdisRequest call. We create a request context and submit
the call to NDIS. If it returns synchronously, we fake asynchronous
behaviour by call the completion routine.
Locks:
None. The ndiswan binding must be valid for the duration of the call
Arguments:
RequestType Type of NDIS request
Oid Ndis OID to set or get
pvInfo Opaque OID specific info
pRequestContext A context for this request
pfnCompletionHandler Completion handler for this request
Return Value:
STATUS_INVALID_PARAMETER
NDIS_STATUS_RESOURCES
NDIS_STATUS_PENDING
other error
--*/
{
PNDIS_REQUEST pRequest;
NDIS_STATUS nsStatus;
if((RequestType isnot NdisRequestSetInformation) and
(RequestType isnot NdisRequestQueryInformation))
{
return STATUS_INVALID_PARAMETER;
}
pRequestContext->pfnCompletionRoutine = pfnCompletionHandler;
pRequest = &(pRequestContext->NdisRequest);
pRequest->RequestType = RequestType;
if(RequestType is NdisRequestSetInformation)
{
pRequest->DATA.SET_INFORMATION.Oid = Oid;
pRequest->DATA.SET_INFORMATION.InformationBuffer = pvInfo;
pRequest->DATA.SET_INFORMATION.InformationBufferLength = uiInBufferLen;
}
else
{
pRequest->DATA.QUERY_INFORMATION.Oid = Oid;
pRequest->DATA.QUERY_INFORMATION.InformationBuffer = pvInfo;
pRequest->DATA.QUERY_INFORMATION.InformationBufferLength = uiInBufferLen;
}
//
// Submit the request.
//
NdisRequest(&nsStatus,
g_nhNdiswanBinding,
pRequest);
if(nsStatus isnot NDIS_STATUS_PENDING)
{
//
// If it finished synchronously, call the handler
//
if(pfnCompletionHandler)
{
(pfnCompletionHandler)(g_nhNdiswanBinding,
pRequestContext,
nsStatus);
}
if(nsStatus is NDIS_STATUS_SUCCESS)
{
//
// Always make this look asynchronous
//
nsStatus = NDIS_STATUS_PENDING;
}
}
return nsStatus;
}
VOID
WanNdisRequestComplete(
IN NDIS_HANDLE nhHandle,
IN PNDIS_REQUEST pRequest,
IN NDIS_STATUS nsStatus
)
/*++
Routine Description:
Handler called by NDIS when it is done processing our request
Locks:
None
Arguments:
nhHandle NdisHandle of the adapter to which the request was submitted
pRequest The original request
nsStatus The status returned by the adapter
Return Value:
None
--*/
{
PWANARP_NDIS_REQUEST_CONTEXT pRequestContext;
//
// Get a pointer to the context
//
pRequestContext = CONTAINING_RECORD(pRequest,
WANARP_NDIS_REQUEST_CONTEXT,
NdisRequest);
if(pRequestContext->pfnCompletionRoutine is NULL)
{
//
// No more handlers to call, we are done
//
RtFree(pRequestContext);
return;
}
//
// If the request is OID_GEN_TRANSPORT_HEADER_OFFSET, ignore the error
//
RtAssert(pRequest is &(pRequestContext->NdisRequest));
if((pRequest->RequestType is NdisRequestSetInformation) and
(pRequest->DATA.SET_INFORMATION.Oid is OID_GEN_TRANSPORT_HEADER_OFFSET))
{
nsStatus = NDIS_STATUS_SUCCESS;
}
//
// Call the request complete handler
//
(pRequestContext->pfnCompletionRoutine)(nhHandle,
pRequestContext,
nsStatus);
}
PUMODE_INTERFACE
WanpFindInterfaceGivenIndex(
DWORD dwIfIndex
)
{
PLIST_ENTRY pleNode;
PUMODE_INTERFACE pIf;
for(pleNode = g_leIfList.Flink;
pleNode isnot &g_leIfList;
pleNode = pleNode->Flink)
{
pIf = CONTAINING_RECORD(pleNode,
UMODE_INTERFACE,
leIfLink);
if(pIf->dwIfIndex is dwIfIndex)
{
RtAcquireSpinLockAtDpcLevel(&(pIf->rlLock));
ReferenceInterface(pIf);
return pIf;
}
}
return NULL;
}
VOID
WanpDeleteAdapter(
IN PADAPTER pAdapter
)
{
#if DBG
Trace(ADPT, TRACE,
("DeleteAdapter: Deleting %x %s\n",
pAdapter, pAdapter->asDeviceNameA.Buffer));
#else
Trace(ADPT, TRACE,
("DeleteAdapter: Deleting %x\n",
pAdapter));
#endif
InterlockedDecrement(&g_ulNumAdapters);
RtFree(pAdapter);
}
NDIS_STATUS
WanNdisIpPnPEventHandler(
IN PNET_PNP_EVENT pNetPnPEvent
)
{
PWANARP_RECONFIGURE_INFO pInfo;
NTSTATUS nStatus = NDIS_STATUS_FAILURE;
RtAssert(pNetPnPEvent->NetEvent is NetEventReconfigure);
pInfo = (PWANARP_RECONFIGURE_INFO) pNetPnPEvent->Buffer;
switch (pInfo->wrcOperation)
{
case WRC_TCP_WINDOW_SIZE_UPDATE:
{
PLIST_ENTRY pleNode;
KIRQL kirql;
PADAPTER pAdapter;
RtAssert(pInfo->ulNumInterfaces is 1);
if(pInfo->ulNumInterfaces isnot 1)
{
break;
}
EnterReader(&g_rwlAdapterLock, &kirql);
for(pleNode = g_leMappedAdapterList.Flink;
pleNode != &g_leMappedAdapterList;
pleNode = pleNode->Flink)
{
pAdapter = CONTAINING_RECORD(pleNode, ADAPTER, leAdapterLink);
if(IsEqualGUID(&(pAdapter->Guid),
&pInfo->rgInterfaces[0]))
{
break;
}
}
if(pleNode is &g_leMappedAdapterList)
{
ExitReader(&g_rwlAdapterLock, kirql);
break;
}
if( (pAdapter->byState is AS_MAPPED)
&& (pAdapter->pInterface)
&& (pAdapter->pInterface->duUsage is DU_CALLOUT))
{
NET_PNP_EVENT pnpEvent;
IP_PNP_RECONFIG_REQUEST Request;
RtlZeroMemory(&pnpEvent, sizeof(pnpEvent));
RtlZeroMemory(&Request, sizeof(Request));
Request.version = IP_PNP_RECONFIG_VERSION;
Request.Flags = IP_PNP_FLAG_INTERFACE_TCP_PARAMETER_UPDATE;
pnpEvent.NetEvent = NetEventReconfigure;
pnpEvent.Buffer = &Request;
pnpEvent.BufferLength = sizeof(Request);
ReferenceAdapter(pAdapter);
ExitReader(&g_rwlAdapterLock, kirql);
nStatus = g_pfnIpPnp(pAdapter->pvIpContext,
&pnpEvent);
DereferenceAdapter(pAdapter);
}
else
{
ExitReader(&g_rwlAdapterLock, kirql);
}
break;
}
default:
{
RtAssert(FALSE);
nStatus = NDIS_STATUS_NOT_RECOGNIZED;
break;
}
}
return nStatus;
}
//
// Misc ndis interface functions
//
NDIS_STATUS
WanNdisPnPEvent(
IN NDIS_HANDLE nhProtocolBindingContext,
IN PNET_PNP_EVENT pNetPnPEvent
)
{
ULONG ulNumGuids, i;
NTSTATUS nStatus, nRetStatus;
PWANARP_RECONFIGURE_INFO pInfo;
TraceEnter(ADPT, "NdisPnPEvent");
if(nhProtocolBindingContext isnot (NDIS_HANDLE)0x0CABB1E5)
{
return NDIS_STATUS_NOT_RECOGNIZED;
}
if(pNetPnPEvent->NetEvent isnot NetEventReconfigure)
{
return NDIS_STATUS_SUCCESS;
}
pInfo = (PWANARP_RECONFIGURE_INFO)(pNetPnPEvent->Buffer);
if(pNetPnPEvent->BufferLength < FIELD_OFFSET(WANARP_RECONFIGURE_INFO, rgInterfaces))
{
return NDIS_STATUS_BUFFER_TOO_SHORT;
}
pInfo = (PWANARP_RECONFIGURE_INFO)(pNetPnPEvent->Buffer);
if(pInfo->wrcOperation isnot WRC_ADD_INTERFACES)
{
nStatus = WanNdisIpPnPEventHandler(pNetPnPEvent);
return nStatus;
}
//
// Make sure the length and matches with whats in the info
//
ulNumGuids = pNetPnPEvent->BufferLength -
FIELD_OFFSET(WANARP_RECONFIGURE_INFO, rgInterfaces);
ulNumGuids /= sizeof(GUID);
if(ulNumGuids < pInfo->ulNumInterfaces)
{
return STATUS_INVALID_PARAMETER;
}
//
// Now go through each guid, and if it isnt present, add it
// If we get a list of only duplicates, return SUCCESS (334575)
//
nRetStatus = STATUS_SUCCESS;
for(i = 0; i < pInfo->ulNumInterfaces; i++)
{
WCHAR rgwcDeviceBuffer[GUID_STR_LEN + 7 + 2];
WCHAR rgwcConfigBuffer[GUID_STR_LEN + 29 + 2];
PADAPTER pNewAdapter;
UNICODE_STRING usDevice;
UNICODE_STRING usConfig;
if(IsBindingPresent(&(pInfo->rgInterfaces[i])))
{
continue;
}
RtlZeroMemory(rgwcDeviceBuffer,
sizeof(rgwcDeviceBuffer));
RtlZeroMemory(rgwcConfigBuffer,
sizeof(rgwcConfigBuffer));
//
// Make sure no problems with people changing the string
//
RtAssert(((wcslen(TCPIP_IF_PREFIX) + 1 + GUID_STR_LEN) * sizeof(WCHAR)) < sizeof(rgwcDeviceBuffer));
RtAssert(((wcslen(TCPIP_REG_PREFIX) + 1 + GUID_STR_LEN) * sizeof(WCHAR)) < sizeof(rgwcConfigBuffer));
//
// Copy over the \Device part
//
RtlCopyMemory(rgwcDeviceBuffer,
TCPIP_IF_PREFIX,
wcslen(TCPIP_IF_PREFIX) * sizeof(WCHAR));
//
// Tack on a '\'
//
rgwcDeviceBuffer[wcslen(TCPIP_IF_PREFIX)] = L'\\';
//
// Convert the guid to a string. Just pass the buffer starting
// after the '\' we just catted. The conversion function returns
// an upcase string - so thats good.
//
ConvertGuidToString(&(pInfo->rgInterfaces[i]),
&(rgwcDeviceBuffer[wcslen(TCPIP_IF_PREFIX) + 1]));
//
// Create the config
//
RtlCopyMemory(rgwcConfigBuffer,
TCPIP_REG_PREFIX,
wcslen(TCPIP_REG_PREFIX) * sizeof(WCHAR));
//
// Put the device guid at the end
//
ConvertGuidToString(&(pInfo->rgInterfaces[i]),
&(rgwcConfigBuffer[wcslen(TCPIP_REG_PREFIX)]));
//
// Set up the strings
//
usDevice.Length = wcslen(rgwcDeviceBuffer) * sizeof(WCHAR);
usDevice.MaximumLength = usDevice.Length;
usDevice.Buffer = rgwcDeviceBuffer;
usConfig.Length = wcslen(rgwcConfigBuffer) * sizeof(WCHAR);
usConfig.MaximumLength = usConfig.Length;
usConfig.Buffer = rgwcConfigBuffer;
//
// Create an adapter with this name and config
//
pNewAdapter = NULL;
Trace(ADPT, INFO,
("NdisPnPEvent: Calling create adapter for %S %S\n",
usConfig.Buffer,
usDevice.Buffer));
nStatus = WanpCreateAdapter(&(pInfo->rgInterfaces[i]),
&usConfig,
&usDevice,
&pNewAdapter);
if(nStatus isnot STATUS_SUCCESS)
{
Trace(ADPT, ERROR,
("NdisPnPEvent: Err %x creating adapter for %S (%S)\n",
nStatus,
usConfig.Buffer,
usDevice.Buffer));
}
else
{
//
// If even one succeeds, we return success
//
nRetStatus = STATUS_SUCCESS;
}
}
return nRetStatus;
}
VOID
WanNdisResetComplete(
NDIS_HANDLE Handle,
NDIS_STATUS Status
)
{
// We dont do anything here.
}
BOOLEAN
IsBindingPresent(
IN GUID *pGuid
)
/*++
Routine Description:
Code to catch duplicate bind notifications
Locks:
Must be called with the AdapterList lock held
Arguments:
pGuid Guid of the adapter
Return Value:
NO_ERROR
--*/
{
BOOLEAN bFound;
PADAPTER pAdapter;
PLIST_ENTRY pleNode;
for(pleNode = g_leAddedAdapterList.Flink;
pleNode != &g_leAddedAdapterList;
pleNode = pleNode->Flink)
{
pAdapter = CONTAINING_RECORD(pleNode, ADAPTER, leAdapterLink);
if(IsEqualGUID(&(pAdapter->Guid),
pGuid))
{
return TRUE;
}
}
for(pleNode = g_leMappedAdapterList.Flink;
pleNode != &g_leMappedAdapterList;
pleNode = pleNode->Flink)
{
pAdapter = CONTAINING_RECORD(pleNode, ADAPTER, leAdapterLink);
if(IsEqualGUID(&(pAdapter->Guid),
pGuid))
{
return TRUE;
}
}
for(pleNode = g_leFreeAdapterList.Flink;
pleNode != &g_leFreeAdapterList;
pleNode = pleNode->Flink)
{
pAdapter = CONTAINING_RECORD(pleNode, ADAPTER, leAdapterLink);
if(IsEqualGUID(&(pAdapter->Guid),
pGuid))
{
return TRUE;
}
}
for(pleNode = g_leChangeAdapterList.Flink;
pleNode != &g_leChangeAdapterList;
pleNode = pleNode->Flink)
{
pAdapter = CONTAINING_RECORD(pleNode, ADAPTER, leAdapterLink);
if(IsEqualGUID(&(pAdapter->Guid),
pGuid))
{
return TRUE;
}
}
if(g_pServerAdapter)
{
if(IsEqualGUID(&(g_pServerAdapter->Guid),
pGuid))
{
return TRUE;
}
}
return FALSE;
}