/*++ 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; }