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.
2826 lines
69 KiB
2826 lines
69 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
net\routing\ip\rtrmgr\demand.c
|
|
|
|
Abstract:
|
|
|
|
Handles demand dial/connection events from WANARP driver.
|
|
|
|
Revision History:
|
|
|
|
Gurdeep Singh Pall 6/8/95 Created
|
|
|
|
--*/
|
|
|
|
#include "allinc.h"
|
|
|
|
DWORD
|
|
InitializeWanArp(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a handle to WANARP and posts an IRP for notification
|
|
Since the IRP is completed asynchrnously and uses DemandDialEvent for
|
|
notification, the event must have already been created
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR or some error code
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwResult;
|
|
ULONG ulSize, ulCount, i;
|
|
NTSTATUS Status;
|
|
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
PWANARP_QUEUE_INFO pQueueInfo;
|
|
|
|
TraceEnter("InitializeWanArp");
|
|
|
|
g_hWanarpRead = CreateFile(WANARP_DOS_NAME_T,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_OVERLAPPED,
|
|
NULL);
|
|
|
|
if(g_hWanarpRead is INVALID_HANDLE_VALUE)
|
|
{
|
|
g_hWanarpRead = NULL;
|
|
|
|
dwResult = GetLastError();
|
|
|
|
Trace1(ERR,
|
|
"InitializeWanArp: Could not open WANARP for read - %d",
|
|
dwResult);
|
|
|
|
TraceLeave("InitializeWanArp");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
g_hWanarpWrite = CreateFile(WANARP_DOS_NAME_T,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_OVERLAPPED,
|
|
NULL);
|
|
|
|
if(g_hWanarpWrite is INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(g_hWanarpRead);
|
|
|
|
g_hWanarpRead = NULL;
|
|
g_hWanarpWrite = NULL;
|
|
|
|
dwResult = GetLastError();
|
|
|
|
Trace1(ERR,
|
|
"InitializeWanArp: Could not open WANARP for write - %d",
|
|
dwResult);
|
|
|
|
TraceLeave("InitializeWanArp");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
//
|
|
// Get the number of call out interfaces and start queueing notifications
|
|
//
|
|
|
|
ulCount = 5;
|
|
i = 0;
|
|
|
|
while(i < 3)
|
|
{
|
|
ulSize = FIELD_OFFSET(WANARP_QUEUE_INFO, rgIfInfo) +
|
|
(ulCount * sizeof(WANARP_IF_INFO));
|
|
|
|
pQueueInfo = HeapAlloc(IPRouterHeap,
|
|
0,
|
|
ulSize);
|
|
|
|
if(pQueueInfo is NULL)
|
|
{
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
break;
|
|
}
|
|
|
|
pQueueInfo->fQueue = 1;
|
|
|
|
Status = NtDeviceIoControlFile(g_hWanarpWrite,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
IOCTL_WANARP_QUEUE,
|
|
pQueueInfo,
|
|
sizeof(WANARP_QUEUE_INFO),
|
|
pQueueInfo,
|
|
ulSize);
|
|
|
|
if(Status isnot STATUS_SUCCESS)
|
|
{
|
|
if(Status is STATUS_MORE_ENTRIES)
|
|
{
|
|
IpRtAssert(ulCount > pQueueInfo->ulNumCallout);
|
|
|
|
i++;
|
|
|
|
ulCount = pQueueInfo->ulNumCallout + (i * 5);
|
|
|
|
HeapFree(IPRouterHeap,
|
|
0,
|
|
pQueueInfo);
|
|
|
|
pQueueInfo = NULL;
|
|
|
|
//
|
|
// Go to the top of while()
|
|
//
|
|
|
|
continue;
|
|
|
|
}
|
|
else
|
|
{
|
|
HeapFree(IPRouterHeap,
|
|
0,
|
|
pQueueInfo);
|
|
|
|
pQueueInfo = NULL;
|
|
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(Status isnot STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// Close the device and return failure
|
|
//
|
|
|
|
CloseHandle(g_hWanarpRead);
|
|
CloseHandle(g_hWanarpWrite);
|
|
|
|
g_hWanarpRead = NULL;
|
|
g_hWanarpWrite = NULL;
|
|
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Create any dial out interfaces
|
|
//
|
|
|
|
for(i = 0; i < pQueueInfo->ulNumCallout; i++)
|
|
{
|
|
UNICODE_STRING usTempName;
|
|
PICB pIcb;
|
|
|
|
dwResult = RtlStringFromGUID(&(pQueueInfo->rgIfInfo[i].InterfaceGuid),
|
|
&usTempName);
|
|
|
|
if(dwResult isnot STATUS_SUCCESS)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// RtlString... returns a NULL terminated buffer
|
|
//
|
|
|
|
dwResult =
|
|
CreateDialOutInterface(usTempName.Buffer,
|
|
pQueueInfo->rgIfInfo[i].dwAdapterIndex,
|
|
pQueueInfo->rgIfInfo[i].dwLocalAddr,
|
|
pQueueInfo->rgIfInfo[i].dwLocalMask,
|
|
pQueueInfo->rgIfInfo[i].dwRemoteAddr,
|
|
&pIcb);
|
|
}
|
|
|
|
|
|
HeapFree(IPRouterHeap,
|
|
0,
|
|
pQueueInfo);
|
|
|
|
//
|
|
// Post an irp for demand dial notifications.
|
|
//
|
|
|
|
PostIoctlForDemandDialNotification() ;
|
|
|
|
TraceLeave("InitializeWanArp");
|
|
|
|
return NO_ERROR ;
|
|
}
|
|
|
|
VOID
|
|
CloseWanArp(
|
|
VOID
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
WANARP_QUEUE_INFO QueueInfo;
|
|
|
|
TraceEnter("CloseWanArp");
|
|
|
|
if(g_hWanarpRead)
|
|
{
|
|
CloseHandle(g_hWanarpRead);
|
|
|
|
g_hWanarpRead = NULL;
|
|
}
|
|
|
|
if(g_hWanarpWrite)
|
|
{
|
|
QueueInfo.fQueue = 0;
|
|
|
|
Status = NtDeviceIoControlFile(g_hWanarpWrite,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
IOCTL_WANARP_QUEUE,
|
|
&QueueInfo,
|
|
sizeof(WANARP_QUEUE_INFO),
|
|
&QueueInfo,
|
|
sizeof(WANARP_QUEUE_INFO));
|
|
|
|
if(Status isnot STATUS_SUCCESS)
|
|
{
|
|
}
|
|
|
|
CloseHandle(g_hWanarpWrite);
|
|
|
|
g_hWanarpWrite = NULL;
|
|
}
|
|
|
|
TraceLeave("CloseWanArp");
|
|
}
|
|
|
|
DWORD
|
|
HandleDemandDialEvent(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called by the main thread whenever a demand dial event is received
|
|
We mereley dispatch it to the right handler
|
|
|
|
Locks:
|
|
|
|
None
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
PICB picb;
|
|
DWORD dwResult;
|
|
DWORD Status, NumBytes;
|
|
BOOL bPost;
|
|
|
|
//
|
|
// drain all demand dial events queued up in WANARP
|
|
//
|
|
|
|
TraceEnter("HandleDemandDialEvent");
|
|
|
|
Status = GetOverlappedResult(g_hWanarpWrite, &WANARPOverlapped, &NumBytes, FALSE);
|
|
if (Status == FALSE || NumBytes<sizeof(WANARP_NOTIFICATION))
|
|
{
|
|
if (NumBytes < sizeof(WANARP_NOTIFICATION))
|
|
{
|
|
Trace1(ENTER, "HandleDemandDialEvent. Error. Returned IRP "
|
|
"small:%d", NumBytes);
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
Status = GetLastError();
|
|
|
|
if (Status == ERROR_OPERATION_ABORTED)
|
|
{
|
|
//
|
|
// cancel IO called for some reason. post another IRP.
|
|
//
|
|
PostIoctlForDemandDialNotification();
|
|
TraceLeave("HandleDemandDialEvent");
|
|
}
|
|
else if (Status == ERROR_FILE_NOT_FOUND)
|
|
{
|
|
//
|
|
// wanarp handle closed
|
|
//
|
|
TraceLeave("HandleDemandDialEvent. IRP cancelled. Wanarp device closed");
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// some other error. do not post any more IRPs
|
|
//
|
|
Trace1(ENTER, "Leaving HandleDemandDialEvent. Error in completed "
|
|
"IRP:%d", Status);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
bPost = TRUE;
|
|
|
|
//
|
|
// Since, potentially, this can cause stuff to be written in the ICB,
|
|
// we take lock as a WRITER
|
|
//
|
|
|
|
// *** Exclusion Begin ***
|
|
ENTER_WRITER(ICB_LIST);
|
|
|
|
EnterCriticalSection(&RouterStateLock);
|
|
|
|
if(RouterState.IRS_State isnot RTR_STATE_RUNNING)
|
|
{
|
|
if(wnWanarpMsg.ddeEvent isnot DDE_INTERFACE_DISCONNECTED)
|
|
{
|
|
Trace1(IF,
|
|
"ProcessDemandDialEvent: Shutting down. Ignoring event %d",
|
|
wnWanarpMsg.ddeEvent);
|
|
|
|
LeaveCriticalSection(&RouterStateLock);
|
|
|
|
return NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
bPost = FALSE;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&RouterStateLock);
|
|
|
|
picb = InterfaceLookupByICBSeqNumber( wnWanarpMsg.dwUserIfIndex );
|
|
|
|
if ((wnWanarpMsg.ddeEvent is DDE_CONNECT_INTERFACE) or
|
|
(wnWanarpMsg.ddeEvent is DDE_INTERFACE_CONNECTED) or
|
|
(wnWanarpMsg.ddeEvent is DDE_INTERFACE_DISCONNECTED))
|
|
{
|
|
IpRtAssert(picb);
|
|
|
|
if (picb isnot NULL)
|
|
{
|
|
switch(wnWanarpMsg.ddeEvent)
|
|
{
|
|
case DDE_CONNECT_INTERFACE:
|
|
{
|
|
HandleConnectionRequest(picb);
|
|
|
|
break ;
|
|
}
|
|
|
|
case DDE_INTERFACE_CONNECTED:
|
|
{
|
|
HandleConnectionNotification(picb);
|
|
|
|
break ;
|
|
}
|
|
|
|
case DDE_INTERFACE_DISCONNECTED:
|
|
{
|
|
HandleDisconnectionNotification(picb);
|
|
|
|
break ;
|
|
}
|
|
|
|
default:
|
|
{
|
|
Trace1(ERR,
|
|
"ProcessDemandDialEvent: Illegal event %d from WanArp",
|
|
wnWanarpMsg.ddeEvent);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
Trace2(
|
|
ANY, "Event %d, could not find interface with ICB %d",
|
|
wnWanarpMsg.ddeEvent, wnWanarpMsg.dwUserIfIndex
|
|
);
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
switch(wnWanarpMsg.ddeEvent)
|
|
{
|
|
case DDE_CALLOUT_LINKUP:
|
|
{
|
|
HandleDialOutLinkUp();
|
|
|
|
break ;
|
|
}
|
|
|
|
case DDE_CALLOUT_LINKDOWN:
|
|
{
|
|
HandleDialOutLinkDown();
|
|
|
|
break ;
|
|
}
|
|
|
|
default:
|
|
{
|
|
Trace1(ERR,
|
|
"ProcessDemandDialEvent: Illegal event %d from WanArp",
|
|
wnWanarpMsg.ddeEvent);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// *** Exclusion End ***
|
|
EXIT_LOCK(ICB_LIST);
|
|
|
|
if(bPost)
|
|
{
|
|
PostIoctlForDemandDialNotification();
|
|
}
|
|
|
|
TraceLeave("HandleDemandDialEvent");
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
VOID
|
|
HandleConnectionRequest(
|
|
PICB picb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called when we get a connection request from WANARP.
|
|
|
|
Locks:
|
|
|
|
ICB_LIST lock held as WRITER. This function releases the lock before
|
|
calling ConnectInterface() and takes the lock again.
|
|
|
|
Note: you need to get the picb entry again after acquiring the lock.
|
|
Remember to have the lock before you return from this function.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL bRet;
|
|
HANDLE hDim;
|
|
DWORD dwResult;
|
|
NTSTATUS nStatus;
|
|
DWORD dwPicbSeqNumber;
|
|
|
|
Trace2(IF,
|
|
"HandleConnectionRequest: Connection request for %S, %d",
|
|
picb->pwszName, picb->dwSeqNumber);
|
|
|
|
if(picb->dwOperationalState is CONNECTED)
|
|
{
|
|
//
|
|
// Really weird. Connection attempt for an i/f that
|
|
// WANARP knows is already connected
|
|
//
|
|
|
|
Trace2(IF,
|
|
"HandleConnectionRequest: Connection request for %S but %S is already UP",
|
|
picb->pwszName, picb->pwszName);
|
|
|
|
return;
|
|
}
|
|
|
|
bRet = FALSE;
|
|
|
|
do
|
|
{
|
|
dwResult = ProcessPacketFromWanArp(picb);
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
//
|
|
// Demand dial filter rules are to drop this packet
|
|
//
|
|
|
|
break;
|
|
}
|
|
|
|
if ((picb->dwAdminState is IF_ADMIN_STATUS_DOWN) or
|
|
(picb->dwOperationalState is UNREACHABLE))
|
|
{
|
|
Trace3(IF,
|
|
"HandleConnectionRequest: %S has admin state %d and operational state %d. Failing connection request",
|
|
picb->pwszName,
|
|
picb->dwAdminState,
|
|
picb->dwOperationalState);
|
|
|
|
break;
|
|
}
|
|
|
|
#if DBG
|
|
|
|
if(picb->dwOperationalState is CONNECTING)
|
|
{
|
|
Trace2(IF,
|
|
"HandleConnectionRequest: RACE CONDITION %S is connecting. Notifications %d",
|
|
picb->pwszName,
|
|
picb->fConnectionFlags);
|
|
}
|
|
|
|
#endif
|
|
|
|
Trace1(DEMAND, "Calling DIM to connect %S",
|
|
picb->pwszName);
|
|
|
|
//
|
|
// Call DIM to make the connection. Let go of the ICB lock
|
|
//
|
|
|
|
hDim = picb->hDIMHandle;
|
|
|
|
dwPicbSeqNumber = picb->dwSeqNumber;
|
|
|
|
EXIT_LOCK(ICB_LIST);
|
|
|
|
dwResult = (ConnectInterface)(hDim,
|
|
PID_IP);
|
|
|
|
ENTER_WRITER(ICB_LIST);
|
|
|
|
//
|
|
// get the picb again after reacquiring the lock.
|
|
// if Null break and return from this function
|
|
//
|
|
|
|
picb = InterfaceLookupByICBSeqNumber( dwPicbSeqNumber );
|
|
if (picb == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
if(dwResult is PENDING)
|
|
{
|
|
//
|
|
// We dont clear notification flags because there may be a
|
|
// race condition and we may have already gotten
|
|
// InterfaceConnected() from DIM
|
|
//
|
|
|
|
Trace1(DEMAND,
|
|
"HandleConnectionRequest: Conn attempt for %S pending",
|
|
picb->pwszName);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// So bRet is TRUE if DIM returned NO_ERROR or PENDING
|
|
//
|
|
|
|
bRet = TRUE;
|
|
|
|
}while(FALSE);
|
|
|
|
|
|
if (picb == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(!bRet)
|
|
{
|
|
nStatus = NotifyWanarpOfFailure(picb);
|
|
|
|
if((nStatus isnot STATUS_PENDING) and
|
|
(nStatus isnot STATUS_SUCCESS))
|
|
{
|
|
Trace2(ERR,
|
|
"HandleConnectionRequest: %X for connection failed for %S",
|
|
nStatus,
|
|
picb->pwszName);
|
|
}
|
|
|
|
//
|
|
// If it was connecting, then the stack has set the
|
|
// interface context to something other than 0xffffffff.
|
|
// Hence he wont dial out on that route We need to change
|
|
// the context in the stack back to invalid so that new
|
|
// packets cause the demand dial
|
|
//
|
|
|
|
ChangeAdapterIndexForDodRoutes(picb->dwIfIndex);
|
|
|
|
}
|
|
else
|
|
{
|
|
picb->dwOperationalState = CONNECTING;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
HandleConnectionNotification(
|
|
PICB picb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called when WANARP informs us that an interface is connected
|
|
|
|
Locks:
|
|
|
|
None
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
PADAPTER_INFO pBindNode;
|
|
|
|
//
|
|
// Plug in the Adapter info we get from the LINE_UP indication.
|
|
// There is only one address for a WAN interface
|
|
//
|
|
|
|
ENTER_WRITER(BINDING_LIST);
|
|
|
|
picb->bBound = TRUE;
|
|
picb->dwNumAddresses = wnWanarpMsg.dwLocalAddr?1:0;
|
|
|
|
IpRtAssert(picb->dwIfIndex is wnWanarpMsg.dwAdapterIndex);
|
|
|
|
if(picb->dwNumAddresses)
|
|
{
|
|
picb->pibBindings[0].dwAddress = wnWanarpMsg.dwLocalAddr;
|
|
picb->pibBindings[0].dwMask = wnWanarpMsg.dwLocalMask;
|
|
|
|
IpRtAssert(picb->pibBindings[0].dwMask is 0xFFFFFFFF);
|
|
}
|
|
else
|
|
{
|
|
picb->pibBindings[0].dwAddress = 0;
|
|
picb->pibBindings[0].dwMask = 0;
|
|
}
|
|
|
|
if(picb->ritType is ROUTER_IF_TYPE_FULL_ROUTER)
|
|
{
|
|
picb->dwRemoteAddress = wnWanarpMsg.dwRemoteAddr;
|
|
}
|
|
else
|
|
{
|
|
picb->dwRemoteAddress = 0;
|
|
}
|
|
|
|
Trace4(IF,
|
|
"HandleConnNotif: Connection notification for %S. Local %d.%d.%d.%d. Remote %d.%d.%d.%d",
|
|
picb->pwszName,
|
|
PRINT_IPADDR(picb->pibBindings[0].dwAddress),
|
|
PRINT_IPADDR(picb->dwRemoteAddress),
|
|
picb->dwSeqNumber);
|
|
|
|
//
|
|
// For wan interfaces we always have a binding struct in the hash
|
|
// table. So retrieve that
|
|
//
|
|
|
|
pBindNode = GetInterfaceBinding(picb->dwIfIndex);
|
|
|
|
if(!pBindNode)
|
|
{
|
|
Trace1(ERR,
|
|
"HandleConnNotif: Binding not found for %S",
|
|
picb->pwszName);
|
|
|
|
IpRtAssert(FALSE);
|
|
|
|
//
|
|
// Something really bad happened and we didnt have a
|
|
// bind block for the interface
|
|
//
|
|
|
|
AddBinding(picb);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Good a binding was found. Assert that it is ours
|
|
// and then update it
|
|
//
|
|
|
|
IpRtAssert(pBindNode->dwIfIndex is picb->dwIfIndex);
|
|
IpRtAssert(pBindNode->pInterfaceCB is picb);
|
|
|
|
pBindNode->bBound = TRUE;
|
|
pBindNode->dwNumAddresses = picb->dwNumAddresses;
|
|
pBindNode->dwRemoteAddress = picb->dwRemoteAddress ;
|
|
|
|
//
|
|
// struct copy out the address and mask
|
|
//
|
|
|
|
pBindNode->rgibBinding[0] = picb->pibBindings[0];
|
|
|
|
//
|
|
// We dont take the IP_ADDR_TABLE lock here because we have the
|
|
// ICB lock. During SNMP get we first take the addr lock then
|
|
// the icb lock. So we cant do the opposite here else we will
|
|
// deadlock. This may cause inconsistent information for one
|
|
// request, but we can live with that
|
|
//
|
|
|
|
g_LastUpdateTable[IPADDRCACHE] = 0;
|
|
|
|
}
|
|
|
|
EXIT_LOCK(BINDING_LIST);
|
|
|
|
if(picb->dwOperationalState is UNREACHABLE)
|
|
{
|
|
//
|
|
// going from unreachable to connecting
|
|
//
|
|
|
|
WanInterfaceDownToInactive(picb);
|
|
}
|
|
|
|
if(picb->dwOperationalState isnot CONNECTING)
|
|
{
|
|
//
|
|
// We can get a LinkUp without getting a ConnectionRequest
|
|
// This is the case when a user explicitly brings up a
|
|
// connection.
|
|
//
|
|
|
|
picb->dwOperationalState = CONNECTING;
|
|
}
|
|
|
|
SetNdiswanNotification(picb);
|
|
|
|
if(HaveAllNotificationsBeenReceived(picb))
|
|
{
|
|
picb->dwOperationalState = CONNECTED ;
|
|
|
|
WanInterfaceInactiveToUp(picb) ;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
HandleDisconnectionNotification(
|
|
PICB picb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handles a disconnection notification from WANARP
|
|
If the interface was connected, we make it inactive
|
|
We remove and bindings on the interface. This removal doesnt free the
|
|
bindings, only set the state to unbound
|
|
If the interface was marked for deletion, we go ahead and delete the
|
|
interface
|
|
|
|
Locks:
|
|
|
|
None
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
Trace2(IF,
|
|
"HandleDisconnectionNotif: Disconnection notification for %S %d",
|
|
picb->pwszName, picb->dwSeqNumber);
|
|
|
|
|
|
if(picb->dwOperationalState is CONNECTED)
|
|
{
|
|
//
|
|
// We would have called InactiveToUp
|
|
//
|
|
|
|
WanInterfaceUpToInactive(picb,
|
|
FALSE);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We have only set the addresses, clear those out
|
|
//
|
|
|
|
DeAllocateBindings(picb);
|
|
}
|
|
|
|
picb->dwOperationalState = DISCONNECTED ;
|
|
|
|
g_LastUpdateTable[IPADDRCACHE] = 0;
|
|
|
|
if(IsInterfaceMarkedForDeletion(picb))
|
|
{
|
|
RemoveInterfaceFromLists(picb);
|
|
|
|
DeleteSingleInterface(picb);
|
|
|
|
HeapFree(IPRouterHeap, 0, picb);
|
|
}
|
|
else
|
|
{
|
|
ClearNotificationFlags(picb);
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
HandleDialOutLinkUp(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handles the notification from wanarp that we have a new dial out interface
|
|
|
|
Locks:
|
|
|
|
ICB list lock as writer
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwResult;
|
|
PICB pNewIcb;
|
|
|
|
INTERFACE_ROUTE_INFO rifRoute;
|
|
|
|
Trace4(IF,
|
|
"DialOutLinkUp: Connection notification for 0x%x %d.%d.%d.%d/%d.%d.%d.%d %d.%d.%d.%d",
|
|
wnWanarpMsg.dwAdapterIndex,
|
|
PRINT_IPADDR(wnWanarpMsg.dwLocalAddr),
|
|
PRINT_IPADDR(wnWanarpMsg.dwLocalMask),
|
|
PRINT_IPADDR(wnWanarpMsg.dwRemoteAddr));
|
|
|
|
dwResult = CreateDialOutInterface(wnWanarpMsg.rgwcName,
|
|
wnWanarpMsg.dwAdapterIndex,
|
|
wnWanarpMsg.dwLocalAddr,
|
|
wnWanarpMsg.dwLocalMask,
|
|
wnWanarpMsg.dwRemoteAddr,
|
|
&pNewIcb);
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
return dwResult;
|
|
}
|
|
|
|
AddAutomaticRoutes(pNewIcb,
|
|
wnWanarpMsg.dwLocalAddr,
|
|
wnWanarpMsg.dwLocalMask);
|
|
|
|
#if 0
|
|
//
|
|
// Add the route to the server
|
|
//
|
|
|
|
if(pNewIcb->dwRemoteAddress isnot INVALID_IP_ADDRESS)
|
|
{
|
|
rifRoute.dwRtInfoMask = HOST_ROUTE_MASK;
|
|
rifRoute.dwRtInfoNextHop = pNewIcb->dwRemoteAddress;
|
|
rifRoute.dwRtInfoDest = pNewIcb->dwRemoteAddress;
|
|
rifRoute.dwRtInfoIfIndex = pNewIcb->dwIfIndex;
|
|
rifRoute.dwRtInfoMetric1 = 1;
|
|
rifRoute.dwRtInfoMetric2 = 0;
|
|
rifRoute.dwRtInfoMetric3 = 0;
|
|
rifRoute.dwRtInfoPreference =
|
|
ComputeRouteMetric(MIB_IPPROTO_NETMGMT);
|
|
rifRoute.dwRtInfoViewSet = RTM_VIEW_MASK_UCAST |
|
|
RTM_VIEW_MASK_MCAST; // XXX config
|
|
rifRoute.dwRtInfoType = MIB_IPROUTE_TYPE_DIRECT;
|
|
rifRoute.dwRtInfoProto = MIB_IPPROTO_NETMGMT;
|
|
rifRoute.dwRtInfoAge = 0;
|
|
rifRoute.dwRtInfoNextHopAS = 0;
|
|
rifRoute.dwRtInfoPolicy = 0;
|
|
|
|
dwResult = AddSingleRoute(pNewIcb->dwIfIndex,
|
|
&rifRoute,
|
|
pNewIcb->pibBindings[0].dwMask,
|
|
0, // RTM_ROUTE_INFO::Flags
|
|
TRUE, // Valid route
|
|
TRUE,
|
|
TRUE,
|
|
NULL);
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
Trace1(ERR,
|
|
"HandleDialOutLinkUp: Couldnt add server route for 0x%x",
|
|
pNewIcb->dwIfIndex);
|
|
}
|
|
}
|
|
|
|
if(wnWanarpMsg.fDefaultRoute)
|
|
{
|
|
INTERFACE_ROUTE_INFO rifRoute;
|
|
|
|
ChangeDefaultRouteMetrics(TRUE);
|
|
|
|
pNewIcb->bChangedMetrics = TRUE;
|
|
|
|
//
|
|
// Add route to def gateway
|
|
//
|
|
|
|
rifRoute.dwRtInfoDest = 0;
|
|
rifRoute.dwRtInfoMask = 0;
|
|
rifRoute.dwRtInfoNextHop = wnWanarpMsg.dwLocalAddr;
|
|
rifRoute.dwRtInfoIfIndex = wnWanarpMsg.dwAdapterIndex;
|
|
rifRoute.dwRtInfoMetric1 = 1;
|
|
rifRoute.dwRtInfoMetric2 = 0;
|
|
rifRoute.dwRtInfoMetric3 = 0;
|
|
rifRoute.dwRtInfoPreference =
|
|
ComputeRouteMetric(PROTO_IP_LOCAL);
|
|
rifRoute.dwRtInfoViewSet = RTM_VIEW_MASK_UCAST |
|
|
RTM_VIEW_MASK_MCAST; // XXX config
|
|
|
|
rifRoute.dwRtInfoType = MIB_IPROUTE_TYPE_DIRECT;
|
|
rifRoute.dwRtInfoProto = PROTO_IP_NETMGMT;
|
|
rifRoute.dwRtInfoAge = INFINITE;
|
|
rifRoute.dwRtInfoNextHopAS = 0;
|
|
rifRoute.dwRtInfoPolicy = 0;
|
|
|
|
dwResult = AddSingleRoute(wnWanarpMsg.dwAdapterIndex,
|
|
&rifRoute,
|
|
ALL_ONES_MASK,
|
|
0, // RTM_ROUTE_INFO::Flags
|
|
TRUE,
|
|
FALSE,
|
|
FALSE,
|
|
NULL);
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
Trace1(ERR,
|
|
"HandleDialOutLinkUp: Couldnt add default route for 0x%x",
|
|
wnWanarpMsg.dwAdapterIndex);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DWORD dwAddr, dwMask;
|
|
|
|
dwMask = GetClassMask(wnWanarpMsg.dwLocalAddr);
|
|
dwAddr = wnWanarpMsg.dwLocalAddr & dwMask;
|
|
|
|
//
|
|
// Add route to class subnet
|
|
//
|
|
|
|
rifRoute.dwRtInfoDest = dwAddr;
|
|
rifRoute.dwRtInfoMask = dwMask;
|
|
rifRoute.dwRtInfoNextHop = wnWanarpMsg.dwLocalAddr;
|
|
rifRoute.dwRtInfoIfIndex = wnWanarpMsg.dwAdapterIndex;
|
|
rifRoute.dwRtInfoMetric1 = 1;
|
|
rifRoute.dwRtInfoMetric2 = 0;
|
|
rifRoute.dwRtInfoMetric3 = 0;
|
|
rifRoute.dwRtInfoPreference = ComputeRouteMetric(PROTO_IP_LOCAL);
|
|
rifRoute.dwRtInfoViewSet = RTM_VIEW_MASK_UCAST |
|
|
RTM_VIEW_MASK_MCAST; // XXX config
|
|
rifRoute.dwRtInfoType = MIB_IPROUTE_TYPE_DIRECT;
|
|
rifRoute.dwRtInfoProto = PROTO_IP_LOCAL;
|
|
rifRoute.dwRtInfoAge = INFINITE;
|
|
rifRoute.dwRtInfoNextHopAS = 0;
|
|
rifRoute.dwRtInfoPolicy = 0;
|
|
|
|
dwResult = AddSingleRoute(wnWanarpMsg.dwAdapterIndex,
|
|
&rifRoute,
|
|
ALL_ONES_MASK,
|
|
0, // RTM_ROUTE_INFO::Flags
|
|
TRUE,
|
|
FALSE,
|
|
FALSE,
|
|
NULL);
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
Trace1(ERR,
|
|
"HandleDialOutLinkUp: Couldnt add subnet route for 0x%x",
|
|
wnWanarpMsg.dwAdapterIndex);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
DWORD
|
|
CreateDialOutInterface(
|
|
IN PWCHAR pwszIfName,
|
|
IN DWORD dwIfIndex,
|
|
IN DWORD dwLocalAddr,
|
|
IN DWORD dwLocalMask,
|
|
IN DWORD dwRemoteAddr,
|
|
OUT ICB **ppIcb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates an ICB for a dial out interface
|
|
We check to see that the interface doesnt already exist and if so, we
|
|
add the interface to our list using the index and name supplied by
|
|
wanarp.
|
|
|
|
Locks:
|
|
|
|
ICB list lock as writer
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR
|
|
|
|
--*/
|
|
|
|
{
|
|
PICB pNewIcb;
|
|
PADAPTER_INFO pBindNode;
|
|
PICB_BINDING pBinding;
|
|
|
|
#if DBG
|
|
|
|
pNewIcb = InterfaceLookupByIfIndex(dwIfIndex);
|
|
|
|
IpRtAssert(pNewIcb is NULL);
|
|
|
|
#endif // DBG
|
|
|
|
pNewIcb = CreateIcb(pwszIfName,
|
|
NULL,
|
|
ROUTER_IF_TYPE_DIALOUT,
|
|
IF_ADMIN_STATUS_UP,
|
|
dwIfIndex);
|
|
|
|
if(pNewIcb is NULL)
|
|
{
|
|
*ppIcb = NULL;
|
|
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
//
|
|
// Set up the bindings
|
|
//
|
|
|
|
pNewIcb->bBound = TRUE;
|
|
pNewIcb->dwNumAddresses = dwLocalAddr ? 1 : 0;
|
|
|
|
pNewIcb->dwRemoteAddress = dwRemoteAddr;
|
|
|
|
IpRtAssert(pNewIcb->dwIfIndex is dwIfIndex);
|
|
|
|
if(pNewIcb->dwNumAddresses)
|
|
{
|
|
pNewIcb->pibBindings[0].dwAddress = dwLocalAddr;
|
|
pNewIcb->pibBindings[0].dwMask = dwLocalMask;
|
|
}
|
|
else
|
|
{
|
|
pNewIcb->pibBindings[0].dwAddress = 0;
|
|
pNewIcb->pibBindings[0].dwMask = 0;
|
|
}
|
|
|
|
ENTER_WRITER(BINDING_LIST);
|
|
|
|
pBindNode = GetInterfaceBinding(pNewIcb->dwIfIndex);
|
|
|
|
if(pBindNode is NULL)
|
|
{
|
|
IpRtAssert(FALSE);
|
|
|
|
AddBinding(pNewIcb);
|
|
}
|
|
else
|
|
{
|
|
IpRtAssert(pBindNode->dwIfIndex is pNewIcb->dwIfIndex);
|
|
IpRtAssert(pBindNode->pInterfaceCB is pNewIcb);
|
|
|
|
pBindNode->bBound = TRUE;
|
|
pBindNode->dwNumAddresses = pNewIcb->dwNumAddresses;
|
|
pBindNode->dwRemoteAddress = pNewIcb->dwRemoteAddress;
|
|
|
|
//
|
|
// struct copy out the address and mask
|
|
//
|
|
|
|
pBindNode->rgibBinding[0] = pNewIcb->pibBindings[0];
|
|
}
|
|
|
|
EXIT_LOCK(BINDING_LIST);
|
|
|
|
//
|
|
// Insert pNewIcb in interface list and hash table
|
|
// This increments the interface count and sets the seq number
|
|
//
|
|
|
|
InsertInterfaceInLists(pNewIcb);
|
|
|
|
*ppIcb = pNewIcb;
|
|
|
|
//
|
|
// Update the address cache
|
|
//
|
|
|
|
g_LastUpdateTable[IPADDRCACHE] = 0;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
DWORD
|
|
HandleDialOutLinkDown(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handles the linkdown notification for a dial out interface.
|
|
|
|
Locks:
|
|
|
|
ICB list lock as writer
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR
|
|
|
|
--*/
|
|
|
|
{
|
|
PICB pIcb;
|
|
|
|
Trace1(IF,
|
|
"DialOutLinkDown: Disconnection notification for %d",
|
|
wnWanarpMsg.dwAdapterIndex);
|
|
|
|
pIcb = InterfaceLookupByIfIndex(wnWanarpMsg.dwAdapterIndex);
|
|
|
|
if(pIcb is NULL)
|
|
{
|
|
IpRtAssert(FALSE);
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
RemoveInterfaceFromLists(pIcb);
|
|
|
|
//
|
|
// This will delete the default route if there was one
|
|
//
|
|
|
|
DeleteSingleInterface(pIcb);
|
|
|
|
if(pIcb->bChangedMetrics)
|
|
{
|
|
ChangeDefaultRouteMetrics(FALSE);
|
|
}
|
|
|
|
HeapFree(IPRouterHeap,
|
|
0,
|
|
pIcb);
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
NTSTATUS
|
|
NotifyWanarpOfFailure(
|
|
PICB picb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sends an IOCTL_WANARP_CONNECT_FAILED to WANARP
|
|
|
|
Locks:
|
|
|
|
None
|
|
|
|
Arguments:
|
|
|
|
picb ICB of the interface on whom the connection failed
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
WANARP_CONNECT_FAILED_INFO ConnectInfo;
|
|
|
|
ConnectInfo.dwUserIfIndex = picb->dwSeqNumber;
|
|
|
|
Status = NtDeviceIoControlFile(g_hWanarpWrite,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
IOCTL_WANARP_CONNECT_FAILED,
|
|
&ConnectInfo,
|
|
sizeof(WANARP_CONNECT_FAILED_INFO),
|
|
NULL,
|
|
0);
|
|
|
|
IpRtAssert(Status isnot STATUS_PENDING);
|
|
|
|
return Status;
|
|
}
|
|
|
|
DWORD
|
|
ProcessPacketFromWanArp(
|
|
PICB picb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Filters the packet which is causing a demand dial connection. If the
|
|
packet is valid, logs the packet
|
|
|
|
Locks:
|
|
|
|
ICB_LIST held as READER
|
|
|
|
Arguments:
|
|
|
|
picb ICB of interface to dial
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR Dial out
|
|
ERROR_INVALID_DATA Dont dial out
|
|
|
|
--*/
|
|
|
|
{
|
|
CHAR pszSrc[20], pszDest[20], pszProto[5], pszLength[32];
|
|
CHAR pszName[MAX_INTERFACE_NAME_LEN + 1];
|
|
DWORD dwSize, dwResult;
|
|
BYTE rgbyPacket[sizeof(IP_HEADER) + MAX_PACKET_COPY_SIZE];
|
|
PBYTE pbyData;
|
|
|
|
PFFORWARD_ACTION faAction;
|
|
PIP_HEADER pHeader;
|
|
|
|
TraceEnter("ProcessPacketFromWanArp");
|
|
|
|
//
|
|
// Now create a packet
|
|
//
|
|
|
|
dwSize = min(wnWanarpMsg.ulPacketLength,
|
|
MAX_PACKET_COPY_SIZE);
|
|
|
|
if(picb->ihDemandFilterInterface isnot INVALID_HANDLE_VALUE)
|
|
{
|
|
IpRtAssert(picb->pDemandFilter);
|
|
|
|
//
|
|
// TCP/IP seems to not give us a packet sometimes
|
|
//
|
|
|
|
if(!dwSize)
|
|
{
|
|
Trace3(ERR,
|
|
"ProcPktFromWanarp: Packet from %d.%d.%d.%d to %d.%d.%d.%d protocol 0x%02x had 0 size!!",
|
|
PRINT_IPADDR(wnWanarpMsg.dwPacketSrcAddr),
|
|
PRINT_IPADDR(wnWanarpMsg.dwPacketDestAddr),
|
|
wnWanarpMsg.byPacketProtocol);
|
|
|
|
TraceLeave("ProcessPacketFromWanArp");
|
|
|
|
return ERROR_INVALID_DATA;
|
|
}
|
|
|
|
pHeader = (PIP_HEADER)rgbyPacket;
|
|
|
|
//
|
|
// Zero out the header
|
|
//
|
|
|
|
ZeroMemory(rgbyPacket,
|
|
sizeof(IP_HEADER));
|
|
|
|
//
|
|
// Set the header with the info we have
|
|
//
|
|
|
|
pHeader->byVerLen = 0x45;
|
|
pHeader->byProtocol = wnWanarpMsg.byPacketProtocol;
|
|
pHeader->dwSrc = wnWanarpMsg.dwPacketSrcAddr;
|
|
pHeader->dwDest = wnWanarpMsg.dwPacketDestAddr;
|
|
pHeader->wLength = htons((WORD)(dwSize + sizeof(IP_HEADER)));
|
|
|
|
//
|
|
// Copy out the data portion
|
|
//
|
|
|
|
pbyData = rgbyPacket + sizeof(IP_HEADER);
|
|
|
|
CopyMemory(pbyData,
|
|
wnWanarpMsg.rgbyPacket,
|
|
dwSize);
|
|
|
|
dwResult = PfTestPacket(picb->ihDemandFilterInterface,
|
|
NULL,
|
|
dwSize + sizeof(IP_HEADER),
|
|
rgbyPacket,
|
|
&faAction);
|
|
|
|
//
|
|
// If the call succeeded and the action was drop, no need to process
|
|
// futher
|
|
//
|
|
|
|
if(dwResult is NO_ERROR)
|
|
{
|
|
if(faAction is PF_ACTION_DROP)
|
|
{
|
|
Trace5(DEMAND,
|
|
"ProcPktFromWanarp: Result %d action %s for packet from %d.%d.%d.%d to %d.%d.%d.%d protocol 0x%02x",
|
|
dwResult, faAction == PF_ACTION_DROP? "Drop": "RtInfo",
|
|
PRINT_IPADDR(wnWanarpMsg.dwPacketSrcAddr),
|
|
PRINT_IPADDR(wnWanarpMsg.dwPacketDestAddr),
|
|
wnWanarpMsg.byPacketProtocol);
|
|
|
|
TraceLeave("ProcessPacketFromWanarp");
|
|
|
|
return ERROR_INVALID_DATA;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// In case of error we fall through and bring the link up
|
|
//
|
|
|
|
Trace4(DEMAND,
|
|
"ProcPktFromWanarp: Result %d for packet from %d.%d.%d.%d to %d.%d.%d.%d protocol 0x%02x",
|
|
dwResult,
|
|
PRINT_IPADDR(wnWanarpMsg.dwPacketSrcAddr),
|
|
PRINT_IPADDR(wnWanarpMsg.dwPacketDestAddr),
|
|
wnWanarpMsg.byPacketProtocol);
|
|
}
|
|
}
|
|
|
|
strcpy(pszSrc,
|
|
inet_ntoa(*((PIN_ADDR)(&(wnWanarpMsg.dwPacketSrcAddr)))));
|
|
|
|
strcpy(pszDest,
|
|
inet_ntoa(*((PIN_ADDR)(&(wnWanarpMsg.dwPacketDestAddr)))));
|
|
|
|
sprintf(pszProto,"%02x",wnWanarpMsg.byPacketProtocol);
|
|
|
|
WideCharToMultiByte(CP_ACP,
|
|
0,
|
|
picb->pwszName,
|
|
-1,
|
|
pszName,
|
|
MAX_INTERFACE_NAME_LEN,
|
|
NULL,
|
|
NULL);
|
|
|
|
pszName[MAX_INTERFACE_NAME_LEN] = '\0';
|
|
|
|
sprintf(pszLength,"%d",dwSize);
|
|
|
|
LogWarnData5(DEMAND_DIAL_PACKET,
|
|
pszSrc,
|
|
pszDest,
|
|
pszProto,
|
|
pszName,
|
|
pszLength,
|
|
dwSize,
|
|
wnWanarpMsg.rgbyPacket);
|
|
|
|
TraceLeave("ProcessPacketFromWanarp");
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
DWORD
|
|
PostIoctlForDemandDialNotification(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Posts a notification irp with WANARP.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD bytesrecvd ;
|
|
DWORD retcode = NO_ERROR;
|
|
|
|
TraceEnter("PostIoctlForDemandDialNotification");
|
|
|
|
ZeroMemory(&WANARPOverlapped,
|
|
sizeof (OVERLAPPED));
|
|
|
|
ZeroMemory(&wnWanarpMsg, sizeof(WANARP_NOTIFICATION));
|
|
|
|
WANARPOverlapped.hEvent = g_hDemandDialEvent ;
|
|
|
|
if (!DeviceIoControl(g_hWanarpWrite,
|
|
(DWORD) IOCTL_WANARP_NOTIFICATION,
|
|
&wnWanarpMsg,
|
|
sizeof(wnWanarpMsg),
|
|
&wnWanarpMsg,
|
|
sizeof(wnWanarpMsg),
|
|
(LPDWORD) &bytesrecvd,
|
|
&WANARPOverlapped))
|
|
{
|
|
retcode = GetLastError();
|
|
|
|
if(retcode isnot ERROR_IO_PENDING)
|
|
{
|
|
Trace1(ERR,
|
|
"PostIoctlForDemandDialNotification: Couldnt post irp with WANARP: %d\n",
|
|
retcode) ;
|
|
}
|
|
else
|
|
{
|
|
Trace0(IF, "PostIoctlForDemandDialNotification: Notification pending in WANARP");
|
|
|
|
}
|
|
}
|
|
|
|
TraceLeave("PostIoctlForDemandDialNotification");
|
|
|
|
return retcode ;
|
|
}
|
|
|
|
DWORD
|
|
AddInterfaceToWanArp(
|
|
PICB picb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds the given interface with WANARP
|
|
Has a side effect of getting an interface index
|
|
|
|
Arguments:
|
|
|
|
The ICB of the interface to add
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD out,dwResult;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
NTSTATUS nStatus;
|
|
PADAPTER_INFO pBindNode;
|
|
|
|
WANARP_ADD_INTERFACE_INFO info;
|
|
|
|
TraceEnter("AddInterfaceToWanArp");
|
|
|
|
Trace1(IF,
|
|
"AddInterfaceToWanArp: Adding %S to WanArp",
|
|
picb->pwszName);
|
|
|
|
info.dwUserIfIndex = picb->dwSeqNumber;
|
|
info.dwAdapterIndex = INVALID_IF_INDEX;
|
|
|
|
if(picb->ritType is ROUTER_IF_TYPE_INTERNAL)
|
|
{
|
|
info.bCallinInterface = TRUE;
|
|
|
|
}
|
|
else
|
|
{
|
|
info.bCallinInterface = FALSE;
|
|
}
|
|
|
|
nStatus = NtDeviceIoControlFile(g_hWanarpWrite,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
IOCTL_WANARP_ADD_INTERFACE,
|
|
&info,
|
|
sizeof(WANARP_ADD_INTERFACE_INFO),
|
|
&info,
|
|
sizeof(WANARP_ADD_INTERFACE_INFO));
|
|
|
|
if(nStatus isnot STATUS_SUCCESS)
|
|
{
|
|
Trace2(ERR,
|
|
"AddInterfaceToWANARP: Status %x adding %S to WanArp",
|
|
nStatus,
|
|
picb->pwszName);
|
|
|
|
return RtlNtStatusToDosError(nStatus);
|
|
}
|
|
|
|
IpRtAssert(info.dwAdapterIndex isnot 0);
|
|
IpRtAssert(info.dwAdapterIndex isnot INVALID_IF_INDEX);
|
|
|
|
picb->dwIfIndex = info.dwAdapterIndex;
|
|
|
|
//
|
|
// If this was the internal interface allocate memory and copy out
|
|
// the name
|
|
//
|
|
|
|
if(picb->ritType is ROUTER_IF_TYPE_INTERNAL)
|
|
{
|
|
info.rgwcDeviceName[WANARP_MAX_DEVICE_NAME_LEN] = UNICODE_NULL;
|
|
|
|
picb->pwszDeviceName =
|
|
HeapAlloc(IPRouterHeap,
|
|
HEAP_ZERO_MEMORY,
|
|
(wcslen(info.rgwcDeviceName) + 1) * sizeof(WCHAR));
|
|
|
|
|
|
if(picb->pwszDeviceName is NULL)
|
|
{
|
|
Trace2(ERR,
|
|
"AddInterfaceToWANARP: Unable to allocate %d bytes when adding %S to wanarp",
|
|
(wcslen(info.rgwcDeviceName) + 1) * sizeof(WCHAR),
|
|
picb->pwszName);
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
wcscpy(picb->pwszDeviceName,
|
|
info.rgwcDeviceName);
|
|
|
|
|
|
Trace2(DEMAND,
|
|
"AddInterfaceToWANARP: %S device name %S\n",
|
|
picb->pwszName,
|
|
picb->pwszDeviceName);
|
|
|
|
g_pInternalInterfaceCb = picb;
|
|
|
|
}
|
|
|
|
|
|
TraceLeave("AddInterfaceToWANARP");
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
DWORD
|
|
DeleteInterfaceWithWanArp(
|
|
PICB picb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deletes the given interface with WANARP
|
|
|
|
Arguments:
|
|
|
|
The ICB of the interface to delete
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD out,dwResult;
|
|
OVERLAPPED overlapped ;
|
|
|
|
WANARP_DELETE_INTERFACE_INFO DeleteInfo;
|
|
|
|
TraceEnter("DeleteInterfaceWithWANARP");
|
|
|
|
DeleteInfo.dwUserIfIndex = picb->dwSeqNumber;
|
|
|
|
memset (&overlapped, 0, sizeof(OVERLAPPED)) ;
|
|
|
|
if (!DeviceIoControl (g_hWanarpWrite,
|
|
IOCTL_WANARP_DELETE_INTERFACE,
|
|
&DeleteInfo,
|
|
sizeof(WANARP_DELETE_INTERFACE_INFO),
|
|
NULL,
|
|
0,
|
|
&out,
|
|
&overlapped))
|
|
{
|
|
dwResult = GetLastError();
|
|
|
|
Trace2(ERR,
|
|
"DeleteInterfaceWithWANARP: Error %d deleting %S",
|
|
dwResult,
|
|
picb->pwszName);
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
TraceLeave("DeleteInterfaceWithWANARP");
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
#ifdef KSL_IPINIP
|
|
|
|
DWORD
|
|
CreateInternalInterfaceIcb(
|
|
PWCHAR pwszName,
|
|
ICB **ppicb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine parses the TCPIP Parameters\Interfaces key to figure out
|
|
the name of the Internal Interface (ServerAdapter). The internal interface
|
|
has the substring "IPIN"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR
|
|
|
|
--*/
|
|
|
|
{
|
|
HKEY hIfKey;
|
|
DWORD i, dwResult, dwSize, dwNumEntries, dwMaxKeyLen;
|
|
BOOL bFoundAdapter;
|
|
CHAR *pbyKeyName, pszServerAdapter[256];
|
|
PICB pInterfaceCb;
|
|
|
|
TraceEnter("CreateInternalInterfaceIcb");
|
|
|
|
*ppicb = NULL;
|
|
|
|
dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
REG_KEY_TCPIP_INTERFACES,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hIfKey);
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
Trace2(ERR,
|
|
"CreateInternalIcb: Error %d opening %s\n",
|
|
dwResult,
|
|
REG_KEY_TCPIP_INTERFACES);
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
dwResult = RegQueryInfoKey(hIfKey,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&dwNumEntries,
|
|
&dwMaxKeyLen,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
Trace1(ERR,
|
|
"CreateIpIpInterface: Error %d querying key",
|
|
dwResult);
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
//
|
|
// Have to have some interfaces
|
|
//
|
|
|
|
IpRtAssert(dwNumEntries isnot 0)
|
|
|
|
//
|
|
// Allocate enough memory for max key len
|
|
//
|
|
|
|
dwSize = (dwMaxKeyLen + 4) * sizeof(CHAR);
|
|
|
|
pbyKeyName = HeapAlloc(IPRouterHeap,
|
|
HEAP_ZERO_MEMORY,
|
|
dwSize);
|
|
|
|
|
|
if(pbyKeyName is NULL)
|
|
{
|
|
Trace1(ERR,
|
|
"CreateIpIpInterface: Error allocating %d bytes",
|
|
dwSize);
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
for(i = 0; ; i++)
|
|
{
|
|
DWORD dwKeyLen;
|
|
FILETIME ftLastTime;
|
|
|
|
|
|
dwKeyLen = dwMaxKeyLen;
|
|
|
|
dwResult = RegEnumKeyExA(hIfKey,
|
|
i,
|
|
pbyKeyName,
|
|
&dwKeyLen,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&ftLastTime);
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
if(dwResult is ERROR_NO_MORE_ITEMS)
|
|
{
|
|
//
|
|
// Done
|
|
//
|
|
|
|
break;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// See if this is the server adapter. That is known by the fact that it contains
|
|
// IPIN as a substring
|
|
//
|
|
|
|
//
|
|
// Upcase the string
|
|
//
|
|
|
|
_strupr(pbyKeyName);
|
|
|
|
if(strstr(pbyKeyName,SERVER_ADAPTER_SUBSTRING) is NULL)
|
|
{
|
|
//
|
|
// This is not the server adapter
|
|
//
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Well we have a server adapter
|
|
//
|
|
|
|
ZeroMemory(pszServerAdapter,256);
|
|
|
|
strcpy(pszServerAdapter,"\\DEVICE\\");
|
|
|
|
strcat(pszServerAdapter,pbyKeyName);
|
|
|
|
Trace1(IF,
|
|
"InitInternalInterface: Using %s as the dial in adapter",
|
|
pszServerAdapter);
|
|
|
|
bFoundAdapter = TRUE;
|
|
|
|
break;
|
|
}
|
|
|
|
HeapFree(IPRouterHeap,
|
|
0,
|
|
pbyKeyName);
|
|
|
|
RegCloseKey(hIfKey);
|
|
|
|
if(!bFoundAdapter)
|
|
{
|
|
return ERROR_NOT_FOUND;
|
|
}
|
|
else
|
|
{
|
|
WCHAR pwszTempName[256];
|
|
DWORD dwICBSize, dwNameLen;
|
|
UNICODE_STRING usTempString,usIcbName;
|
|
|
|
usTempString.MaximumLength = 256 * sizeof(WCHAR);
|
|
usTempString.Buffer = pwszTempName;
|
|
usIcbName.MaximumLength = 256 * sizeof(WCHAR);
|
|
|
|
//
|
|
// Only copy out the name and not the \Device\ part
|
|
//
|
|
|
|
MultiByteToWideChar(CP_ACP,
|
|
0,
|
|
pszServerAdapter + strlen(ADAPTER_PREFIX_STRING),
|
|
-1,
|
|
pwszTempName,
|
|
256);
|
|
|
|
//
|
|
// Add a WCHAR each for UNICODE_NULL for name and device name
|
|
// Add 2 bytes for alignment issues
|
|
//
|
|
|
|
dwNameLen =
|
|
(sizeof(WCHAR) * (wcslen(pwszName) + wcslen(pwszTempName) + 2)) + 2;
|
|
|
|
dwICBSize = sizeof(ICB) + dwNameLen;
|
|
|
|
pInterfaceCb = (PICB)HeapAlloc(IPRouterHeap,
|
|
HEAP_ZERO_MEMORY,
|
|
dwICBSize);
|
|
|
|
if(pInterfaceCb is NULL)
|
|
{
|
|
Trace1(ERR,
|
|
"InitInternalInterface: Error allocating %d bytes for ICB",
|
|
dwICBSize);
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Save the DIM name in the pwszName field
|
|
//
|
|
|
|
pInterfaceCb->pwszName = (PWCHAR) ((PBYTE)pInterfaceCb + sizeof(ICB));
|
|
|
|
//
|
|
// Word align the pointer
|
|
//
|
|
|
|
pInterfaceCb->pwszName =
|
|
(PWCHAR)(((UINT_PTR)pInterfaceCb->pwszName + 1) & ~0x1);
|
|
|
|
CopyMemory(pInterfaceCb->pwszName,
|
|
pwszName,
|
|
wcslen(pwszName) * sizeof(WCHAR));
|
|
|
|
//
|
|
// 1 WCHAR for UNICODE_NULL and 1 byte for alignment
|
|
//
|
|
|
|
pInterfaceCb->pwszDeviceName =
|
|
(PWCHAR)((PBYTE)pInterfaceCb->pwszName +
|
|
((wcslen(pwszName) + 1) * sizeof(WCHAR)) + 1);
|
|
|
|
//
|
|
// And align this, too
|
|
//
|
|
|
|
pInterfaceCb->pwszDeviceName =
|
|
(PWCHAR)(((UINT_PTR)pInterfaceCb->pwszDeviceName + 1) & ~0x1);
|
|
|
|
|
|
usTempString.Length = sizeof(WCHAR) * wcslen(pwszTempName);
|
|
usIcbName.Buffer = pInterfaceCb->pwszDeviceName;
|
|
|
|
RtlUpcaseUnicodeString(&usIcbName,
|
|
&usTempString,
|
|
FALSE);
|
|
|
|
pInterfaceCb->pwszDeviceName[wcslen(pwszTempName)] = UNICODE_NULL;
|
|
|
|
*ppicb = pInterfaceCb;
|
|
}
|
|
|
|
TraceLeave("CreateInternalInterfaceIcb");
|
|
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
#endif //KSL_IPINIP
|
|
|
|
DWORD
|
|
AccessIfEntryWanArp(
|
|
IN DWORD dwAction,
|
|
IN PICB picb,
|
|
IN OUT PMIB_IFROW lpOutBuf
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Gets or sets the statistics from the wanarp
|
|
|
|
Arguments:
|
|
|
|
dwAction Can be SET_IF or GET_IF
|
|
picb the Interface Control Block
|
|
pOutBuf
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR or some error code
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
WANARP_GET_IF_STATS_INFO GetStatsInfo;
|
|
|
|
|
|
TraceEnter("AccessIfEntryWanArp");
|
|
|
|
GetStatsInfo.dwUserIfIndex = picb->dwSeqNumber;
|
|
|
|
if(dwAction is ACCESS_GET)
|
|
{
|
|
Status = NtDeviceIoControlFile(g_hWanarpRead,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
IOCTL_WANARP_GET_IF_STATS,
|
|
&GetStatsInfo,
|
|
sizeof(WANARP_GET_IF_STATS_INFO),
|
|
&GetStatsInfo,
|
|
sizeof(WANARP_GET_IF_STATS_INFO));
|
|
|
|
RtlCopyMemory(&(lpOutBuf->dwIndex),
|
|
&(GetStatsInfo.ifeInfo),
|
|
sizeof(IFEntry));
|
|
|
|
}
|
|
else
|
|
{
|
|
// To be implemented: return SUCCESS for now
|
|
}
|
|
|
|
if(Status isnot STATUS_SUCCESS)
|
|
{
|
|
IpRtAssert(Status isnot STATUS_PENDING);
|
|
|
|
Trace2(ERR,
|
|
"AccessIfEntryWanArp: NtStatus %x when getting information for %S",
|
|
Status,
|
|
picb->pwszName);
|
|
|
|
TraceLeave("AccessIfEntryWanArp");
|
|
|
|
return Status;
|
|
}
|
|
|
|
TraceLeave("AccessIfEntryWanArp");
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
DWORD
|
|
DeleteInternalInterface(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deletes the ServerAdapter (internal) interface
|
|
|
|
Locks:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
if(g_pInternalInterfaceCb is NULL)
|
|
{
|
|
return NO_ERROR;
|
|
}
|
|
|
|
if(g_pInternalInterfaceCb->pwszDeviceName isnot NULL)
|
|
{
|
|
HeapFree(IPRouterHeap,
|
|
0,
|
|
g_pInternalInterfaceCb->pwszDeviceName);
|
|
|
|
g_pInternalInterfaceCb->pwszDeviceName = NULL;
|
|
}
|
|
|
|
//
|
|
// Call DeleteSingleInterface to do the same thing as is done
|
|
// for LAN interfaces
|
|
//
|
|
|
|
DeleteSingleInterface(g_pInternalInterfaceCb);
|
|
|
|
RemoveInterfaceLookup(g_pInternalInterfaceCb);
|
|
|
|
HeapFree(IPRouterHeap,
|
|
0,
|
|
g_pInternalInterfaceCb);
|
|
|
|
|
|
g_pInternalInterfaceCb = NULL;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
DWORD
|
|
AddDemandFilterInterface(
|
|
PICB picb,
|
|
PRTR_INFO_BLOCK_HEADER pInterfaceInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds an interface to the filter driver. This interface is never bound to
|
|
an IP interface, instead we add demand dial filters to it and when a
|
|
request is made to dial out, we match the packet causing the dialling
|
|
against the filters (using the TestPacket() function) and use the returned
|
|
action to determine whether we should dial out or not.
|
|
|
|
If there are no filters, the interface is not added to the driver.
|
|
Otherwise, a copy of the filters is kept with the picb, and a transformed
|
|
set of filters is added to the driver
|
|
The handle associated with the interface and the driver is kept in the
|
|
picb
|
|
|
|
Arguments:
|
|
|
|
picb
|
|
pInterfaceInfo
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwResult;
|
|
PPF_FILTER_DESCRIPTOR pfdFilters;
|
|
PFFORWARD_ACTION faAction;
|
|
PRTR_TOC_ENTRY pToc;
|
|
PFILTER_DESCRIPTOR pInfo;
|
|
ULONG i, j, ulSize, ulNumFilters;
|
|
|
|
TraceEnter("AddDemandFilterInterface");
|
|
|
|
IpRtAssert((picb->ritType is ROUTER_IF_TYPE_HOME_ROUTER) or
|
|
(picb->ritType is ROUTER_IF_TYPE_FULL_ROUTER));
|
|
|
|
IpRtAssert(picb->pDemandFilter is NULL);
|
|
|
|
picb->ihDemandFilterInterface = INVALID_HANDLE_VALUE;
|
|
|
|
pToc = GetPointerToTocEntry(IP_DEMAND_DIAL_FILTER_INFO,
|
|
pInterfaceInfo);
|
|
|
|
//
|
|
// We dont add if there is no INFO, or if the info size is 0 or
|
|
// if the number of filters is 0 AND the default action is DROP
|
|
//
|
|
|
|
if((pToc is NULL) or (pToc->InfoSize is 0))
|
|
{
|
|
//
|
|
// Either there is no filter info (TOC is NULL) or the user
|
|
// wanted the filters deleted (which they have been)
|
|
//
|
|
|
|
Trace1(IF,
|
|
"AddDemandFilterInterface: filter info NULL or info size 0 for %S, so leaving",
|
|
picb->pwszName);
|
|
|
|
TraceLeave("AddDemandFilterInterface");
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
pInfo = GetInfoFromTocEntry(pInterfaceInfo,
|
|
pToc);
|
|
|
|
if(pInfo is NULL)
|
|
{
|
|
Trace1(IF,
|
|
"AddDemandFilterInterface: filter info NULL for %S, so leaving",
|
|
picb->pwszName);
|
|
|
|
TraceLeave("AddDemandFilterInterface");
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
//
|
|
// See how many filters we have
|
|
//
|
|
|
|
pfdFilters = NULL;
|
|
|
|
ulNumFilters = pInfo->dwNumFilters;
|
|
|
|
if((ulNumFilters is 0) and
|
|
(pInfo->faDefaultAction is PF_ACTION_FORWARD))
|
|
{
|
|
Trace1(IF,
|
|
"AddDemandFilterInterface: 0 filters and default of FORWARD for %S, so leaving",
|
|
picb->pwszName);
|
|
|
|
TraceLeave("AddDemandFilterInterface");
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// The size we need for these many filters
|
|
//
|
|
|
|
ulSize = FIELD_OFFSET(FILTER_DESCRIPTOR,fiFilter[0]) +
|
|
(ulNumFilters * sizeof(FILTER_INFO));
|
|
|
|
//
|
|
// The infosize must be atleast as large as the filters
|
|
//
|
|
|
|
IpRtAssert(ulSize <= pToc->InfoSize);
|
|
|
|
//
|
|
// Copy out the info for ourselves
|
|
//
|
|
|
|
picb->pDemandFilter = HeapAlloc(IPRouterHeap,
|
|
0,
|
|
ulSize);
|
|
|
|
if(picb->pDemandFilter is NULL)
|
|
{
|
|
Trace1(ERR,
|
|
"AddDemandFilterInterface: Error allocating %d bytes for demand dial filters",
|
|
ulSize);
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
CopyMemory(picb->pDemandFilter,
|
|
pInfo,
|
|
ulSize);
|
|
|
|
faAction = pInfo->faDefaultAction;
|
|
|
|
if(ulNumFilters isnot 0)
|
|
{
|
|
PDWORD pdwAddr;
|
|
|
|
//
|
|
// We have filters, so copy them to the new format
|
|
// The address and mask will come at the end of all of the filters
|
|
// so we allocate 16 bytes extra for each filter. Then we add a
|
|
// 8 bytes so that we can align the block
|
|
//
|
|
|
|
|
|
ulSize = ulNumFilters * (sizeof(PF_FILTER_DESCRIPTOR) + 16) + 8;
|
|
|
|
|
|
pfdFilters = HeapAlloc(IPRouterHeap,
|
|
0,
|
|
ulSize);
|
|
|
|
if(pfdFilters is NULL)
|
|
{
|
|
HeapFree(IPRouterHeap,
|
|
0,
|
|
picb->pDemandFilter);
|
|
|
|
Trace1(ERR,
|
|
"AddDemandFilterInterface: Error allocating %d bytes",
|
|
ulSize);
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Pointer to the start of the address block
|
|
//
|
|
|
|
pdwAddr = (PDWORD)&(pfdFilters[ulNumFilters]);
|
|
|
|
//
|
|
// Now convert the filters
|
|
//
|
|
|
|
for(i = 0, j = 0; i < ulNumFilters; i++)
|
|
{
|
|
pfdFilters[i].dwFilterFlags = 0;
|
|
pfdFilters[i].dwRule = 0;
|
|
pfdFilters[i].pfatType = PF_IPV4;
|
|
|
|
//
|
|
// Set the pointers
|
|
//
|
|
|
|
pfdFilters[i].SrcAddr = (PBYTE)&(pdwAddr[j++]);
|
|
pfdFilters[i].SrcMask = (PBYTE)&(pdwAddr[j++]);
|
|
pfdFilters[i].DstAddr = (PBYTE)&(pdwAddr[j++]);
|
|
pfdFilters[i].DstMask = (PBYTE)&(pdwAddr[j++]);
|
|
|
|
//
|
|
// Copy in the src/dst addr/masks
|
|
//
|
|
|
|
*(PDWORD)pfdFilters[i].SrcAddr = pInfo->fiFilter[i].dwSrcAddr;
|
|
*(PDWORD)pfdFilters[i].SrcMask = pInfo->fiFilter[i].dwSrcMask;
|
|
*(PDWORD)pfdFilters[i].DstAddr = pInfo->fiFilter[i].dwDstAddr;
|
|
*(PDWORD)pfdFilters[i].DstMask = pInfo->fiFilter[i].dwDstMask;
|
|
|
|
//
|
|
// Copy the protocol
|
|
//
|
|
|
|
pfdFilters[i].dwProtocol = pInfo->fiFilter[i].dwProtocol;
|
|
|
|
//
|
|
// Late bound makes no sense for this
|
|
//
|
|
|
|
pfdFilters[i].fLateBound = 0;
|
|
|
|
//
|
|
// The ports
|
|
//
|
|
|
|
pfdFilters[i].wSrcPort = pInfo->fiFilter[i].wSrcPort;
|
|
pfdFilters[i].wDstPort = pInfo->fiFilter[i].wDstPort;
|
|
|
|
//
|
|
// Since we dont support ranges, set to 0
|
|
//
|
|
|
|
pfdFilters[i].wSrcPortHighRange = 0;
|
|
pfdFilters[i].wDstPortHighRange = 0;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Now add create the interace and set the info
|
|
//
|
|
|
|
dwResult = PfCreateInterface(0,
|
|
faAction,
|
|
PF_ACTION_FORWARD,
|
|
FALSE,
|
|
FALSE,
|
|
&(picb->ihDemandFilterInterface));
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
Trace2(ERR,
|
|
"AddDemandFilterInterface: Err %d creating filter i/f for %S",
|
|
dwResult,
|
|
picb->pwszName);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Set the filters
|
|
//
|
|
|
|
if(ulNumFilters isnot 0)
|
|
{
|
|
dwResult = PfAddFiltersToInterface(picb->ihDemandFilterInterface,
|
|
ulNumFilters,
|
|
pfdFilters,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
Trace2(ERR,
|
|
"AddDemandFilterInterface: Err %d setting filters on %S",
|
|
dwResult,
|
|
picb->pwszName);
|
|
|
|
PfDeleteInterface(picb->ihDemandFilterInterface);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(pfdFilters)
|
|
{
|
|
HeapFree(IPRouterHeap,
|
|
0,
|
|
pfdFilters);
|
|
}
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
//
|
|
// Something bad happened. Set the handles to invalid so that
|
|
// we know we did not add the filters
|
|
//
|
|
|
|
picb->ihDemandFilterInterface = INVALID_HANDLE_VALUE;
|
|
|
|
if(picb->pDemandFilter)
|
|
{
|
|
HeapFree(IPRouterHeap,
|
|
0,
|
|
picb->pDemandFilter);
|
|
|
|
picb->pDemandFilter = NULL;
|
|
}
|
|
}
|
|
|
|
TraceLeave("SetInterfaceFilterInfo");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
|
|
DWORD
|
|
DeleteDemandFilterInterface(
|
|
PICB picb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function deletes a filter interface (and all associated filters)
|
|
Also frees the memory holding the filters
|
|
|
|
Locks:
|
|
|
|
ICB_LIST held as WRITER
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
TraceEnter("DeleteDemandFilterInterface");
|
|
|
|
IpRtAssert((picb->ritType is ROUTER_IF_TYPE_HOME_ROUTER) or
|
|
(picb->ritType is ROUTER_IF_TYPE_FULL_ROUTER));
|
|
|
|
if(picb->pDemandFilter isnot NULL)
|
|
{
|
|
HeapFree(IPRouterHeap,
|
|
0,
|
|
picb->pDemandFilter);
|
|
|
|
picb->pDemandFilter = NULL;
|
|
}
|
|
|
|
if(picb->ihDemandFilterInterface is INVALID_HANDLE_VALUE)
|
|
{
|
|
Trace1(IF,
|
|
"DeleteDemandFilterInterface: No context, assuming interface %S not added to filter driver",
|
|
picb->pwszName);
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
PfDeleteInterface(picb->ihDemandFilterInterface);
|
|
|
|
picb->ihDemandFilterInterface = INVALID_HANDLE_VALUE;
|
|
|
|
TraceLeave("DeleteDemandFilterInterface");
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
DWORD
|
|
SetDemandDialFilters(
|
|
PICB picb,
|
|
PRTR_INFO_BLOCK_HEADER pInterfaceInfo
|
|
)
|
|
{
|
|
DWORD dwResult;
|
|
PRTR_TOC_ENTRY pToc;
|
|
|
|
if((picb->ritType isnot ROUTER_IF_TYPE_HOME_ROUTER) and
|
|
(picb->ritType isnot ROUTER_IF_TYPE_FULL_ROUTER))
|
|
{
|
|
return NO_ERROR;
|
|
}
|
|
|
|
TraceEnter("SetDemandDialFilters");
|
|
|
|
pToc = GetPointerToTocEntry(IP_DEMAND_DIAL_FILTER_INFO,
|
|
pInterfaceInfo);
|
|
|
|
if(pToc is NULL)
|
|
{
|
|
//
|
|
// Both NULL, means we dont need to change anything
|
|
//
|
|
|
|
Trace1(DEMAND,
|
|
"SetDemandDialFilters: No filters for %S, so leaving",
|
|
picb->pwszName);
|
|
|
|
TraceLeave("SetDemandDialFilters");
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
if(picb->ihDemandFilterInterface isnot INVALID_HANDLE_VALUE)
|
|
{
|
|
//
|
|
// This interface was added to the filter driver,
|
|
// Delete it so that the filters are all deleted and then readd
|
|
// the filters
|
|
//
|
|
|
|
IpRtAssert(picb->pDemandFilter isnot NULL);
|
|
|
|
dwResult = DeleteDemandFilterInterface(picb);
|
|
|
|
//
|
|
// This better succeed, we dont have a failure path here
|
|
//
|
|
|
|
IpRtAssert(dwResult is NO_ERROR);
|
|
|
|
}
|
|
|
|
dwResult = AddDemandFilterInterface(picb,
|
|
pInterfaceInfo);
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
CHAR Name[MAX_INTERFACE_NAME_LEN + 1];
|
|
PCHAR pszName;
|
|
|
|
pszName = Name;
|
|
|
|
WideCharToMultiByte(CP_ACP,
|
|
0,
|
|
picb->pwszName,
|
|
-1,
|
|
pszName,
|
|
MAX_INTERFACE_NAME_LEN,
|
|
NULL,
|
|
NULL);
|
|
|
|
LogErr1(CANT_ADD_DD_FILTERS,
|
|
pszName,
|
|
dwResult);
|
|
}
|
|
|
|
TraceLeave("SetDemandDialFilters");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
DWORD
|
|
GetDemandFilters(
|
|
PICB picb,
|
|
PRTR_TOC_ENTRY pToc,
|
|
PBYTE pbDataPtr,
|
|
PRTR_INFO_BLOCK_HEADER pInfoHdrAndBuffer,
|
|
PDWORD pdwSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function copies out the demand dial filters and set the TOC
|
|
|
|
Locks:
|
|
|
|
ICB_LIST lock held as READER
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwInBufLen,i;
|
|
PFILTER_DESCRIPTOR pFilterDesc;
|
|
|
|
TraceEnter("GetDemandFilters");
|
|
|
|
IpRtAssert((picb->ritType is ROUTER_IF_TYPE_HOME_ROUTER) or
|
|
(picb->ritType is ROUTER_IF_TYPE_FULL_ROUTER));
|
|
|
|
//
|
|
// Set size returned to 0
|
|
//
|
|
|
|
*pdwSize = 0;
|
|
|
|
//
|
|
// Safe init of both the TOCs.
|
|
//
|
|
|
|
//pToc[0].InfoVersion = IP_DEMAND_DIAL_FILTER_INFO;
|
|
pToc[0].InfoType = IP_DEMAND_DIAL_FILTER_INFO;
|
|
pToc[0].Count = 0;
|
|
pToc[0].InfoSize = 0;
|
|
|
|
if((picb->ihDemandFilterInterface is INVALID_HANDLE_VALUE) or
|
|
(picb->pDemandFilter is NULL))
|
|
{
|
|
Trace1(IF,
|
|
"GetDemandFilters: No context or no filters for %S",
|
|
picb->pwszName);
|
|
|
|
return ERROR_NO_DATA;
|
|
}
|
|
|
|
//
|
|
// Set the offset in the TOC
|
|
//
|
|
|
|
pToc[0].Offset = (ULONG) (pbDataPtr - (PBYTE)pInfoHdrAndBuffer);
|
|
pToc[0].Count = 1;
|
|
pToc[0].InfoSize = FIELD_OFFSET(FILTER_DESCRIPTOR,fiFilter[0]) +
|
|
(picb->pDemandFilter->dwNumFilters * sizeof(FILTER_INFO));
|
|
//pToc[0].Version = IPRTR_INFO_VERSION_5;
|
|
|
|
//
|
|
// Just copy out the filters
|
|
//
|
|
|
|
CopyMemory(pbDataPtr,
|
|
picb->pDemandFilter,
|
|
pToc[0].InfoSize);
|
|
|
|
//
|
|
// The size copied in
|
|
//
|
|
|
|
*pdwSize = pToc[0].InfoSize;
|
|
|
|
TraceLeave("GetDemandFilters");
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
VOID
|
|
TryUpdateInternalInterface(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called when a client dials in and we have not
|
|
bound the internal interface
|
|
The way of doing this is as follows:
|
|
If the server adapter is not initialized, read the address from the
|
|
registry. If we read the address, all is good, break out and move on
|
|
If no address was found, wait on the DHCP event with a time out
|
|
If someone configures the server adapter in the meantime, we will get
|
|
the DHCP event, if we miss the event (since it is PULSED), we will
|
|
timeout and we loop back and retry the steps above.
|
|
Now we do this N times. If we fail, then we just wait for the next
|
|
client to dial in
|
|
|
|
Locks:
|
|
|
|
ICB_LIST held as WRITER
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwResult, dwInitCount;
|
|
|
|
TraceEnter("TryUpdateInternalInterface");
|
|
|
|
dwInitCount = 0;
|
|
|
|
//
|
|
// This is only called when the server is not initialized
|
|
//
|
|
|
|
IpRtAssert(g_bUninitServer);
|
|
|
|
while(g_bUninitServer)
|
|
{
|
|
Trace0(ERR,
|
|
"TryUpdateInternalInterface: Server adapter not init");
|
|
|
|
dwResult = UpdateBindingInformation(g_pInternalInterfaceCb);
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
if((dwResult is ERROR_ADDRESS_ALREADY_ASSOCIATED) and
|
|
(g_pInternalInterfaceCb->bBound is TRUE))
|
|
{
|
|
//
|
|
// This means that the worker thread found an address
|
|
//
|
|
|
|
IpRtAssert(g_pInternalInterfaceCb->dwNumAddresses is 1);
|
|
|
|
Trace1(IF,
|
|
"TryUpdateInternalInterface: Address already present for %S",
|
|
g_pInternalInterfaceCb->pwszName);
|
|
|
|
g_bUninitServer = FALSE;
|
|
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
Trace2(ERR,
|
|
"TryUpdateInternalInterface: Err %d trying to update binding for %S",
|
|
dwResult,
|
|
g_pInternalInterfaceCb->pwszName);
|
|
}
|
|
|
|
dwInitCount++;
|
|
|
|
if(dwInitCount >= MAX_SERVER_INIT_TRIES)
|
|
{
|
|
//
|
|
// We try x times and then give up. Next client around
|
|
// things should work
|
|
//
|
|
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
Sleep(SERVER_INIT_SLEEP_TIME);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
g_bUninitServer = FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we broke out because the interface was initialized, bring it up
|
|
//
|
|
|
|
if(!g_bUninitServer)
|
|
{
|
|
dwResult = LanEtcInterfaceDownToUp(g_pInternalInterfaceCb,
|
|
FALSE);
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
Trace1(ERR,
|
|
"TryUpdateInternalInterface: Error %d bringing up server if",
|
|
dwResult);
|
|
}
|
|
}
|
|
|
|
TraceLeave("TryUpdateInternalInterface");
|
|
|
|
}
|