windows-nt/Source/XPSP1/NT/net/rras/ip/rtrmgr/ipipcfg.c
2020-09-26 16:20:57 +08:00

894 lines
19 KiB
C

/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
net\routing\ip\rtrmgr\ipipcfg.c
Abstract:
The configuration code for ipinip
Revision History:
Amritansh Raghav
--*/
#include "allinc.h"
//
// All the following are protected by the ICB_LIST lock
//
HKEY g_hIpIpIfKey;
DWORD g_dwNumIpIpInterfaces;
HANDLE g_hIpInIpDevice;
DWORD
OpenIpIpKey(
VOID
)
/*++
Routine Description
Opens the necessary reg keys for IP in IP
Locks
None
Arguments
None
Return Value
Win32 errors
--*/
{
DWORD dwResult;
g_hIpIpIfKey = NULL;
dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
REG_KEY_TCPIP_INTERFACES,
0,
KEY_ALL_ACCESS,
&g_hIpIpIfKey);
if(dwResult isnot NO_ERROR)
{
g_hIpIpIfKey = NULL;
Trace1(ERR,
"OpenIpIpKey: Error %d opening interfaces key\n",
dwResult);
return dwResult;
}
return NO_ERROR;
}
VOID
CloseIpIpKey(
VOID
)
/*++
Routine Description
Closes the necessary reg keys for IP in IP
Locks
None
Arguments
None
Return Value
None
--*/
{
if(g_hIpIpIfKey isnot NULL)
{
RegCloseKey(g_hIpIpIfKey);
g_hIpIpIfKey = NULL;
}
}
VOID
DeleteIpIpKeyAndInfo(
IN PICB pIcb
)
/*++
Routine Description
Deletes the key used for the interface
Locks
ICB_LIST as writer
Arguments
pIcb ICB of the interface to delete
Return Value
None
--*/
{
if(pIcb->pIpIpInfo)
{
HeapFree(IPRouterHeap,
0,
pIcb->pIpIpInfo);
pIcb->pIpIpInfo = NULL;
}
RegDeleteKeyW(g_hIpIpIfKey,
pIcb->pwszName);
}
DWORD
CreateIpIpKeyAndInfo(
IN PICB pIcb
)
/*++
Routine Description
Creates a key under the tcpip interfaces
Locks
ICB_LIST lock held as READER (atleast)
Arguments
ICB for whom to create a key
Return Value
Win32 errors
--*/
{
DWORD dwResult, dwDisposition, dwIndex, dwSize;
HKEY hNewIfKey;
TCHAR ptszNoAddr[] = "0.0.0.0\0";
dwDisposition = 0;
dwResult = RegCreateKeyExW(g_hIpIpIfKey,
pIcb->pwszName,
0,
UNICODE_NULL,
0,
KEY_ALL_ACCESS,
NULL,
&hNewIfKey,
&dwDisposition);
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"CreateIpIpKey: Error %d creating %S",
dwResult,
pIcb->pwszName);
return ERROR_CAN_NOT_COMPLETE;
}
//
// Good, key is done, now do the minimum needed by IP
//
do
{
//
// Create a block for the configuration. When the dwLocalAddress is
// 0, it means that the information hasnt been set
//
pIcb->pIpIpInfo = HeapAlloc(IPRouterHeap,
HEAP_ZERO_MEMORY,
sizeof(IPINIP_CONFIG_INFO));
if(pIcb->pIpIpInfo is NULL)
{
dwResult = ERROR_NOT_ENOUGH_MEMORY;
break;
}
dwResult = RegSetValueEx(hNewIfKey,
REG_VAL_DEFGATEWAY,
0,
REG_MULTI_SZ,
NULL,
0);
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"CreateIpIpKey: Error %d setting %s",
dwResult, REG_VAL_DEFGATEWAY);
break;
}
dwDisposition = 0;
dwResult = RegSetValueEx(hNewIfKey,
REG_VAL_ENABLEDHCP,
0,
REG_DWORD,
(CONST BYTE *)&dwDisposition,
sizeof(DWORD));
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"CreateIpIpKey: Error %d setting %s",
dwResult, REG_VAL_ENABLEDHCP);
break;
}
dwResult = RegSetValueEx(hNewIfKey,
REG_VAL_IPADDRESS,
0,
REG_MULTI_SZ,
(CONST BYTE *)ptszNoAddr,
sizeof(ptszNoAddr));
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"CreateIpIpKey: Error %d setting %s",
dwResult, REG_VAL_IPADDRESS);
break;
}
dwResult = RegSetValueEx(hNewIfKey,
REG_VAL_NTECONTEXTLIST,
0,
REG_MULTI_SZ,
NULL,
0);
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"CreateIpIpKey: Error %d setting %s",
dwResult, REG_VAL_NTECONTEXTLIST);
break;
}
dwResult = RegSetValueEx(hNewIfKey,
REG_VAL_SUBNETMASK,
0,
REG_MULTI_SZ,
(CONST BYTE *)ptszNoAddr,
sizeof(ptszNoAddr));
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"CreateIpIpKey: Error %d setting %s",
dwResult, REG_VAL_SUBNETMASK);
break;
}
dwDisposition = 0;
dwResult = RegSetValueEx(hNewIfKey,
REG_VAL_ZEROBCAST,
0,
REG_DWORD,
(CONST BYTE *)&dwDisposition,
sizeof(DWORD));
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"CreateIpIpKey: Error %d setting %s",
dwResult, REG_VAL_ZEROBCAST);
break;
}
}while(FALSE);
RegCloseKey(hNewIfKey);
if(dwResult isnot NO_ERROR)
{
DeleteIpIpKeyAndInfo(pIcb);
}
return dwResult;
}
DWORD
AddInterfaceToIpInIp(
IN GUID *pGuid,
IN PICB pIcb
)
/*++
Routine Description
Adds an interface to IP in IP driver
Locks
ICB_LIST lock held as WRITER
Arguments
pIcb ICB of the interface to add
Return Value
NO_ERROR
--*/
{
DWORD dwResult;
NTSTATUS ntStatus;
PADAPTER_INFO pBindNode;
ULONG ulSize;
IO_STATUS_BLOCK IoStatusBlock;
IPINIP_CREATE_TUNNEL CreateInfo;
IpRtAssert(pIcb->ritType is ROUTER_IF_TYPE_TUNNEL1);
//
// Get a key for this interface
//
dwResult = CreateIpIpKeyAndInfo(pIcb);
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"AddInterfaceToIpInIp: Error %d creating key for %S",
dwResult,
pIcb->pwszName);
return ERROR_CAN_NOT_COMPLETE;
}
//
// See if we need to start IP in IP
//
g_dwNumIpIpInterfaces++;
if(g_dwNumIpIpInterfaces is 1)
{
dwResult = StartDriverAndOpenHandle(IPINIP_SERVICE_NAME,
DD_IPINIP_DEVICE_NAME,
&g_hIpInIpDevice);
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"AddInterfaceToIpInIp: Error %d starting ipinip for %S",
dwResult,
pIcb->pwszName);
g_dwNumIpIpInterfaces--;
DeleteIpIpKeyAndInfo(pIcb);
return dwResult;
}
//
// Once you start, post a notification
//
PostIpInIpNotification();
}
//
// Copy out the name
//
CreateInfo.Guid = *pGuid;
ntStatus = NtDeviceIoControlFile(g_hIpInIpDevice,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_IPINIP_CREATE_TUNNEL,
&CreateInfo,
sizeof(IPINIP_CREATE_TUNNEL),
&CreateInfo,
sizeof(IPINIP_CREATE_TUNNEL));
if(!NT_SUCCESS(ntStatus))
{
Trace1(ERR,
"AddInterfaceToIpInIp: NtStatus %x creating tunnel",
ntStatus);
g_dwNumIpIpInterfaces--;
if(g_dwNumIpIpInterfaces is 0)
{
StopDriverAndCloseHandle(IPINIP_SERVICE_NAME,
g_hIpInIpDevice);
}
DeleteIpIpKeyAndInfo(pIcb);
return ERROR_CAN_NOT_COMPLETE;
}
//
// Set the interface index
//
pIcb->bBound = TRUE;
pIcb->dwNumAddresses = 0;
pIcb->dwIfIndex = CreateInfo.dwIfIndex;
return NO_ERROR;
}
DWORD
DeleteInterfaceFromIpInIp(
PICB pIcb
)
/*++
Routine Description
Removes an interface to IP in IP driver. Also removes binding information
and frees the ipipcfg
Locks
ICB_LIST lock held as WRITER
Arguments
pIcb ICB of the interface to remove
Return Value
NO_ERROR
--*/
{
NTSTATUS ntStatus;
IPINIP_DELETE_TUNNEL DeleteInfo;
PADAPTER_INFO pBindNode;
IO_STATUS_BLOCK IoStatusBlock;
DWORD dwResult;
IpRtAssert(pIcb->ritType is ROUTER_IF_TYPE_TUNNEL1);
//
// See if the interface was added to ipinip
//
if(pIcb->pIpIpInfo is NULL)
{
return NO_ERROR;
}
DeleteInfo.dwIfIndex = pIcb->dwIfIndex;
ntStatus = NtDeviceIoControlFile(g_hIpInIpDevice,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_IPINIP_DELETE_TUNNEL,
(PVOID)&DeleteInfo,
sizeof(IPINIP_DELETE_TUNNEL),
NULL,
0);
if(!NT_SUCCESS(ntStatus))
{
Trace1(ERR,
"DeleteInterfaceFromIpInIp: NtStatus %x setting info",
ntStatus);
}
pIcb->bBound = FALSE;
pIcb->dwNumAddresses = 0;
//
// These interfaces always have a binding
// Clear out any info there
//
pIcb->pibBindings[0].dwAddress = 0;
pIcb->pibBindings[0].dwMask = 0;
DeleteIpIpKeyAndInfo(pIcb);
g_dwNumIpIpInterfaces--;
if(g_dwNumIpIpInterfaces is 0)
{
StopDriverAndCloseHandle(IPINIP_SERVICE_NAME,
g_hIpInIpDevice);
}
return NO_ERROR;
}
DWORD
SetIpInIpInfo(
PICB pIcb,
PRTR_INFO_BLOCK_HEADER pInterfaceInfo
)
/*++
Routine Description
The routine sets the IP in IP info to the driver. The interface must
have already been added to the driver
Locks
ICB_LIST lock held as WRITER
Arguments
pIcb ICB of the tunnel interface
pInterfaceInfo Header to the interface info
Return Value
NO_ERROR
--*/
{
PRTR_TOC_ENTRY pToc;
PIPINIP_CONFIG_INFO pInfo;
IPINIP_SET_TUNNEL_INFO SetInfo;
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS ntStatus;
DWORD dwResult;
if(pIcb->ritType isnot ROUTER_IF_TYPE_TUNNEL1)
{
return NO_ERROR;
}
pToc = GetPointerToTocEntry(IP_IPINIP_CFG_INFO,
pInterfaceInfo);
if(pToc is NULL)
{
//
// No change
//
return NO_ERROR;
}
IpRtAssert(pToc->InfoSize isnot 0);
#if 0
if(pToc->InfoSize is 0)
{
//
// Blow the interface away from protocols etc
//
dwResult = LanEtcInterfaceUpToDown(pIcb,
FALSE);
if(dwResult isnot NO_ERROR)
{
Trace2(ERR,
"SetIpInIpInfo: Error %d bringing %S down\n",
dwResult,
pIcb->pwszName);
}
//
// Tear down the tunnel
//
DeleteInterfaceFromIpInIp(pIcb);
return NO_ERROR;
}
#endif
//
// Verify the information
//
pInfo = GetInfoFromTocEntry(pInterfaceInfo,
pToc);
if (pInfo is NULL)
{
return ERROR_INVALID_PARAMETER;
}
if((pInfo->dwLocalAddress is INVALID_IP_ADDRESS) or
(pInfo->dwRemoteAddress is INVALID_IP_ADDRESS) or
((DWORD)(pInfo->dwLocalAddress & 0x000000E0) >= (DWORD)0x000000E0) or
((DWORD)(pInfo->dwRemoteAddress & 0x000000E0) >= (DWORD)0x000000E0) or
(pInfo->byTtl is 0))
{
return ERROR_INVALID_PARAMETER;
}
//
// See if the interface has already been added to the driver
//
IpRtAssert(pIcb->pIpIpInfo isnot NULL);
SetInfo.dwIfIndex = pIcb->dwIfIndex;
SetInfo.dwRemoteAddress = pInfo->dwRemoteAddress;
SetInfo.dwLocalAddress = pInfo->dwLocalAddress;
SetInfo.byTtl = pInfo->byTtl;
//
// Set the info to the driver
//
ntStatus = NtDeviceIoControlFile(g_hIpInIpDevice,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_IPINIP_SET_TUNNEL_INFO,
(PVOID)&SetInfo,
sizeof(IPINIP_SET_TUNNEL_INFO),
NULL,
0);
if(!NT_SUCCESS(ntStatus))
{
Trace1(ERR,
"SetIpInIpInfo: NtStatus %x setting info",
ntStatus);
#if 0
DeleteInterfaceFromIpInIp(pIcb);
#endif
return ERROR_CAN_NOT_COMPLETE;
}
pIcb->dwOperationalState = SetInfo.dwOperationalState;
pIcb->pIpIpInfo->dwRemoteAddress = SetInfo.dwRemoteAddress;
pIcb->pIpIpInfo->dwLocalAddress = SetInfo.dwLocalAddress;
pIcb->pIpIpInfo->byTtl = SetInfo.byTtl;
//
// Also set the operational state to UP
//
pIcb->dwOperationalState = CONNECTED;
return NO_ERROR;
}
DWORD
GetInterfaceIpIpInfo(
IN PICB pIcb,
IN PRTR_TOC_ENTRY pToc,
IN PBYTE pbDataPtr,
IN OUT PRTR_INFO_BLOCK_HEADER pInfoHdr,
IN OUT PDWORD pdwInfoSize
)
{
PIPINIP_CONFIG_INFO pInfo;
TraceEnter("GetInterfaceIpIpInfo");
IpRtAssert(pIcb->ritType is ROUTER_IF_TYPE_TUNNEL1);
if(*pdwInfoSize < sizeof(IPINIP_CONFIG_INFO))
{
*pdwInfoSize = sizeof(IPINIP_CONFIG_INFO);
return ERROR_INSUFFICIENT_BUFFER;
}
*pdwInfoSize = 0;
if(pIcb->pIpIpInfo is NULL)
{
//
// Have no info
//
return ERROR_NO_DATA;
}
*pdwInfoSize = sizeof(IPINIP_CONFIG_INFO);
//pToc->InfoVersion sizeof(IPINIP_CONFIG_INFO);
pToc->InfoSize = sizeof(IPINIP_CONFIG_INFO);
pToc->InfoType = IP_IPINIP_CFG_INFO;
pToc->Count = 1;
pToc->Offset = (ULONG)(pbDataPtr - (PBYTE) pInfoHdr);
pInfo = (PIPINIP_CONFIG_INFO)pbDataPtr;
*pInfo = *(pIcb->pIpIpInfo);
TraceLeave("GetInterfaceIpIpInfo");
return NO_ERROR;
}
DWORD
PostIpInIpNotification(
VOID
)
{
DWORD dwBytesRead;
DWORD dwErr = NO_ERROR;
TraceEnter("PostIpInIpNotification");
ZeroMemory(&g_IpInIpOverlapped,
sizeof(OVERLAPPED));
g_IpInIpOverlapped.hEvent = g_hIpInIpEvent ;
if (!DeviceIoControl(g_hIpInIpDevice,
IOCTL_IPINIP_NOTIFICATION,
&g_inIpInIpMsg,
sizeof(g_inIpInIpMsg),
&g_inIpInIpMsg,
sizeof(g_inIpInIpMsg),
(PDWORD) &dwBytesRead,
&g_IpInIpOverlapped))
{
dwErr = GetLastError();
if(dwErr isnot ERROR_IO_PENDING)
{
Trace1(ERR,
"PostIpInIpNotification: Couldnt post irp with IpInIp: %d",
dwErr);
dwErr = NO_ERROR;
}
else
{
Trace0(IF,
"PostIpInIpNotification: Notification pending in IpInIP");
}
}
return dwErr;
}
VOID
HandleIpInIpEvent(
VOID
)
{
PICB pIcb;
DWORD dwBytes;
ENTER_WRITER(ICB_LIST);
TraceEnter("HandleIpInIpEvent");
do
{
if((g_inIpInIpMsg.ieEvent isnot IE_INTERFACE_UP) and
(g_inIpInIpMsg.ieEvent isnot IE_INTERFACE_DOWN))
{
Trace1(IF,
"HandleIpInIpEvent: Unknown event code %d\n",
g_inIpInIpMsg.ieEvent);
break;
}
if(!GetOverlappedResult(g_hIpInIpDevice,
&g_IpInIpOverlapped,
&dwBytes,
FALSE))
{
Trace1(IF,
"HandleIpInIpEvent: Error %d from GetOverlappedResult",
GetLastError());
break;
}
pIcb = InterfaceLookupByIfIndex(g_inIpInIpMsg.dwIfIndex);
if(pIcb is NULL)
{
Trace1(IF,
"HandleIpInIpEvent: Interface %x not found",
g_inIpInIpMsg.dwIfIndex);
break;
}
if(pIcb->ritType isnot ROUTER_IF_TYPE_TUNNEL1)
{
Trace1(IF,
"HandleIpInIpEvent: Interface %x not an IpInIp tunnel",
g_inIpInIpMsg.dwIfIndex);
IpRtAssert(FALSE);
break;
}
Trace3(IF,
"HandleIpInIpEvent: Interface %S is %s due to %d",
pIcb->pwszName,
(g_inIpInIpMsg.ieEvent is IE_INTERFACE_UP) ? "operational" : "non-operational",
g_inIpInIpMsg.iseSubEvent);
pIcb->dwOperationalState =
(g_inIpInIpMsg.ieEvent is IE_INTERFACE_UP) ? OPERATIONAL : NON_OPERATIONAL;
}while(FALSE);
EXIT_LOCK(ICB_LIST);
PostIpInIpNotification();
return;
}