/*++ Copyright (c) 1995 Microsoft Corporation Module Name: routing\ip\rtrmgr\if.c Abstract: IP Router Manager interface related functions Revision History: Gurdeep Singh Pall 6/26/95 Created --*/ #include "allinc.h" ////////////////////////////////////////////////////////////////////////////// // // // The interface state machine: // // // // ---------- // // | Unbound | // // ------------>| Disabled |<--------------- // // | ---------- | // // V V // // ---------- --------- // // | Bound | | Unbound | // // | Disabled | | Enabled | // // ---------- --------- // // ^ ^ // // | --------- | // // ------------->| Bound |<---------------- // // | Enabled | // // --------- // // // // // // LAN interfaces: // // // // Characteristics UP (Operational) DOWN (Non-Operational) // // ------------------------------------------------------------------ // // Binding (IP Address) Yes No // // Protocols Added Yes Yes // // Static Routes Yes No // // Other Routes Yes No // // Added to Filter Driver Yes Yes // // Filters Added Not added // // Filter Ctxt in IP Stack Set (Valid) Not Set (Invalid) // // Router Discovery Active (if necc) Inactive // // Adapter ID (and Map) Valid Invalid // // // // WAN interfaces: // // // // Characteristics CONNECTED DISCON/CONNECTING UNREACHABLE // // ------------------------------------------------------------------- // // Binding (IP Address) Yes No No // // Protocols Added Yes Yes Yes // // Static Routes Yes Yes No // // Other Routes Yes No No // // Added to Filter Driver Yes Yes Yes // // Filters Yes Yes No // // Filter Ctxt in IP Stack Set (Valid) Not Set (Invalid) Not Set // // Router Discovery Active Inactive Inactive // // Adapter ID (and Map) Valid Invalid Invalid // // // // Enabled/Disabled depends upon the AdminState and not upon the // // operational state // // // ////////////////////////////////////////////////////////////////////////////// #if __PIX__ BOOL IsRemoteAddressPrivate(PICB pIcb); #endif PICB CreateIcb( PWSTR pwszInterfaceName, HANDLE hDIMInterface, ROUTER_INTERFACE_TYPE InterfaceType, DWORD dwAdminState, DWORD dwIfIndex OPTIONAL ) /*++ Routine Description This function creates an interface control block Locks None Arguments None Return Value None --*/ { DWORD dwResult; PICB pNewInterfaceCb; GUID Guid; #ifdef KSL_IPINIP // // Make sure this is a valid name // if(InterfaceType is ROUTER_IF_TYPE_TUNNEL1) { UNICODE_STRING usTempName; // // For now only these interfaces are GUIDs // usTempName.Length = wcslen(pwszInterfaceName) * sizeof(WCHAR); usTempName.MaximumLength = usTempName.Length + sizeof(WCHAR); usTempName.Buffer = pwszInterfaceName; if(RtlGUIDFromString(&usTempName, &Guid) isnot STATUS_SUCCESS) { Trace1(ERR, "CreateIcb: %S is not a GUID\n", pwszInterfaceName); return NULL; } } #endif //KSL_IPINIP // // Allocate an ICB // dwResult = AllocateIcb(pwszInterfaceName, &pNewInterfaceCb); if(dwResult isnot NO_ERROR) { return NULL; } pNewInterfaceCb->dwIfIndex = INVALID_IF_INDEX; pNewInterfaceCb->hDIMHandle = hDIMInterface; pNewInterfaceCb->ritType = InterfaceType; pNewInterfaceCb->dwMcastTtl = 1; // // "Unique" interface ID used for ICBs. // This ID is passed to WANARP and DIM and they in // turn pass this back to Router Manager when // requesting/indicating actions on the interface. // pNewInterfaceCb->dwSeqNumber = g_dwNextICBSeqNumberCounter; // // Initialize the filter, and wanarp contexts to invalid values // (NAT invalid is NULL) // pNewInterfaceCb->ihFilterInterface = INVALID_HANDLE_VALUE; pNewInterfaceCb->ihDemandFilterInterface = INVALID_HANDLE_VALUE; // // Initialize the lists of which async notifications and // the protocol blocks are queued // InitializeListHead(&pNewInterfaceCb->lePendingResultList); InitializeListHead(&pNewInterfaceCb->leProtocolList); // // Since we HEAP zeroed the ICB, all our binding related // stuff is already zero, the bBound is FALSE and dwNumAddress is 0 // The adapter id was set to invalid in InitializeInterfaceContext // // // set the operational status based on the interface type // Also figure out the interface index // dwResult = NO_ERROR; switch(pNewInterfaceCb->ritType) { case ROUTER_IF_TYPE_CLIENT: { // // Clients come up in connecting, since we dont get a LINE_UP for // them. We also set the notification flags to fake the LINE UP // pNewInterfaceCb->dwAdminState = IF_ADMIN_STATUS_UP; pNewInterfaceCb->dwOperationalState = CONNECTING; pNewInterfaceCb->nitProtocolType = REMOTE_WORKSTATION_DIAL; SetNdiswanNotification(pNewInterfaceCb); pNewInterfaceCb->dwBCastBit = 1; pNewInterfaceCb->dwReassemblySize = DEFAULT_MTU; // // We dont really care about dial out ifIndex // so clients will have an index of -1 (since we init to -1) // break; } case ROUTER_IF_TYPE_HOME_ROUTER: case ROUTER_IF_TYPE_FULL_ROUTER: { // // HOME and FULL routers are disconnected // pNewInterfaceCb->dwAdminState = dwAdminState; pNewInterfaceCb->dwOperationalState = DISCONNECTED; pNewInterfaceCb->nitProtocolType = DEMAND_DIAL; pNewInterfaceCb->dwBCastBit = 1; pNewInterfaceCb->dwReassemblySize = DEFAULT_MTU; // // WANARP reserves and index when we add an interface to it // dwResult = AddInterfaceToWanArp(pNewInterfaceCb); break; } case ROUTER_IF_TYPE_DEDICATED: { // // LAN interfaces come up as NON_OPERATIONAL. If the admin // wants them up we will try to do a LanInterfaceDownToUp() // If that succeeds, it will set the operational state // correctly // pNewInterfaceCb->dwAdminState = dwAdminState; pNewInterfaceCb->dwOperationalState = NON_OPERATIONAL; pNewInterfaceCb->nitProtocolType = PERMANENT; dwResult = NhpGetInterfaceIndexFromStack( pNewInterfaceCb->pwszName, &(pNewInterfaceCb->dwIfIndex) ); break; } case ROUTER_IF_TYPE_INTERNAL: { pNewInterfaceCb->dwAdminState = IF_ADMIN_STATUS_UP; pNewInterfaceCb->dwOperationalState = DISCONNECTED; pNewInterfaceCb->nitProtocolType = LOCAL_WORKSTATION_DIAL; pNewInterfaceCb->dwBCastBit = 1; pNewInterfaceCb->dwReassemblySize = DEFAULT_MTU; // // WANARP reserves and index when we add an interface to it // dwResult = AddInterfaceToWanArp(pNewInterfaceCb); break; } case ROUTER_IF_TYPE_LOOPBACK: { pNewInterfaceCb->dwAdminState = IF_ADMIN_STATUS_UP; pNewInterfaceCb->dwOperationalState = OPERATIONAL; pNewInterfaceCb->nitProtocolType = PERMANENT; // // Note that IP uses 1 // pNewInterfaceCb->dwIfIndex = LOOPBACK_INTERFACE_INDEX; break; } #ifdef KSL_IPINIP case ROUTER_IF_TYPE_TUNNEL1: { pNewInterfaceCb->dwAdminState = dwAdminState; pNewInterfaceCb->dwOperationalState = NON_OPERATIONAL; pNewInterfaceCb->nitProtocolType = PERMANENT; pNewInterfaceCb->dwBCastBit = 1; pNewInterfaceCb->dwReassemblySize = DEFAULT_MTU; // // IP in IP does the same thing as WANARP // dwResult = AddInterfaceToIpInIp(&Guid, pNewInterfaceCb); break; } #endif //KSL_IPINIP case ROUTER_IF_TYPE_DIALOUT: { // // Dial out interface are not known to DIM. We learn about // them via a back door mechanism. // IpRtAssert(dwIfIndex isnot INVALID_IF_INDEX); IpRtAssert(dwIfIndex isnot 0); pNewInterfaceCb->dwAdminState = IF_ADMIN_STATUS_UP; pNewInterfaceCb->dwOperationalState = CONNECTED; pNewInterfaceCb->nitProtocolType = REMOTE_WORKSTATION_DIAL; pNewInterfaceCb->dwIfIndex = dwIfIndex; pNewInterfaceCb->dwBCastBit = 1; pNewInterfaceCb->dwReassemblySize = DEFAULT_MTU; break; } default: { IpRtAssert(FALSE); break; } } if(dwResult isnot NO_ERROR) { Trace2(ERR, "CreateIcb: Error %d in getting index for %S\n", dwResult, pNewInterfaceCb->pwszName); HeapFree(IPRouterHeap, 0, pNewInterfaceCb); return NULL; } // // Once the interface index is done we can Initialize the bindings // dwResult = CreateBindingForNewIcb(pNewInterfaceCb); if(dwResult isnot NO_ERROR) { Trace2(ERR, "CreateIcb: Error %d in creating binding for %S\n", dwResult, pNewInterfaceCb->pwszName); HeapFree(IPRouterHeap, 0, pNewInterfaceCb); return NULL; } return pNewInterfaceCb; } DWORD AllocateIcb( PWCHAR pwszName, ICB **ppIcb ) /*++ Routine Description Allocates memory for the ICB Locks None Arguments pwszName Interface name ppIcb OUT: pointer to allocate ICB Return Value NO_ERROR --*/ { DWORD dwNameLen, dwAllocSize; PICB pNewInterfaceCb; *ppIcb = NULL; dwNameLen = sizeof(WCHAR) * (wcslen(pwszName) + 1); // +1 for NULL dwNameLen = min(dwNameLen, MAX_INTERFACE_NAME_LEN); dwAllocSize = sizeof (ICB) + dwNameLen + 4; // +4 for alignment pNewInterfaceCb = HeapAlloc(IPRouterHeap, HEAP_ZERO_MEMORY, dwAllocSize); if(pNewInterfaceCb is NULL) { return ERROR_NOT_ENOUGH_MEMORY; } // // The interface name is after the ICB // pNewInterfaceCb->pwszName = (PWCHAR)((PBYTE)pNewInterfaceCb + sizeof (ICB)); // // Align it to DWORD boundary - easier to copy out the name // pNewInterfaceCb->pwszName = (PWCHAR)(((ULONG_PTR)pNewInterfaceCb->pwszName + 3) & ~((ULONG_PTR)0x3)); // // Initialize the name // CopyMemory(pNewInterfaceCb->pwszName, pwszName, dwNameLen); pNewInterfaceCb->pwszName[wcslen(pwszName)] = UNICODE_NULL; *ppIcb = pNewInterfaceCb; return NO_ERROR; } DWORD CreateBindingForNewIcb( PICB pNewIcb ) /*++ Routine Description Creates a binding and bind node for the ICB LAN interfaces get the binding setup when they are being brought UP. Since the other interfaces will ALWAYS have ONLY 1 address, we can set their binding info here, even if we dont have the address We skip INTERNAL, too because of the way the internal address is got. Otherwise we will get an assert in UpdateBindingInformation when we find an existing binding with no address Locks Arguments Return Value --*/ { PADAPTER_INFO pBindNode; PICB_BINDING pBinding; #ifdef KSL_IPINIP if((pNewIcb->ritType is ROUTER_IF_TYPE_TUNNEL1) or #endif //KSL_IPINIP if((pNewIcb->ritType is ROUTER_IF_TYPE_HOME_ROUTER) or (pNewIcb->ritType is ROUTER_IF_TYPE_FULL_ROUTER) or (pNewIcb->ritType is ROUTER_IF_TYPE_LOOPBACK) or (pNewIcb->ritType is ROUTER_IF_TYPE_DIALOUT)) { IpRtAssert(pNewIcb->dwIfIndex isnot INVALID_IF_INDEX); pBindNode = HeapAlloc(IPRouterHeap, HEAP_ZERO_MEMORY, SIZEOF_ADAPTER_INFO(1)); pBinding = HeapAlloc(IPRouterHeap, HEAP_ZERO_MEMORY, sizeof(ICB_BINDING)); if((pBinding is NULL) or (pBindNode is NULL)) { return ERROR_NOT_ENOUGH_MEMORY; } pBindNode->pInterfaceCB = pNewIcb; pBindNode->dwIfIndex = pNewIcb->dwIfIndex; pBindNode->dwSeqNumber = pNewIcb->dwSeqNumber; pBindNode->bBound = pNewIcb->bBound; pBindNode->dwRemoteAddress = INVALID_IP_ADDRESS; pBindNode->rgibBinding[0].dwAddress = INVALID_IP_ADDRESS; pBindNode->rgibBinding[0].dwMask = INVALID_IP_ADDRESS; pBindNode->dwBCastBit = pNewIcb->dwBCastBit; pBindNode->dwReassemblySize = pNewIcb->dwReassemblySize; pBindNode->ritType = pNewIcb->ritType; pNewIcb->pibBindings = pBinding; // // Set the binding in the hash table // ENTER_WRITER(BINDING_LIST); InsertHeadList( &g_leBindingTable[BIND_HASH(pNewIcb->dwIfIndex)], &(pBindNode->leHashLink) ); g_ulNumBindings++; g_LastUpdateTable[IPADDRCACHE] = 0; EXIT_LOCK(BINDING_LIST); return NO_ERROR; } // // For client (dial in our out) interfaces, we only create the BINDING // if((pNewIcb->ritType is ROUTER_IF_TYPE_CLIENT) or (pNewIcb->ritType is ROUTER_IF_TYPE_DIALOUT)) { pBinding = HeapAlloc(IPRouterHeap, HEAP_ZERO_MEMORY, sizeof(ICB_BINDING)); if(pBinding is NULL) { return ERROR_NOT_ENOUGH_MEMORY; } pNewIcb->pibBindings = pBinding; return NO_ERROR; } return NO_ERROR; } VOID InsertInterfaceInLists( PICB pNewIcb ) /*++ Routine Description Insert the new ICB. The newicb must have a valid interface index. The code walks all the current ICBs and inserts this ICB in increasing ifIndex order. It also sets a sequence number in the ICB and increments the global counter. Locks ICB_LIST as writer Arguments newicb The ICB of the interface to init Return Value None --*/ { PLIST_ENTRY pleNode; PICB pIcb; for(pleNode = &ICBList; pleNode->Flink != &ICBList; pleNode = pleNode->Flink) { pIcb = CONTAINING_RECORD(pleNode->Flink, ICB, leIfLink); if(pIcb->dwIfIndex > pNewIcb->dwIfIndex) { break; } } InsertHeadList(pleNode, &pNewIcb->leIfLink); AddInterfaceLookup(pNewIcb); // // Find next unassigned ICB number // do { InterlockedIncrement(&g_dwNextICBSeqNumberCounter); // // WANARP considers 0 to be an invalid value for an // interface // if ((g_dwNextICBSeqNumberCounter == 0) or (g_dwNextICBSeqNumberCounter == INVALID_IF_INDEX)) { InterlockedIncrement(&g_dwNextICBSeqNumberCounter); } } while(InterfaceLookupByICBSeqNumber(g_dwNextICBSeqNumberCounter) != NULL); // // Increment total number of interfaces // InterlockedIncrement(&g_ulNumInterfaces); // // Count for non client interfaces // if(pNewIcb->ritType isnot ROUTER_IF_TYPE_CLIENT) { InterlockedIncrement(&g_ulNumNonClientInterfaces); } } VOID RemoveInterfaceFromLists( PICB pIcb ) /*++ Routine Description This Locks None Arguments None Return Value None --*/ { RemoveEntryList(&(pIcb->leIfLink)); pIcb->leIfLink.Flink = NULL; pIcb->leIfLink.Blink = NULL; RemoveInterfaceLookup(pIcb); if(pIcb->ritType isnot ROUTER_IF_TYPE_CLIENT) { InterlockedDecrement(&g_ulNumNonClientInterfaces); } InterlockedDecrement(&g_ulNumInterfaces); } DWORD BindInterfaceInAllProtocols( PICB pIcb ) /*++ Routine Description Binds the interface in all protocols running over the interface Locks The ICB_LIST lock must be held as READER. Acquires the PROTOCOL_CB_LIST as READER Arguments pIcb ICB of the interface to bind Return Value NO_ERROR --*/ { IP_ADAPTER_BINDING_INFO *pBindInfo; DWORD i = 0 ; DWORD dwResult,dwReturn; PLIST_ENTRY pleNode; TraceEnter("BindInterfaceInAllProtocols"); CheckBindingConsistency(pIcb); if(!pIcb->bBound) { // // This may happen if we are in non operational state // It is not an error. We could do this check at the place // we called the function but it would make it tougher // Trace1(IF, "BindInterfaceInAllProtocols: Not binding %S since no addresses present", pIcb->pwszName); return NO_ERROR; } pBindInfo = HeapAlloc(IPRouterHeap, 0, SIZEOF_IP_BINDING(pIcb->dwNumAddresses)); if(pBindInfo is NULL) { Trace1(ERR, "BindInterfaceInAllProtocols: Error allocating %d bytes for bindings", SIZEOF_IP_BINDING(pIcb->dwNumAddresses)); return ERROR_NOT_ENOUGH_MEMORY; } pBindInfo->AddressCount = pIcb->dwNumAddresses ; pBindInfo->RemoteAddress = pIcb->dwRemoteAddress; pBindInfo->Mtu = pIcb->ulMtu; pBindInfo->Speed = pIcb->ullSpeed; for (i = 0; i < pIcb->dwNumAddresses; i++) { pBindInfo->Address[i].Address = pIcb->pibBindings[i].dwAddress; pBindInfo->Address[i].Mask = pIcb->pibBindings[i].dwMask; } // // walk the array of routing protocols to activate // dwReturn = NO_ERROR; // *** Exclusion Begin *** ENTER_READER(PROTOCOL_CB_LIST); for(pleNode = pIcb->leProtocolList.Flink; pleNode isnot &(pIcb->leProtocolList); pleNode = pleNode->Flink) { PIF_PROTO pProto; pProto = CONTAINING_RECORD(pleNode, IF_PROTO, leIfProtoLink); dwResult = BindInterfaceInProtocol(pIcb, pProto->pActiveProto, pBindInfo); if(dwResult isnot NO_ERROR) { Trace3(ERR, "BindInterfaceInAllProtocols: Couldnt bind interface %S to %S. Error %d", pIcb->pwszName, pProto->pActiveProto->pwszDisplayName, dwResult); dwReturn = ERROR_CAN_NOT_COMPLETE; } } HeapFree(IPRouterHeap, 0, pBindInfo); // *** Exclusion End *** EXIT_LOCK(PROTOCOL_CB_LIST); return dwReturn; } DWORD BindInterfaceInProtocol( PICB pIcb, PPROTO_CB pProto, PIP_ADAPTER_BINDING_INFO pBindInfo ) /*++ Routine Description Binds the interface in the given protocol Locks The ICB_LIST lock must be held as READER. The PROTOCOL_CB_LIST lock must also be held as READER Arguments pIcb ICB of the interface to bind pProto PROTO_CB of the protocol pBindInfo Binding info Return Value NO_ERROR --*/ { DWORD dwResult; // // If this is a mcast protocol and the interface is not // mcast enabled, do so now // if((pIcb->bMcastEnabled is FALSE) and (TYPE_FROM_PROTO_ID(pProto->dwProtocolId) is PROTO_TYPE_MCAST)) { dwResult = SetMcastOnIf(pIcb, TRUE); if(dwResult isnot NO_ERROR) { WCHAR rgwcName[MAX_INTERFACE_NAME_LEN + 2]; PWCHAR pName; Trace2(ERR, "BindInterfaceInProtocol: Err %d activating mcast on %S", dwResult, pIcb->pwszName); if(MprConfigGetFriendlyName(g_hMprConfig, pIcb->pwszName, rgwcName, sizeof(rgwcName)) is NO_ERROR) { pName = rgwcName; } else { pName = pIcb->pwszName; } RouterLogEventEx(g_hLogHandle, EVENTLOG_ERROR_TYPE, dwResult, ROUTERLOG_IP_MCAST_NOT_ENABLED, TEXT("%S%S"), pName, pProto->pwszDisplayName); // // Dont add this protocol // return dwResult; } pIcb->bMcastEnabled = TRUE; } // // Call the routing protocol's BindInterface() entrypoint // dwResult = (pProto->pfnInterfaceStatus)( pIcb->dwIfIndex, (pIcb->dwOperationalState >= CONNECTED), RIS_INTERFACE_ADDRESS_CHANGE, pBindInfo ); if(dwResult isnot NO_ERROR) { Trace3(ERR, "BindInterfaceInProtocol: Couldnt bind interface %S to %S.Error %d", pIcb->pwszName, pProto->pwszDisplayName, dwResult); } return dwResult; } DWORD UnbindInterfaceInAllProtocols( PICB pIcb ) /*++ Routine Description Removes the binding information from the protocols on this interface Locks ICB_LIST lock as READER Acquires the PROTOCOL_CB_LIST as READER Arguments Return Value NO_ERROR --*/ { PLIST_ENTRY pleNode; DWORD dwResult,dwReturn = NO_ERROR; IP_ADAPTER_BINDING_INFO BindInfo; BindInfo.AddressCount = 0; TraceEnter("UnbindInterfaceInAllProtocols"); // *** Exclusion Begin *** ENTER_READER(PROTOCOL_CB_LIST); for(pleNode = pIcb->leProtocolList.Flink; pleNode isnot &(pIcb->leProtocolList); pleNode = pleNode->Flink) { PIF_PROTO pProto; pProto = CONTAINING_RECORD(pleNode,IF_PROTO,leIfProtoLink); dwResult = (pProto->pActiveProto->pfnInterfaceStatus)( pIcb->dwIfIndex, FALSE, RIS_INTERFACE_ADDRESS_CHANGE, &BindInfo ); if(dwResult isnot NO_ERROR) { Trace3(ERR, "UnbindInterfaceInAllProtocols: Error %d unbinding %S in %S", dwResult, pIcb->pwszName, pProto->pActiveProto->pwszDisplayName); dwReturn = ERROR_CAN_NOT_COMPLETE; } } // *** Exclusion Begin *** EXIT_LOCK(PROTOCOL_CB_LIST); return dwReturn; } DWORD AddInterfaceToAllProtocols( PICB pIcb, PRTR_INFO_BLOCK_HEADER pInfoHdr ) /*++ Routine Description Walks thru list of routing protocols and calls AddInterface if TOC and info for that protocol exists Locks ICB_LIST lock as WRITER Acquires PROTOCOL_CB_LIST as READER Arguments Return Value NO_ERROR --*/ { DWORD i = 0 , dwResult; LPVOID pvProtoInfo ; PPROTO_CB pProtoCbPtr ; PLIST_ENTRY pleNode; PRTR_TOC_ENTRY pToc; ULONG ulStructureVersion, ulStructureSize, ulStructureCount; TraceEnter("AddInterfaceToAllProtocols"); if(!ARGUMENT_PRESENT(pInfoHdr)) { Trace1(IF, "AddInterfaceToAllProtocols: No interface info for %S. Not adding to any protocols", pIcb->pwszName); return NO_ERROR; } // *** Exclusion Begin *** ENTER_READER(PROTOCOL_CB_LIST); for(pleNode = g_leProtoCbList.Flink; pleNode != &g_leProtoCbList; pleNode = pleNode->Flink) { pProtoCbPtr = CONTAINING_RECORD(pleNode, PROTO_CB, leList); pToc = GetPointerToTocEntry(pProtoCbPtr->dwProtocolId, pInfoHdr); pvProtoInfo = NULL; if(pToc and (pToc->InfoSize > 0)) { pvProtoInfo = GetInfoFromTocEntry(pInfoHdr, pToc); //ulStructureVersion = pInfoHdr->TocEntry[i].InfoVersion; ulStructureVersion = 0x500; ulStructureSize = pInfoHdr->TocEntry[i].InfoSize; ulStructureCount = pInfoHdr->TocEntry[i].Count; } // // If the protocol block is found, add the interface with the // routing protocol. // if((pProtoCbPtr->fSupportedFunctionality & RF_ADD_ALL_INTERFACES) or (pvProtoInfo)) { dwResult = AddInterfaceToProtocol(pIcb, pProtoCbPtr, pvProtoInfo, ulStructureVersion, ulStructureSize, ulStructureCount); if(dwResult isnot NO_ERROR) { Trace3(ERR, "AddInterfaceToAllProtocols: Error %d adding %S to %S", dwResult, pIcb->pwszName, pProtoCbPtr->pwszDisplayName); } } } // *** Exclusion End *** EXIT_LOCK(PROTOCOL_CB_LIST); return NO_ERROR; } DWORD AddInterfaceToProtocol( IN PICB pIcb, IN PPROTO_CB pProtocolCb, IN PVOID pvProtoInfo, IN ULONG ulStructureVersion, IN ULONG ulStructureSize, IN ULONG ulStructureCount ) /*++ Routine Description Adds an interface to a single routing protocol Locks Arguments Return Value --*/ { PIF_PROTO pProto; DWORD dwResult; pProto = HeapAlloc(IPRouterHeap, 0, sizeof(IF_PROTO)); if(pProto is NULL) { Trace3(ERR, "AddInterfaceToProtocol: Error allocating %d bytes to add %S to %S", sizeof(IF_PROTO), pIcb->pwszName, pProtocolCb->pwszDisplayName); return ERROR_NOT_ENOUGH_MEMORY; } // // The protocol wants all the interfaces indicated to it or // there is info for this protocol // Trace2(IF, "AddInterfaceToProtocol: Adding %S to %S", pIcb->pwszName, pProtocolCb->pwszDisplayName); dwResult = (pProtocolCb->pfnAddInterface)(pIcb->pwszName, pIcb->dwIfIndex, pIcb->nitProtocolType, pIcb->dwMediaType, pIcb->wAccessType, pIcb->wConnectionType, pvProtoInfo, ulStructureVersion, ulStructureSize, ulStructureCount); if(dwResult isnot NO_ERROR) { Trace3(ERR, "AddInterfaceToProtocol: Error %d adding %S to %S", dwResult, pIcb->pwszName, pProtocolCb->pwszDisplayName); HeapFree(IPRouterHeap, 0, pProto); } else { pProto->pActiveProto = pProtocolCb; // // Mark this block as being added, because of prom. // mode, if that is the case // pProto->bPromiscuous = (pvProtoInfo is NULL); InsertTailList(&(pIcb->leProtocolList), &(pProto->leIfProtoLink)); } return dwResult; } DWORD DeleteInterfaceFromAllProtocols( PICB pIcb ) /*++ Routine Description Deletes the interface from all protocols running on it Frees the protocol info on the interface Locks Called with ICB_LIST as WRITER Acquires PROTOCOL_CB_LIST as READER Arguments pIcb ICB of interface Return Value NO_ERROR --*/ { DWORD i = 0 ; PLIST_ENTRY pleNode; TraceEnter("DeleteInterfaceFromAllProtocols"); // // If the router has stopped we do not need to delete the interface // from the routing protocol. This is handled before we get here by // the UnloadRoutingProtocol() // if (RouterState.IRS_State is RTR_STATE_STOPPED) { return NO_ERROR; } // *** Exclusion Begin *** ENTER_READER(PROTOCOL_CB_LIST); while(!(IsListEmpty(&(pIcb->leProtocolList)))) { PIF_PROTO pProto; pleNode = RemoveHeadList(&(pIcb->leProtocolList)); pProto = CONTAINING_RECORD(pleNode,IF_PROTO,leIfProtoLink); // // Call the routing protocol's deleteinterface entrypoint // (pProto->pActiveProto->pfnDeleteInterface) (pIcb->dwIfIndex); // // Delete this protocol from the list of protocols in the Interface // HeapFree(IPRouterHeap,0,pProto); } // *** Exclusion End *** EXIT_LOCK(PROTOCOL_CB_LIST); return NO_ERROR; } DWORD DisableInterfaceWithAllProtocols( PICB pIcb ) { PLIST_ENTRY pleNode; DWORD dwResult,dwReturn = NO_ERROR; TraceEnter("DisableInterfaceWithAllProtocols"); ENTER_READER(PROTOCOL_CB_LIST); for(pleNode = pIcb->leProtocolList.Flink; pleNode isnot &(pIcb->leProtocolList); pleNode = pleNode->Flink) { PIF_PROTO pProto; pProto = CONTAINING_RECORD(pleNode,IF_PROTO,leIfProtoLink); // // Call the routing protocol's DisableInterface() entrypoint // dwResult = (pProto->pActiveProto->pfnInterfaceStatus)( pIcb->dwIfIndex, FALSE, RIS_INTERFACE_DISABLED, NULL ); if(dwResult isnot NO_ERROR) { Trace3(ERR, "DisableInterfaceWithAllProtocols: Couldnt disable %S with %S. Error %d", pIcb->pwszName, pProto->pActiveProto->pwszDisplayName, dwResult); dwReturn = ERROR_CAN_NOT_COMPLETE; } } EXIT_LOCK(PROTOCOL_CB_LIST); return dwReturn; } DWORD EnableInterfaceWithAllProtocols( PICB pIcb ) { PLIST_ENTRY pleNode; DWORD dwResult, dwReturn = NO_ERROR; TraceEnter("EnableInterfaceWithAllProtocols"); ENTER_READER(PROTOCOL_CB_LIST); for(pleNode = pIcb->leProtocolList.Flink; pleNode isnot &(pIcb->leProtocolList); pleNode = pleNode->Flink) { PIF_PROTO pProto; pProto = CONTAINING_RECORD(pleNode,IF_PROTO,leIfProtoLink); dwResult = (pProto->pActiveProto->pfnInterfaceStatus)( pIcb->dwIfIndex, (pIcb->dwOperationalState >= CONNECTED), RIS_INTERFACE_ENABLED, NULL ); if(dwResult isnot NO_ERROR) { Trace3(ERR, "EnableInterfaceWithAllProtocols: Couldnt enable %S with %S. Error %d", pIcb->pwszName, pProto->pActiveProto->pwszDisplayName, dwResult); dwReturn = ERROR_CAN_NOT_COMPLETE; continue; } } EXIT_LOCK(PROTOCOL_CB_LIST); return dwReturn; } VOID DeleteAllInterfaces( VOID ) { PLIST_ENTRY pleNode ; PICB pIcb ; TraceEnter("DeleteAllInterfaces"); // *** Exclusion Begin *** ENTER_WRITER(ICB_LIST); // // We do this backwards. Quick hack for fixing OSPF // // // First we unlink the internal interface because if the worker function // finds the ICB list non empty, it loops, waiting for the interfaces // to get deleted. After all interfaces are deleted it deletes the // internal interface // Hence we remove the i/f from the list here and decrement the count. // if(g_pInternalInterfaceCb) { RemoveEntryList(&(g_pInternalInterfaceCb->leIfLink)); InterlockedDecrement(&g_ulNumInterfaces); } if(g_pLoopbackInterfaceCb) { g_pLoopbackInterfaceCb = NULL; } for(pleNode = ICBList.Blink; pleNode != &ICBList;) { pIcb = CONTAINING_RECORD (pleNode, ICB, leIfLink) ; if((pIcb->dwOperationalState is CONNECTED) and ((pIcb->ritType is ROUTER_IF_TYPE_HOME_ROUTER) or (pIcb->ritType is ROUTER_IF_TYPE_FULL_ROUTER))) { MarkInterfaceForDeletion(pIcb); pleNode = pleNode->Blink; continue; } pleNode = pleNode->Blink; RemoveInterfaceFromLists(pIcb); DeleteSingleInterface(pIcb); // clean up interface. // // Free the ICB // HeapFree(IPRouterHeap, 0, pIcb); } // *** Exclusion End *** EXIT_LOCK(ICB_LIST); } DWORD DeleteSingleInterface( PICB pIcb ) { PICB_BINDING pBinding; PADAPTER_INFO pBindNode; DWORD dwResult; TraceEnter("DeleteSingleInterface"); if(pIcb->ritType is ROUTER_IF_TYPE_CLIENT) { IpRtAssert(g_pInternalInterfaceCb); if(pIcb->bBound) { PLIST_ENTRY pleNode; IP_LOCAL_BINDING clientAddr; clientAddr.Address = pIcb->pibBindings->dwAddress; clientAddr.Mask = pIcb->pibBindings->dwMask; #if 0 // // Remove the client host route // DeleteSingleRoute(g_pInternalInterfaceCb->dwIfIndex, clientAddr.Address, HOST_ROUTE_MASK, clientAddr.Address, MIB_IPPROTO_NETMGMT, FALSE); #endif if (g_pInternalInterfaceCb isnot NULL) { ENTER_READER(PROTOCOL_CB_LIST); // // Call ConnectClient for all the protocols configured // over the ServerInterface // for(pleNode = g_pInternalInterfaceCb->leProtocolList.Flink; pleNode isnot &(g_pInternalInterfaceCb->leProtocolList); pleNode = pleNode->Flink) { PIF_PROTO pIfProto; pIfProto = CONTAINING_RECORD(pleNode, IF_PROTO, leIfProtoLink); if(pIfProto->pActiveProto->pfnDisconnectClient) { pIfProto->pActiveProto->pfnDisconnectClient( g_pInternalInterfaceCb->dwIfIndex, &clientAddr ); } } EXIT_LOCK(PROTOCOL_CB_LIST); // // Delete static routes from RTM (and the stack) // DeleteAllClientRoutes(pIcb, g_pInternalInterfaceCb->dwIfIndex); } if(pIcb->pStoredRoutes) { HeapFree(IPRouterHeap, 0, pIcb->pStoredRoutes); pIcb->pStoredRoutes = NULL; } HeapFree(IPRouterHeap, 0, pIcb->pibBindings); pIcb->pibBindings = NULL; } // // Delete the interface from the filter driver // DeleteFilterInterface(pIcb); return NO_ERROR; } if(pIcb->ritType is ROUTER_IF_TYPE_DIALOUT) { IpRtAssert(pIcb->bBound); pBinding = pIcb->pibBindings; IpRtAssert(pBinding); DeleteAutomaticRoutes(pIcb, pBinding[0].dwAddress, pBinding[0].dwMask); DeleteAllRoutes(pIcb->dwIfIndex, FALSE); ENTER_WRITER(BINDING_LIST); #if DBG pBindNode = GetInterfaceBinding(pIcb->dwIfIndex); IpRtAssert(pBindNode); #endif // DBG RemoveBinding(pIcb); EXIT_LOCK(BINDING_LIST); HeapFree(IPRouterHeap, 0, pBinding); pIcb->pibBindings = NULL; return NO_ERROR; } // // So at this point we are only dealing with FULL_ROUTER, HOME_ROUTER and // DEDICATED type interfaces // // // Delete static routes from RTM (and the stack) // DeleteAllRoutes(pIcb->dwIfIndex, FALSE); // // WAN interfaces: bringing down an interface will not delete // the binding. Hence we do it here // pBinding = NULL; pBindNode = NULL; if((pIcb->ritType is ROUTER_IF_TYPE_FULL_ROUTER) or (pIcb->ritType is ROUTER_IF_TYPE_HOME_ROUTER)) { pBinding = pIcb->pibBindings; pBindNode = GetInterfaceBinding(pIcb->dwIfIndex); } // // Bringing down the interfaces clears out stack contexts // if((pIcb->ritType is ROUTER_IF_TYPE_DEDICATED) or (pIcb->ritType is ROUTER_IF_TYPE_LOOPBACK) or #ifdef KSL_IPINIP (pIcb->ritType is ROUTER_IF_TYPE_TUNNEL1) or #endif //KSL_IPINIP (pIcb->ritType is ROUTER_IF_TYPE_INTERNAL)) { LanEtcInterfaceUpToDown(pIcb, TRUE); } else { WanInterfaceInactiveToDown(pIcb, TRUE); } // // This also frees up the list of IF_PROTO blocks // DeleteInterfaceFromAllProtocols(pIcb); // // Now remove the interface from the stack components // if((pIcb->ritType is ROUTER_IF_TYPE_FULL_ROUTER) or (pIcb->ritType is ROUTER_IF_TYPE_HOME_ROUTER) or (pIcb->ritType is ROUTER_IF_TYPE_INTERNAL)) { if(pIcb->ritType isnot ROUTER_IF_TYPE_INTERNAL) { DeleteDemandFilterInterface(pIcb); } DeleteInterfaceWithWanArp(pIcb); } if((pIcb->ritType isnot ROUTER_IF_TYPE_INTERNAL) and (pIcb->ritType isnot ROUTER_IF_TYPE_LOOPBACK)) { dwResult = DeleteFilterInterface(pIcb); if(dwResult isnot NO_ERROR) { Trace2(ERR, "Error %d deleting %S from the filter driver", dwResult, pIcb->pwszName); } } #ifdef KSL_IPINIP if(pIcb->ritType is ROUTER_IF_TYPE_TUNNEL1) { dwResult = DeleteInterfaceFromIpInIp(pIcb); if(dwResult isnot NO_ERROR) { Trace2(ERR, "Error %d deleting %S from the IpInIp driver", dwResult, pIcb->pwszName); } RemoveBinding(pIcb); } #endif //KSL_IPINIP // // Delete the binding for wan interfaces // if(pBindNode) { ENTER_WRITER(BINDING_LIST); RemoveBinding(pIcb); EXIT_LOCK(BINDING_LIST); } if(pBinding) { HeapFree(IPRouterHeap, 0, pBinding); } if(pIcb->pRtrDiscAdvt) { HeapFree(IPRouterHeap, 0, pIcb->pRtrDiscAdvt); pIcb->pRtrDiscAdvt = NULL; } return NO_ERROR; } #ifdef KSL_IPINIP DWORD IpIpTunnelDownToUp( PICB pIcb ) { return NO_ERROR; } #endif //KSL_IPINIP DWORD LanEtcInterfaceDownToUp( PICB pIcb, BOOL bAdding ) /*++ Routine Description The interface's admin state MUST be UP or this function will simply return The interface to adapter map MUST have already been stored before this is called Locks ICB_LIST lock held as writer Arguments pIcb ICB of the interface to bring up bAdding Set to TRUE if we are adding the interface (as opposed to bringing it up when the admin state changed etc) Return Value NO_ERROR --*/ { DWORD dwResult; PRESTORE_INFO_CONTEXT pricInfo; TraceEnter("LanInterfaceDownToUp"); if(pIcb->dwAdminState isnot IF_ADMIN_STATUS_UP) { Trace2(ERR, "LanInterfaceDownToUp: Tried to bring up %S when its admin state is %d", pIcb->pwszName, pIcb->dwAdminState); return ERROR_INVALID_PARAMETER; } // // Read the address from the registry for LAN interfaces. This function // is also called for the INTERNAL interface, whose address is already // plumbed by the time it is called and for TUNNEL which currently // run in unnumbered mode // if(pIcb->ritType is ROUTER_IF_TYPE_DEDICATED) { IpRtAssert(!pIcb->bBound); IpRtAssert(pIcb->dwNumAddresses is 0); CheckBindingConsistency(pIcb); dwResult = UpdateBindingInformation(pIcb); if(dwResult isnot NO_ERROR) { // // UpdateBindingInf can return ERROR_ALREADY_ASSOC, // but since we have asserted earlier that we dont have // an address, that error only means we still dont have an // address // if(dwResult isnot ERROR_ADDRESS_ALREADY_ASSOCIATED) { Trace1(ERR, "LanInterfaceDownToUp: Couldnt read binding information for %S", pIcb->pwszName); } pIcb->dwOperationalState = IF_OPER_STATUS_NON_OPERATIONAL; return ERROR_CAN_NOT_COMPLETE; } } IpRtAssert(pIcb->bBound); if(pIcb->ritType isnot ROUTER_IF_TYPE_INTERNAL) { pIcb->dwOperationalState = IF_OPER_STATUS_OPERATIONAL; } else { pIcb->dwOperationalState = IF_OPER_STATUS_CONNECTED; } // // First do the generic interface to up stuff // GenericInterfaceComingUp(pIcb); // // We restore routes even when this function is being called from // add interface, because that is the only way to pick up stack // routes // pricInfo = HeapAlloc(IPRouterHeap, 0, sizeof(RESTORE_INFO_CONTEXT)); if(pricInfo isnot NULL) { pricInfo->dwIfIndex = pIcb->dwIfIndex; pIcb->bRestoringRoutes = TRUE; dwResult = QueueAsyncFunction(RestoreStaticRoutes, (PVOID)pricInfo, FALSE); if(dwResult isnot NO_ERROR) { pIcb->bRestoringRoutes = FALSE; IpRtAssert(FALSE); Trace2(ERR, "LanInterfaceDownToUp: Error %d queueing function for %S", dwResult, pIcb->pwszName); } } else { IpRtAssert(FALSE); Trace1(ERR, "LanInterfaceDownToUp: Error allocating context for %S", pIcb->pwszName); } return NO_ERROR; } DWORD WanInterfaceInactiveToUp( PICB pIcb ) /*++ Routine Description This function does things slighlty differently from above because, for one, there is no UpdateBindingInfo() call for such adapters Locks Arguments Return Value --*/ { PRESTORE_INFO_CONTEXT pricInfo; DWORD dwResult; INTERFACE_ROUTE_INFO rifRoute; TraceEnter("WanInterfaceInactiveToUp"); CheckBindingConsistency(pIcb); Trace1(IF, "WanInterfaceInactiveToUp: %S coming up", pIcb->pwszName); // // quick look up of interface given the adapter index. // This is done in UpdateBindingInfo for LAN interfaces. // //StoreAdapterToInterfaceMap(pIcb->dwAdapterId, // pIcb->dwIfIndex); // // First do the generic thing // GenericInterfaceComingUp(pIcb); // // Delete all static routes. These will be re-added // by RestoreStaticRoutes (below) with the correct next hop // DeleteAllRoutes(pIcb->dwIfIndex, TRUE); // // Restore all static and NON-Dod routes on this interface // pricInfo = HeapAlloc(IPRouterHeap, 0, sizeof(RESTORE_INFO_CONTEXT)); if(pricInfo isnot NULL) { pricInfo->dwIfIndex = pIcb->dwIfIndex; pIcb->bRestoringRoutes = TRUE; dwResult = QueueAsyncFunction(RestoreStaticRoutes, (PVOID)pricInfo, FALSE); if(dwResult isnot NO_ERROR) { pIcb->bRestoringRoutes = FALSE; IpRtAssert(FALSE); Trace2(ERR, "WanInterfaceInactiveToUp: Error %d queueing function for %S", dwResult, pIcb->pwszName); } } else { IpRtAssert(FALSE); Trace1(ERR, "WanInterfaceInactiveToUp: Error allocating context for %S", pIcb->pwszName); } // // Change Static route so that it uses the correct adapter index // // ChangeAdapterIndexForDodRoutes(pIcb->dwIfIndex); // // Add a host route for the remote side // if(pIcb->dwRemoteAddress isnot INVALID_IP_ADDRESS #if __PIX__ && (IsRemoteAddressPrivate(pIcb))) #else ) #endif { rifRoute.dwRtInfoMask = HOST_ROUTE_MASK; rifRoute.dwRtInfoNextHop = pIcb->pibBindings[0].dwAddress; rifRoute.dwRtInfoDest = pIcb->dwRemoteAddress; rifRoute.dwRtInfoIfIndex = pIcb->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(pIcb->dwIfIndex, &rifRoute, pIcb->pibBindings[0].dwMask, 0, // RTM_ROUTE_INFO::Flags TRUE, // Valid route TRUE, TRUE, NULL); if(dwResult isnot NO_ERROR) { Trace1(ERR, "WanInterfaceInactiveToUp: Couldnt add host route for %x", pIcb->dwRemoteAddress); } } return NO_ERROR; } DWORD GenericInterfaceComingUp( PICB pIcb ) /*++ Routine Description This function has the common code for bringing up an interface. It assumes that the interface is bound. If NAT is running and we have an address (not unnumbered) we add the address to NAT. We activate router discovery and multicast heartbeat (if they are present) Then we add (i) local loopback (ii) local multicast (iii) all subnets broadcast (iv) all 1's broadcast routes Then we call out to the routing protocols and the filter driver to inform them of the binding Locks ICB_LIST lock held as WRITER Arguments pIcb ICB of the interface to bring up Return Value --*/ { DWORD dwResult, i; MIB_IPFORWARDROW rifRoute; PADAPTER_INFO pBinding; TraceEnter("GenericInterfaceComingUp"); Trace1(IF, "GenericInterfaceComingUp: %S coming UP", pIcb->pwszName); // Join the All-Routers multicast group { extern SOCKET McMiscSocket; Trace1(IF, "CreateSockets: Joining ALL_ROUTERS on %S", pIcb->pwszName); if ( McJoinGroupByIndex( McMiscSocket, SOCK_RAW, ALL_ROUTERS_MULTICAST_GROUP, pIcb->dwIfIndex ) is SOCKET_ERROR ) { Trace2(ERR, "GenericInterfaceComingUp: Error %d joining all-routers group on %S", WSAGetLastError(), pIcb->pwszName); } } // // Start router discovery on this interface. This will cause // the advertisement to get updated // dwResult = ActivateRouterDiscovery(pIcb); if(dwResult isnot NO_ERROR) { Trace2(ERR, "GenericInterfaceComingUp: Error %d activating router discovery on %S", dwResult, pIcb->pwszName); } dwResult = ActivateMHeartbeat(pIcb); if(dwResult isnot NO_ERROR) { Trace2(ERR, "GenericInterfaceComingUp: Error %d activating router discovery on %S", dwResult, pIcb->pwszName); } // // Add default routes for the connected network // for(i = 0; i < pIcb->dwNumAddresses; i++) { if(pIcb->pibBindings[i].dwAddress is INVALID_IP_ADDRESS) { continue; } AddAutomaticRoutes(pIcb, pIcb->pibBindings[i].dwAddress, pIcb->pibBindings[i].dwMask); } // // Interfaces going to UP must have valid binding information. // This is passed to the routing protocols // BindInterfaceInAllProtocols(pIcb); // Set Multicast limits in stack ActivateMcastLimits(pIcb); for (i=0; ipwszName, g_rgicInfoCb[i].pszInfoName); } } return NO_ERROR ; } DWORD LanEtcInterfaceUpToDown( PICB pIcb, BOOL bDeleted ) /*++ Routine Description This function is called when a LAN, INTERNAL or LOOPBACK interface goes down. If the interface is not being deleted, we delete all the static routes. We then disable the interface with the routing protocols and call the generic routing to handle all the rest Locks ICB_LOCK held as WRITER Arguments pIcb bDeleted Return Value None --*/ { DWORD i,dwResult; TraceEnter("LanInterfaceUpToDown"); if(!bDeleted) { DeleteAllRoutes(pIcb->dwIfIndex, FALSE); } GenericInterfaceNoLongerUp(pIcb, bDeleted); pIcb->dwOperationalState = IF_OPER_STATUS_NON_OPERATIONAL; return NO_ERROR; } DWORD WanInterfaceUpToInactive( PICB pIcb, BOOL bDeleted ) { DWORD dwResult; PRESTORE_INFO_CONTEXT pricInfo; TraceEnter("WanInterfaceUpToInactive"); // // Delete the route before deallocating the address (which is called in // GenericInterfaceNoLongerUp), because that will set Remote addr to // invalid and then this route will never be deleted // CheckBindingConsistency(pIcb); // // If it was up, it should be bound // IpRtAssert(pIcb->bBound); if(!bDeleted and (pIcb->dwRemoteAddress isnot INVALID_IP_ADDRESS)) { dwResult = DeleteSingleRoute(pIcb->dwIfIndex, pIcb->dwRemoteAddress, HOST_ROUTE_MASK, pIcb->pibBindings[0].dwAddress, PROTO_IP_NETMGMT, TRUE); if(dwResult isnot NO_ERROR) { Trace1(ERR, "WanInterfaceUpToInactive: Couldnt delete host route for %d.%d.%d.%d", PRINT_IPADDR(pIcb->dwRemoteAddress)); } } GenericInterfaceNoLongerUp(pIcb, bDeleted); if(!bDeleted) { #if 1 // // Delete all static routes/nexthops // DeleteAllRoutes(pIcb->dwIfIndex, FALSE); /* // // Delete all netmgmt routes/nexthops // dwResult = DeleteRtmRoutes(g_hNetMgmtRoute, pIcb->dwIfIndex, FALSE); if (dwResult is NO_ERROR) { dwResult = DeleteRtmNexthopsOnInterface( g_hNetMgmtRoute, pIcb->dwIfIndex ); if (dwResult isnot NO_ERROR) { Trace1( ERR, "WanInterfaceUpToInactive: Couldnt delete next hops for " "Interface 0x%x", pIcb->dwIfIndex ); } } */ // // Restore all static and NON-Dod routes on this interface // pricInfo = HeapAlloc( IPRouterHeap, 0, sizeof(RESTORE_INFO_CONTEXT) ); if(pricInfo isnot NULL) { pricInfo->dwIfIndex = pIcb->dwIfIndex; pIcb->bRestoringRoutes = TRUE; dwResult = QueueAsyncFunction(RestoreStaticRoutes, (PVOID)pricInfo, FALSE); if(dwResult isnot NO_ERROR) { pIcb->bRestoringRoutes = FALSE; IpRtAssert(FALSE); Trace2(ERR, "WanInterfaceUpToInactive: Error %d queueing" " function for %S", dwResult, pIcb->pwszName); } } else { IpRtAssert(FALSE); Trace1(ERR, "WanInterfaceInactiveToUp: Error allocating context for %S", pIcb->pwszName); } #else // // Delete all NON-Dod, Netmgmt routes on this interface // DeleteRtmRoutes(g_hNonDodRoute, pIcb->dwIfIndex, FALSE); DeleteRtmRoutes(g_hNetMgmtRoute, pIcb->dwIfIndex, FALSE); ChangeAdapterIndexForDodRoutes(pIcb->dwIfIndex); #endif } pIcb->dwOperationalState = IF_OPER_STATUS_DISCONNECTED; return NO_ERROR; } DWORD GenericInterfaceNoLongerUp( PICB pIcb, BOOL bDeleted ) /*++ Routine Description This function is called by all interfaces (other than CLIENT) when they go to DOWN state (The actual state depends upon the interface). This may happen because of state change or because the interface is being deleted If we are not deleting the interface, we delete all the automatically generated routes We deactivate router discovery and multicast hearbeat. If NAT is running, we remove the FIREWALL context for the interface from IP and THEN unbind the address in NAT (This MUST be done in this order) Then we Unbind the interface in the routing protocols running over it. We delete the Adapter->Interface map, deallocate the bindings (which does different things depending on LAN/WAN) and if there is a DIM event we set the event Locks ICB_LIST lock held as WRITER Arguments pIcb ICB of the interface bDeleted Set to TRUE if the state change is because of deletion Return Value None --*/ { DWORD dwResult; DWORD i, j; TraceEnter("GenericInterfaceNoLongerUp"); Trace1(IF, "GenericInterfaceNoLongerUp: %S no longer UP", pIcb->pwszName); if(pIcb->bMcastEnabled) { pIcb->bMcastEnabled = FALSE; dwResult = SetMcastOnIf(pIcb, FALSE); if(dwResult isnot NO_ERROR) { Trace2(ERR, "GenericIfNoLongerUp: Error %d deactivating mcast on %S", dwResult, pIcb->pwszName); } } if(!bDeleted) { for (i = 0; i < pIcb->dwNumAddresses; i++) { if(pIcb->pibBindings[i].dwAddress isnot INVALID_IP_ADDRESS) { DeleteAutomaticRoutes(pIcb, pIcb->pibBindings[i].dwAddress, pIcb->pibBindings[i].dwMask); } } } // // Delete any gateways on this // for(i = 0; i < g_ulGatewayMaxCount; i++) { if(g_pGateways[i].dwIfIndex is pIcb->dwIfIndex) { g_pGateways[i].dwAddress = 0; } } // // Compress the array // for(i = 0, j = 1; j < g_ulGatewayMaxCount;j++) { if(g_pGateways[i].dwAddress isnot 0) { i++; } else { if(g_pGateways[j].dwAddress isnot 0) { g_pGateways[i] = g_pGateways[j]; g_pGateways[j].dwAddress = 0; i++; } } } g_ulGatewayCount = i; dwResult = DeActivateRouterDiscovery(pIcb); if(dwResult isnot NO_ERROR) { Trace2(ERR, "GenericInterfaceNoLongerUp: Error %d deactivating router discovery on %S", dwResult, pIcb->pwszName); } dwResult = DeActivateMHeartbeat(pIcb); if(dwResult isnot NO_ERROR) { Trace2(ERR, "GenericInterfaceNoLongerUp: Error %d deactivating multicast heartbeat on %S", dwResult, pIcb->pwszName); } if((pIcb->ritType isnot ROUTER_IF_TYPE_INTERNAL) and (pIcb->ritType isnot ROUTER_IF_TYPE_LOOPBACK)) { UnbindFilterInterface(pIcb); } // // When going out of UP state, the interface loses its address // UnbindInterfaceInAllProtocols(pIcb); //if(pIcb->pibBindings) //{ // DeleteAdapterToInterfaceMap(pIcb->dwAdapterId) ; //} DeAllocateBindings(pIcb); if(pIcb->hDIMNotificationEvent isnot NULL) { // // There was an update pending. Set the event, when the user asks us // for info, we will fail the request // if(!SetEvent(pIcb->hDIMNotificationEvent)) { Trace1(ERR, "GenericInterfaceNoLongerUp: Error %d setting update route event", GetLastError()); } CloseHandle(pIcb->hDIMNotificationEvent); pIcb->hDIMNotificationEvent = NULL; } return NO_ERROR ; } DWORD WanInterfaceInactiveToDown( PICB pIcb, BOOL bDeleted ) { TraceEnter("WanInterfaceInactiveToDown"); CheckBindingConsistency(pIcb); IpRtAssert(!pIcb->bBound); if(!bDeleted) { DeleteAllRoutes(pIcb->dwIfIndex, FALSE); } pIcb->dwOperationalState = UNREACHABLE; //DisableInterfacewithWanArp(pIcb); return NO_ERROR; } DWORD WanInterfaceDownToInactive( PICB pIcb ) { PRESTORE_INFO_CONTEXT pricInfo; DWORD dwResult; PADAPTER_INFO pBinding; TraceEnter("WanInterfaceDownToInactive"); #if STATIC_RT_DBG ENTER_WRITER(BINDING_LIST); pBinding = GetInterfaceBinding(pIcb->dwIfIndex); pBinding->bUnreach = FALSE; EXIT_LOCK(BINDING_LIST); #endif // // Set the state before calling restore // pIcb->dwOperationalState = DISCONNECTED; pricInfo = HeapAlloc(IPRouterHeap, 0, sizeof(RESTORE_INFO_CONTEXT)); if(pricInfo isnot NULL) { pricInfo->dwIfIndex = pIcb->dwIfIndex; pIcb->bRestoringRoutes = TRUE; dwResult = QueueAsyncFunction(RestoreStaticRoutes, (PVOID)pricInfo, FALSE); if(dwResult isnot NO_ERROR) { pIcb->bRestoringRoutes = FALSE; IpRtAssert(FALSE); Trace2(ERR, "WanInterfaceDownToInactive: Error %d queueing function for %S", dwResult, pIcb->pwszName); HeapFree( IPRouterHeap, 0, pricInfo ); } } else { IpRtAssert(FALSE); Trace1(ERR, "WanInterfaceDownToInactive: Error allocating context for %S", pIcb->pwszName); } return NO_ERROR; } DWORD GetInterfaceStatusInfo( IN PICB pIcb, IN PRTR_TOC_ENTRY pToc, IN PBYTE pbDataPtr, IN OUT PRTR_INFO_BLOCK_HEADER pInfoHdr, IN OUT PDWORD pdwInfoSize ) { PINTERFACE_STATUS_INFO pisiInfo; TraceEnter("GetInterfaceStatusInfo"); if(*pdwInfoSize < sizeof(INTERFACE_STATUS_INFO)) { *pdwInfoSize = sizeof(INTERFACE_STATUS_INFO); return ERROR_INSUFFICIENT_BUFFER; } *pdwInfoSize = sizeof(INTERFACE_STATUS_INFO); //pToc->InfoVersion sizeof(INTERFACE_STATUS_INFO); pToc->InfoSize = sizeof(INTERFACE_STATUS_INFO); pToc->InfoType = IP_INTERFACE_STATUS_INFO; pToc->Count = 1; pToc->Offset = (ULONG)(pbDataPtr - (PBYTE) pInfoHdr) ; pisiInfo = (PINTERFACE_STATUS_INFO)pbDataPtr; pisiInfo->dwAdminStatus = pIcb->dwAdminState; return NO_ERROR; } DWORD SetInterfaceStatusInfo( PICB pIcb, PRTR_INFO_BLOCK_HEADER pInfoHdr, PBOOL pbUpdateDIM ) { PINTERFACE_STATUS_INFO pisiInfo; PRTR_TOC_ENTRY pToc; DWORD dwResult; TraceEnter("SetInterfaceStatusInfo"); pToc = GetPointerToTocEntry(IP_INTERFACE_STATUS_INFO, pInfoHdr); if((pToc is NULL) or (pToc->InfoSize is 0)) { // // No TOC means no change. Also empty TOC means no change (IN THIS // ONE CASE ONLY) // return NO_ERROR; } pisiInfo = (PINTERFACE_STATUS_INFO)GetInfoFromTocEntry(pInfoHdr, pToc); if (pisiInfo is NULL) { // // no info block means no change. // return NO_ERROR; } dwResult = SetInterfaceAdminStatus(pIcb, pisiInfo->dwAdminStatus, pbUpdateDIM); if(dwResult isnot NO_ERROR) { Trace2(ERR, "SetInterfaceStatusInfo: Error %d setting admin status for %S", dwResult, pIcb->pwszName); } return dwResult; } VOID DeAllocateBindings( PICB pIcb ) { PADAPTER_INFO pBinding; TraceEnter("DeAllocateBindings"); ENTER_WRITER(BINDING_LIST); // // For LAN interfaces we remove the binding from the // list and free the addresses // For WAN interfaces, to avoid allocations when // connections are coming up and down, we zero out the fields and keep // the memory around. Which means we need to free the memory and the // binding when the interface is deleted // if((pIcb->ritType is ROUTER_IF_TYPE_DEDICATED) or (pIcb->ritType is ROUTER_IF_TYPE_INTERNAL) or (pIcb->ritType is ROUTER_IF_TYPE_LOOPBACK)) { if(pIcb->bBound) { // // These can not be unnumbered // IpRtAssert(pIcb->dwNumAddresses isnot 0); IpRtAssert(pIcb->pibBindings); RemoveBinding(pIcb); HeapFree(IPRouterHeap, 0, pIcb->pibBindings); pIcb->pibBindings = NULL; pIcb->dwNumAddresses = 0; pIcb->bBound = FALSE; pIcb->dwRemoteAddress = INVALID_IP_ADDRESS; } } else { pBinding = GetInterfaceBinding(pIcb->dwIfIndex); if (pBinding) { IpRtAssert(pBinding isnot NULL); pIcb->bBound = FALSE; pBinding->bBound = FALSE; pIcb->dwNumAddresses = 0; pBinding->dwNumAddresses = 0; pIcb->dwRemoteAddress = INVALID_IP_ADDRESS; pBinding->dwRemoteAddress = INVALID_IP_ADDRESS; pIcb->pibBindings[0].dwAddress = INVALID_IP_ADDRESS; pIcb->pibBindings[0].dwMask = INVALID_IP_ADDRESS; pBinding->rgibBinding[0].dwAddress = INVALID_IP_ADDRESS; pBinding->rgibBinding[0].dwMask = INVALID_IP_ADDRESS; g_LastUpdateTable[IPADDRCACHE] = 0; } } EXIT_LOCK(BINDING_LIST); } DWORD GetInterfaceStatistics( IN PICB pIcb, OUT PMIB_IFROW pOutBuffer ) { DWORD dwResult; dwResult = NO_ERROR; TraceEnter("GetInterfaceStatistics"); switch(pIcb->ritType) { case ROUTER_IF_TYPE_HOME_ROUTER: case ROUTER_IF_TYPE_FULL_ROUTER: { dwResult = AccessIfEntryWanArp(ACCESS_GET, pIcb, pOutBuffer); pOutBuffer->dwIndex = pIcb->dwIfIndex; wcscpy(pOutBuffer->wszName, pIcb->pwszName); pOutBuffer->dwAdminStatus = pIcb->dwAdminState; pOutBuffer->dwOperStatus = pIcb->dwOperationalState; strncpy(pOutBuffer->bDescr, g_rgcWanString, MAXLEN_IFDESCR - 1); pOutBuffer->dwDescrLen = min((MAXLEN_IFDESCR-1),strlen(g_rgcWanString)); pOutBuffer->bDescr[MAXLEN_IFDESCR -1] = '\0'; break; } case ROUTER_IF_TYPE_DEDICATED: #ifdef KSL_IPINIP case ROUTER_IF_TYPE_TUNNEL1: #endif //KSL_IPINIP case ROUTER_IF_TYPE_DIALOUT: { // // A Lan Interface that is up // dwResult = GetIfEntryFromStack(pOutBuffer, pIcb->dwIfIndex, FALSE); if(dwResult is NO_ERROR) { // // Bug 486465 // // The stack and user mode RRAS service are out // of sync. with respect to IF indices. This // problem appears to be PnP related. // For now, flag this error and return. // Investigate this further in the next release. // if(pOutBuffer->dwIndex isnot pIcb->dwIfIndex) { Trace2(ERR, "GetInterfaceStatistics: failed due to i/f index " "mistmatch, stack %d, IP Router Manager %d", pOutBuffer->dwIndex, pIcb->dwIfIndex); dwResult = ERROR_INVALID_PARAMETER; break; } //IpRtAssert(pOutBuffer->dwIndex is pIcb->dwIfIndex); // // Copy out the name too // wcscpy(pOutBuffer->wszName, pIcb->pwszName); // // Set the user mode status // pOutBuffer->dwAdminStatus = pIcb->dwAdminState; #ifdef KSL_IPINIP // // Till the notification from ipinip to router is done // pass the driver status back for tunnels //pOutBuffer->dwOperStatus = pIcb->dwOperationalState; if(pIcb->ritType is ROUTER_IF_TYPE_TUNNEL1) { strncpy(pOutBuffer->bDescr, g_rgcIpIpString, MAXLEN_IFDESCR - 1); pOutBuffer->dwDescrLen = min((MAXLEN_IFDESCR-1), strlen(g_rgcIpIpString)); pOutBuffer->bDescr[MAXLEN_IFDESCR -1] = '\0'; } else { pOutBuffer->dwOperStatus = pIcb->dwOperationalState; } #endif //KSL_IPINIP pOutBuffer->dwOperStatus = pIcb->dwOperationalState; } break; } case ROUTER_IF_TYPE_INTERNAL: { pOutBuffer->dwIndex = pIcb->dwIfIndex; wcscpy(pOutBuffer->wszName, pIcb->pwszName); pOutBuffer->dwAdminStatus = pIcb->dwAdminState; pOutBuffer->dwOperStatus = pIcb->dwOperationalState; strncpy(pOutBuffer->bDescr, g_rgcInternalString, MAXLEN_IFDESCR - 1); pOutBuffer->dwDescrLen = min((MAXLEN_IFDESCR-1),strlen(g_rgcInternalString)); pOutBuffer->bDescr[MAXLEN_IFDESCR -1] = '\0'; pOutBuffer->dwType = IF_TYPE_PPP; dwResult = NO_ERROR; break; } case ROUTER_IF_TYPE_LOOPBACK: { pOutBuffer->dwIndex = pIcb->dwIfIndex; wcscpy(pOutBuffer->wszName, pIcb->pwszName); pOutBuffer->dwAdminStatus = pIcb->dwAdminState; pOutBuffer->dwOperStatus = pIcb->dwOperationalState; strncpy(pOutBuffer->bDescr, g_rgcLoopbackString, MAXLEN_IFDESCR - 1); pOutBuffer->dwDescrLen = min((MAXLEN_IFDESCR-1),strlen(g_rgcLoopbackString)); pOutBuffer->bDescr[MAXLEN_IFDESCR - 1] = '\0'; pOutBuffer->dwType = IF_TYPE_SOFTWARE_LOOPBACK; pOutBuffer->dwMtu = 32768; pOutBuffer->dwSpeed = 10000000; dwResult = NO_ERROR; break; } case ROUTER_IF_TYPE_CLIENT: { RtlZeroMemory(pOutBuffer, sizeof(MIB_IFROW)); pOutBuffer->dwIndex = pIcb->dwIfIndex; wcscpy(pOutBuffer->wszName, pIcb->pwszName); pOutBuffer->dwAdminStatus = pIcb->dwAdminState; pOutBuffer->dwOperStatus = pIcb->dwOperationalState; pOutBuffer->dwType = IF_TYPE_PPP; dwResult = NO_ERROR; } default: { IpRtAssert(FALSE); } } if((dwResult isnot NO_ERROR) and ((pIcb->dwOperationalState is NON_OPERATIONAL) or (pIcb->dwAdminState is IF_ADMIN_STATUS_DOWN))) { RtlZeroMemory(pOutBuffer, sizeof(MIB_IFROW)); pOutBuffer->dwIndex = pIcb->dwIfIndex; wcscpy(pOutBuffer->wszName, pIcb->pwszName); pOutBuffer->dwAdminStatus = pIcb->dwAdminState; pOutBuffer->dwOperStatus = pIcb->dwOperationalState; if(pIcb->ritType is ROUTER_IF_TYPE_CLIENT) { pOutBuffer->dwType = IF_TYPE_PPP; } else { #ifdef KSL_IPINIP if(pIcb->ritType is ROUTER_IF_TYPE_TUNNEL1) { strncpy(pOutBuffer->bDescr, g_rgcIpIpString, MAXLEN_IFDESCR - 1); pOutBuffer->dwDescrLen = min((MAXLEN_IFDESCR-1), strlen(g_rgcIpIpString)); pOutBuffer->bDescr[MAXLEN_IFDESCR -1] = '\0'; pOutBuffer->dwType = IF_TYPE_TUNNEL; } #endif //KSL_IPINIP pOutBuffer->dwType = IF_TYPE_OTHER; } dwResult = NO_ERROR; } return dwResult; } DWORD SetInterfaceStatistics( IN PICB pIcb, IN PMIB_IFROW lpInBuffer, OUT PBOOL pbUpdateDIM ) { DWORD dwResult = NO_ERROR; TraceEnter("SetInterfaceStatistics"); dwResult = SetInterfaceAdminStatus(pIcb, lpInBuffer->dwAdminStatus, pbUpdateDIM); if(dwResult isnot NO_ERROR) { Trace2(ERR, "SetInterfaceStatistics: Error %d setting admin status for %S", dwResult, pIcb->pwszName); } return dwResult; } DWORD SetInterfaceAdminStatus( IN PICB pIcb, IN DWORD dwAdminStatus, OUT PBOOL pbUpdateDIM ) { DWORD dwResult; TraceEnter("SetInterfaceAdminStatus"); // // Not allowed to set to TESTING in NT // CheckBindingConsistency(pIcb); if(!((dwAdminStatus is IF_ADMIN_STATUS_DOWN) or (dwAdminStatus is IF_ADMIN_STATUS_UP))) { return ERROR_INVALID_PARAMETER; } dwResult = NO_ERROR; *pbUpdateDIM = FALSE; if((pIcb->dwAdminState is IF_ADMIN_STATUS_UP) and (dwAdminStatus is IF_ADMIN_STATUS_DOWN)) { // // Going from up to down // dwResult = InterfaceAdminStatusSetToDown(pIcb, pbUpdateDIM); if(dwResult isnot NO_ERROR) { Trace2(ERR, "SetInterfaceAdminStatus: Error %d bringing down %S", dwResult, pIcb->pwszName); } } if((pIcb->dwAdminState is IF_ADMIN_STATUS_DOWN) and (dwAdminStatus is IF_ADMIN_STATUS_UP)) { // // Going from down to up // dwResult = InterfaceAdminStatusSetToUp(pIcb, pbUpdateDIM); if(dwResult isnot NO_ERROR) { Trace2(ERR, "SetInterfaceAdminStatus: Error %d bringing up %S", dwResult, pIcb->pwszName); } } // // Check the state after you leave // CheckBindingConsistency(pIcb); // // All other cases, no change // return dwResult; } DWORD InterfaceAdminStatusSetToUp( IN PICB pIcb, OUT PBOOL pbUpdateDIM ) { DWORD dwResult; MIB_IFROW riInBuffer; TraceEnter("InterfaceAdminStatusSetToUp"); riInBuffer.dwIndex = pIcb->dwIfIndex; riInBuffer.dwAdminStatus = IF_ADMIN_STATUS_UP; // // Going from Down to UP // dwResult = NO_ERROR; // // Set the state to UP first so that any functions that checks it sees that // we want to be up // pIcb->dwAdminState = IF_ADMIN_STATUS_UP; switch(pIcb->ritType) { case ROUTER_IF_TYPE_HOME_ROUTER: case ROUTER_IF_TYPE_FULL_ROUTER: { // // Couldnt be in down state and have been connecting or // connected // IpRtAssert((pIcb->dwOperationalState isnot CONNECTING) and (pIcb->dwOperationalState isnot CONNECTED)); dwResult = AccessIfEntryWanArp(ACCESS_SET, pIcb, &riInBuffer); if(dwResult isnot NO_ERROR) { Trace1(ERR, "InterfaceAdminStatusSetToUp: Couldnt set IFEntry for %S", pIcb->pwszName); pIcb->dwAdminState = IF_ADMIN_STATUS_DOWN; } else { WanInterfaceDownToInactive(pIcb); } break; } case ROUTER_IF_TYPE_DEDICATED: #ifdef KSL_IPINIP case ROUTER_IF_TYPE_TUNNEL1: #endif //KSL_IPINIP { // // Bring the stuff up in stack // We need to set to stack before we add routes etc // riInBuffer.dwIndex = pIcb->dwIfIndex; // // Force an update // dwResult = SetIfEntryToStack(&riInBuffer, TRUE); if(dwResult isnot NO_ERROR) { Trace2(ERR, "InterfaceAdminStatusSetToDown: Couldnt set IFEntry for %S. Error %d", pIcb->pwszName, dwResult); LanEtcInterfaceUpToDown(pIcb, FALSE); pIcb->dwAdminState = IF_ADMIN_STATUS_DOWN; dwResult = ERROR_CAN_NOT_COMPLETE; break; } dwResult = LanEtcInterfaceDownToUp(pIcb, FALSE); if(dwResult isnot NO_ERROR) { Trace1(ERR, "InterfaceAdminStatusSetToUp: Error %d bringing up LanInterface", dwResult); pIcb->dwAdminState = IF_ADMIN_STATUS_DOWN; } break; } default: { // TBD: Handle other types too Trace1(ERR, "InterfaceAdminStatusSetToUp: Tried to set status for %S", pIcb->pwszName); break; } } // // If we succeeded in setting status, let DIM know // if(dwResult is NO_ERROR) { IpRtAssert(pIcb->dwAdminState is IF_ADMIN_STATUS_UP); EnableInterfaceWithAllProtocols(pIcb); *pbUpdateDIM = TRUE; //EnableInterfaceWithDIM(pIcb->hDIMHandle, // PID_IP, // TRUE); } return dwResult; } DWORD InterfaceAdminStatusSetToDown( IN PICB pIcb, OUT PBOOL pbUpdateDIM ) { DWORD dwResult; MIB_IFROW riInBuffer; TraceEnter("InterfaceAdminStatusSetToDown"); riInBuffer.dwIndex = pIcb->dwIfIndex; riInBuffer.dwAdminStatus = IF_ADMIN_STATUS_DOWN; // // Going from up to down // dwResult = NO_ERROR; switch(pIcb->ritType) { case ROUTER_IF_TYPE_DEDICATED: #ifdef KSL_IPINIP case ROUTER_IF_TYPE_TUNNEL1: #endif //KSL_IPINIP { // // A Lan Interface that is up or non operational. We can only go // to stack if we have an IP Address // if(pIcb->bBound) { riInBuffer.dwIndex = pIcb->dwIfIndex; // // Force an update // dwResult = SetIfEntryToStack(&riInBuffer, TRUE); } if(dwResult isnot NO_ERROR) { Trace1(ERR, "InterfaceAdminStatusSetToDown: Couldnt set IFEntry for %S", pIcb->pwszName); } else { LanEtcInterfaceUpToDown(pIcb, FALSE); pIcb->dwAdminState = IF_ADMIN_STATUS_DOWN; } break; } case ROUTER_IF_TYPE_HOME_ROUTER: case ROUTER_IF_TYPE_FULL_ROUTER: { // // A Wan Interface that is down.We need to disable // the interface and set the status in WANARP // if((pIcb->dwOperationalState is CONNECTED) or (pIcb->dwOperationalState is CONNECTING)) { Trace1(ERR, "InterfaceAdminStatusSetToDown: Can set %S down since it is a connected WAN interface", pIcb->pwszName); dwResult = ERROR_INVALID_DATA; break; } dwResult = AccessIfEntryWanArp(ACCESS_SET, pIcb, &riInBuffer); if(dwResult isnot NO_ERROR) { Trace1(ERR, "InterfaceAdminStatusSetToDown: Couldnt set IFEntry for %S", pIcb->pwszName); } else { WanInterfaceInactiveToDown(pIcb, FALSE); pIcb->dwAdminState = IF_ADMIN_STATUS_DOWN; } break; } default: { // TBD: Handle other types too Trace1(ERR, "InterfaceAdminStatusSetToDown: Tried to set status for %S", pIcb->pwszName); break; } } // // If we succeeded in setting status, let DIM know // if(dwResult is NO_ERROR) { IpRtAssert(pIcb->dwAdminState is IF_ADMIN_STATUS_DOWN); DisableInterfaceWithAllProtocols(pIcb); *pbUpdateDIM = TRUE; //EnableInterfaceWithDIM(pIcb->hDIMHandle, // PID_IP, // FALSE); } return dwResult; } VOID HandleAddressChangeNotification( VOID ) /*++ Routine Description Called in the context of the worker thread when we get a address change notification from winsock Locks Acquires the ICB LOCK as WRITER Arguments None Return Value None --*/ { DWORD dwResult; PLIST_ENTRY pleNode; PICB pIcb; ENTER_WRITER(ICB_LIST); if(g_pInternalInterfaceCb isnot NULL) { dwResult = UpdateBindingInformation(g_pInternalInterfaceCb); if(dwResult isnot NO_ERROR) { // // Cases in which no address was found // if(dwResult is ERROR_ADDRESS_ALREADY_ASSOCIATED) { // // This may mean that the i/f had no // address and still has no address // Trace1(IF, "AddressChange: No address change for %S", g_pInternalInterfaceCb->pwszName); } else { if(dwResult is ERROR_NO_DATA) { // // No data means we had an address and now have none // IpRtAssert(!g_bUninitServer); dwResult = LanEtcInterfaceUpToDown(g_pInternalInterfaceCb, FALSE); g_bUninitServer = TRUE; if(dwResult isnot NO_ERROR) { Trace2(ERR, "AddressChange: Error %d bringing down interface %S", dwResult, g_pInternalInterfaceCb->pwszName); } } else { // // All others // Trace2(ERR, "AddressChange: Error %d trying to update binding for %S", dwResult, g_pInternalInterfaceCb->pwszName); } } } else { // // Cases in which an address was actually read out // if(g_bUninitServer) { // // First time we are getting an address // g_bUninitServer = FALSE; dwResult = LanEtcInterfaceDownToUp(g_pInternalInterfaceCb, FALSE); if(dwResult isnot NO_ERROR) { Trace1(ERR, "AddressChange: Error %d bringing up server if", dwResult); } } else { // // We had an address, it is changing // UnbindInterfaceInAllProtocols(g_pInternalInterfaceCb); BindInterfaceInAllProtocols(g_pInternalInterfaceCb); } } } for(pleNode = &ICBList; pleNode->Flink isnot &ICBList; pleNode = pleNode->Flink) { pIcb = CONTAINING_RECORD(pleNode->Flink, ICB, leIfLink); // // Already handled the INTERNAL case above, We only // handle LAN cards here // if(pIcb->ritType isnot ROUTER_IF_TYPE_DEDICATED) { continue; } if(pIcb->dwOperationalState is IF_OPER_STATUS_NON_OPERATIONAL) { // // If the admin state is down, we skip the interface // if(pIcb->dwAdminState isnot IF_ADMIN_STATUS_UP) { continue; } // // If the interface is DOWN, maybe this DHCP event will get it // up. So lets try that first // IpRtAssert(pIcb->bBound is FALSE); dwResult = LanEtcInterfaceDownToUp(pIcb, FALSE); if(dwResult isnot NO_ERROR) { Trace2(IF, "AddressChange: Tried to bring up %S on receiving DHCP notification. However LanInterfaceDownToUp() returned error %d", pIcb->pwszName, dwResult); } else { Trace1(IF, "AddressChange: Succesfully brought up %S", pIcb->pwszName); } continue; } // // This interface was already up. Maybe the // address is changing // IpRtAssert(pIcb->bBound); dwResult = UpdateBindingInformation(pIcb); CheckBindingConsistency(pIcb); if(dwResult isnot NO_ERROR) { if(dwResult is ERROR_ADDRESS_ALREADY_ASSOCIATED) { // // This may mean that the i/f had no // address and still has no address // Trace1(IF, "AddressChange: No address change for %S", pIcb->pwszName); continue; } if(dwResult is ERROR_NO_DATA) { // // No data means we lost addresses // dwResult = LanEtcInterfaceUpToDown(pIcb, FALSE); if(dwResult isnot NO_ERROR) { Trace2(ERR, "AddressChange: Error %d bringing down interface %S", dwResult, pIcb->pwszName); } continue; } Trace2(ERR, "AddressChange: Error %d trying to update binding for %S", dwResult, pIcb->pwszName); continue; } // // Addresses changed so bind and unbind // with all protocols // UnbindInterfaceInAllProtocols(pIcb); BindInterfaceInAllProtocols(pIcb); UpdateAdvertisement(pIcb); } EXIT_LOCK(ICB_LIST); } DWORD UpdateBindingInformation( PICB pIcb ) /*++ Routine Description Reads the registry for the ip address and mask associated with the interface. Then calls down into the stack to get a valid index Locks Arguments Return Value NO_ERROR There was an address change and a new address was found ERROR_NO_DATA No addresses were found (and there were addresses on this interface originally) ERROR_ADDRESS_ALREADY_ASSOCIATED If there is no change in addresses. Also returned if the interface had no addresses to begin with and still has no addresses --*/ { DWORD dwResult, dwNumNewAddresses, dwNumOldAddresses; PICB_BINDING pNewBinding,pOldBinding; DWORD dwNewIfIndex,dwBCastBit,dwReasmSize; BOOL bFound, bChange, bStack; DWORD i, j; PWCHAR pwszName; DWORD dwAddr, dwLen; TraceEnter("UpdateBindingInformation"); CheckBindingConsistency(pIcb); // // Only called for LAN and ras server interfaces. These DO NOT run in // unnumbered mode. Thus we can continue making assumptions that // if bound, dwNumAddresses != 0 // if((pIcb->ritType isnot ROUTER_IF_TYPE_DEDICATED) and (pIcb->ritType isnot ROUTER_IF_TYPE_INTERNAL)) { Trace2(IF, "UpdateBindingInformation: %S is type %d so not updating binding information", pIcb->pwszName, pIcb->ritType); return ERROR_ADDRESS_ALREADY_ASSOCIATED; } IpRtAssert((pIcb->dwIfIndex isnot 0) and (pIcb->dwIfIndex isnot INVALID_IF_INDEX)); dwNumNewAddresses = 0; pNewBinding = NULL; pOldBinding = pIcb->pibBindings; dwNumOldAddresses = pIcb->dwNumAddresses; dwResult = GetIpInfoForInterface(pIcb->dwIfIndex, &dwNumNewAddresses, &pNewBinding, &dwBCastBit, &dwReasmSize); if(dwResult isnot NO_ERROR) { if(dwResult isnot ERROR_NO_DATA) { Trace2(ERR, "UpdateBindingInformation: Error %d getting IP info for interface %S", dwResult, pIcb->pwszName); } else { // // If no addresses were found and there were no addresses to begin // with, then change the error code // if(pIcb->dwNumAddresses is 0) { dwResult = ERROR_ADDRESS_ALREADY_ASSOCIATED; } } return dwResult; } IpRtAssert(dwNumNewAddresses); IpRtAssert(pNewBinding); // // Make sure you will find an adapter index. Otherwise all this is no use // #if DBG for(i = 0; i < dwNumNewAddresses; i++) { Trace4(IF, "UpdateBindingInformation: Interface: %S, Address: %d.%d.%d.%d Mask: %d.%d.%d.%d Index: 0x%x", pIcb->pwszName, PRINT_IPADDR(pNewBinding[i].dwAddress), PRINT_IPADDR(pNewBinding[i].dwMask), pIcb->dwIfIndex); } #endif // // At this point the interface can be considered bound // pIcb->bBound = TRUE; // // Go through the address you have and if they dont appear in the list of // the ones you read out, delete the associated static route // bChange = FALSE; for(i = 0; i < dwNumOldAddresses; i++) { bFound = FALSE; for(j = 0; j < dwNumNewAddresses; j++) { // // Check both the mask and the address // if((pOldBinding[i].dwAddress is pNewBinding[j].dwAddress) and (pOldBinding[i].dwMask is pNewBinding[j].dwMask)) { bFound = TRUE; break; } } if(!bFound) { bChange = TRUE; // // Only delete routes we would have added in the first place // Trace2(IF, "UpdateBindingInformation: Address %d.%d.%d.%d existed on %S earlier, but is now absent", PRINT_IPADDR(pOldBinding[i].dwAddress), pIcb->pwszName); DeleteAutomaticRoutes(pIcb, pOldBinding[i].dwAddress, pOldBinding[i].dwMask); } } // // Now go through the stuff read out from the registry and see if you // already have the address(es). // for(i = 0; i < dwNumNewAddresses; i++) { bFound = FALSE; for(j = 0; j < dwNumOldAddresses; j++) { if((pNewBinding[i].dwAddress is pOldBinding[j].dwAddress) and (pNewBinding[i].dwMask is pOldBinding[j].dwMask)) { bFound = TRUE; break; } } if(!bFound) { bChange = TRUE; } } if(!bChange) { // // No change so we can leave // if(pNewBinding) { HeapFree(IPRouterHeap, 0, pNewBinding); } return ERROR_ADDRESS_ALREADY_ASSOCIATED; } // // So there has been some change // At this point we need to add the binding to the hash table // ENTER_WRITER(BINDING_LIST); // // If you had old bindings, remove them // Also remove the adapter to Interface map // if(pOldBinding) { RemoveBinding(pIcb); } pIcb->pibBindings = pNewBinding; pIcb->dwNumAddresses = dwNumNewAddresses; pIcb->dwBCastBit = dwBCastBit; pIcb->dwReassemblySize = dwReasmSize; AddBinding(pIcb); // // We do the same thing we did above, but now we add the routes. // We cant do this before because the adapter id and binding info // hasnt been set in the hash table // for(i = 0; i < dwNumNewAddresses; i++) { bFound = FALSE; for(j = 0; j < dwNumOldAddresses; j++) { if((pNewBinding[i].dwAddress is pOldBinding[j].dwAddress) and (pNewBinding[i].dwMask is pOldBinding[j].dwMask)) { bFound = TRUE; } } if(!bFound) { Trace3(IF, "UpdateBindingInformation: Address %d.%d.%d.%d/%d.%d.%d.%d new for %S", PRINT_IPADDR(pNewBinding[i].dwAddress), PRINT_IPADDR(pNewBinding[i].dwMask), pIcb->pwszName); AddAutomaticRoutes(pIcb, pNewBinding[i].dwAddress, pNewBinding[i].dwMask); } } if(pOldBinding) { HeapFree(IPRouterHeap, 0, pOldBinding); } // // Such interfaces can not have a kernel context // EXIT_LOCK(BINDING_LIST); return NO_ERROR; } DWORD GetAdapterInfo( DWORD dwIpAddress, PDWORD pdwAdapterId, PDWORD pdwBCastBit, PDWORD pdwReasmSize ) /*++ Routine Description Queries the tcpip driver with IP_MIB_STATS to figure out the adapter index for the adapter with the given ip address. Locks Arguments Return Value Index if successfule INVALID_IF_INDEX otherwise --*/ { DWORD i, dwNumEntries, MatchIndex, dwResult, Size; PMIB_IPADDRTABLE pAddrTable; *pdwAdapterId = INVALID_ADAPTER_ID; *pdwBCastBit = 1; *pdwReasmSize = 0; dwResult = AllocateAndGetIpAddrTableFromStack(&pAddrTable, FALSE, IPRouterHeap, 0); if(dwResult isnot NO_ERROR) { Trace1(ERR, "GetAdapterInfo: Error %d getting IP Address table from stack", dwResult); return dwResult; } for (i = 0; i < pAddrTable->dwNumEntries; i++) { if(pAddrTable->table[i].dwAddr is dwIpAddress) { *pdwAdapterId = pAddrTable->table[i].dwIndex; *pdwBCastBit = pAddrTable->table[i].dwBCastAddr; *pdwReasmSize = pAddrTable->table[i].dwReasmSize; HeapFree(IPRouterHeap, 0, pAddrTable); return NO_ERROR; } } HeapFree(IPRouterHeap, 0, pAddrTable); return ERROR_INVALID_DATA; } DWORD GetBestNextHopMaskGivenICB( PICB pIcb, DWORD dwNextHopAddr ) /*++ Routine Description Gets the longest mask for the next hop Locks Arguments pIcb the Interface Control Block over which the route goes out dwNextHopAddr The next hop addr Return Value 0xFFFFFFFF if not found --*/ { DWORD i, dwLastMask; #if DBG BOOL bFound = FALSE; #endif CheckBindingConsistency(pIcb); dwLastMask = 0; for(i = 0; i < pIcb->dwNumAddresses; i++) { if((pIcb->pibBindings[i].dwAddress & pIcb->pibBindings[i].dwMask) is (dwNextHopAddr & pIcb->pibBindings[i].dwMask)) { #if DBG bFound = TRUE; #endif if(pIcb->pibBindings[i].dwMask > dwLastMask) { dwLastMask = pIcb->pibBindings[i].dwMask; } } } #if DBG if(!bFound) { Trace2(ERR, "GetBestNextHopMaskGivenICB: Didnt find match. I/f 0x%x Nexthop %x", pIcb->dwIfIndex, dwNextHopAddr); } #endif if(dwLastMask is 0x00000000) { return 0xFFFFFFFF; } else { return dwLastMask; } } DWORD GetBestNextHopMaskGivenIndex( DWORD dwIfIndex, DWORD dwNextHopAddr ) /*++ Routine Description Gets the longest mask for the next hop Locks Arguments pIcb the Interface Control Block over which the route goes out dwNextHopAddr The next hop addr Return Value 0x00000000 if not found --*/ { PICB pIcb; pIcb = InterfaceLookupByIfIndex(dwIfIndex); if(pIcb is NULL) { Trace1(ERR, "GetBestNextHopMaskGivenIndex: Couldnt find pIcb for index 0x%x", dwIfIndex); return 0x00000000; } return GetBestNextHopMaskGivenICB(pIcb, dwNextHopAddr); } DWORD InitializeLoopbackInterface( PICB pIcb ) { DWORD dwResult, i, j; PADAPTER_INFO pBindNode; INTERFACE_ROUTE_INFO rifRoute; PLIST_ENTRY pleNode; TraceEnter("InitLoopIf"); g_pLoopbackInterfaceCb = pIcb; dwResult = GetAdapterInfo(IP_LOOPBACK_ADDRESS, &(pIcb->dwIfIndex), &(pIcb->dwBCastBit), &(pIcb->dwReassemblySize)); if(dwResult isnot NO_ERROR) { Trace0(ERR, "InitLoopIf: Couldnt find adapter id for loopback interface"); return ERROR_CAN_NOT_COMPLETE; } IpRtAssert(pIcb->dwIfIndex is LOOPBACK_INTERFACE_INDEX); IpRtAssert(pIcb->pibBindings isnot NULL); // // This will always have one address // pIcb->dwNumAddresses = 1; pIcb->bBound = TRUE; // // Loopback interfaces have a class A mask // pIcb->pibBindings[0].dwAddress = IP_LOOPBACK_ADDRESS; pIcb->pibBindings[0].dwMask = CLASSA_MASK; ENTER_WRITER(BINDING_LIST); pBindNode = GetInterfaceBinding(pIcb->dwIfIndex); if(!pBindNode) { Trace1(ERR, "IniteLoopIf: 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 { pBindNode->bBound = TRUE; pBindNode->dwNumAddresses = 1; pBindNode->dwRemoteAddress = INVALID_IP_ADDRESS; pBindNode->rgibBinding[0].dwAddress = IP_LOOPBACK_ADDRESS; pBindNode->rgibBinding[0].dwMask = CLASSA_MASK; pBindNode->dwBCastBit = pIcb->dwBCastBit; pBindNode->dwReassemblySize = pIcb->dwReassemblySize; pBindNode->ritType = pIcb->ritType; } EXIT_LOCK(BINDING_LIST); rifRoute.dwRtInfoMask = CLASSA_MASK; rifRoute.dwRtInfoNextHop = IP_LOOPBACK_ADDRESS; rifRoute.dwRtInfoDest = (IP_LOOPBACK_ADDRESS & CLASSA_MASK); rifRoute.dwRtInfoIfIndex = pIcb->dwIfIndex; rifRoute.dwRtInfoMetric1 = 1; rifRoute.dwRtInfoMetric2 = 0; rifRoute.dwRtInfoMetric3 = 0; rifRoute.dwRtInfoViewSet = RTM_VIEW_MASK_UCAST | RTM_VIEW_MASK_MCAST; // XXX config rifRoute.dwRtInfoPreference = ComputeRouteMetric(MIB_IPPROTO_LOCAL); rifRoute.dwRtInfoType = MIB_IPROUTE_TYPE_DIRECT; rifRoute.dwRtInfoProto = MIB_IPPROTO_LOCAL; rifRoute.dwRtInfoAge = 0; rifRoute.dwRtInfoNextHopAS = 0; rifRoute.dwRtInfoPolicy = 0; dwResult = AddSingleRoute(pIcb->dwIfIndex, &rifRoute, CLASSA_MASK, 0, // RTM_ROUTE_INFO::Flags FALSE, // We dont know what protocols might do FALSE, // No need to add to stack FALSE, NULL); // // Now we need to go through all the bindings that are there // and add the loopback route for them. We do this here because // the loopback interface may be add AFTER the other interfaces // // // NOTE - this is going to take a lock recursively when it goes // to rtmif.c // ENTER_READER(BINDING_LIST); for(i = 0; i < BINDING_HASH_TABLE_SIZE; i++) { for(pleNode = g_leBindingTable[i].Flink; pleNode isnot &g_leBindingTable[i]; pleNode = pleNode->Flink) { PADAPTER_INFO pBinding; pBinding = CONTAINING_RECORD(pleNode, ADAPTER_INFO, leHashLink); for(j = 0; j < pBinding->dwNumAddresses; j++) { if(pBinding->rgibBinding[j].dwAddress is INVALID_IP_ADDRESS) { continue; } AddLoopbackRoute( pBinding->rgibBinding[j].dwAddress, pBinding->rgibBinding[j].dwMask ); } } } EXIT_LOCK(BINDING_LIST); return NO_ERROR; } #ifdef KSL_IPINIP DWORD IpIpTunnelInitToDown( PICB pIcb ) { return NO_ERROR; } #endif //KSL_IPINIP DWORD LanEtcInterfaceInitToDown( PICB pIcb ) { DWORD dwResult, dwNumAddresses, dwMask; PICB_BINDING pBinding; DWORD dwIfIndex = INVALID_IF_INDEX,dwBCastBit,dwReasmSize; DWORD i; MIB_IFROW riInBuffer; PWCHAR pwszName; PLIST_ENTRY ple; PROUTE_LIST_ENTRY prl; IPRouteEntry *pRouteEntry; TraceEnter("LanInterfaceInitToDown"); dwNumAddresses = 0; pBinding = NULL; pwszName = pIcb->pwszName; dwResult = ReadAddressFromRegistry(pwszName, &dwNumAddresses, &pBinding, FALSE); if(dwResult isnot NO_ERROR) { // // If there is no data, means the lan card wasnot UP anyway // if(dwResult is ERROR_NO_DATA) { return NO_ERROR; } Trace2(ERR, "LanInterfaceInitToDown: Error %d reading IP Address information for interface %S", dwResult, pIcb->pwszName); return dwResult; } // // Make sure you will find an adapter index. Otherwise all this is no use // for(i = 0; i < dwNumAddresses; i++) { // // Try to get an index using all possible addresses // dwResult = GetAdapterInfo(pBinding[i].dwAddress, &dwIfIndex, &dwBCastBit, &dwReasmSize); if(dwResult is NO_ERROR) { // // Ok so we found a valid index from a good address // break; } } if((dwIfIndex is INVALID_IF_INDEX) or (dwIfIndex isnot pIcb->dwIfIndex)) { Trace2(ERR, "LanInterfaceInitToDown: Couldnt find adapter index for interface %S using %d.%d.%d.%d", pIcb->pwszName, PRINT_IPADDR(pBinding[0].dwAddress)); HeapFree(IPRouterHeap, 0, pBinding); return ERROR_CAN_NOT_COMPLETE; } // // Delete all the routes in the stack // for (ple = g_leStackRoutesToRestore.Flink; ple != &g_leStackRoutesToRestore; ple = ple->Flink) { prl = (PROUTE_LIST_ENTRY) CONTAINING_RECORD(ple, ROUTE_LIST_ENTRY, leRouteList); TraceRoute2( ROUTE, "%d.%d.%d.%d/%d.%d.%d.%d", PRINT_IPADDR( prl->mibRoute.dwForwardDest ), PRINT_IPADDR( prl->mibRoute.dwForwardMask ) ); if(prl->mibRoute.dwForwardIfIndex isnot dwIfIndex) { // // Not going out over this interface // continue; } prl->mibRoute.dwForwardType = MIB_IPROUTE_TYPE_INVALID; dwResult = SetIpForwardEntryToStack(&(prl->mibRoute)); if (dwResult isnot NO_ERROR) { Trace2(ERR, "ReinstallOldRoutes: Failed to add route to %x from " " init table. Error %x", prl->mibRoute.dwForwardDest, dwResult); } } // // Dont really need it anymore // HeapFree(IPRouterHeap, 0, pBinding); // // Going from up to down // riInBuffer.dwIndex = dwIfIndex; riInBuffer.dwAdminStatus = IF_ADMIN_STATUS_DOWN; dwResult = SetIfEntryToStack(&riInBuffer, TRUE); if(dwResult isnot NO_ERROR) { Trace1(ERR, "LanInterfaceInitToDown: Couldnt set IFEntry for %S", pIcb->pwszName); } DeleteAllRoutes(pIcb->dwIfIndex, FALSE); return dwResult; } DWORD GetIpInfoForInterface( IN DWORD dwIfIndex, OUT PULONG pulNumAddresses, OUT ICB_BINDING **ppAddresses, OUT PDWORD pdwBCastBit, OUT PDWORD pdwReasmSize ) /*++ Routine Description Gets the addresses and other ip information for an interface Locks None needed Arguments dwIfIndex, pdwNumAddresses ppAddresses pdwBCastBit pdwReasmSize Return Value NO_ERROR Win32 Errorcode --*/ { DWORD dwResult, i; ULONG ulAddrIndex, ulCount, ulValid; PMIB_IPADDRTABLE pAddrTable; *pulNumAddresses = 0; *pdwBCastBit = 1; *pdwReasmSize = 0; *ppAddresses = NULL; dwResult = AllocateAndGetIpAddrTableFromStack(&pAddrTable, TRUE, IPRouterHeap, 0); if(dwResult isnot NO_ERROR) { Trace1(ERR, "GetIpInfoForInterface: Error %d getting IP Address table from stack", dwResult); return dwResult; } ulCount = 0; ulValid = 0; for (i = 0; i < pAddrTable->dwNumEntries; i++) { if(pAddrTable->table[i].dwIndex is dwIfIndex) { ulCount++; if(!(IsValidIpAddress(pAddrTable->table[i].dwAddr)) or (pAddrTable->table[i].dwMask is 0)) { // // Since this is only called for numbered links // continue; } // // Make sure this is not a duplicate. Since this is ordered, we // merely check the next address // if((i isnot (pAddrTable->dwNumEntries - 1)) and (pAddrTable->table[i].dwAddr is pAddrTable->table[i + 1].dwAddr)) { Trace1(ERR, "GetIpInfoForInterface: %d.%d.%d.%d duplicate address", PRINT_IPADDR(pAddrTable->table[i].dwAddr)); continue; } ulValid++; } } // // See if we have good addresses // if(ulValid is 0) { if(ulCount isnot 0) { Trace1(ERR, "GetIpInfoForInterface: If 0x%x has addresses entries which are 0s", dwIfIndex); } HeapFree(IPRouterHeap, 0, pAddrTable); return ERROR_NO_DATA; } // // Allocate from private heap // *ppAddresses = HeapAlloc(IPRouterHeap, HEAP_ZERO_MEMORY, (sizeof(ICB_BINDING) * ulValid)); if(*ppAddresses is NULL) { Trace0(ERR, "GetIpInfoForInterface: Error allocating memory"); HeapFree(IPRouterHeap, 0, pAddrTable); return ERROR_NOT_ENOUGH_MEMORY; } // // Now copy out the valid addresses // ulAddrIndex = 0; for (i = 0; i < pAddrTable->dwNumEntries; i++) { if(pAddrTable->table[i].dwIndex is dwIfIndex) { if(!(IsValidIpAddress(pAddrTable->table[i].dwAddr)) or (pAddrTable->table[i].dwMask is 0)) { continue; } if((i isnot (pAddrTable->dwNumEntries - 1)) and (pAddrTable->table[i].dwAddr is pAddrTable->table[i + 1].dwAddr)) { continue; } if(!(*pdwReasmSize)) { *pdwReasmSize = pAddrTable->table[i].dwReasmSize; *pdwBCastBit = pAddrTable->table[i].dwBCastAddr; } (*ppAddresses)[ulAddrIndex].dwAddress = pAddrTable->table[i].dwAddr; (*ppAddresses)[ulAddrIndex].dwMask = pAddrTable->table[i].dwMask; ulAddrIndex++; } } IpRtAssert(ulAddrIndex is ulValid); *pulNumAddresses = ulValid; HeapFree(IPRouterHeap, 0, pAddrTable); return NO_ERROR; } DWORD ReadAddressFromRegistry( IN PWCHAR pwszIfName, OUT PDWORD pdwNumAddresses, OUT ICB_BINDING **ppibAddressInfo, IN BOOL bInternalIf ) { HKEY hadapkey ; CHAR buff[512], pszInterfaceName[256]; DWORD dwDhcp, dwResult, dwSize, dwType; TraceEnter("ReadAddressFromRegistry"); Trace1(IF, "ReadAddressFromRegistry: Reading address for %S", pwszIfName); wcstombs(pszInterfaceName, pwszIfName, wcslen(pwszIfName)); pszInterfaceName[wcslen(pwszIfName)] = '\0'; *pdwNumAddresses = 0; *ppibAddressInfo = NULL; // // The IP address should be in the registry // strcpy(buff, REG_KEY_TCPIP_INTERFACES); strcat(buff,"\\"); strcat(buff, pszInterfaceName) ; dwResult = RegOpenKey(HKEY_LOCAL_MACHINE, buff, &hadapkey); if(dwResult isnot NO_ERROR) { Trace1(ERR, "ReadAddressFromRegistry: Unable to open key %s", buff); return dwResult; } dwDhcp = 0; if(!bInternalIf) { // // Get the EnableDHCP flag // dwSize = sizeof(DWORD); dwResult = RegQueryValueEx(hadapkey, REGISTRY_ENABLE_DHCP, NULL, &dwType, (PBYTE)&dwDhcp, &dwSize); if(dwResult isnot NO_ERROR) { Trace0(ERR, "ReadAddressFromRegistry: Unable to read DHCP Enabled key"); RegCloseKey(hadapkey); return dwResult; } } else { // // tcpcfg writes server adapter address as DHCP but // does not set dhcp enable // dwDhcp = 1; } // // Get the ip address for the net interface // dwSize = 0 ; if(dwDhcp == 0) { dwResult = ReadAddressAndMaskValues(hadapkey, REGISTRY_IPADDRESS, REGISTRY_SUBNETMASK, ppibAddressInfo, pdwNumAddresses); } else { // // First try autonet, and if that fails, read the DHCP // This needs to be done because the DHCP address is not cleared // out when running in autonet mode, but the autonet address is set // to 0.0.0.0 when in DHCP mode // dwResult = ReadAddressAndMaskValues(hadapkey, REGISTRY_AUTOCONFIGIPADDRESS, REGISTRY_AUTOCONFIGSUBNETMASK, ppibAddressInfo, pdwNumAddresses); if(dwResult isnot NO_ERROR) { dwResult = ReadAddressAndMaskValues(hadapkey, REGISTRY_DHCPIPADDRESS, REGISTRY_DHCPSUBNETMASK, ppibAddressInfo, pdwNumAddresses); } } RegCloseKey(hadapkey); if(dwResult isnot NO_ERROR) { Trace3(ERR, "ReadAddressFromRegistry: Couldnt read address for %S. Error %d. DHCP %d", pwszIfName, dwResult, dwDhcp); return dwResult; } else { #if DBG DWORD i; Trace2(IF, "--%d addresses on %S\n", *pdwNumAddresses, pwszIfName); for(i = 0; i < *pdwNumAddresses; i++) { Trace1(IF, "%d.%d.%d.%d", PRINT_IPADDR((*ppibAddressInfo)[i].dwAddress)); } #endif } return dwResult; } DWORD ReadAddressAndMaskValues( IN HKEY hkeyAdapterSection, IN PSZ pszRegAddressValue, IN PSZ pszRegMaskValue, OUT ICB_BINDING **ppibAddressInfo, OUT PDWORD pdwNumAddresses ) { DWORD dwResult, dwType; PBYTE pbyAddresses,pbyMasks; DWORD dwAddressSize, dwMaskSize; dwAddressSize = dwMaskSize = 0; dwResult = RegQueryValueEx(hkeyAdapterSection, pszRegAddressValue, NULL, &dwType, NULL, &dwAddressSize); if((dwAddressSize is 0) or (dwResult isnot NO_ERROR)) { Trace3(ERR, "ReadAddressAndMaskValues: Registry reported size = %d with error %d for size of %s", dwAddressSize, dwResult, pszRegAddressValue); return ERROR_REGISTRY_CORRUPT; } // // We allocate size+4 so that even if we read out a REG_SZ, it looks // like a REG_MULTI_SZ to the parse routine because we guarantee atleast // 2 terminating NULLS // pbyAddresses = HeapAlloc(IPRouterHeap, HEAP_ZERO_MEMORY, dwAddressSize + 4); if(pbyAddresses is NULL) { Trace2(ERR, "ReadAddressAndMaskValues: Error allocating %d bytes for %s", dwAddressSize + 4, pszRegAddressValue); return ERROR_NOT_ENOUGH_MEMORY; } dwResult = RegQueryValueEx(hkeyAdapterSection, pszRegAddressValue, NULL, &dwType, pbyAddresses, &dwAddressSize); if(dwResult isnot NO_ERROR) { HeapFree(IPRouterHeap, 0, pbyAddresses); Trace2(ERR, "ReadAddressAndMaskValues: Error %d reading %s from registry", dwResult, pszRegAddressValue); return dwResult; } // // Now get the subnet mask for the net interface // dwResult = RegQueryValueEx(hkeyAdapterSection, pszRegMaskValue, NULL, &dwType, NULL, &dwMaskSize); if((dwMaskSize is 0) or (dwResult isnot NO_ERROR)) { HeapFree(IPRouterHeap, 0, pbyAddresses); Trace3(ERR, "ReadAddressAndMaskValues: Registry reported size = %d with error %d for size of %s", dwMaskSize, dwResult, pszRegMaskValue); return ERROR_REGISTRY_CORRUPT; } pbyMasks = HeapAlloc(IPRouterHeap, HEAP_ZERO_MEMORY, dwMaskSize + 4); if(pbyMasks is NULL) { HeapFree(IPRouterHeap, 0, pbyAddresses); Trace2(ERR, "ReadAddressAndMaskValues: Error allocating %d bytes for %s", dwMaskSize + 4, pszRegMaskValue); return ERROR_NOT_ENOUGH_MEMORY; } dwResult = RegQueryValueEx(hkeyAdapterSection, pszRegMaskValue, NULL, &dwType, pbyMasks, &dwMaskSize) ; if(dwResult isnot NO_ERROR) { HeapFree(IPRouterHeap, 0, pbyAddresses); HeapFree(IPRouterHeap, 0, pbyMasks); Trace2(ERR, "ReadAddressAndMaskValues: Error %d reading %s from registry", dwResult, pszRegMaskValue); return dwResult; } dwResult = ParseAddressAndMask(pbyAddresses, dwAddressSize, pbyMasks, dwMaskSize, ppibAddressInfo, pdwNumAddresses); HeapFree(IPRouterHeap, 0, pbyAddresses); HeapFree(IPRouterHeap, 0, pbyMasks); return dwResult; } DWORD ParseAddressAndMask( IN PBYTE pbyAddresses, IN DWORD dwAddressSize, IN PBYTE pbyMasks, IN DWORD dwMaskSize, OUT ICB_BINDING **ppibAddressInfo, OUT PDWORD pdwNumAddresses ) { DWORD dwAddrCount, dwMaskCount, dwTempLen, dwAddrIndex; DWORD dwMask, dwAddr, i, j; PBYTE pbyTempAddr, pbyTempMask; BOOL bDuplicate; *pdwNumAddresses = 0; *ppibAddressInfo = NULL; // // If there are only two characters in the string or if the // the first two are NULL, we have no data. Due to tcp/ip config // we may be passed a REG_SZ instead of a REG_MULTI_SZ. The code works // around that by assuming that if a REG_SZ was read out then extra // padding was added to the end so that we ALWAYS have 2 terminating NULLs // if((dwAddressSize < 2) or ((pbyAddresses[0] is '\0') and (pbyAddresses[1] is '\0'))) { Trace0(IF, "ParseAddressAndMask: No addresses found"); return ERROR_NO_DATA; } // // The mask should also have some data // if((dwMaskSize < 2) or ((pbyMasks[0] is '\0') and (pbyMasks[1] is '\0'))) { Trace0(IF, "ParseAddressAndMask: No masks found"); return ERROR_NO_DATA; } // // Count the number of addresses // dwAddrCount = 0; pbyTempAddr = pbyAddresses; dwTempLen = dwAddressSize; while(dwTempLen) { if(*pbyTempAddr == '\0') { dwAddrCount++; if(*(pbyTempAddr+1) == '\0') { break; } } pbyTempAddr++ ; dwTempLen-- ; } if(dwAddrCount is 0) { Trace0(IF, "ParseAddressAndMask: No addresses found"); return ERROR_NO_DATA; } // // Count the number of masks // dwMaskCount = 0; pbyTempMask = pbyMasks; dwTempLen = dwMaskSize; while(dwTempLen) { if(*pbyTempMask is '\0') { dwMaskCount++; if(*(pbyTempMask+1) is '\0') { break; } } pbyTempMask++ ; dwTempLen-- ; } // // Make sure that the two are the same // if(dwAddrCount isnot dwMaskCount) { Trace0(IF, "ParseAddressAndMask: Address and mask count is not same"); return ERROR_NO_DATA; } // // Allocate the memory required to store all the addresses // *ppibAddressInfo = HeapAlloc(IPRouterHeap, HEAP_ZERO_MEMORY, (sizeof(ICB_BINDING) * dwAddrCount)); if(*ppibAddressInfo is NULL) { Trace1(ERR, "ParseAddressAndMask: Error allocating %d bytes for AddressInfo", sizeof(ICB_BINDING) * dwAddrCount); return ERROR_NOT_ENOUGH_MEMORY; } pbyTempAddr = pbyAddresses; pbyTempMask = pbyMasks; dwAddrIndex = 0; for (i = 0; i < dwAddrCount; i++) { dwAddr = inet_addr(pbyTempAddr); dwMask = inet_addr(pbyTempMask); pbyTempAddr = strchr(pbyTempAddr, '\0'); pbyTempMask = strchr(pbyTempMask, '\0'); pbyTempAddr++; pbyTempMask++; bDuplicate = FALSE; for(j = 0; j < dwAddrIndex; j++) { if((*ppibAddressInfo)[j].dwAddress is dwAddr) { Trace1(ERR, "ParseAddressAndMask: Addr %x is duplicate", dwAddr); bDuplicate = TRUE; break; } } if(bDuplicate or (dwAddr is INVALID_IP_ADDRESS) or (dwMask is 0x00000000)) { continue; } (*ppibAddressInfo)[dwAddrIndex].dwAddress = dwAddr; (*ppibAddressInfo)[dwAddrIndex].dwMask = dwMask; dwAddrIndex++; } *pdwNumAddresses = dwAddrIndex; // // Make sure that there is atleast one valid address // if(dwAddrIndex is 0) { Trace0(ERR, "ParseAddressAndMask: No valid addresses found"); HeapFree(IPRouterHeap, 0, *ppibAddressInfo); *ppibAddressInfo = NULL; return ERROR_NO_DATA; } return NO_ERROR; } DWORD SetInterfaceReceiveType( IN DWORD dwProtocolId, IN DWORD dwIfIndex, IN DWORD dwInterfaceReceiveType, IN BOOL bActivate ) { DWORD dwResult; IO_STATUS_BLOCK ioStatus; IP_SET_IF_PROMISCUOUS_INFO PromInfo; HANDLE hEvent; hEvent = CreateEvent(NULL,FALSE,FALSE,NULL); if(hEvent is NULL) { dwResult = GetLastError(); Trace1(ERR, "SetInterfaceReceiveType: Error %d creating event", dwResult); return dwResult; } if(dwInterfaceReceiveType is IR_PROMISCUOUS_MULTICAST) { PromInfo.Type = PROMISCUOUS_MCAST; } else { if(dwInterfaceReceiveType is IR_PROMISCUOUS) { PromInfo.Type = PROMISCUOUS_BCAST; } else { return ERROR_INVALID_PARAMETER; } } PromInfo.Index = dwIfIndex; PromInfo.Add = bActivate?1:0; dwResult = NtDeviceIoControlFile(g_hIpDevice, hEvent, NULL, NULL, &ioStatus, IOCTL_IP_SET_IF_PROMISCUOUS, (PVOID)&PromInfo, sizeof(IP_SET_IF_PROMISCUOUS_INFO), NULL, 0); if(dwResult is STATUS_PENDING) { Trace0(ERR, "SetInterfaceReceiveType: Pending from ioctl"); dwResult = WaitForSingleObject(hEvent, INFINITE); if(dwResult isnot WAIT_OBJECT_0) // 0 { Trace1(ERR, "SetInterfaceReceiveType: Error %d from wait", dwResult); dwResult = GetLastError(); } else { dwResult = STATUS_SUCCESS; } } if(dwResult isnot STATUS_SUCCESS) { Trace4(ERR, "SetInterfaceReceiveType: NtStatus %x while %s i/f %x into %s mode", dwResult, (PromInfo.Add == 1) ? "activating" : "deactivating", dwIfIndex, (PromInfo.Type == PROMISCUOUS_MCAST) ? "prom mcast" : "prom all"); return dwResult; } return NO_ERROR; } DWORD HandleMediaSenseEvent( IN PICB pIcb, IN BOOL bSensed ) /*++ Routine Description: Called when media sense status changes for a LAN interface Locks: Called with the ICB list lock held as WRITER Arguments: pIcb ICB of the interface for which the event it bSensed TRUE is cable is present Return Value: NO_ERROR --*/ { DWORD dwErr; return NO_ERROR; // // Not for NT 5.0 // if(pIcb->ritType isnot ROUTER_IF_TYPE_DEDICATED) { IpRtAssert(FALSE); return ERROR_INVALID_PARAMETER; } if(bSensed) { // // Bring the interface up // dwErr = LanEtcInterfaceDownToUp(pIcb, FALSE); } else { dwErr = LanEtcInterfaceUpToDown(pIcb, FALSE); } if(dwErr isnot NO_ERROR) { Trace2(ERR, "HandleMediaSense: Err %d when changing status for %S", dwErr, pIcb->pwszName); } return dwErr; } DWORD GetRouterId() { PLIST_ENTRY pleNode; PICB picb; ULONG ulIdx; DWORD dwRouterId = -1; // lower is better DWORD dwRouterTypePri = -1; // lower is better DWORD dwTypePri; TraceEnter("GetRouterId"); ENTER_READER(ICB_LIST); for (pleNode = ICBList.Flink; // walk the ICBList pleNode isnot &ICBList; pleNode = pleNode->Flink) { picb = CONTAINING_RECORD (pleNode, ICB, leIfLink) ; // Get Type priority switch(picb->ritType) { case ROUTER_IF_TYPE_LOOPBACK : dwTypePri = 0; break; // best case ROUTER_IF_TYPE_INTERNAL : dwTypePri = 1; break; #ifdef KSL_IPINIP case ROUTER_IF_TYPE_TUNNEL1 : dwTypePri = 2; break; #endif //KSL_IPINIP case ROUTER_IF_TYPE_DEDICATED: dwTypePri = 2; break; default: dwTypePri = 10; break; // worst } // Walk addresses for (ulIdx=0; ulIdxdwNumAddresses; ulIdx++) { if (!IS_ROUTABLE(picb->pibBindings[ulIdx].dwAddress)) { continue; } // update if better if (dwTypePri < dwRouterTypePri || (dwTypePri==dwRouterTypePri && picb->pibBindings[ulIdx].dwAddresspibBindings[ulIdx].dwAddress; } } } // *** Exclusion End *** EXIT_LOCK(ICB_LIST); TraceLeave("GetRouterId"); return dwRouterId; } #if __PIX__ BOOL IsRemoteAddressPrivate( PICB pIcb ) /*++ Routine Description: Checks to see if the address of the remote end point of the DoD (VPN/PPP) interface is private. This is done by querying the TCPIP stack for the forwarding table and ensuring that a host route does not already exist for the remote end-point. This is at best a heuristic to solve the following problem: - Third party VPN/PPP servers e.g. Cisco PIX firewall return the public address rather than the address of the PPP interface or the private network address as the remote address of the PPP link. - Adding a host route to the public address of the VPN/PPP server over the PPP interface causes the host route added by PPTP (for its control traffic) to be overwritten. This causes PPTP control packets to be routed over the PPP interface rather than the public interface. This in turn causes the control traffic to loop in the TCPIP stack and never make it to the other end. --*/ { DWORD dwErr, dwSize = 0, dwCount = 0; MIB_IPFORWARDROW mibRoute; TraceEnter("IsRemoteAddressPrivate"); // // Query stack for route table // SecureZeroMemory(&mibRoute, sizeof(MIB_IPFORWARDROW)); dwErr = GetBestRouteFromStack( pIcb->dwRemoteAddress, 0, &mibRoute ); if(dwErr isnot NO_ERROR) { Trace1( ERR, "IsRemoteAddressPrivate: error %d querying best route", dwErr ); TraceLeave("IsRemoteAddressPrivate"); return FALSE; } TraceRoute4( ROUTE, "%d.%d.%d.%d/%d.%d.%d.%d via %d.%d.%d.%d over %d", PRINT_IPADDR( mibRoute.dwForwardDest ), PRINT_IPADDR( mibRoute.dwForwardMask ), PRINT_IPADDR( mibRoute.dwForwardNextHop ), mibRoute.dwForwardIfIndex ); // // Check if this is host route and that is dest is the remote address // if((mibRoute.dwForwardMask is ALL_ONES_MASK) and (mibRoute.dwForwardDest is pIcb->dwRemoteAddress)) { // // A host route to the remote address of the PPP interface // is already present // Trace0( IF, "IsRemoteAddressPrivate: matching host route already " "present in the stack" ); TraceLeave("IsRemoteAddressPrivate"); return FALSE; } Trace0( IF, "IsRemoteAddressPrivate: no matching host route present " "in the stack" ); TraceLeave("IsRemoteAddressPrivate"); return TRUE; } #endif