Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

2762 lines
64 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;
NTSTATUS Status;
BOOL bPost;
//
// drain all demand dial events queued up in WANARP
//
TraceEnter("HandleDemandDialEvent");
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
Arguments:
None
Return Value:
None
--*/
{
BOOL bRet;
HANDLE hDim;
DWORD dwResult;
NTSTATUS nStatus;
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;
EXIT_LOCK(ICB_LIST);
dwResult = (ConnectInterface)(hDim,
PID_IP);
ENTER_WRITER(ICB_LIST);
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(!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));
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;
}
#if 0
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
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");
}