mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2237 lines
53 KiB
2237 lines
53 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
wanarp\conn.c
|
|
|
|
Abstract:
|
|
|
|
The file contains the code needed for connection management
|
|
|
|
Revision History:
|
|
|
|
AmritanR
|
|
|
|
--*/
|
|
|
|
|
|
#define __FILE_SIG__ CONN_SIG
|
|
|
|
#include "inc.h"
|
|
|
|
VOID
|
|
WanNdisStatus(
|
|
NDIS_HANDLE nhHandle,
|
|
NDIS_STATUS nsNdisStatus,
|
|
PVOID pvStatusInfo,
|
|
UINT uiStatusInfoSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Status handler for NDIS. we simply pass the buffer on to our private
|
|
handlers
|
|
|
|
Locks:
|
|
|
|
None needed
|
|
|
|
Arguments:
|
|
|
|
nhHandle
|
|
nsNdisStatus
|
|
pvStatusInfo
|
|
uiSatusInfoSize
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
UNREFERENCED_PARAMETER(uiStatusInfoSize);
|
|
UNREFERENCED_PARAMETER(nhHandle);
|
|
|
|
switch(nsNdisStatus)
|
|
{
|
|
case NDIS_STATUS_WAN_LINE_UP:
|
|
{
|
|
PNDIS_WAN_LINE_UP pLineUp;
|
|
|
|
pLineUp = (PNDIS_WAN_LINE_UP)pvStatusInfo;
|
|
|
|
WanpLinkUpIndication(pLineUp);
|
|
|
|
break;
|
|
}
|
|
|
|
case NDIS_STATUS_WAN_LINE_DOWN:
|
|
{
|
|
PNDIS_WAN_LINE_DOWN pLineDown;
|
|
|
|
pLineDown = (PNDIS_WAN_LINE_DOWN)pvStatusInfo;
|
|
|
|
WanpLinkDownIndication(pLineDown);
|
|
|
|
break;
|
|
}
|
|
|
|
case NDIS_STATUS_WAN_FRAGMENT:
|
|
default:
|
|
{
|
|
//
|
|
// Ignore all other indications
|
|
//
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
WanNdisStatusComplete(
|
|
NDIS_HANDLE nhHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called after the driver is done indicating a set of status
|
|
indications
|
|
We dont do anything
|
|
|
|
Locks:
|
|
|
|
None
|
|
|
|
Arguments:
|
|
|
|
nhHandle
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
UNREFERENCED_PARAMETER(nhHandle);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
WanpLinkUpIndication(
|
|
PNDIS_WAN_LINE_UP pInfoBuffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The routine that handles a new connection. We also get this when a
|
|
link in a multi-linked bundle comes up or goes down.
|
|
If this is a new connection, we allocate a CONN_ENTRY for this.
|
|
Then, if this is a dial in connection, we lock and ref the server
|
|
adapter and interface. If this is a router connection, we see if
|
|
we already have a mapped adapter. If we do, we lock the adapter
|
|
otherwise, we find a free adapter to map for the linkup.
|
|
If this is a dial out connection, we create an interface and find a
|
|
free adapter to map for the connection.
|
|
We set up the needed cross mappings between the conn entry, adapter
|
|
and interface and initialize the conn entry
|
|
If this is a router connection, we drain all packets, and complete
|
|
an IRP to tell router manager about it.
|
|
For non dial in connections we indicate a Status change to IP, while
|
|
for dial in, we add a link to IP for the client.
|
|
|
|
|
|
Locks:
|
|
|
|
MUST be called at PASSIVE because we call IPAddInterface.
|
|
We acquire the g_rlConnTableLock, g_rwlAdapterLock, g_rwlIfLock
|
|
in addition to locking down the adapter and the interface
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS
|
|
NDIS_STATUS_ADAPTER_NOT_READY
|
|
STATUS_INVALID_PARAMETER
|
|
NDIS_STATUS_RESOURCES
|
|
STATUS_OBJECT_NAME_NOT_FOUND
|
|
STATUS_INVALID_DEVICE_STATE
|
|
|
|
--*/
|
|
|
|
{
|
|
PADAPTER pAdapter;
|
|
PCONN_ENTRY pConnEntry;
|
|
ULONG ulConnIndex;
|
|
KIRQL kiIrql;
|
|
LLIPMTUChange mtuChangeInfo;
|
|
LLIPSpeedChange speedChangeInfo;
|
|
IP_STATUS isStatus;
|
|
ULONG ulIndex;
|
|
UNICODE_STRING usTempName;
|
|
WCHAR rgwcGuid[GUID_STR_LEN + 1];
|
|
|
|
PUMODE_INTERFACE pInterface;
|
|
PIP_WAN_LINKUP_INFO pLinkInfo;
|
|
PPENDING_NOTIFICATION pMsg;
|
|
|
|
//
|
|
// This must be at PASSIVE (because we may need to drive a
|
|
// IPAddInterface from here)
|
|
//
|
|
|
|
TraceEnter(CONN, "LinkUpIndication");
|
|
|
|
pLinkInfo = (PIP_WAN_LINKUP_INFO)pInfoBuffer->ProtocolBuffer;
|
|
|
|
Trace(CONN, INFO,
|
|
("HandleLinkUpIndication: %d.%d.%d.%d/%d.%d.%d.%d - %d.%d.%d.%d\n",
|
|
PRINT_IPADDR(pLinkInfo->dwLocalAddr),
|
|
PRINT_IPADDR(pLinkInfo->dwLocalMask),
|
|
PRINT_IPADDR(pLinkInfo->dwRemoteAddr)));
|
|
|
|
if(!EnterDriverCode())
|
|
{
|
|
return NDIS_STATUS_ADAPTER_NOT_READY;
|
|
}
|
|
|
|
|
|
ulConnIndex = GetConnIndexFromAddr(pInfoBuffer->LocalAddress);
|
|
|
|
if(ulConnIndex isnot 0)
|
|
{
|
|
PVOID pvLinkContext;
|
|
|
|
//
|
|
// This is not the first lineup for this entry
|
|
// We should find the entry (if it is on this interface)
|
|
// and update speed and mtu info
|
|
//
|
|
|
|
RtAcquireSpinLock(&g_rlConnTableLock,
|
|
&kiIrql);
|
|
|
|
pConnEntry = GetConnEntryGivenIndex(ulConnIndex);
|
|
|
|
if((pConnEntry is NULL) or
|
|
(pConnEntry->byState isnot CS_CONNECTED))
|
|
{
|
|
RtAssert(FALSE);
|
|
|
|
RtReleaseSpinLock(&g_rlConnTableLock,
|
|
kiIrql);
|
|
|
|
ExitDriverCode();
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
RtAssert(pConnEntry->pAdapter);
|
|
|
|
//
|
|
// Lock the conn entry or the adapter
|
|
//
|
|
|
|
RtAcquireSpinLockAtDpcLevel(pConnEntry->prlLock);
|
|
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&g_rlConnTableLock);
|
|
|
|
if(pInfoBuffer->MaximumTotalSize isnot pConnEntry->ulMtu)
|
|
{
|
|
pConnEntry->ulMtu = pInfoBuffer->MaximumTotalSize;
|
|
mtuChangeInfo.lmc_mtu = pConnEntry->ulMtu;
|
|
}
|
|
else
|
|
{
|
|
mtuChangeInfo.lmc_mtu = 0;
|
|
}
|
|
|
|
if((pInfoBuffer->LinkSpeed * 100L) isnot pConnEntry->ulSpeed)
|
|
{
|
|
pConnEntry->ulSpeed = pInfoBuffer->LinkSpeed * 100L;
|
|
speedChangeInfo.lsc_speed = pConnEntry->ulSpeed;
|
|
}
|
|
else
|
|
{
|
|
speedChangeInfo.lsc_speed = 0;
|
|
}
|
|
|
|
RtReleaseSpinLock(pConnEntry->prlLock,
|
|
kiIrql);
|
|
|
|
if(mtuChangeInfo.lmc_mtu isnot 0)
|
|
{
|
|
g_pfnIpStatus(pConnEntry->pAdapter->pvIpContext,
|
|
LLIP_STATUS_MTU_CHANGE,
|
|
&mtuChangeInfo,
|
|
sizeof(LLIPMTUChange),
|
|
pConnEntry->pvIpLinkContext);
|
|
}
|
|
|
|
if(speedChangeInfo.lsc_speed isnot 0)
|
|
{
|
|
g_pfnIpStatus(pConnEntry->pAdapter->pvIpContext,
|
|
LLIP_STATUS_SPEED_CHANGE,
|
|
&speedChangeInfo,
|
|
sizeof(LLIPSpeedChange),
|
|
pConnEntry->pvIpLinkContext);
|
|
}
|
|
|
|
DereferenceConnEntry(pConnEntry);
|
|
|
|
TraceLeave(CONN, "LinkUpIndication");
|
|
|
|
ExitDriverCode();
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
PASSIVE_ENTRY();
|
|
|
|
if((pLinkInfo->duUsage isnot DU_CALLIN) and
|
|
(pLinkInfo->duUsage isnot DU_CALLOUT) and
|
|
(pLinkInfo->duUsage isnot DU_ROUTER))
|
|
{
|
|
RtAssert(FALSE);
|
|
|
|
Trace(CONN,ERROR,
|
|
("LinkUpIndication: Invalid usage %d\n", pLinkInfo->duUsage));
|
|
|
|
TraceLeave(CONN, "LinkUpIndication");
|
|
|
|
ExitDriverCode();
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
RtlZeroMemory(pInfoBuffer->LocalAddress,
|
|
ARP_802_ADDR_LENGTH);
|
|
|
|
//
|
|
// Get a connection entry for this connection
|
|
// This function finds a free slot in the connection table and puts
|
|
// the conn entry into the slot. It sets the ulSlot field in the
|
|
// conn entry to be the index of the slot
|
|
//
|
|
|
|
RtAcquireSpinLock(&g_rlConnTableLock,
|
|
&kiIrql);
|
|
|
|
pConnEntry = WanpCreateConnEntry(pLinkInfo->duUsage);
|
|
|
|
if(pConnEntry is NULL)
|
|
{
|
|
RtReleaseSpinLock(&g_rlConnTableLock,
|
|
kiIrql);
|
|
|
|
Trace(CONN,ERROR,
|
|
("LinkUpIndication: Couldnt allocate conn entry\n"));
|
|
|
|
TraceLeave(CONN, "LinkUpIndication");
|
|
|
|
ExitDriverCode();
|
|
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
RtReleaseSpinLock(&g_rlConnTableLock,
|
|
kiIrql);
|
|
|
|
//
|
|
// Create a GUID from a name
|
|
//
|
|
|
|
usTempName.MaximumLength = (GUID_STR_LEN + 1) * sizeof(WCHAR);
|
|
usTempName.Length = GUID_STR_LEN * sizeof(WCHAR);
|
|
usTempName.Buffer = rgwcGuid;
|
|
|
|
ConvertGuidToString((GUID *)(pInfoBuffer->DeviceName.Buffer),
|
|
rgwcGuid);
|
|
|
|
rgwcGuid[GUID_STR_LEN] = UNICODE_NULL;
|
|
|
|
pAdapter = NULL;
|
|
|
|
//
|
|
// Do this usage specific thing. At the end of this switch statement
|
|
// we have a locked and referenced Adapter and Interface for the
|
|
// connection
|
|
//
|
|
|
|
switch(pLinkInfo->duUsage)
|
|
{
|
|
case DU_CALLIN:
|
|
{
|
|
//
|
|
// Just get the server adapter and interface
|
|
//
|
|
|
|
Trace(CONN, INFO,
|
|
("LinkUpIndication: Linkup Usage is CALLIN\n"));
|
|
|
|
//
|
|
// Just use 0 as adapter index, since it is not really needed
|
|
// for the CALLIN case
|
|
//
|
|
|
|
pAdapter = WanpFindAdapterToMap(DU_CALLIN,
|
|
&kiIrql,
|
|
0,
|
|
NULL);
|
|
|
|
if(pAdapter is NULL)
|
|
{
|
|
WanpDeleteConnEntry(pConnEntry);
|
|
|
|
ExitDriverCode();
|
|
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
RtAssert(pAdapter is g_pServerAdapter);
|
|
|
|
//
|
|
// clients lock the connection entry
|
|
//
|
|
|
|
RtInitializeSpinLock(&(pConnEntry->rlLock));
|
|
|
|
pConnEntry->prlLock = &(pConnEntry->rlLock);
|
|
|
|
|
|
RtAssert(pAdapter->pInterface is g_pServerInterface);
|
|
RtAssert(pAdapter->byState is AS_MAPPED);
|
|
|
|
//
|
|
// Lock the server interface. We have to have a server interface.
|
|
//
|
|
|
|
pInterface = g_pServerInterface;
|
|
|
|
//
|
|
// Lock and reference the interface
|
|
//
|
|
|
|
RtAcquireSpinLockAtDpcLevel(&(pInterface->rlLock));
|
|
|
|
ReferenceInterface(pInterface);
|
|
|
|
break;
|
|
}
|
|
|
|
case DU_CALLOUT:
|
|
{
|
|
Trace(CONN, INFO,
|
|
("LinkUpIndication: Linkup Usage is CALLOUT\n"));
|
|
|
|
//
|
|
// Allocate a notification for informing the router manager
|
|
// of this connection
|
|
//
|
|
|
|
pMsg = AllocateNotification();
|
|
|
|
if(pMsg is NULL)
|
|
{
|
|
Trace(CONN, ERROR,
|
|
("LinkUpIndication: Couldnt allocate msg\n"));
|
|
|
|
TraceLeave(CONN, "LinkUpIndication");
|
|
|
|
WanpDeleteConnEntry(pConnEntry);
|
|
|
|
ExitDriverCode();
|
|
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// For dial out, we dynamically create an interface
|
|
//
|
|
|
|
pInterface = RtAllocate(NonPagedPool,
|
|
sizeof(UMODE_INTERFACE),
|
|
WAN_INTERFACE_TAG);
|
|
|
|
if(pInterface is NULL)
|
|
{
|
|
Trace(CONN, ERROR,
|
|
("LinkUpIndication: Couldnt allocate I/f\n"));
|
|
|
|
TraceLeave(CONN, "LinkUpIndication");
|
|
|
|
WanpDeleteConnEntry(pConnEntry);
|
|
|
|
FreeNotification(pMsg);
|
|
|
|
ExitDriverCode();
|
|
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(pInterface,
|
|
sizeof(UMODE_INTERFACE));
|
|
|
|
//
|
|
// Get a new index from IP for this
|
|
// This sets the value to INVALID_IF_INDEX if it fails
|
|
//
|
|
|
|
isStatus = WanpGetNewIndex(&(pInterface->dwRsvdAdapterIndex));
|
|
|
|
if(isStatus isnot STATUS_SUCCESS)
|
|
{
|
|
RtFree(pInterface);
|
|
|
|
Trace(CONN, ERROR,
|
|
("LinkUpIndication: Couldnt get index for I/f\n"));
|
|
|
|
TraceLeave(CONN, "LinkUpIndication");
|
|
|
|
WanpDeleteConnEntry(pConnEntry);
|
|
|
|
FreeNotification(pMsg);
|
|
|
|
ExitDriverCode();
|
|
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
Trace(CONN, INFO,
|
|
("LinkUpIndication: DialOut name is %S\n",
|
|
rgwcGuid));
|
|
|
|
//
|
|
// Find an adapter
|
|
//
|
|
|
|
pAdapter = WanpFindAdapterToMap(DU_CALLOUT,
|
|
&kiIrql,
|
|
pInterface->dwRsvdAdapterIndex,
|
|
&usTempName);
|
|
|
|
if(pAdapter is NULL)
|
|
{
|
|
WanpFreeIndex(pInterface->dwRsvdAdapterIndex);
|
|
|
|
RtFree(pInterface);
|
|
|
|
WanpDeleteConnEntry(pConnEntry);
|
|
|
|
FreeNotification(pMsg);
|
|
|
|
ExitDriverCode();
|
|
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Initialize the interface block
|
|
//
|
|
|
|
RtInitializeSpinLock(&(pInterface->rlLock));
|
|
|
|
//
|
|
// Structure copy
|
|
//
|
|
|
|
pInterface->Guid = *((GUID *)(pInfoBuffer->DeviceName.Buffer));
|
|
|
|
pInterface->dwAdminState = IF_ADMIN_STATUS_UP;
|
|
pInterface->dwOperState = IF_OPER_STATUS_CONNECTING;
|
|
pInterface->dwLastChange = GetTimeTicks();
|
|
pInterface->dwIfIndex = INVALID_IF_INDEX;
|
|
|
|
pInterface->duUsage = DU_CALLOUT;
|
|
|
|
InitInterfaceRefCount(pInterface);
|
|
|
|
//
|
|
// Reference and lock the interface because the code after
|
|
// the switch statement expects pInterface to be locked and
|
|
// ref'ed
|
|
//
|
|
|
|
ReferenceInterface(pInterface);
|
|
|
|
RtAcquireSpinLockAtDpcLevel(&(pInterface->rlLock));
|
|
|
|
EnterWriterAtDpcLevel(&g_rwlIfLock);
|
|
|
|
InsertHeadList(&g_leIfList,
|
|
&(pInterface->leIfLink));
|
|
|
|
//
|
|
// No need to insert this in the quick lookup table since
|
|
// this interface is never accessed by the index
|
|
//
|
|
|
|
InterlockedIncrement(&g_ulNumDialOutInterfaces);
|
|
|
|
ExitWriterFromDpcLevel(&g_rwlIfLock);
|
|
|
|
//
|
|
// Initialize the message
|
|
//
|
|
|
|
pMsg->wnMsg.ddeEvent = DDE_CALLOUT_LINKUP;
|
|
pMsg->wnMsg.dwUserIfIndex = INVALID_IF_INDEX;
|
|
pMsg->wnMsg.dwAdapterIndex = pInterface->dwRsvdAdapterIndex;
|
|
pMsg->wnMsg.dwLocalMask = pLinkInfo->dwLocalMask;
|
|
pMsg->wnMsg.dwLocalAddr = pLinkInfo->dwLocalAddr;
|
|
pMsg->wnMsg.dwRemoteAddr = pLinkInfo->dwRemoteAddr;
|
|
pMsg->wnMsg.fDefaultRoute = pLinkInfo->fDefaultRoute;
|
|
|
|
RtAssert(pInfoBuffer->DeviceName.Length <= WANARP_MAX_DEVICE_NAME_LEN);
|
|
RtAssert((pInfoBuffer->DeviceName.Length % sizeof(WCHAR)) is 0)
|
|
|
|
RtlCopyMemory(pMsg->wnMsg.rgwcName,
|
|
usTempName.Buffer,
|
|
usTempName.Length);
|
|
|
|
pMsg->wnMsg.rgwcName[usTempName.Length/sizeof(WCHAR)] = UNICODE_NULL;
|
|
|
|
break;
|
|
}
|
|
|
|
case DU_ROUTER:
|
|
{
|
|
pMsg = AllocateNotification();
|
|
|
|
if(pMsg is NULL)
|
|
{
|
|
Trace(CONN, ERROR,
|
|
("LinkUpIndication: Couldnt allocate msg\n"));
|
|
|
|
TraceLeave(CONN, "LinkUpIndication");
|
|
|
|
WanpDeleteConnEntry(pConnEntry);
|
|
|
|
ExitDriverCode();
|
|
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Get the interface
|
|
//
|
|
|
|
EnterReader(&g_rwlIfLock,
|
|
&kiIrql);
|
|
|
|
pInterface = WanpFindInterfaceGivenIndex(
|
|
pLinkInfo->dwUserIfIndex
|
|
);
|
|
|
|
if(pInterface is NULL)
|
|
{
|
|
ExitReader(&g_rwlIfLock,
|
|
kiIrql);
|
|
|
|
Trace(CONN, ERROR,
|
|
("LinkUpIndication: No interface %d\n",
|
|
pLinkInfo->dwUserIfIndex));
|
|
|
|
WanpDeleteConnEntry(pConnEntry);
|
|
|
|
FreeNotification(pMsg);
|
|
|
|
TraceLeave(CONN, "LinkUpIndication");
|
|
|
|
ExitDriverCode();
|
|
|
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
|
}
|
|
|
|
ExitReaderFromDpcLevel(&g_rwlIfLock);
|
|
|
|
if((pInterface->dwOperState isnot IF_OPER_STATUS_CONNECTING) and
|
|
(pInterface->dwOperState isnot IF_OPER_STATUS_DISCONNECTED))
|
|
{
|
|
Trace(CONN, ERROR,
|
|
("LinkUpIndication: Interface %p is in state %d\n",
|
|
pInterface,
|
|
pInterface->dwOperState));
|
|
|
|
RtReleaseSpinLock(&(pInterface->rlLock),
|
|
kiIrql);
|
|
|
|
WanpDeleteConnEntry(pConnEntry);
|
|
|
|
FreeNotification(pMsg);
|
|
|
|
TraceLeave(CONN, "LinkUpIndication");
|
|
|
|
ExitDriverCode();
|
|
|
|
return STATUS_INVALID_DEVICE_STATE;
|
|
}
|
|
|
|
pInterface->Guid = *((GUID *)(pInfoBuffer->DeviceName.Buffer));
|
|
|
|
Trace(CONN, TRACE,
|
|
("LinkUpIndication: For interface %p\n",
|
|
pInterface));
|
|
|
|
//
|
|
// See if the interface is mapped to an adapter. This happens
|
|
// if this connection is being brought up due to a DODCallout
|
|
//
|
|
|
|
pAdapter = pInterface->pAdapter;
|
|
|
|
if(pAdapter isnot NULL)
|
|
{
|
|
//
|
|
// We have an adapter and we need to lock it. However
|
|
// we cant lock it till we unlock the interface
|
|
// So we let go of the interface lock, but dont deref
|
|
//
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(pInterface->rlLock));
|
|
|
|
//
|
|
// Acquire the adapter lock
|
|
//
|
|
|
|
RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
|
|
|
|
//
|
|
// This adapter better be mapped to the above interface
|
|
// because the only way to unmap an adapter is to delete it
|
|
// or to get a LinkDown or a ConnFailure. All these cases are
|
|
// mutually exclusive with LinkUp
|
|
//
|
|
|
|
RtAssert(pAdapter->pInterface is pInterface);
|
|
RtAssert(pAdapter->byState is AS_MAPPED);
|
|
|
|
ReferenceAdapter(pAdapter);
|
|
|
|
//
|
|
// Go back and lock the interface
|
|
//
|
|
|
|
RtAcquireSpinLockAtDpcLevel(&(pInterface->rlLock));
|
|
|
|
RtAssert(pInterface->dwOperState is IF_OPER_STATUS_CONNECTING);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// So we dont have an adapter...
|
|
// This function MUST be called at PASSIVE
|
|
//
|
|
|
|
RtReleaseSpinLock(&(pInterface->rlLock),
|
|
kiIrql);
|
|
|
|
pAdapter = WanpFindAdapterToMap(DU_ROUTER,
|
|
&kiIrql,
|
|
pInterface->dwRsvdAdapterIndex,
|
|
&usTempName);
|
|
|
|
if(pAdapter is NULL)
|
|
{
|
|
DereferenceInterface(pInterface);
|
|
|
|
WanpDeleteConnEntry(pConnEntry);
|
|
|
|
FreeNotification(pMsg);
|
|
|
|
ExitDriverCode();
|
|
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Got the adapter, lock the interface. We are at
|
|
// DPC since the adapter is locked
|
|
//
|
|
|
|
RtAcquireSpinLockAtDpcLevel(&(pInterface->rlLock));
|
|
}
|
|
|
|
//
|
|
// Interface and adapter refcounted and locked
|
|
//
|
|
|
|
pMsg->wnMsg.ddeEvent = DDE_INTERFACE_CONNECTED;
|
|
pMsg->wnMsg.dwUserIfIndex = pInterface->dwIfIndex;
|
|
pMsg->wnMsg.dwAdapterIndex = pInterface->dwRsvdAdapterIndex;
|
|
pMsg->wnMsg.dwLocalMask = pLinkInfo->dwLocalMask;
|
|
pMsg->wnMsg.dwLocalAddr = pLinkInfo->dwLocalAddr;
|
|
pMsg->wnMsg.dwRemoteAddr = pLinkInfo->dwRemoteAddr;
|
|
pMsg->wnMsg.fDefaultRoute = pLinkInfo->fDefaultRoute;
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
RtAssert(FALSE);
|
|
|
|
WanpDeleteConnEntry(pConnEntry);
|
|
|
|
ExitDriverCode();
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
//
|
|
// At this point we have a locked and refcounted adapter
|
|
// The adapter has been moved to the MAPPED adapter list
|
|
// We also have a locked and recfounted interface
|
|
// pConnEntry points to a CONN_ENTRY which is in the table but
|
|
// is neither locked nor refcounted
|
|
//
|
|
|
|
Trace(CONN, INFO,
|
|
("LinkUpIndication: Found adapter %x to map to i/f %x %d\n",
|
|
pAdapter, pInterface, pInterface->dwIfIndex));
|
|
|
|
#if DBG
|
|
|
|
Trace(CONN, INFO,
|
|
("LinkUpIndication: Adapter Name is %s\n",
|
|
pAdapter->asDeviceNameA.Buffer));
|
|
#endif
|
|
|
|
|
|
if(pLinkInfo->duUsage isnot DU_CALLIN)
|
|
{
|
|
//
|
|
// Set the cross mappings between the interface and the adapter
|
|
//
|
|
|
|
pAdapter->pInterface = pInterface;
|
|
pInterface->pAdapter = pAdapter;
|
|
|
|
pAdapter->byState = AS_MAPPED;
|
|
pInterface->dwOperState = IF_OPER_STATUS_CONNECTED;
|
|
pInterface->dwLastChange= GetTimeTicks();
|
|
|
|
//
|
|
// Put a refcount on both the adapter and the interface
|
|
// because the mapping stored pointers to them
|
|
//
|
|
|
|
ReferenceAdapter(pAdapter);
|
|
ReferenceInterface(pInterface);
|
|
|
|
//
|
|
// Set the lock in the conn entry
|
|
//
|
|
|
|
pConnEntry->prlLock = &(pAdapter->rlLock);
|
|
|
|
//
|
|
// Non Client adapters store a pointer to the connection entry
|
|
// However we dont ref the conn entry for that
|
|
//
|
|
|
|
pAdapter->pConnEntry = pConnEntry;
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// For callin, the mappings are already set up
|
|
//
|
|
|
|
RtAssert(pAdapter->pInterface is pInterface);
|
|
RtAssert(pInterface->pAdapter is pAdapter);
|
|
RtAssert(pInterface->dwOperState is IF_OPER_STATUS_CONNECTED);
|
|
}
|
|
|
|
RtlZeroMemory(pInfoBuffer->DeviceName.Buffer,
|
|
pInfoBuffer->DeviceName.MaximumLength);
|
|
|
|
//
|
|
// Copy the adapter(device) name into the buffer.
|
|
//
|
|
|
|
RtAssert(pAdapter->usDeviceNameW.Length <= pInfoBuffer->DeviceName.MaximumLength);
|
|
|
|
pInfoBuffer->DeviceName.Length = pAdapter->usDeviceNameW.Length;
|
|
|
|
RtlCopyMemory(pInfoBuffer->DeviceName.Buffer,
|
|
pAdapter->usDeviceNameW.Buffer,
|
|
pAdapter->usDeviceNameW.Length);
|
|
|
|
//
|
|
// Copy out the connection index for this connection into NDISWAN's
|
|
// LocalAddress - this will then be put in the DestAddr field by
|
|
// NDISWAN in all the receive indications, and in the linkdown
|
|
//
|
|
|
|
InsertConnIndexInAddr(pInfoBuffer->LocalAddress,
|
|
pConnEntry->ulSlotIndex);
|
|
|
|
|
|
//
|
|
// Set up the connection entry
|
|
//
|
|
|
|
pConnEntry->dwLocalMask = pLinkInfo->dwLocalMask;
|
|
pConnEntry->dwLocalAddr = pLinkInfo->dwLocalAddr;
|
|
pConnEntry->dwRemoteAddr = pLinkInfo->dwRemoteAddr;
|
|
pConnEntry->ulMtu = pInfoBuffer->MaximumTotalSize;
|
|
pConnEntry->ulSpeed = pInfoBuffer->LinkSpeed * 100L;
|
|
pConnEntry->bFilterNetBios = (pLinkInfo->fFilterNetBios == 1);
|
|
pConnEntry->byState = CS_CONNECTED;
|
|
RtAssert(pConnEntry->duUsage is pLinkInfo->duUsage);
|
|
pConnEntry->pvIpLinkContext = NULL;
|
|
|
|
//
|
|
// Map the entry to the adapter
|
|
// Because of the stored pointer, refcount the adapter
|
|
//
|
|
|
|
pConnEntry->pAdapter = pAdapter;
|
|
|
|
ReferenceAdapter(pAdapter);
|
|
|
|
//
|
|
// Initialize the prebuilt ethernet header
|
|
// First zero out the source address in the ethernet header
|
|
//
|
|
|
|
RtlZeroMemory(pConnEntry->ehHeader.rgbySourceAddr,
|
|
ARP_802_ADDR_LENGTH);
|
|
|
|
//
|
|
// Put our context in the right place in the ethernet source
|
|
// address
|
|
//
|
|
|
|
InsertConnIndexInAddr(pConnEntry->ehHeader.rgbySourceAddr,
|
|
pConnEntry->ulSlotIndex);
|
|
|
|
//
|
|
// Refcount the connentry because it lies in the connection table,
|
|
// NDISWAN has a "pointer" to it and because pAdapter->pConnEntry
|
|
// may have a pointer to it.
|
|
// NOTE: since we keep only one ref for all these conditions, all the
|
|
// pointer must be cleared in the same function with the connection
|
|
// locked
|
|
//
|
|
|
|
ReferenceConnEntry(pConnEntry);
|
|
|
|
pConnEntry->ehHeader.wType = RtlUshortByteSwap(ARP_ETYPE_IP);
|
|
|
|
//
|
|
// A send is from WANARP -> NDISWAN so put the NDISWAN context in
|
|
// the DEST address of our prebuilt ethernet header
|
|
//
|
|
|
|
RtlCopyMemory(pConnEntry->ehHeader.rgbyDestAddr,
|
|
pInfoBuffer->RemoteAddress,
|
|
ARP_802_ADDR_LENGTH);
|
|
|
|
//
|
|
// For a router connection, tell router manager about it
|
|
//
|
|
|
|
if(pLinkInfo->duUsage is DU_ROUTER)
|
|
{
|
|
//
|
|
// If there are packets queued to the interface, drain them now
|
|
//
|
|
|
|
WanpTransmitQueuedPackets(pAdapter,
|
|
pInterface,
|
|
pConnEntry,
|
|
kiIrql);
|
|
|
|
//
|
|
// Let Router Manager know of a new connection
|
|
//
|
|
|
|
WanpCompleteIrp(pMsg);
|
|
}
|
|
else
|
|
{
|
|
|
|
//
|
|
// Done with the interfaces. We can unlock them now
|
|
// Router interfaces are unlocked in WanpSendPackets which
|
|
// is called from WanpTransmitQueuedPackets
|
|
//
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(pInterface->rlLock));
|
|
RtReleaseSpinLock(&(pAdapter->rlLock),
|
|
kiIrql);
|
|
|
|
if(pLinkInfo->duUsage is DU_CALLOUT)
|
|
{
|
|
//
|
|
// Complete the IRP to the router manager (or queue if no IRPs
|
|
// are pending)
|
|
//
|
|
|
|
WanpCompleteIrp(pMsg);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Need to make this call without holding locks.
|
|
// We can let go of the locks since we wont get any NDIS layer
|
|
// calls for this connection till this function completes and
|
|
// the IP and IOCTL interface functions can be handled with no
|
|
// consistency problems
|
|
//
|
|
|
|
if(pLinkInfo->duUsage isnot DU_CALLIN)
|
|
{
|
|
|
|
//
|
|
// Notify upper layer of mtu change
|
|
//
|
|
|
|
mtuChangeInfo.lmc_mtu = pConnEntry->ulMtu;
|
|
speedChangeInfo.lsc_speed = pConnEntry->ulSpeed;
|
|
|
|
|
|
g_pfnIpStatus(pAdapter->pvIpContext,
|
|
LLIP_STATUS_MTU_CHANGE,
|
|
&mtuChangeInfo,
|
|
sizeof(LLIPMTUChange),
|
|
NULL);
|
|
|
|
g_pfnIpStatus(pConnEntry->pAdapter->pvIpContext,
|
|
LLIP_STATUS_SPEED_CHANGE,
|
|
&speedChangeInfo,
|
|
sizeof(LLIPSpeedChange),
|
|
pConnEntry->pvIpLinkContext);
|
|
}
|
|
else
|
|
{
|
|
isStatus = g_pfnIpAddLink(pAdapter->pvIpContext,
|
|
pConnEntry->dwRemoteAddr,
|
|
pConnEntry,
|
|
&(pConnEntry->pvIpLinkContext),
|
|
pConnEntry->ulMtu);
|
|
|
|
if(isStatus isnot IP_SUCCESS)
|
|
{
|
|
Trace(CONN, ERROR,
|
|
("LinkUpIndication: IpAddLink returned %x\n",
|
|
isStatus));
|
|
|
|
RtlZeroMemory(pInfoBuffer->DeviceName.Buffer,
|
|
pInfoBuffer->DeviceName.MaximumLength);
|
|
|
|
pInfoBuffer->DeviceName.Length = 0;
|
|
|
|
RtlZeroMemory(pInfoBuffer->LocalAddress,
|
|
ARP_802_ADDR_LENGTH);
|
|
|
|
//
|
|
// Just deref the connection entry
|
|
// This will clear up everything
|
|
//
|
|
|
|
DereferenceConnEntry(pConnEntry);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Reference it once for the fact that we now have this entry
|
|
// with IP
|
|
//
|
|
|
|
ReferenceConnEntry(pConnEntry);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Done with the interface and adapter. Dereference them now because
|
|
// the Find..() functions put a reference on them
|
|
//
|
|
|
|
|
|
DereferenceAdapter(pAdapter);
|
|
DereferenceInterface(pInterface);
|
|
|
|
ExitDriverCode();
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
WanpLinkDownIndication(
|
|
PNDIS_WAN_LINE_DOWN pInfoBuffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
Locks:
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PADAPTER pAdapter;
|
|
PUMODE_INTERFACE pInterface;
|
|
KIRQL kiIrql;
|
|
PCONN_ENTRY pConnEntry;
|
|
ULONG ulIndex;
|
|
|
|
PPENDING_NOTIFICATION pMsg;
|
|
|
|
TraceEnter(CONN, "LinkDownIndication");
|
|
|
|
ulIndex = GetConnIndexFromAddr(pInfoBuffer->LocalAddress);
|
|
|
|
//
|
|
// Lock out the connection entry
|
|
//
|
|
|
|
RtAcquireSpinLock(&g_rlConnTableLock,
|
|
&kiIrql);
|
|
|
|
pConnEntry = GetConnEntryGivenIndex(ulIndex);
|
|
|
|
if(pConnEntry is NULL)
|
|
{
|
|
Trace(CONN, ERROR,
|
|
("LinkDownIndication: No entry in slot %d\n",
|
|
ulIndex));
|
|
|
|
RtReleaseSpinLock(&g_rlConnTableLock,
|
|
kiIrql);
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Lock the connection entry or adapter
|
|
//
|
|
|
|
RtAcquireSpinLockAtDpcLevel(pConnEntry->prlLock);
|
|
|
|
//
|
|
// Done with the connection table
|
|
//
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&g_rlConnTableLock);
|
|
|
|
//
|
|
// Mark this connection/adapter as disconnecting
|
|
// We can reference these field of the CONN_ENTRY since they cant
|
|
// change during its lifetime
|
|
//
|
|
|
|
pAdapter = pConnEntry->pAdapter;
|
|
|
|
RtAssert(pAdapter);
|
|
RtAssert(pAdapter->byState is AS_MAPPED);
|
|
|
|
pInterface = pAdapter->pInterface;
|
|
pMsg = NULL;
|
|
|
|
if(pInterface->duUsage is DU_CALLIN)
|
|
{
|
|
IP_STATUS isStatus;
|
|
|
|
//
|
|
// Client connection. This means we have the connection entry
|
|
// locked, but the adapter is unlocked
|
|
//
|
|
|
|
pConnEntry->byState = CS_DISCONNECTING;
|
|
|
|
RtReleaseSpinLock(pConnEntry->prlLock,
|
|
kiIrql);
|
|
|
|
isStatus = g_pfnIpDeleteLink(g_pServerAdapter->pvIpContext,
|
|
pConnEntry->pvIpLinkContext);
|
|
|
|
if(isStatus isnot IP_SUCCESS)
|
|
{
|
|
Trace(CONN, ERROR,
|
|
("LinkDownIndication: IpDeleteLink returned %x\n",
|
|
isStatus));
|
|
|
|
//
|
|
// This is really bad
|
|
//
|
|
|
|
RtAssert(FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Here we have the adapter locked
|
|
// The connection entry is protected by the same lock
|
|
//
|
|
|
|
pConnEntry->byState = CS_DISCONNECTING;
|
|
|
|
//
|
|
// Free the interface mapping
|
|
//
|
|
|
|
pAdapter->pInterface = NULL;
|
|
pAdapter->byState = AS_UNMAPPING;
|
|
|
|
//
|
|
// Lock the interface list and the interface
|
|
// The interface has to be present since it is ref counted
|
|
//
|
|
|
|
EnterWriterAtDpcLevel(&g_rwlIfLock);
|
|
|
|
RtAcquireSpinLockAtDpcLevel(&(pInterface->rlLock));
|
|
|
|
//
|
|
// Clear out the adapter field.
|
|
//
|
|
|
|
pInterface->pAdapter = NULL;
|
|
|
|
pInterface->dwOperState = IF_OPER_STATUS_DISCONNECTED;
|
|
pInterface->dwLastChange= GetTimeTicks();
|
|
|
|
pMsg = AllocateNotification();
|
|
|
|
if(pMsg is NULL)
|
|
{
|
|
Trace(CONN, ERROR,
|
|
("LinkDownIndication: Couldnt allocate msg\n"));
|
|
|
|
//
|
|
// Really no failure path here
|
|
//
|
|
|
|
RtAssert(FALSE);
|
|
}
|
|
|
|
if(pInterface->duUsage is DU_CALLOUT)
|
|
{
|
|
if(pMsg)
|
|
{
|
|
//
|
|
// Setup the message
|
|
//
|
|
|
|
pMsg->wnMsg.ddeEvent = DDE_CALLOUT_LINKDOWN;
|
|
pMsg->wnMsg.dwAdapterIndex = pInterface->dwRsvdAdapterIndex;
|
|
pMsg->wnMsg.dwUserIfIndex = INVALID_IF_INDEX;
|
|
pMsg->wnMsg.dwAdapterIndex = pAdapter->dwAdapterIndex;
|
|
pMsg->wnMsg.dwLocalAddr = pConnEntry->dwLocalAddr;
|
|
pMsg->wnMsg.dwLocalMask = pConnEntry->dwLocalMask;
|
|
pMsg->wnMsg.dwRemoteAddr = pConnEntry->dwRemoteAddr;
|
|
}
|
|
|
|
//
|
|
// Remove from list and dereference the interface
|
|
//
|
|
|
|
RemoveEntryList(&(pInterface->leIfLink));
|
|
|
|
InterlockedDecrement(&g_ulNumDialOutInterfaces);
|
|
|
|
//
|
|
// Done with the interface list
|
|
//
|
|
|
|
ExitWriterFromDpcLevel(&g_rwlIfLock);
|
|
|
|
//
|
|
// One ref kept for being on list
|
|
// The final deletion will free the index
|
|
//
|
|
|
|
DereferenceInterface(pInterface);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Dont need the interface list lock
|
|
//
|
|
|
|
ExitWriterFromDpcLevel(&g_rwlIfLock);
|
|
|
|
Trace(CONN, TRACE,
|
|
("LinkDownIndication: For interface %p\n",
|
|
pInterface));
|
|
|
|
//
|
|
// For ROUTER interfaces notify user mode of the connection
|
|
// going down
|
|
//
|
|
|
|
if(pMsg)
|
|
{
|
|
//
|
|
// Setup the message
|
|
//
|
|
|
|
pMsg->wnMsg.ddeEvent = DDE_INTERFACE_DISCONNECTED;
|
|
pMsg->wnMsg.dwAdapterIndex = pInterface->dwRsvdAdapterIndex;
|
|
pMsg->wnMsg.dwUserIfIndex = pInterface->dwIfIndex;
|
|
pMsg->wnMsg.dwAdapterIndex = pAdapter->dwAdapterIndex;
|
|
pMsg->wnMsg.dwLocalAddr = pConnEntry->dwLocalAddr;
|
|
pMsg->wnMsg.dwLocalMask = pConnEntry->dwLocalMask;
|
|
pMsg->wnMsg.dwRemoteAddr = pConnEntry->dwRemoteAddr;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Done with the interface and adapter
|
|
//
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(pInterface->rlLock));
|
|
|
|
RtReleaseSpinLock(&(pAdapter->rlLock),
|
|
kiIrql);
|
|
|
|
//
|
|
// Deref the adapter because it was mapped to the interface
|
|
//
|
|
|
|
DereferenceAdapter(pAdapter);
|
|
|
|
//
|
|
// Deref the interface because it was mapped to the adapter
|
|
//
|
|
|
|
DereferenceInterface(pInterface);
|
|
}
|
|
|
|
//
|
|
// Dereference the connection entry twice. Once because NDISWAN is
|
|
// removing the connection, and again because GetConnEntry put a
|
|
// reference on it
|
|
//
|
|
|
|
DereferenceConnEntry(pConnEntry);
|
|
DereferenceConnEntry(pConnEntry);
|
|
|
|
if(pMsg)
|
|
{
|
|
//
|
|
// Will be non null only for callout where allocation succeeded
|
|
//
|
|
|
|
WanpCompleteIrp(pMsg);
|
|
}
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
UINT
|
|
WanDemandDialRequest(
|
|
ROUTE_CONTEXT Context,
|
|
IPAddr dwDest,
|
|
IPAddr dwSource,
|
|
BYTE byProtocol,
|
|
PBYTE pbyBuffer,
|
|
UINT uiLength,
|
|
IPAddr dwHdrSrc
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function services the request by IP to dial out an interface.
|
|
IP passes us the context stored within the route. This context is
|
|
nothing but the index of the interface to dial.
|
|
We first find the interface. If found, we see if the interface is
|
|
already mapped. This can happen in some window of time. In such a case
|
|
we simply return the adapter mapped to the interface. Otherwise, we
|
|
find a free adapter. We map this adapter to the interface and
|
|
complete an IRP to the router manager to ask it to connect the interface.
|
|
We set the state on the interface and the adapter to reflect the fact
|
|
that they are mapped and awaiting connection.
|
|
If we dont find a free adapter, we nevertheless ask the router manager
|
|
to dial out the interface, but we fail the demand dial request to IP.
|
|
We return the adapter (IP) index of the adapter that was mapped.
|
|
|
|
Locks:
|
|
|
|
Acquires the g_rwlIfLock as READER to lock out the interface
|
|
The release the g_rwlIfLock and acquires the g_rwlAdapterlock to
|
|
lock out a free adapter. (NOTE: DOES NOT FOLLOW adapter->interface
|
|
hierarchy)
|
|
|
|
Arguments:
|
|
|
|
Context
|
|
dwDest
|
|
dwSource
|
|
byProtocol
|
|
pbyBuffer
|
|
uiLength
|
|
|
|
Return Value:
|
|
|
|
The adapter of the index mapped
|
|
INVALID_IF_INDEX on failure
|
|
|
|
--*/
|
|
|
|
{
|
|
PADAPTER pAdapter;
|
|
PPENDING_NOTIFICATION pMsg;
|
|
PUMODE_INTERFACE pInterface;
|
|
KIRQL kiIrql;
|
|
DWORD dwAdapterIndex;
|
|
PLIST_ENTRY pleNode;
|
|
|
|
TraceEnter(CONN, "DemandDialRequest");
|
|
|
|
EnterWriter(&g_rwlAdapterLock,
|
|
&kiIrql);
|
|
|
|
EnterReaderAtDpcLevel(&g_rwlIfLock);
|
|
|
|
pInterface = WanpFindInterfaceGivenIndex(Context);
|
|
|
|
if(pInterface is NULL)
|
|
{
|
|
ExitReaderFromDpcLevel(&g_rwlIfLock);
|
|
|
|
ExitWriter(&g_rwlAdapterLock,
|
|
kiIrql);
|
|
|
|
Trace(CONN, ERROR,
|
|
("DemandDialRequest: Couldnt find interface %d\n",
|
|
Context));
|
|
|
|
TraceLeave(CONN, "DemandDialRequest");
|
|
|
|
return INVALID_IF_INDEX;
|
|
}
|
|
|
|
ExitReaderFromDpcLevel(&g_rwlIfLock);
|
|
|
|
Trace(CONN, TRACE,
|
|
("DemandDialRequest: For interface %p\n",
|
|
pInterface));
|
|
|
|
//
|
|
// If the interface is already connected, this is just race condition
|
|
//
|
|
|
|
if(pInterface->dwOperState >= IF_OPER_STATUS_CONNECTING)
|
|
{
|
|
Trace(CONN, WARN,
|
|
("DemandDialRequest: I/f state %d, returning old adapter %p\n",
|
|
pInterface->dwOperState,
|
|
pInterface->pAdapter));
|
|
|
|
|
|
if(pInterface->pAdapter)
|
|
{
|
|
//
|
|
// We can get the adapter index without the holding the adapter
|
|
// lock , because it is a read-only field once the adapter has
|
|
// been added to IP, and can not change while the adapter is
|
|
// is mapped to the interface
|
|
//
|
|
|
|
RtAssert(pInterface->pAdapter->dwAdapterIndex is pInterface->dwRsvdAdapterIndex);
|
|
|
|
dwAdapterIndex = pInterface->dwRsvdAdapterIndex;
|
|
}
|
|
else
|
|
{
|
|
dwAdapterIndex = INVALID_IF_INDEX;
|
|
}
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(pInterface->rlLock));
|
|
|
|
ExitWriter(&g_rwlAdapterLock,
|
|
kiIrql);
|
|
|
|
DereferenceInterface(pInterface);
|
|
|
|
TraceLeave(CONN, "DemandDialRequest");
|
|
|
|
return dwAdapterIndex;
|
|
}
|
|
|
|
//
|
|
// We will need to connect this. If we cant get the memory
|
|
// needed for the connection message, bail out
|
|
//
|
|
|
|
pMsg = AllocateNotification();
|
|
|
|
if(pMsg is NULL)
|
|
{
|
|
Trace(CONN, ERROR,
|
|
("DemandDialRequest: Couldnt allocate notification\n"));
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(pInterface->rlLock));
|
|
|
|
ExitWriter(&g_rwlAdapterLock,
|
|
kiIrql);
|
|
|
|
DereferenceInterface(pInterface);
|
|
|
|
TraceLeave(CONN, "DemandDialRequest");
|
|
|
|
return INVALID_IF_INDEX;
|
|
}
|
|
|
|
pInterface->dwOperState = IF_OPER_STATUS_CONNECTING;
|
|
pInterface->dwLastChange= GetTimeTicks();
|
|
|
|
//
|
|
// So we dont have an adapter mapped to the interface. Try and find one
|
|
// We dont call FindAdapterToMap because that needs to be at passive
|
|
//
|
|
|
|
if(IsListEmpty(&g_leAddedAdapterList))
|
|
{
|
|
Trace(CONN, INFO,
|
|
("DemandDialRequest: Couldnt find an adapter already added to IP\n"));
|
|
|
|
ExitWriterFromDpcLevel(&g_rwlAdapterLock);
|
|
|
|
pAdapter = NULL;
|
|
|
|
dwAdapterIndex = INVALID_IF_INDEX;
|
|
}
|
|
else
|
|
{
|
|
pleNode = RemoveHeadList(&g_leAddedAdapterList);
|
|
|
|
pAdapter = CONTAINING_RECORD(pleNode,
|
|
ADAPTER,
|
|
leAdapterLink);
|
|
|
|
RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
|
|
|
|
InsertHeadList(&g_leMappedAdapterList,
|
|
&(pAdapter->leAdapterLink));
|
|
|
|
ExitWriterFromDpcLevel(&g_rwlAdapterLock);
|
|
|
|
|
|
RtAssert(pAdapter->byState is AS_ADDED);
|
|
|
|
//
|
|
// So we have a locked adapter
|
|
//
|
|
|
|
dwAdapterIndex = pAdapter->dwAdapterIndex;
|
|
|
|
//
|
|
// Map the adapter to the interface and refcount the adapter
|
|
// to account for the fact that there is a stored pointer to it
|
|
//
|
|
|
|
pInterface->pAdapter = pAdapter;
|
|
|
|
ReferenceAdapter(pAdapter);
|
|
|
|
//
|
|
// Setup the cross mapping
|
|
//
|
|
|
|
pAdapter->pInterface = pInterface;
|
|
pAdapter->byState = AS_MAPPED;
|
|
|
|
ReferenceInterface(pInterface);
|
|
|
|
Trace(CONN, INFO,
|
|
("DemandDialRequest: Found adapter %d free for %d\n",
|
|
pAdapter->dwAdapterIndex,
|
|
pInterface->dwIfIndex));
|
|
|
|
#if DBG
|
|
|
|
Trace(CONN, INFO,
|
|
("DemandDialRequest: Adapter Index is %d. Name is %s\n",
|
|
pAdapter->dwAdapterIndex,
|
|
pAdapter->asDeviceNameA.Buffer));
|
|
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Initialize the info to be sent to the router manager
|
|
//
|
|
|
|
pMsg->wnMsg.ddeEvent = DDE_CONNECT_INTERFACE;
|
|
pMsg->wnMsg.dwUserIfIndex = pInterface->dwIfIndex;
|
|
pMsg->wnMsg.dwAdapterIndex = dwAdapterIndex;
|
|
pMsg->wnMsg.dwPacketSrcAddr = dwHdrSrc;
|
|
pMsg->wnMsg.dwPacketDestAddr = dwDest;
|
|
pMsg->wnMsg.ulPacketLength = uiLength;
|
|
pMsg->wnMsg.byPacketProtocol = byProtocol;
|
|
|
|
if(uiLength)
|
|
{
|
|
RtlCopyMemory(pMsg->wnMsg.rgbyPacket,
|
|
pbyBuffer,
|
|
MIN(MAX_PACKET_COPY_SIZE,uiLength));
|
|
}
|
|
|
|
//
|
|
// Complete any pending IRP or queue the notification
|
|
//
|
|
|
|
ExInitializeWorkItem(&pMsg->wqi,
|
|
WanpCompleteIrp,
|
|
pMsg);
|
|
|
|
ExQueueWorkItem(&pMsg->wqi,
|
|
DelayedWorkQueue);
|
|
|
|
|
|
// WanpCompleteIrp(pMsg);
|
|
|
|
//
|
|
// Ok so we are done with the adapter and the interface
|
|
//
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(pInterface->rlLock));
|
|
|
|
DereferenceInterface(pInterface);
|
|
|
|
if(pAdapter)
|
|
{
|
|
RtReleaseSpinLock(&(pAdapter->rlLock),
|
|
kiIrql);
|
|
}
|
|
else
|
|
{
|
|
KeLowerIrql(kiIrql);
|
|
}
|
|
|
|
//
|
|
// No need to deref the adapter, since we didnt call FindAdapter
|
|
//
|
|
|
|
Trace(CONN, INFO,
|
|
("DemandDialRequest: Returning adapter %d\n",
|
|
dwAdapterIndex));
|
|
|
|
return dwAdapterIndex;
|
|
}
|
|
|
|
|
|
PCONN_ENTRY
|
|
WanpCreateConnEntry(
|
|
DIAL_USAGE duUsage
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate a connection entry and find a free slot for it in the
|
|
connection table. Sets the slot into the conn entry
|
|
The connection entry returned is not refcounted.
|
|
|
|
Locks:
|
|
|
|
Must be called with the g_rlConnTableLock held.
|
|
|
|
Arguments:
|
|
|
|
duUsage Type of the connection.
|
|
|
|
Return Value:
|
|
|
|
Pointer to allocate conn entry (if successfull)
|
|
|
|
--*/
|
|
|
|
{
|
|
PCONN_ENTRY pConnEntry;
|
|
KIRQL kiIrql;
|
|
PULONG_PTR puipTable;
|
|
ULONG ulSize;
|
|
ULONG i, ulIndex;
|
|
|
|
TraceEnter(CONN, "CreateConnEntry");
|
|
|
|
pConnEntry = AllocateConnection();
|
|
|
|
if(pConnEntry is NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
RtlZeroMemory(pConnEntry,
|
|
sizeof(CONN_ENTRY));
|
|
|
|
//
|
|
// The refcount of a connection entry is set to 0 and not 1
|
|
//
|
|
|
|
InitConnEntryRefCount(pConnEntry);
|
|
|
|
pConnEntry->byState = CS_CONNECTING;
|
|
pConnEntry->duUsage = duUsage;
|
|
|
|
//
|
|
// Find a free slot. g_ulNextIndex is a hint
|
|
//
|
|
|
|
for(i = 0, ulIndex = g_ulNextConnIndex;
|
|
i < g_ulConnTableSize;
|
|
i++)
|
|
{
|
|
//
|
|
// Slot 0 is initialized to (ULONG_PTR)-1 so it cant match
|
|
//
|
|
|
|
if(g_puipConnTable[ulIndex] is (ULONG_PTR)0)
|
|
{
|
|
//
|
|
// Free Slot
|
|
//
|
|
|
|
g_puipConnTable[ulIndex] = (ULONG_PTR)pConnEntry;
|
|
|
|
g_rgulConns[duUsage]++;
|
|
|
|
pConnEntry->ulSlotIndex = ulIndex;
|
|
|
|
//
|
|
// We just assume that the next one will be free
|
|
// If not, the timer can fix it. If we get a connection before
|
|
// the timer gets a chance to fix it then we will take a
|
|
// perf hit
|
|
//
|
|
|
|
g_ulNextConnIndex++;
|
|
|
|
g_ulNextConnIndex = g_ulNextConnIndex % g_ulConnTableSize;
|
|
|
|
return pConnEntry;
|
|
}
|
|
|
|
ulIndex++;
|
|
|
|
//
|
|
// Wrap around
|
|
//
|
|
|
|
ulIndex = ulIndex % g_ulConnTableSize;
|
|
}
|
|
|
|
//
|
|
// Couldnt find a slot. Grow the table. We are still holding the
|
|
// lock. The way we do this is by growing the table in blocks of
|
|
// 64 entries. We then copy out what we have and update the next index
|
|
// etc
|
|
//
|
|
|
|
ulSize = (g_ulConnTableSize + WAN_CONN_TABLE_INCREMENT) * sizeof(ULONG_PTR);
|
|
|
|
puipTable = RtAllocate(NonPagedPool,
|
|
ulSize,
|
|
WAN_CONN_TAG);
|
|
|
|
if(puipTable is NULL)
|
|
{
|
|
Trace(CONN, ERROR,
|
|
("AllocateConnEntry: couldnt realloc table of size %d\n",
|
|
ulSize));
|
|
|
|
FreeConnection(pConnEntry);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Zero out the new memory
|
|
//
|
|
|
|
RtlZeroMemory(puipTable,
|
|
ulSize);
|
|
|
|
//
|
|
// Copy out the old table
|
|
//
|
|
|
|
RtlCopyMemory(puipTable,
|
|
g_puipConnTable,
|
|
g_ulConnTableSize * sizeof(ULONG_PTR));
|
|
|
|
|
|
//
|
|
// Free the old table
|
|
//
|
|
|
|
RtFree(g_puipConnTable);
|
|
|
|
//
|
|
// Set up pointers, indices etc
|
|
//
|
|
|
|
g_puipConnTable = puipTable;
|
|
|
|
//
|
|
// Since the table was totally full, the next index will be
|
|
// at the start of the new memory. Set the entry to that
|
|
//
|
|
|
|
g_puipConnTable[g_ulConnTableSize] = (ULONG_PTR)pConnEntry;
|
|
|
|
g_rgulConns[duUsage]++;
|
|
|
|
pConnEntry->ulSlotIndex = g_ulConnTableSize;
|
|
|
|
//
|
|
// Set the next index to one after the slot we just used
|
|
//
|
|
|
|
g_ulNextConnIndex = g_ulConnTableSize + 1;
|
|
|
|
//
|
|
// Increast the size to what is currently is
|
|
//
|
|
|
|
g_ulConnTableSize += WAN_CONN_TABLE_INCREMENT;
|
|
|
|
return pConnEntry;
|
|
}
|
|
|
|
VOID
|
|
WanIpCloseLink(
|
|
PVOID pvAdapterContext,
|
|
PVOID pvLinkContext
|
|
)
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called by IP when its ref counts on the link fall
|
|
to 0.
|
|
|
|
Locks:
|
|
|
|
None needed
|
|
|
|
Arguments:
|
|
|
|
pvAdapterContext The context we passed for the P2MP interface
|
|
pvLinkContext The context we passed for a link in IpAddLink()
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
PCONN_ENTRY pConnEntry;
|
|
|
|
TraceEnter(CONN, "IpCloseLink");
|
|
|
|
RtAssert(pvAdapterContext is g_pServerAdapter);
|
|
|
|
pConnEntry = (PCONN_ENTRY)pvLinkContext;
|
|
|
|
DereferenceConnEntry(pConnEntry);
|
|
}
|
|
|
|
VOID
|
|
WanpDeleteConnEntry(
|
|
PCONN_ENTRY pConnEntry
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called when the refcount on a connection falls to zero
|
|
The connection entry is different from the other structures in wanarp
|
|
in that even when the refcount falls to zero, the pAdapter has a
|
|
pointer to the connection. However when we get here we know that
|
|
no new sends could be forthcoming on this connection because we
|
|
set the connection state to be disconnecting. We have already
|
|
gotten a LinkDown indication on this and all our pending SendComplete's
|
|
have been called
|
|
|
|
We also sets the next free index for the connection table
|
|
No shrinking is done here because we do that off a timer
|
|
|
|
Locks:
|
|
|
|
Acquires the g_rlConnTableLock. The connection entry itself should
|
|
not be locked
|
|
|
|
Arguments:
|
|
|
|
pConnEntry The connection entry to free
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG ulIndex;
|
|
KIRQL kiIrql;
|
|
PULONG_PTR puipTable;
|
|
SIZE_T stSize;
|
|
PADAPTER pAdapter;
|
|
|
|
|
|
//
|
|
// Get the slot number
|
|
//
|
|
|
|
ulIndex = pConnEntry->ulSlotIndex;
|
|
|
|
RtAcquireSpinLock(&g_rlConnTableLock,
|
|
&kiIrql);
|
|
|
|
|
|
g_puipConnTable[ulIndex] = (ULONG_PTR)0;
|
|
|
|
#if DBG
|
|
RtAssert((pConnEntry->duUsage is DU_CALLIN) or
|
|
(pConnEntry->duUsage is DU_CALLOUT) or
|
|
(pConnEntry->duUsage is DU_ROUTER));
|
|
#endif
|
|
|
|
g_rgulConns[pConnEntry->duUsage]--;
|
|
|
|
if(g_puipConnTable[g_ulNextConnIndex] isnot (ULONG_PTR)0)
|
|
{
|
|
g_ulNextConnIndex = ulIndex;
|
|
}
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&g_rlConnTableLock);
|
|
|
|
//
|
|
// Get the adapter this connection is mapped to
|
|
//
|
|
|
|
pAdapter = pConnEntry->pAdapter;
|
|
|
|
#if DBG
|
|
|
|
pConnEntry->ulSlotIndex = 0;
|
|
pConnEntry->pAdapter = NULL;
|
|
|
|
#endif
|
|
|
|
//
|
|
// Done with the connection entry
|
|
//
|
|
|
|
FreeConnection(pConnEntry);
|
|
|
|
if(pAdapter is NULL)
|
|
{
|
|
KeLowerIrql(kiIrql);
|
|
|
|
//
|
|
// Wasnt mapped. Can happen when this function is called to
|
|
// merely free resources from an error case
|
|
//
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// Lock the adapter list
|
|
//
|
|
|
|
EnterWriterAtDpcLevel(&g_rwlAdapterLock);
|
|
|
|
if(pAdapter is g_pServerAdapter)
|
|
{
|
|
ExitWriter(&g_rwlAdapterLock,
|
|
kiIrql);
|
|
|
|
//
|
|
// Client connection, simply deref the adapter
|
|
//
|
|
|
|
DereferenceAdapter(pAdapter);
|
|
|
|
return;
|
|
}
|
|
|
|
ExitWriterFromDpcLevel(&g_rwlAdapterLock);
|
|
|
|
//
|
|
// Lock the adapter
|
|
//
|
|
|
|
RtAcquireSpinLockAtDpcLevel(&(pAdapter->rlLock));
|
|
|
|
//
|
|
// Remove the entry from the adapter
|
|
//
|
|
|
|
pAdapter->pConnEntry = NULL;
|
|
|
|
//
|
|
// Done with the adapter
|
|
//
|
|
|
|
RtReleaseSpinLock(&(pAdapter->rlLock),
|
|
kiIrql);
|
|
|
|
|
|
//
|
|
// Called with no locks held
|
|
//
|
|
|
|
WanpUnmapAdapter(pAdapter);
|
|
|
|
//
|
|
// Dereference the adapter because the conn entry had a pointer
|
|
// to it, which is now gone
|
|
//
|
|
|
|
DereferenceAdapter(pAdapter);
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
WanpNotifyRouterManager(
|
|
PPENDING_NOTIFICATION pMsg,
|
|
PUMODE_INTERFACE pInterface,
|
|
PADAPTER pAdapter,
|
|
PCONN_ENTRY pConnEntry,
|
|
BOOLEAN bConnected
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Notifies the router manager when an interface is connected or
|
|
disconnected
|
|
|
|
Locks:
|
|
|
|
The interface must be locked
|
|
|
|
Arguments:
|
|
|
|
pMsg
|
|
pInterface The interface being connected or disconnected
|
|
pAdapter
|
|
bConnected Set to TRUE if the interface is being connected
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
KIRQL kiIrql;
|
|
|
|
TraceEnter(CONN, "WanpNotifyRouterManager");
|
|
|
|
if(bConnected)
|
|
{
|
|
pMsg->wnMsg.ddeEvent = DDE_INTERFACE_CONNECTED;
|
|
}
|
|
else
|
|
{
|
|
pMsg->wnMsg.ddeEvent = DDE_INTERFACE_DISCONNECTED;
|
|
}
|
|
|
|
pMsg->wnMsg.dwUserIfIndex = pInterface->dwIfIndex;
|
|
pMsg->wnMsg.dwAdapterIndex = pAdapter->dwAdapterIndex;
|
|
pMsg->wnMsg.dwLocalAddr = pConnEntry->dwLocalAddr;
|
|
pMsg->wnMsg.dwLocalMask = pConnEntry->dwLocalMask;
|
|
pMsg->wnMsg.dwRemoteAddr = pConnEntry->dwRemoteAddr;
|
|
|
|
//
|
|
// Complete any pending IRP or queue the notification
|
|
//
|
|
|
|
WanpCompleteIrp(pMsg);
|
|
|
|
}
|
|
|
|
PCONN_ENTRY
|
|
WanpGetConnEntryGivenAddress(
|
|
DWORD dwAddress
|
|
)
|
|
{
|
|
ULONG i;
|
|
KIRQL kiIrql;
|
|
PCONN_ENTRY pConnEntry;
|
|
BOOLEAN bFindFirst;
|
|
|
|
pConnEntry = NULL;
|
|
|
|
RtAcquireSpinLock(&g_rlConnTableLock,
|
|
&kiIrql);
|
|
|
|
if((dwAddress is 0xFFFFFFFF) and
|
|
(g_rgulConns[DU_CALLIN] is 1))
|
|
{
|
|
bFindFirst = TRUE;
|
|
}
|
|
else
|
|
{
|
|
bFindFirst = FALSE;
|
|
}
|
|
|
|
//
|
|
// Slot 0 is never used
|
|
//
|
|
|
|
for(i = 1; i < g_ulConnTableSize; i++)
|
|
{
|
|
//
|
|
// If there is a non-null connection and
|
|
// If either the dest matches, or we want to send a bcast to the
|
|
// first client (that is fully connected)
|
|
//
|
|
|
|
if(((PCONN_ENTRY)(g_puipConnTable[i]) isnot NULL) and
|
|
((((PCONN_ENTRY)(g_puipConnTable[i]))->dwRemoteAddr is dwAddress) or
|
|
(bFindFirst and
|
|
(((PCONN_ENTRY)(g_puipConnTable[i]))->duUsage is DU_CALLIN) and
|
|
(((PCONN_ENTRY)(g_puipConnTable[i]))->byState is CS_CONNECTED))))
|
|
{
|
|
pConnEntry = (PCONN_ENTRY)(g_puipConnTable[i]);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
RtReleaseSpinLock(&g_rlConnTableLock,
|
|
kiIrql);
|
|
|
|
return pConnEntry;
|
|
}
|
|
|
|
ULONG
|
|
WanpRemoveAllConnections(
|
|
VOID
|
|
)
|
|
{
|
|
KIRQL kiIrql;
|
|
ULONG ulCount, i;
|
|
|
|
RtAcquireSpinLock(&g_rlConnTableLock,
|
|
&kiIrql);
|
|
|
|
//
|
|
// Slot 0 is never used
|
|
//
|
|
|
|
for(ulCount = 0, i = 1; i < g_ulConnTableSize; i++)
|
|
{
|
|
PCONN_ENTRY pConnEntry;
|
|
|
|
pConnEntry = (PCONN_ENTRY)(g_puipConnTable[i]);
|
|
|
|
if(pConnEntry is NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
g_rgulConns[pConnEntry->duUsage]--;
|
|
|
|
FreeConnection(pConnEntry);
|
|
|
|
ulCount++;
|
|
|
|
g_puipConnTable[i] = 0;
|
|
}
|
|
|
|
#if DBG
|
|
|
|
RtAssert((g_rgulConns[DU_CALLIN] + g_rgulConns[DU_CALLOUT] + g_rgulConns[DU_ROUTER]) is 0);
|
|
|
|
#endif
|
|
|
|
RtReleaseSpinLock(&g_rlConnTableLock,
|
|
kiIrql);
|
|
|
|
return ulCount;
|
|
}
|
|
|
|
BOOLEAN
|
|
WanpIsConnectionTableEmpty(
|
|
VOID
|
|
)
|
|
|
|
{
|
|
ULONG i;
|
|
KIRQL kiIrql;
|
|
|
|
RtAcquireSpinLock(&g_rlConnTableLock,
|
|
&kiIrql);
|
|
|
|
for(i = 1; i < g_ulConnTableSize; i++)
|
|
{
|
|
PCONN_ENTRY pConnEntry;
|
|
|
|
pConnEntry = (PCONN_ENTRY)(g_puipConnTable[i]);
|
|
|
|
if(pConnEntry isnot NULL)
|
|
{
|
|
RtAssert((g_rgulConns[DU_CALLIN] + g_rgulConns[DU_CALLOUT] + g_rgulConns[DU_ROUTER]) isnot 0);
|
|
|
|
RtReleaseSpinLock(&g_rlConnTableLock,
|
|
kiIrql);
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
RtAssert((g_rgulConns[DU_CALLIN] + g_rgulConns[DU_CALLOUT] + g_rgulConns[DU_ROUTER]) is 0);
|
|
|
|
|
|
RtReleaseSpinLock(&g_rlConnTableLock,
|
|
kiIrql);
|
|
|
|
return TRUE;
|
|
}
|
|
|