//============================================================================ // Copyright (c) 1995, Microsoft Corporation // // File: table.c // // History: // Abolade Gbadegesin Aug-8-1995 Created. // // V Raman Oct-3-1996 // Added code to create/delete/wait on // ITE_DeactivateEvent. Also added code to set // ITE_Flags when deactivate is pending. // // V Raman Oct-27-1996 // Removed deactivate event and made // DeactivateInterface synchronous // // interface table and peer table implementation //============================================================================ #include "pchrip.h" #pragma hdrstop DWORD CreateIfSocket(PIF_TABLE_ENTRY pITE); DWORD DeleteIfSocket(PIF_TABLE_ENTRY pITE); DWORD InsertIfByAddress(PIF_TABLE pTable, PIF_TABLE_ENTRY pITE); DWORD InsertPeerByAddress(PPEER_TABLE pTable, PPEER_TABLE_ENTRY pPTE); DWORD AddNeighborToIfConfig(DWORD dwRemoteAddress, PIF_TABLE_ENTRY pite); //---------------------------------------------------------------------------- // Function: CreateIfTable // // initializes an interface table //---------------------------------------------------------------------------- DWORD CreateIfTable( PIF_TABLE pTable ) { DWORD dwErr; PLIST_ENTRY phead, plstart, plend; // // initialize the multiple-reader/single-writer synchronization object // dwErr = CreateReadWriteLock(&pTable->IT_RWL); if (dwErr != NO_ERROR) { TRACE1(IF, "error %d creating read-write-lock", dwErr); return dwErr; } // // initialize the hash table // plstart = pTable->IT_HashTableByIndex; plend = plstart + IF_HASHTABLE_SIZE; for (phead = plstart; phead < plend; phead++) { InitializeListHead(phead); } // // initialize the lists ordered by address and by index // InitializeListHead(&pTable->IT_ListByAddress); InitializeListHead(&pTable->IT_ListByIndex); // // initialize the table's critical section // try { InitializeCriticalSection(&pTable->IT_CS); } except(EXCEPTION_EXECUTE_HANDLER) { dwErr = GetExceptionCode(); } // // Create timers for full updates and for triggered updates // if (!CreateTimerQueueTimer( &pTable->IT_FinishFullUpdateTimer, ig.IG_TimerQueueHandle, WorkerFunctionFinishFullUpdate, NULL, 10000000, 10000000, 0 )) { dwErr = GetLastError(); TRACE1(IF, "error %d creating finish full update timer", dwErr); return dwErr; } if (!CreateTimerQueueTimer( &pTable->IT_FinishTriggeredUpdateTimer, ig.IG_TimerQueueHandle, WorkerFunctionFinishTriggeredUpdate, NULL, 10000000, 10000000, 0 )) { dwErr = GetLastError(); TRACE1(IF, "error %d creating finish triggered update timer", dwErr); return dwErr; } // // initialize remainder of struct // if (dwErr == NO_ERROR) { pTable->IT_Created = 0x12345678; pTable->IT_Flags = 0; pTable->IT_LastUpdateTime.LowPart = pTable->IT_LastUpdateTime.HighPart = 0; } return dwErr; } //---------------------------------------------------------------------------- // Function: DeleteIfTable // // frees resources used by an interface table. // this assumes the table is locked for writing //---------------------------------------------------------------------------- DWORD DeleteIfTable( PIF_TABLE pTable ) { DWORD dwIndex; PIF_TABLE_ENTRY pite; PLIST_ENTRY ple, plend, phead; // // free memory for all existing interfaces // plend = pTable->IT_HashTableByIndex + IF_HASHTABLE_SIZE; for (ple = plend - IF_HASHTABLE_SIZE; ple < plend; ple++) { while (!IsListEmpty(ple)) { phead = RemoveHeadList(ple); pite = CONTAINING_RECORD(phead, IF_TABLE_ENTRY, ITE_HTLinkByIndex); if (IF_IS_BOUND(pite)) { DeleteIfSocket(pite); if (IF_IS_ENABLED(pite)) { RemoveEntryList(&pite->ITE_LinkByAddress); } RIP_FREE(pite->ITE_Binding); } RIP_FREE(pite->ITE_Config); RIP_FREE(pite); } } // // delete synchronization objects // DeleteCriticalSection(&pTable->IT_CS); DeleteReadWriteLock(&pTable->IT_RWL); pTable->IT_Created = 0; pTable->IT_Flags = 0; return NO_ERROR; } //---------------------------------------------------------------------------- // Function: CreateIfEntry // // inserts an entry into the interface table. // this assumes the table is locked for writing //---------------------------------------------------------------------------- DWORD CreateIfEntry( PIF_TABLE pTable, DWORD dwIndex, NET_INTERFACE_TYPE dwIfType, PIPRIP_IF_CONFIG pConfig, PIF_TABLE_ENTRY *ppEntry ) { DWORD dwErr, dwSize; PIF_TABLE_ENTRY pite; PLIST_ENTRY ple, phead; PIPRIP_IF_CONFIG picsrc, picdst; if (ppEntry != NULL) { *ppEntry = NULL; } dwErr = NO_ERROR; do { // // fail if the interface exists // pite = GetIfByIndex(pTable, dwIndex); if (pite != NULL) { pite = NULL; TRACE1(IF, "interface %d already exists", dwIndex); dwErr = ERROR_INVALID_PARAMETER; break; } // // allocate memory for the new interface // pite = RIP_ALLOC(sizeof(IF_TABLE_ENTRY)); if (pite == NULL) { dwErr = GetLastError(); TRACE3( ANY, "error %d allocating %d bytes for interface %d", dwErr, sizeof(IF_TABLE_ENTRY), dwIndex ); LOGERR0(HEAP_ALLOC_FAILED, dwErr); break; } // // initialize interface fields // pite->ITE_Index = dwIndex; pite->ITE_Type = dwIfType; // // Change semantics to come up in UNBOUND-DISABLED state // //pite->ITE_Flags = ITEFLAG_ENABLED; pite-> ITE_Flags = 0; pite->ITE_Config = NULL; pite->ITE_Binding = NULL; pite->ITE_Sockets = NULL; pite->ITE_FullOrDemandUpdateTimer = NULL; picsrc = (PIPRIP_IF_CONFIG)pConfig; dwSize = IPRIP_IF_CONFIG_SIZE(picsrc); // // validate the configuration parameters // dwErr = ValidateIfConfig(pConfig); if (dwErr != NO_ERROR) { TRACE1(IF, "invalid config specified for interface %d", dwIndex); break; } // // allocate space to hold the interface configuration // pite->ITE_Config = picdst = RIP_ALLOC(dwSize); if (picdst == NULL) { dwErr = GetLastError(); TRACE3( IF, "error %d allocating %d bytes for interface %d config", dwErr, dwSize, dwIndex ); LOGERR0(HEAP_ALLOC_FAILED, dwErr); break; } // // copy the configuration // CopyMemory(picdst, picsrc, dwSize); // // initialize the binding information and interface stats // pite->ITE_Binding = NULL; ZeroMemory(&pite->ITE_Stats, sizeof(IPRIP_IF_STATS)); // // insert the interface in the hash table // InsertHeadList( pTable->IT_HashTableByIndex + IF_HASHVALUE(dwIndex), &pite->ITE_HTLinkByIndex ); // // insert the interface in the list ordered by index // phead = &pTable->IT_ListByIndex; for (ple = phead->Flink; ple != phead; ple = ple->Flink) { PIF_TABLE_ENTRY ptemp; ptemp = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_LinkByIndex); if (pite->ITE_Index < ptemp->ITE_Index) { break; } } InsertTailList(ple, &pite->ITE_LinkByIndex); if (ppEntry != NULL) { *ppEntry = pite; } } while(FALSE); if (dwErr != NO_ERROR && pite != NULL) { if (pite->ITE_Config != NULL) { RIP_FREE(pite->ITE_Config); } RIP_FREE(pite); } return dwErr; } //---------------------------------------------------------------------------- // Function: DeleteIfEntry // // removes an entry from the interface table. // this assumes the table is locked for writing //---------------------------------------------------------------------------- DWORD DeleteIfEntry( PIF_TABLE pTable, DWORD dwIndex ) { PIF_TABLE_ENTRY pite; // // find the interface if it exists // pite = GetIfByIndex(pTable, dwIndex); if (pite == NULL) { TRACE1(IF, "could not find interface %d", dwIndex); return ERROR_INVALID_PARAMETER; } // // cleanup the socket depending on its state // if (IF_IS_BOUND(pite)) { DeleteIfSocket(pite); if (IF_IS_ENABLED(pite)) { RemoveEntryList(&pite->ITE_LinkByAddress); } RIP_FREE(pite->ITE_Binding); } // // remove it from the list ordered by index // as well as from the hash table // RemoveEntryList(&pite->ITE_LinkByIndex); RemoveEntryList(&pite->ITE_HTLinkByIndex); RIP_FREE(pite->ITE_Config); RIP_FREE(pite); return NO_ERROR; } //---------------------------------------------------------------------------- // Function: ValidateIfConfig // // Checks the parameters in an IPRIP_IF_CONFIG structure. //---------------------------------------------------------------------------- DWORD ValidateIfConfig( PIPRIP_IF_CONFIG pic ) { CHAR szStr[12]; if (pic->IC_Metric > IPRIP_INFINITE) { TRACE1( IF, "Invalid interface metric %d specified", pic->IC_Metric ); _ltoa(pic->IC_Metric, szStr, 10); LOGERR2( INVALID_IF_CONFIG, "Metric", szStr, ERROR_INVALID_PARAMETER ); return ERROR_INVALID_PARAMETER; } if (pic->IC_UpdateMode != IPRIP_UPDATE_PERIODIC && pic->IC_UpdateMode != IPRIP_UPDATE_DEMAND) { TRACE1( IF, "Invalid update mode %d specified", pic->IC_UpdateMode ); _ltoa(pic->IC_UpdateMode, szStr, 10); LOGERR2( INVALID_IF_CONFIG, "Update Mode", szStr, ERROR_INVALID_PARAMETER ); return ERROR_INVALID_PARAMETER; } if (pic->IC_AcceptMode != IPRIP_ACCEPT_DISABLED && pic->IC_AcceptMode != IPRIP_ACCEPT_RIP1 && pic->IC_AcceptMode != IPRIP_ACCEPT_RIP1_COMPAT && pic->IC_AcceptMode != IPRIP_ACCEPT_RIP2) { TRACE1( IF, "Invalid accept mode %d specified", pic->IC_AcceptMode ); _ltoa(pic->IC_AcceptMode, szStr, 10); LOGERR2( INVALID_IF_CONFIG, "Accept Mode", szStr, ERROR_INVALID_PARAMETER ); return ERROR_INVALID_PARAMETER; } if (pic->IC_AnnounceMode != IPRIP_ANNOUNCE_DISABLED && pic->IC_AnnounceMode != IPRIP_ANNOUNCE_RIP1 && pic->IC_AnnounceMode != IPRIP_ANNOUNCE_RIP1_COMPAT && pic->IC_AnnounceMode != IPRIP_ANNOUNCE_RIP2) { TRACE1( IF, "Invalid announce mode %d specified", pic->IC_AnnounceMode ); _ltoa(pic->IC_AnnounceMode, szStr, 10); LOGERR2( INVALID_IF_CONFIG, "Announce Mode", szStr, ERROR_INVALID_PARAMETER ); return ERROR_INVALID_PARAMETER; } if (pic->IC_AuthenticationType != IPRIP_AUTHTYPE_NONE && pic->IC_AuthenticationType != IPRIP_AUTHTYPE_SIMPLE_PASSWORD) { TRACE1( IF, "Invalid authentication type %d specified", pic->IC_AuthenticationType ); _ltoa(pic->IC_AuthenticationType, szStr, 10); LOGERR2( INVALID_IF_CONFIG, "Authentication Type", szStr, ERROR_INVALID_PARAMETER ); return ERROR_INVALID_PARAMETER; } if (pic->IC_UnicastPeerMode != IPRIP_PEER_DISABLED && pic->IC_UnicastPeerMode != IPRIP_PEER_ALSO && pic->IC_UnicastPeerMode != IPRIP_PEER_ONLY) { TRACE1( IF, "Invalid unicast peer mode %d specified", pic->IC_UnicastPeerMode ); _ltoa(pic->IC_UnicastPeerMode, szStr, 10); LOGERR2( INVALID_IF_CONFIG, "unicast peer mode", szStr, ERROR_INVALID_PARAMETER ); return ERROR_INVALID_PARAMETER; } if (pic->IC_AcceptFilterMode != IPRIP_FILTER_DISABLED && pic->IC_AcceptFilterMode != IPRIP_FILTER_INCLUDE && pic->IC_AcceptFilterMode != IPRIP_FILTER_EXCLUDE) { TRACE1( IF, "Invalid accept filter mode %d specified", pic->IC_AcceptFilterMode ); _ltoa(pic->IC_AcceptFilterMode, szStr, 10); LOGERR2( INVALID_IF_CONFIG, "Accept filter mode", szStr, ERROR_INVALID_PARAMETER ); return ERROR_INVALID_PARAMETER; } if (pic->IC_AnnounceFilterMode != IPRIP_FILTER_DISABLED && pic->IC_AnnounceFilterMode != IPRIP_FILTER_INCLUDE && pic->IC_AnnounceFilterMode != IPRIP_FILTER_EXCLUDE) { TRACE1( IF, "Invalid announce filter mode %d specified", pic->IC_AnnounceFilterMode ); _ltoa(pic->IC_AnnounceFilterMode, szStr, 10); LOGERR2( INVALID_IF_CONFIG, "Announce filter mode", szStr, ERROR_INVALID_PARAMETER ); return ERROR_INVALID_PARAMETER; } return NO_ERROR; } //---------------------------------------------------------------------------- // Function: BindIfEntry // // Updates the binding information for the specified interface. // Assumes interface table is locked for writing //---------------------------------------------------------------------------- DWORD BindIfEntry( PIF_TABLE pTable, DWORD dwIndex, PIP_ADAPTER_BINDING_INFO pBinding ) { DWORD i, j, dwErr = NO_ERROR, dwSize; PIF_TABLE_ENTRY pite; PIPRIP_IF_BINDING pib; PIPRIP_IP_ADDRESS paddr; PIP_ADAPTER_BINDING_INFO piabi; BOOL bFound; pib = NULL; do { // // retrieve the interface entry // pite = GetIfByIndex(pTable, dwIndex); if (pite == NULL) { dwErr = ERROR_INVALID_PARAMETER; break; } // // If the interface is already bound, check to see if he is giving // us a different binding. If he is, then it is an error. Otherwise // we shall be obliging and not complain too much // if (IF_IS_BOUND(pite)) { TRACE1(IF, "interface %d is already bound", dwIndex); pib = pite->ITE_Binding; if(pib->IB_AddrCount != pBinding->AddressCount) { TRACE1(IF, "interface %d is bound and has different binding",dwIndex); dwErr = ERROR_INVALID_PARAMETER; break; } paddr = IPRIP_IF_ADDRESS_TABLE(pib); for(i = 0; i < pBinding->AddressCount; i++) { bFound = FALSE; for(j = 0; j < pib->IB_AddrCount; j++) { if((paddr[j].IA_Address == pBinding->Address[i].Address) && (paddr[j].IA_Netmask == pBinding->Address[i].Mask)) { bFound = TRUE; break; } } if(!bFound) { TRACE1(IF,"interface %d is bound and has different binding",dwIndex); dwErr = ERROR_INVALID_PARAMETER; break; } } // // At this time we have dwErr as either NO_ERROR or // ERROR_INVALID_PARAMETER. Either case we can break here // since we are done // break; } // // make sure there is at least one address // if (pBinding->AddressCount == 0) { break; } dwSize = sizeof(IPRIP_IF_BINDING) + pBinding->AddressCount * sizeof(IPRIP_IP_ADDRESS); // // allocate memory to store the binding // in our format // pib = RIP_ALLOC(dwSize); if (pib == NULL) { dwErr = GetLastError(); TRACE3( IF, "error %d allocating %d bytes for binding on interface %d", dwErr, dwSize, dwIndex ); LOGERR0(HEAP_ALLOC_FAILED, dwErr); break; } // // convert the binding into our format // pib->IB_AddrCount = pBinding->AddressCount; paddr = IPRIP_IF_ADDRESS_TABLE(pib); for (i = 0; i < pib->IB_AddrCount; i++, paddr++) { paddr->IA_Address = pBinding->Address[i].Address; paddr->IA_Netmask = pBinding->Address[i].Mask; } // // save the binding in the interface entry // pite->ITE_Binding = pib; #if 0 // // for demand dial interfaces add neighbor // if ( pite-> ITE_Type == DEMAND_DIAL ) { dwErr = AddNeighborToIfConfig( pBinding-> RemoteAddress, pite ); if ( dwErr != NO_ERROR ) { break ; } } #endif // // create sockets for interface's addresses // dwErr = CreateIfSocket(pite); if (dwErr != NO_ERROR) { TRACE2( IF, "error %d creating sockets for interface %d", dwErr, dwIndex ); break; } // // mark the interface as being bound // pite->ITE_Flags |= ITEFLAG_BOUND; // // we save the binding information in a private table // so it can be quickly accessed and searched when we are // trying to guess subnet masks given IP addresses; // ACQUIRE_BINDING_LOCK_EXCLUSIVE(); dwErr = CreateBindingEntry(ig.IG_BindingTable, pib); RELEASE_BINDING_LOCK_EXCLUSIVE(); // // if interface is also enabled, it is now active // so queue activation work-item // if (IF_IS_ENABLED(pite)) { // // place interface on the list of active interfaces // dwErr = InsertIfByAddress(pTable, pite); if (dwErr != NO_ERROR) { TRACE2( IF, "error %d inserting interface %d in active list", dwErr, dwIndex ); pite->ITE_Flags &= ~ITEFLAG_BOUND; DeleteIfSocket(pite); break; } // // queue the work-item to send initial request // dwErr = QueueRipWorker( WorkerFunctionActivateInterface, (PVOID)UlongToPtr(dwIndex) ); if (dwErr != NO_ERROR) { TRACE2( IF, "error %d queuing work-item for interface %d", dwErr, dwIndex ); LOGERR0(QUEUE_WORKER_FAILED, dwErr); RemoveEntryList(&pite->ITE_LinkByAddress); pite->ITE_Flags &= ~ITEFLAG_BOUND; DeleteIfSocket(pite); break; } } } while(FALSE); if (dwErr != NO_ERROR) { if (pib) { RIP_FREE(pib); } if (pite) { pite->ITE_Binding = NULL; } } return dwErr; } //---------------------------------------------------------------------------- // Function: UnBindIfEntry // // removes the binding for the specified interface. // assumes the interface table is locked for writing. //---------------------------------------------------------------------------- DWORD UnBindIfEntry( PIF_TABLE pTable, DWORD dwIndex ) { DWORD dwErr; PIF_TABLE_ENTRY pite; do { // // retrieve the interface specified // pite = GetIfByIndex(pTable, dwIndex); if (pite == NULL) { dwErr = ERROR_INVALID_PARAMETER; break; } // // quit if the interface is already unbound // if (IF_IS_UNBOUND(pite)) { dwErr = ERROR_INVALID_PARAMETER; TRACE1( IF, "interface %d is already unbound", dwIndex ); break; } // // clear the "bound" flag // pite->ITE_Flags &= ~ITEFLAG_BOUND; // // if the interface isn't enabled, close the socket for the interface; // if the interface is enabled, that means it was active // and we must queue the deactivation work-item // if (!IF_IS_ENABLED(pite)) { DeleteIfSocket(pite); ACQUIRE_BINDING_LOCK_EXCLUSIVE(); dwErr = DeleteBindingEntry(ig.IG_BindingTable, pite->ITE_Binding); RELEASE_BINDING_LOCK_EXCLUSIVE(); RIP_FREE(pite->ITE_Binding); pite->ITE_Binding = NULL; } else { // // the interface was active, so deactivate it // // remove from active list // RemoveEntryList(&pite->ITE_LinkByAddress); WorkerFunctionDeactivateInterface( (PVOID)UlongToPtr(dwIndex)); // // close the socket ourselves if required // if ( pite-> ITE_Binding ) { DeleteIfSocket(pite); ACQUIRE_BINDING_LOCK_EXCLUSIVE(); dwErr = DeleteBindingEntry( ig.IG_BindingTable, pite->ITE_Binding ); RELEASE_BINDING_LOCK_EXCLUSIVE(); RIP_FREE(pite->ITE_Binding); pite->ITE_Binding = NULL; } else { dwErr = NO_ERROR; } } } while(FALSE); return dwErr; } //---------------------------------------------------------------------------- // Function: EnableIfEntry // // configures an interface for RIP activity, including setting up // a socket and linking the interface into the list ordered by address. // this assumes the table is locked for writing //---------------------------------------------------------------------------- DWORD EnableIfEntry( PIF_TABLE pTable, DWORD dwIndex ) { DWORD dwErr; PLIST_ENTRY ple, phead; PIF_TABLE_ENTRY pite; do { // // retrieve the interface // pite = GetIfByIndex(pTable, dwIndex); if (pite == NULL) { TRACE1(IF, "could not find interface %d",dwIndex); dwErr = ERROR_INVALID_PARAMETER; break; } // // quit if the interface is already enabled // if (IF_IS_ENABLED(pite)) { TRACE1(IF, "interface %d is already enabled", dwIndex); dwErr = NO_ERROR; break; } pite->ITE_Flags |= ITEFLAG_ENABLED; // // if interface is already bound, it is now active, // so queue the interface activation work-item // if (IF_IS_BOUND(pite)) { // // place interface on the list of active interfaces // dwErr = InsertIfByAddress(pTable, pite); if (dwErr != NO_ERROR) { TRACE2( IF, "error %d inserting interface %d in active list", dwErr, dwIndex ); pite->ITE_Flags &= ~ITEFLAG_ENABLED; break; } // // queue the work-item to send initial request // dwErr = QueueRipWorker( WorkerFunctionActivateInterface, (PVOID)UlongToPtr(dwIndex) ); if (dwErr != NO_ERROR) { TRACE2( IF, "error %d queuing work-item for interface %d", dwErr, dwIndex ); LOGERR0(QUEUE_WORKER_FAILED, dwErr); RemoveEntryList(&pite->ITE_LinkByAddress); pite->ITE_Flags &= ~ITEFLAG_ENABLED; break; } } dwErr = NO_ERROR; } while(FALSE); return dwErr; } //---------------------------------------------------------------------------- // Function: ConfigureIfEntry // // modifies the configuration for an already-existing interface // this assumes the table is locked for writing //---------------------------------------------------------------------------- DWORD ConfigureIfEntry( PIF_TABLE pTable, DWORD dwIndex, PIPRIP_IF_CONFIG pConfig ) { DWORD dwErr, dwSize; PIF_TABLE_ENTRY pite; PIPRIP_IF_CONFIG picsrc, picdst; dwErr = NO_ERROR; do { // // retrieve the interface to be configured // pite = GetIfByIndex(pTable, dwIndex); if (pite == NULL) { TRACE1(IF, "could not find interface %d", dwIndex); dwErr = ERROR_INVALID_PARAMETER; break; } // // get the size of the new configuration // picsrc = (PIPRIP_IF_CONFIG)pConfig; dwSize = IPRIP_IF_CONFIG_SIZE(picsrc); // // validate the new configuration // dwErr = ValidateIfConfig(picsrc); if (dwErr != NO_ERROR) { TRACE1(IF, "invalid config specified for interface %d", dwIndex); break; } // // allocate space to hold the new configuration // picdst = RIP_ALLOC(dwSize); if (picdst == NULL) { dwErr = GetLastError(); TRACE3( IF, "error %d allocating %d bytes for interface %d config", dwErr, dwSize, dwIndex ); LOGERR0(HEAP_ALLOC_FAILED, dwErr); break; } // // copy the new configuration, and free the old one // CopyMemory(picdst, picsrc, dwSize); if (pite->ITE_Config != NULL) { RIP_FREE(pite->ITE_Config); } pite->ITE_Config = picdst; // // if the interface is bound, re-initialize the interface // if (IF_IS_BOUND(pite)) { // // close the sockets and set them up again // dwErr = DeleteIfSocket(pite); dwErr = CreateIfSocket(pite); if (dwErr != NO_ERROR) { TRACE2( IF, "error %d creating sockets for interface %d", dwErr, dwIndex ); break; } // // re-activate the interface if it is active // if (IF_IS_ENABLED(pite)) { // // queue the work-item to activate the interface // dwErr = QueueRipWorker( WorkerFunctionActivateInterface, (PVOID)UlongToPtr(dwIndex) ); if (dwErr != NO_ERROR) { TRACE2( IF, "error %d queueing work-item for interface %d", dwErr, dwIndex ); LOGERR0(QUEUE_WORKER_FAILED, dwErr); break; } } } dwErr = NO_ERROR; } while(FALSE); return dwErr; } //---------------------------------------------------------------------------- // Function: DisableIfEntry // // stops RIP activity on an interface, removing the interface // from the list of interfaces ordered by address. // this assumes the table is locked for writing //---------------------------------------------------------------------------- DWORD DisableIfEntry( PIF_TABLE pTable, DWORD dwIndex ) { DWORD dwErr; PIF_TABLE_ENTRY pite; do { // // retrieve the interface to be disabled // pite = GetIfByIndex(pTable, dwIndex); if (pite == NULL) { TRACE1(IF, "could not find interface %d", dwIndex); dwErr = ERROR_INVALID_PARAMETER; break; } // // quit if already disabled // if (IF_IS_DISABLED(pite)) { TRACE1(IF, "interface %d is already disabled", dwIndex); dwErr = ERROR_INVALID_PARAMETER; break; } // // clear the enabled flag // pite->ITE_Flags &= ~ITEFLAG_ENABLED; // // if this interface was not bound, clearing the flag is enough; // if the interface was bound (and therefore active), // deactivate it here // if (IF_IS_BOUND(pite)) { // // remove from active list // RemoveEntryList(&pite->ITE_LinkByAddress); // // execute the work-item to send final updates // WorkerFunctionDeactivateInterface( (PVOID) UlongToPtr(dwIndex) ); } dwErr = NO_ERROR; } while(FALSE); return dwErr; } //---------------------------------------------------------------------------- // Function: CreateIfSocket // // creates sockets for an interface, setting it up according to // the configuration including in the interface control block. // this assumes the table containing the interface is locked for writing //---------------------------------------------------------------------------- DWORD CreateIfSocket( PIF_TABLE_ENTRY pite ) { SOCKADDR_IN sinsock; PIPRIP_IF_CONFIG pic; PIPRIP_IF_BINDING pib; PIPRIP_IP_ADDRESS paddr; DWORD i, dwErr, dwOption, dwIndex; LPSTR lpszAddr; pic = pite->ITE_Config; pib = pite->ITE_Binding; dwIndex = pite->ITE_Index; // // allocate an array of sockets // pite->ITE_Sockets = RIP_ALLOC(pib->IB_AddrCount * sizeof(SOCKET)); if (pite->ITE_Sockets == NULL) { dwErr = GetLastError(); TRACE3( IF, "error %d allocating %d bytes for interface %d sockets", dwErr, pib->IB_AddrCount * sizeof(SOCKET), dwIndex ); LOGERR0(HEAP_ALLOC_FAILED, dwErr); return dwErr; } // // initialize the array of sockets // for (i = 0; i < pib->IB_AddrCount; i++) { pite->ITE_Sockets[i] = INVALID_SOCKET; } // // create sockets for each address in the binding // paddr = IPRIP_IF_ADDRESS_TABLE(pib); for (i = 0; i < pib->IB_AddrCount; i++, paddr++) { // // create the socket // pite->ITE_Sockets[i] = WSASocket( AF_INET, SOCK_DGRAM, 0, NULL, 0, 0 ); if (pite->ITE_Sockets[i] == INVALID_SOCKET) { dwErr = WSAGetLastError(); lpszAddr = INET_NTOA(paddr->IA_Address); if (lpszAddr != NULL) { TRACE3( IF, "error %d creating socket for interface %d (%s)", dwErr, dwIndex, lpszAddr ); LOGERR1(CREATE_SOCKET_FAILED_2, lpszAddr, dwErr); } break; } // // try to increase the recv buffer size // dwOption = RIPRECVBUFFERSIZE; dwErr = setsockopt( pite->ITE_Sockets[i], SOL_SOCKET, SO_RCVBUF, (PBYTE)&dwOption, sizeof(dwOption) ); if (dwErr == SOCKET_ERROR) { dwErr = WSAGetLastError(); lpszAddr = INET_NTOA(paddr->IA_Address); if (lpszAddr != NULL) { TRACE3( IF, "error %d setting SO_RCVBUF for interface %d (%s)", dwErr, dwIndex, INET_NTOA(paddr->IA_Address) ); } } // // try to allow re-use of this address // dwOption = 1; dwErr = setsockopt( pite->ITE_Sockets[i], SOL_SOCKET, SO_REUSEADDR, (PBYTE)&dwOption, sizeof(dwOption) ); if (dwErr == SOCKET_ERROR) { dwErr = WSAGetLastError(); lpszAddr = INET_NTOA(paddr->IA_Address); if (lpszAddr != NULL) { TRACE3( IF, "error %d setting re-use flag for interface %d (%s)", dwErr, dwIndex, INET_NTOA(paddr->IA_Address) ); } } // // enable broadcasting if not exclusively RIP2 mode, // or if there are any unicast peers configured // if (pic->IC_AcceptMode == IPRIP_ACCEPT_RIP1 || pic->IC_AcceptMode == IPRIP_ACCEPT_RIP1_COMPAT || pic->IC_AnnounceMode == IPRIP_ANNOUNCE_RIP1 || pic->IC_AnnounceMode == IPRIP_ANNOUNCE_RIP1_COMPAT || (pic->IC_UnicastPeerMode != IPRIP_PEER_DISABLED && pic->IC_UnicastPeerCount != 0)) { // // make sure broadcasting is enabled for this socket // dwOption = 1; dwErr = setsockopt( pite->ITE_Sockets[i], SOL_SOCKET, SO_BROADCAST, (PBYTE)&dwOption, sizeof(dwOption) ); if (dwErr == SOCKET_ERROR) { dwErr = WSAGetLastError(); lpszAddr = INET_NTOA(paddr->IA_Address); if (lpszAddr != NULL) { TRACE3( IF, "error %d enabling broadcast on interface %d (%s)", dwErr, dwIndex, lpszAddr ); LOGERR1(ENABLE_BROADCAST_FAILED, lpszAddr, dwErr); } break; } } // // bind the socket to the RIP port // sinsock.sin_family = AF_INET; sinsock.sin_port = htons(IPRIP_PORT); sinsock.sin_addr.s_addr = paddr->IA_Address; dwErr = bind( pite->ITE_Sockets[i], (LPSOCKADDR)&sinsock, sizeof(SOCKADDR_IN) ); if (dwErr == SOCKET_ERROR) { dwErr = WSAGetLastError(); lpszAddr = INET_NTOA(paddr->IA_Address); if (lpszAddr != NULL) { TRACE3( IF, "error %d binding on socket for interface %d (%s)", dwErr, dwIndex, lpszAddr ); LOGERR1(BIND_FAILED, lpszAddr, dwErr); } break; } // // enable multicasting if not exclusively RIP1/RIP1-compatible mode // if (pic->IC_AcceptMode == IPRIP_ACCEPT_RIP2 || pic->IC_AcceptMode == IPRIP_ACCEPT_RIP1_COMPAT || pic->IC_AnnounceMode == IPRIP_ANNOUNCE_RIP2) { struct ip_mreq imOption; // // set the interface from which multicasts must be sent // sinsock.sin_addr.s_addr = paddr->IA_Address; dwErr = setsockopt( pite->ITE_Sockets[i], IPPROTO_IP, IP_MULTICAST_IF, (PBYTE)&sinsock.sin_addr, sizeof(IN_ADDR) ); if (dwErr == SOCKET_ERROR) { dwErr = WSAGetLastError(); lpszAddr = INET_NTOA(paddr->IA_Address); if (lpszAddr != NULL) { TRACE3( IF, "error %d setting interface %d (%s) as multicast", dwErr, dwIndex, lpszAddr ); LOGERR1(SET_MCAST_IF_FAILED, lpszAddr, dwErr); } break; } // // join the IPRIP multicast group // imOption.imr_multiaddr.s_addr = IPRIP_MULTIADDR; imOption.imr_interface.s_addr = paddr->IA_Address; dwErr = setsockopt( pite->ITE_Sockets[i], IPPROTO_IP, IP_ADD_MEMBERSHIP, (PBYTE)&imOption, sizeof(imOption) ); if (dwErr == SOCKET_ERROR) { dwErr = WSAGetLastError(); lpszAddr = INET_NTOA(paddr->IA_Address); if (lpszAddr != NULL) { TRACE3( IF, "error %d enabling multicast on interface %d (%s)", dwErr, dwIndex, lpszAddr ); LOGERR1(JOIN_GROUP_FAILED, lpszAddr, dwErr); } break; } } dwErr = NO_ERROR; } if (i < pib->IB_AddrCount) { // // something failed if we are here // DeleteIfSocket(pite); } return dwErr; } //---------------------------------------------------------------------------- // Function: DeleteIfSocket // // closes the sockets used by an interface, if any. // assumes that the interface is active, and that the interface table // is locked for writing //---------------------------------------------------------------------------- DWORD DeleteIfSocket( PIF_TABLE_ENTRY pite ) { DWORD i; for (i = 0; i < pite->ITE_Binding->IB_AddrCount; i++) { if (pite->ITE_Sockets[i] != INVALID_SOCKET) { if (closesocket(pite->ITE_Sockets[i]) == SOCKET_ERROR) { TRACE1(IF, "error %d closing socket", WSAGetLastError()); } pite->ITE_Sockets[i] = INVALID_SOCKET; } } RIP_FREE(pite->ITE_Sockets); pite->ITE_Sockets = NULL; return NO_ERROR; } //---------------------------------------------------------------------------- // Function: GetIfByIndex // // returns the interface with the given index. // assumes the table is locked for reading or writing //---------------------------------------------------------------------------- PIF_TABLE_ENTRY GetIfByIndex( PIF_TABLE pTable, DWORD dwIndex ) { PIF_TABLE_ENTRY pite = NULL; PLIST_ENTRY phead, ple; phead = pTable->IT_HashTableByIndex + IF_HASHVALUE(dwIndex); for (ple = phead->Flink; ple != phead; ple = ple->Flink) { pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_HTLinkByIndex); if (pite->ITE_Index == dwIndex) { break; } } if (ple == phead) { return NULL; } else { return pite; } } //---------------------------------------------------------------------------- // Function: GetIfByAddress // // returns the interface bound to the given address. // assumes the table is locked for reading or writing //---------------------------------------------------------------------------- PIF_TABLE_ENTRY GetIfByAddress( PIF_TABLE pTable, DWORD dwAddress, DWORD dwGetMode, PDWORD pdwErr ) { DWORD i; PIPRIP_IF_BINDING pib; PLIST_ENTRY phead, pfl; PIPRIP_IP_ADDRESS paddr; PIF_TABLE_ENTRY pite, piterec; if (pdwErr != NULL) { *pdwErr = NO_ERROR; } phead = &pTable->IT_ListByAddress; pite = NULL; // // return record at head of list if mode is GetFirst // if (dwGetMode == GETMODE_FIRST) { if (phead->Flink == phead) { if (pdwErr != NULL) { *pdwErr = ERROR_NO_MORE_ITEMS; } return NULL; } else { pfl = phead->Flink; return CONTAINING_RECORD(pfl, IF_TABLE_ENTRY, ITE_LinkByAddress); } } // // search for the entry // for (pfl = phead->Flink; pfl != phead; pfl = pfl->Flink) { piterec = CONTAINING_RECORD(pfl, IF_TABLE_ENTRY, ITE_LinkByAddress); pib = piterec->ITE_Binding; paddr = IPRIP_IF_ADDRESS_TABLE(pib); for (i = 0; i < pib->IB_AddrCount; i++, paddr++) { if (dwAddress == paddr->IA_Address) { pite = piterec; break; } } if (pite) { break; } } // // return record after the one found if mode is GetNext // if (dwGetMode == GETMODE_NEXT && pite != NULL) { pfl = &pite->ITE_LinkByAddress; // // if entry found is last one, return NULL, // otherwise, return the following entry // if (pfl->Flink == phead) { if (pdwErr != NULL) { *pdwErr = ERROR_NO_MORE_ITEMS; } pite = NULL; } else { pfl = pfl->Flink; pite = CONTAINING_RECORD(pfl, IF_TABLE_ENTRY, ITE_LinkByAddress); } } // // if the interface wasn't found, this will still be NULL // return pite; } //---------------------------------------------------------------------------- // Function: GetIfByListIndex // // This function is similar to GetIfByAddress in that it supports // three modes of retrieval, but it is different in that it looks // in the list of interfaces sorted by index. //---------------------------------------------------------------------------- PIF_TABLE_ENTRY GetIfByListIndex( PIF_TABLE pTable, DWORD dwIndex, DWORD dwGetMode, PDWORD pdwErr ) { PIF_TABLE_ENTRY pite; PLIST_ENTRY ple, phead; if (pdwErr != NULL) { *pdwErr = NO_ERROR; } phead = &pTable->IT_ListByIndex; pite = NULL; // // return record at head of list if mode is GETMODE_FIRST; // if list is empty, return NULL. // if (dwGetMode == GETMODE_FIRST) { if (phead->Flink == phead) { if (pdwErr != NULL) { *pdwErr = ERROR_NO_MORE_ITEMS; } return NULL; } else { ple = phead->Flink; return CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_LinkByIndex); } } // // get the entry requested // pite = GetIfByIndex(pTable, dwIndex); // // if mode is GETMODE_NEXT, return the item after the one retrieved // if (dwGetMode == GETMODE_NEXT && pite != NULL) { ple = &pite->ITE_LinkByIndex; // // if entry found is last one, return NULL, // otherwise return the following entry // if (ple->Flink == phead) { if (pdwErr != NULL) { *pdwErr = ERROR_NO_MORE_ITEMS; } pite = NULL; } else { ple = ple->Flink; pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_LinkByIndex); } } return pite; } //---------------------------------------------------------------------------- // Function: InsertIfByAddress // // inserts the given interface into the list of interfaces sorted by address. // assumes the table is locked for writing //---------------------------------------------------------------------------- DWORD InsertIfByAddress( PIF_TABLE pTable, PIF_TABLE_ENTRY pITE ) { INT cmp; PIF_TABLE_ENTRY pite; PIPRIP_IP_ADDRESS paddr; DWORD dwAddress, dwITEAddress; PLIST_ENTRY phead, pfl; phead = &pTable->IT_ListByAddress; paddr = IPRIP_IF_ADDRESS_TABLE(pITE->ITE_Binding); dwAddress = paddr->IA_Address; // // search for the insertion point // for (pfl = phead->Flink; pfl != phead; pfl = pfl->Flink) { pite = CONTAINING_RECORD(pfl, IF_TABLE_ENTRY, ITE_LinkByAddress); paddr = IPRIP_IF_ADDRESS_TABLE(pite->ITE_Binding); dwITEAddress = paddr->IA_Address; if (INET_CMP(dwAddress, dwITEAddress, cmp) < 0) { break; } else if (cmp == 0) { return ERROR_ALREADY_EXISTS; } } InsertTailList(pfl, &pITE->ITE_LinkByAddress); return NO_ERROR; } //---------------------------------------------------------------------------- // Function: AddNeighborToIfConfig // // Adds a unicast neighbor to an interface config block. //---------------------------------------------------------------------------- DWORD AddNeighborToIfConfig( DWORD dwRemoteAddress, PIF_TABLE_ENTRY pite ) { BOOL bFound = FALSE; DWORD dwErr = (DWORD) -1, dwSize = 0, dwCnt = 0; PDWORD pdwAddr = NULL; PIPRIP_IF_CONFIG pic = NULL, picNew = NULL; do { pic = pite-> ITE_Config; // // verify neighbor is not aready present // pdwAddr = IPRIP_IF_UNICAST_PEER_TABLE( pic ); for ( dwCnt = 0; dwCnt < pic-> IC_UnicastPeerCount; dwCnt++ ) { if ( dwRemoteAddress == pdwAddr[ dwCnt ] ) { bFound = TRUE; break; } } // // entry exits, enable unicast peer mode and quit // if ( bFound ) { LPSTR lpszAddr = INET_NTOA( dwRemoteAddress ); pic-> IC_UnicastPeerMode = IPRIP_PEER_ALSO; dwErr = NO_ERROR; if (lpszAddr != NULL) { TRACE2( IF, "Unicast neighbor %s already present in configuration on interface %d", lpszAddr, pite-> ITE_Index ); } break; } // // allocate new config block // dwSize = IPRIP_IF_CONFIG_SIZE( pic ) + sizeof( DWORD ); picNew = RIP_ALLOC( dwSize ); if ( picNew == NULL ) { dwErr = GetLastError(); TRACE3( IF, "error %d allocating %d bytes for configuration on interface %d", dwErr, dwSize, pite-> ITE_Index ); LOGERR0(HEAP_ALLOC_FAILED, dwErr); break; } // // copy base structure // CopyMemory( picNew, pic, sizeof( IPRIP_IF_CONFIG ) ); // // copy uicast peer table // CopyMemory( IPRIP_IF_UNICAST_PEER_TABLE( picNew ), IPRIP_IF_UNICAST_PEER_TABLE( pic ), pic-> IC_UnicastPeerCount * sizeof( DWORD ) ); // // add new neighbor and set unicast neighbor mode // pdwAddr = IPRIP_IF_UNICAST_PEER_TABLE( picNew ); pdwAddr[ picNew-> IC_UnicastPeerCount++ ] = dwRemoteAddress; picNew-> IC_UnicastPeerMode = IPRIP_PEER_ALSO; // // Copy accept and annouce filters // CopyMemory( IPRIP_IF_ACCEPT_FILTER_TABLE( picNew ), IPRIP_IF_ACCEPT_FILTER_TABLE( pic ), pic-> IC_AcceptFilterCount * sizeof( IPRIP_IP_ADDRESS ) ); CopyMemory( IPRIP_IF_ANNOUNCE_FILTER_TABLE( picNew ), IPRIP_IF_ANNOUNCE_FILTER_TABLE( pic ), pic-> IC_AnnounceFilterCount * sizeof( IPRIP_IP_ADDRESS ) ); // // save the new config // pite-> ITE_Config = picNew; RIP_FREE( pic ); dwErr = NO_ERROR; } while ( FALSE ); return dwErr; } //---------------------------------------------------------------------------- // Function: CreatePeerTable // // initializes the given peer table //---------------------------------------------------------------------------- DWORD CreatePeerTable( PPEER_TABLE pTable ) { DWORD dwErr; PLIST_ENTRY ple, plstart, plend; // // initialize the hash table of peers // plstart = pTable->PT_HashTableByAddress; plend = plstart + PEER_HASHTABLE_SIZE; for (ple = plstart; ple < plend; ple++) { InitializeListHead(ple); } // // initialize the list of peers ordered by address // InitializeListHead(&pTable->PT_ListByAddress); // // initialize the multiple-read/single-write synchronization object // dwErr = CreateReadWriteLock(&pTable->PT_RWL); if (dwErr == NO_ERROR) { pTable->PT_Created = 0x12345678; } return dwErr; } //---------------------------------------------------------------------------- // Function: DeletePeerTable // // frees the resources used by the given peer table // assumes the table is locked for writing //---------------------------------------------------------------------------- DWORD DeletePeerTable( PPEER_TABLE pTable ) { PLIST_ENTRY ple, phead; PPEER_TABLE_ENTRY ppte; // // empty the hash table of peer stats structures // phead = &pTable->PT_ListByAddress; while (!IsListEmpty(phead)) { ple = RemoveHeadList(phead); ppte = CONTAINING_RECORD(ple, PEER_TABLE_ENTRY, PTE_LinkByAddress); RIP_FREE(ppte); } // // delete the table's synchronization object // DeleteReadWriteLock(&pTable->PT_RWL); pTable->PT_Created = 0; return NO_ERROR; } //---------------------------------------------------------------------------- // Function: CreatePeerEntry // // creates an entry in the given table for a peer with the given address // assumes the table is locked for writing //---------------------------------------------------------------------------- DWORD CreatePeerEntry( PPEER_TABLE pTable, DWORD dwAddress, PPEER_TABLE_ENTRY *ppEntry ) { DWORD dwErr; PLIST_ENTRY ple, phead; PPEER_TABLE_ENTRY ppte; if (ppEntry != NULL) { *ppEntry = NULL; } // // make sure the entry does not already exist // ppte = GetPeerByAddress(pTable, dwAddress, GETMODE_EXACT, NULL); if (ppte != NULL) { if (ppEntry != NULL) { *ppEntry = ppte; } return NO_ERROR; } // // allocate memory for the new peer entry // ppte = RIP_ALLOC(sizeof(PEER_TABLE_ENTRY)); if (ppte == NULL) { LPSTR lpszAddr = INET_NTOA(dwAddress); dwErr = GetLastError(); if (lpszAddr != NULL) { TRACE3( IF, "error %d allocating %d bytes for peer %s entry", dwErr, sizeof(PEER_TABLE_ENTRY), lpszAddr ); LOGERR0(HEAP_ALLOC_FAILED, dwErr); } return dwErr; } // // initialize the fields // ppte->PTE_Address = dwAddress; ZeroMemory(&ppte->PTE_Stats, sizeof(IPRIP_PEER_STATS)); // // insert the peer stats entry in the hash table // phead = pTable->PT_HashTableByAddress + PEER_HASHVALUE(dwAddress); InsertHeadList(phead, &ppte->PTE_HTLinkByAddress); // // insert the entry in the list sorted by address // dwErr = InsertPeerByAddress(pTable, ppte); if (ppEntry != NULL) { *ppEntry = ppte; } return NO_ERROR; } //---------------------------------------------------------------------------- // Function: DeletePeerEntry // // deletes the entry for the peer with the given address // assumes the table is locked for writing //---------------------------------------------------------------------------- DWORD DeletePeerEntry( PPEER_TABLE pTable, DWORD dwAddress ) { PPEER_TABLE_ENTRY ppte; // // quit if the entry cannot be found // ppte = GetPeerByAddress(pTable, dwAddress, GETMODE_EXACT, NULL); if (ppte == NULL) { return ERROR_INVALID_PARAMETER; } // // remove the entry from the hash-table // and from the list sorted by address // RemoveEntryList(&ppte->PTE_LinkByAddress); RemoveEntryList(&ppte->PTE_HTLinkByAddress); RIP_FREE(ppte); return NO_ERROR; } //---------------------------------------------------------------------------- // Function: GetPeerByAddress // // returns the entry for the peer with the given address // assumes the table is locked for reading or writing //---------------------------------------------------------------------------- PPEER_TABLE_ENTRY GetPeerByAddress( PPEER_TABLE pTable, DWORD dwAddress, DWORD dwGetMode, PDWORD pdwErr ) { PLIST_ENTRY phead, pfl; PPEER_TABLE_ENTRY ppte, ppterec; if (pdwErr != NULL) { *pdwErr = NO_ERROR; } // // return head of list if in GetFirst mode // if (dwGetMode == GETMODE_FIRST) { phead = &pTable->PT_ListByAddress; if (phead->Flink == phead) { if (pdwErr != NULL) { *pdwErr = ERROR_NO_MORE_ITEMS; } return NULL; } else { pfl = phead->Flink; return CONTAINING_RECORD(pfl, PEER_TABLE_ENTRY, PTE_LinkByAddress); } } phead = pTable->PT_HashTableByAddress + PEER_HASHVALUE(dwAddress); ppte = NULL; // // search for the entry // for (pfl = phead->Flink; pfl != phead; pfl = pfl->Flink) { ppterec = CONTAINING_RECORD(pfl, PEER_TABLE_ENTRY, PTE_HTLinkByAddress); if (ppterec->PTE_Address == dwAddress) { ppte = ppterec; break; } } // // return entry after the one found if in GetNext mode // if (dwGetMode == GETMODE_NEXT && ppte != NULL) { phead = &pTable->PT_ListByAddress; pfl = &ppte->PTE_LinkByAddress; // // return NULL if entry is last one // if (pfl->Flink == phead) { if (pdwErr != NULL) { *pdwErr = ERROR_NO_MORE_ITEMS; } return NULL; } else { pfl = pfl->Flink; return CONTAINING_RECORD(pfl, PEER_TABLE_ENTRY, PTE_LinkByAddress); } } // // if the peer wasn't found, this will still be NULL // return ppte; } //---------------------------------------------------------------------------- // Function: InsertPeerByAddress // // inserts the given entry into the list of peers sorted by address // assumes the table is locked for writing //---------------------------------------------------------------------------- DWORD InsertPeerByAddress( PPEER_TABLE pTable, PPEER_TABLE_ENTRY pPTE ) { INT cmp; PPEER_TABLE_ENTRY ppte; DWORD dwAddress, dwPTEAddress; PLIST_ENTRY phead, pfl; dwAddress = pPTE->PTE_Address; phead = &pTable->PT_ListByAddress; // // search for the peer entry // for (pfl = phead->Flink; pfl != phead; pfl = pfl->Flink) { ppte = CONTAINING_RECORD(pfl, PEER_TABLE_ENTRY, PTE_LinkByAddress); dwPTEAddress = ppte->PTE_Address; if (INET_CMP(dwAddress, dwPTEAddress, cmp) < 0) { break; } else if (cmp == 0) { return ERROR_ALREADY_EXISTS; } } InsertTailList(pfl, &pPTE->PTE_LinkByAddress); return NO_ERROR; } //---------------------------------------------------------------------------- // Function: CreateRouteTable // // Initializes a route table. Note that no synchronization is provided. //---------------------------------------------------------------------------- DWORD CreateRouteTable( PROUTE_TABLE pTable ) { PLIST_ENTRY plstart, plend, ple; // // initialize the hash table buckets // plstart = pTable->RT_HashTableByNetwork; plend = plstart + ROUTE_HASHTABLE_SIZE; for (ple = plstart; ple < plend; ple++) { InitializeListHead(ple); } pTable->RT_Created = 0x12345678; return NO_ERROR; } //---------------------------------------------------------------------------- // Function: DeleteRouteTable // // Removes all entries from a route table and frees resources used. //---------------------------------------------------------------------------- DWORD DeleteRouteTable( PROUTE_TABLE pTable ) { PROUTE_TABLE_ENTRY prte; PLIST_ENTRY ple, plend, phead; // // empty the hash-table buckets // plend = pTable->RT_HashTableByNetwork + ROUTE_HASHTABLE_SIZE; for (ple = plend - ROUTE_HASHTABLE_SIZE; ple < plend; ple++) { while (!IsListEmpty(ple)) { phead = RemoveHeadList(ple); prte = CONTAINING_RECORD(phead, ROUTE_TABLE_ENTRY, RTE_Link); RIP_FREE(prte); } } pTable->RT_Created = 0; return NO_ERROR; } //---------------------------------------------------------------------------- // Function: WriteSummaryRoutes // // Writes to RTM all entries which are marked as summary routes. //---------------------------------------------------------------------------- DWORD WriteSummaryRoutes( PROUTE_TABLE pTable, HANDLE hRtmHandle ) { DWORD dwFlags, dwErr; PRIP_IP_ROUTE prir; PROUTE_TABLE_ENTRY prte; PLIST_ENTRY ple, phead, plstart, plend; BOOL bRelDest = FALSE, bRelRoute = FALSE; RTM_NET_ADDRESS rna; RTM_DEST_INFO rdi; PRTM_ROUTE_INFO prri; CHAR szNetwork[20], szNetmask[20]; // // allocate route info structure // prri = RIP_ALLOC( RTM_SIZE_OF_ROUTE_INFO( ig.IG_RtmProfile.MaxNextHopsInRoute ) ); if (prri == NULL) { dwErr = GetLastError(); TRACE2( ANY, "error %d allocated %d bytes in WriteSummaryRoutes", dwErr, RTM_SIZE_OF_ROUTE_INFO(ig.IG_RtmProfile.MaxNextHopsInRoute) ); LOGERR0(HEAP_ALLOC_FAILED, dwErr); return dwErr; } // // go through each bucket writing routes // plstart = pTable->RT_HashTableByNetwork; plend = plstart + ROUTE_HASHTABLE_SIZE; for (phead = plstart; phead < plend; phead++) { for (ple = phead->Flink; ple != phead; ple = ple->Flink) { prte = CONTAINING_RECORD(ple, ROUTE_TABLE_ENTRY, RTE_Link); prir = &prte->RTE_Route; bRelDest = bRelRoute = FALSE; do { // // if a valid route exists do not overwrite it with // a summary route // RTM_IPV4_SET_ADDR_AND_MASK( &rna, prir-> RR_Network.N_NetNumber, prir-> RR_Network.N_NetMask ); dwErr = RtmGetExactMatchDestination( hRtmHandle, &rna, RTM_BEST_PROTOCOL, RTM_VIEW_MASK_UCAST, &rdi ); if (dwErr == NO_ERROR) { bRelDest = TRUE; // // Get info for the best route to this destination // dwErr = RtmGetRouteInfo( hRtmHandle, rdi.ViewInfo[0].Route, prri, NULL ); if (dwErr != NO_ERROR) { TRACE1( ANY, "error %d getting route info in" "WriteSummaryRoutes", dwErr ); break; } bRelRoute = TRUE; // // Check if this route is active. If it is skip // adding an inactive summary route // if (!(prri-> Flags & RTM_ROUTE_FLAGS_INACTIVE)) { lstrcpy(szNetwork, INET_NTOA(prir-> RR_Network.N_NetNumber)); lstrcpy(szNetmask, INET_NTOA(prir-> RR_Network.N_NetMask)); TRACE2( ROUTE, "Route %s %s not overwritten in summary route addition", szNetwork, szNetmask ); break; } } // // you reach here only if you don't have an active // route to the summary route's destination // // // if this is a summary entry (i.e. is a RIP route // with the summary entry set) // if (prir->RR_RoutingProtocol == PROTO_IP_RIP && GETROUTEFLAG(prir) == ROUTEFLAG_SUMMARY) { LPSTR lpszAddr; COMPUTE_ROUTE_METRIC(prir); dwErr = AddRtmRoute( hRtmHandle, prir, NULL, prte->RTE_TTL, prte->RTE_HoldTTL, FALSE ); lpszAddr = INET_NTOA(prir-> RR_Network.N_NetNumber); if (lpszAddr != NULL) { lstrcpy(szNetwork, lpszAddr ); lpszAddr = INET_NTOA(prir-> RR_Network.N_NetMask); if (lpszAddr != NULL) { lstrcpy(szNetmask, INET_NTOA(prir-> RR_Network.N_NetMask)); #if ROUTE_DBG TRACE2( ROUTE, "Adding summary route %s %s", szNetwork, szNetmask ); #endif if (dwErr != NO_ERROR) { LPSTR lpszNexthop = INET_NTOA(prir->RR_NextHopAddress.N_NetNumber); if (lpszNexthop != NULL) { TRACE4( ROUTE, "error %d writing summary route to %s:%s via %s", dwErr, szNetwork, szNetmask, lpszNexthop ); LOGWARN2( ADD_ROUTE_FAILED_1, szNetwork, lpszNexthop, dwErr ); } } } } } } while (FALSE); if (dwErr != NO_ERROR) { // // in case one of the INET_NTOA statements failed above, just // trace the fact that there was an error // TRACE1( ROUTE, "error %d writing summary route", dwErr ); } // // release handles as required // if (bRelRoute) { dwErr = RtmReleaseRouteInfo(hRtmHandle, prri); if (dwErr != NO_ERROR) { TRACE1( ANY, "error %d releasing route info in" " WriteSummaryRoutes", dwErr ); } } if (bRelDest) { dwErr = RtmReleaseDestInfo(hRtmHandle, &rdi); if (dwErr != NO_ERROR) { TRACE1( ANY, "error %d releasing route info in" " WriteSummaryRoutes", dwErr ); } } } } if (prri) { RIP_FREE(prri); } return NO_ERROR; } //---------------------------------------------------------------------------- // Function: CreateRouteEntry // // Makes an entry in the route table for the given route. //---------------------------------------------------------------------------- DWORD CreateRouteEntry( PROUTE_TABLE pTable, PRIP_IP_ROUTE pRoute, DWORD dwTTL, DWORD dwHoldTTL ) { DWORD dwErr; PLIST_ENTRY ple; PROUTE_TABLE_ENTRY prte; // // see if the entry exists first // if ((prte = GetRouteByRoute(pTable, pRoute)) != NULL) { // // just update the metric if the new route has a lower one // if (GETROUTEMETRIC(&prte->RTE_Route) > GETROUTEMETRIC(pRoute)) { SETROUTEMETRIC(&prte->RTE_Route, GETROUTEMETRIC(pRoute)); } return NO_ERROR; } // // allocate space for the new route // prte = RIP_ALLOC(sizeof(ROUTE_TABLE_ENTRY)); if (prte == NULL) { dwErr = GetLastError(); TRACE2( ANY, "error %d allocating %d bytes for route table entry", dwErr, sizeof(ROUTE_TABLE_ENTRY) ); LOGERR0(HEAP_ALLOC_FAILED, dwErr); return dwErr; } // // initialize the entry's fields and copy the actual route structure // prte->RTE_TTL = dwTTL; prte->RTE_HoldTTL = dwHoldTTL; CopyMemory(&prte->RTE_Route, pRoute, sizeof(RIP_IP_ROUTE)); // // insert the route in the hash table // ple = pTable->RT_HashTableByNetwork + ROUTE_HASHVALUE(pRoute->RR_Network.N_NetNumber); InsertHeadList(ple, &prte->RTE_Link); #if ROUTE_DBG { LPSTR lpszAddr; char szNet[20], szMask[20]; lpszAddr = INET_NTOA(pRoute-> RR_Network.N_NetNumber); if (lpszAddr != NULL) { lstrcpy(szNet, lpszAddr); lpszAddr = INET_NTOA(pRoute-> RR_Network.N_NetMask); if (lpszAddr != NULL) { lstrcpy(szMask, lpszAddr); lpszAddr = INET_NTOA(pRoute-> RR_NextHopAddress.N_NetNumber); if (lpszAddr != NULL) { TRACE4( ROUTE, "Creating summary route : Route %s %s via %s" "on interface %d", szNet, szMask, lpszAddr, pRoute-> RR_InterfaceID ); } } } } #endif return NO_ERROR; } //---------------------------------------------------------------------------- // Function: DeleteRouteEntry // // Remove the entry which matches the given route. //---------------------------------------------------------------------------- DWORD DeleteRouteEntry( PROUTE_TABLE pTable, PRIP_IP_ROUTE pRoute ) { PROUTE_TABLE_ENTRY prte; // // find the route to be deleted // prte = GetRouteByRoute(pTable, pRoute); if (prte == NULL) { return ERROR_INVALID_PARAMETER; } // // remove it from the hash table and free the memory it used // RemoveEntryList(&prte->RTE_Link); RIP_FREE(prte); return NO_ERROR; } //---------------------------------------------------------------------------- // Function: GetRouteByRoute // // Searches for the route entry which matches the given route, if any, // and returns a pointer to it if it is found. //---------------------------------------------------------------------------- PROUTE_TABLE_ENTRY GetRouteByRoute( PROUTE_TABLE pTable, PRIP_IP_ROUTE pRoute ) { DWORD dwNetNumber; PLIST_ENTRY phead, pfl; PROUTE_TABLE_ENTRY prte, prterec; // // get the net number to be found and find the corresponding bucket // prte = NULL; dwNetNumber = pRoute->RR_Network.N_NetNumber; phead = pTable->RT_HashTableByNetwork + ROUTE_HASHVALUE(dwNetNumber); // // search the bucket for the route // for (pfl = phead->Flink; pfl != phead; pfl = pfl->Flink) { prterec = CONTAINING_RECORD(pfl, ROUTE_TABLE_ENTRY, RTE_Link); if (prterec->RTE_Route.RR_Network.N_NetNumber == dwNetNumber) { prte = prterec; break; } } // // if the route wasn't found, this will still be NULL // return prte; } //---------------------------------------------------------------------------- // Function: CreateBindingTable // // Initializes a table of bindings. //---------------------------------------------------------------------------- DWORD CreateBindingTable( PBINDING_TABLE pTable ) { DWORD dwErr; PLIST_ENTRY plend, ple; // // initialize the hash table of bindings // plend = pTable->BT_HashTableByNetwork + BINDING_HASHTABLE_SIZE; for (ple = plend - BINDING_HASHTABLE_SIZE; ple < plend; ple++) { InitializeListHead(ple); } // // initialize the table's synchronization object // dwErr = CreateReadWriteLock(&pTable->BT_RWL); if (dwErr == NO_ERROR) { pTable->BT_Created = 0x12345678; } return dwErr; } //---------------------------------------------------------------------------- // Function: DeleteBindingTable // // Cleans up resources used by a binding table. //---------------------------------------------------------------------------- DWORD DeleteBindingTable( PBINDING_TABLE pTable ) { PBINDING_TABLE_ENTRY pbte; PLIST_ENTRY plend, ple, phead; // // destroy the synchronization object // DeleteReadWriteLock(&pTable->BT_RWL); // // empty the hash-table buckets // plend = pTable->BT_HashTableByNetwork + BINDING_HASHTABLE_SIZE; for (ple = plend - BINDING_HASHTABLE_SIZE; ple < plend; ple++) { while (!IsListEmpty(ple)) { phead = RemoveHeadList(ple); pbte = CONTAINING_RECORD(phead, BINDING_TABLE_ENTRY, BTE_Link); RIP_FREE(pbte); } } pTable->BT_Created = 0; return NO_ERROR; } //---------------------------------------------------------------------------- // Function: CreateBindingEntry // // Adds a binding to the table. // assumes the binding table is locked for writing //---------------------------------------------------------------------------- DWORD CreateBindingEntry( PBINDING_TABLE pTable, PIPRIP_IF_BINDING pib ) { INT cmp; PLIST_ENTRY ple, phead; PIPRIP_IP_ADDRESS paddr; PBINDING_TABLE_ENTRY pbte; DWORD i, dwErr, dwAddress, dwNetmask, dwNetwork; // // go through the IP addresses in the interface binding, // adding each to the binding table // paddr = IPRIP_IF_ADDRESS_TABLE(pib); for (i = 0; i < pib->IB_AddrCount; i++, paddr++) { dwAddress = paddr->IA_Address; dwNetmask = paddr->IA_Netmask; // // compute the network part of the binding // dwNetwork = (dwAddress & NETCLASS_MASK(dwAddress)); // // get the hash bucket to which the binding belongs, // and find the insertion point in the bucket // phead = pTable->BT_HashTableByNetwork + BINDING_HASHVALUE(dwNetwork); for (ple = phead->Flink; ple != phead; ple = ple->Flink) { pbte = CONTAINING_RECORD(ple, BINDING_TABLE_ENTRY, BTE_Link); INET_CMP(dwNetwork, pbte->BTE_Network, cmp); if (cmp < 0) { break; } else if (cmp > 0) { continue; } // // the network parts are equal; further compare // against the IP address fields // INET_CMP(dwAddress, pbte->BTE_Address, cmp); if (cmp < 0) { break; } else if (cmp > 0) { continue; } // // the addresses are also equal; return an error // return ERROR_ALREADY_EXISTS; } // // we now have the insertion point, so create the new item // pbte = RIP_ALLOC(sizeof(BINDING_TABLE_ENTRY)); if (pbte == NULL) { dwErr = GetLastError(); TRACE2( IF, "error %d allocating %d bytes for binding entry", dwErr, sizeof(BINDING_TABLE_ENTRY) ); LOGERR0(HEAP_ALLOC_FAILED, dwErr); return dwErr; } pbte->BTE_Address = dwAddress; pbte->BTE_Network = dwNetwork; pbte->BTE_Netmask = dwNetmask; // // insert the entry // InsertTailList(ple, &pbte->BTE_Link); } return NO_ERROR; } //---------------------------------------------------------------------------- // Function: DeleteBindingEntry // // Removes a binding from the table. // assumes the binding table is locked for writing //---------------------------------------------------------------------------- DWORD DeleteBindingEntry( PBINDING_TABLE pTable, PIPRIP_IF_BINDING pib ) { PLIST_ENTRY ple, phead; PIPRIP_IP_ADDRESS paddr; PBINDING_TABLE_ENTRY pbte; DWORD i, dwNetwork, dwAddress, dwNetmask; paddr = IPRIP_IF_ADDRESS_TABLE(pib); for (i = 0; i < pib->IB_AddrCount; i++, paddr++) { dwAddress = paddr->IA_Address; dwNetmask = paddr->IA_Netmask; // // get the hash bucket to be searched // dwNetwork = (dwAddress & NETCLASS_MASK(dwAddress)); phead = pTable->BT_HashTableByNetwork + BINDING_HASHVALUE(dwNetwork); // // search the bucket for the binding specified // for (ple = phead->Flink; ple != phead; ple = ple->Flink) { pbte = CONTAINING_RECORD(ple, BINDING_TABLE_ENTRY, BTE_Link); if (dwAddress != pbte->BTE_Address || dwNetmask != pbte->BTE_Netmask) { continue; } // // the entry to be deleted has been found; // remove it from the list and free its memory // RemoveEntryList(&pbte->BTE_Link); RIP_FREE(pbte); break; } } return NO_ERROR; } //--------------------------------------------------------------------------- // Function: GuessSubnetMask // // This function attempts to deduce the subnet mask of an IP address // based on the configured addresses and masks on the local host. // assumes the binding table is locked for reading or writing //--------------------------------------------------------------------------- DWORD GuessSubnetMask( DWORD dwAddress, PDWORD pdwNetclassMask ) { INT cmp; PLIST_ENTRY ple, phead; PBINDING_TABLE_ENTRY pbte; DWORD dwNetwork, dwNetmask, dwGuessMask; // // the mask for a default route (0.0.0.0) is zero // if (dwAddress == 0) { if (pdwNetclassMask != NULL) { *pdwNetclassMask = 0; } return 0; } // // the mask for the broadcast route is all-ones (255.255.255.255) // if (dwAddress == INADDR_BROADCAST) { if (pdwNetclassMask != NULL) { *pdwNetclassMask = INADDR_BROADCAST; } return INADDR_BROADCAST; } // // otherwise, we start with the network-class mask // dwGuessMask = dwNetmask = NETCLASS_MASK(dwAddress); if (pdwNetclassMask != NULL) { *pdwNetclassMask = dwNetmask; } // // if the route is a network route, we're done // if ((dwAddress & ~dwNetmask) == 0) { return dwNetmask; } // // otherwise, search through the bindings table // to see if one is on the same network as this address // dwNetwork = (dwAddress & dwNetmask); phead = ig.IG_BindingTable->BT_HashTableByNetwork + BINDING_HASHVALUE(dwNetwork); for (ple = phead->Flink; ple != phead; ple = ple->Flink) { pbte = CONTAINING_RECORD(ple, BINDING_TABLE_ENTRY, BTE_Link); INET_CMP(dwNetwork, pbte->BTE_Network, cmp); if (cmp < 0) { break; } else if (cmp > 0) { continue; } // // this entry is on the same network as the address passed in // so see if the entry's netmask matches the address; // if it does, we're done; otherwise, save this mask // as a guess, and keep looking. // note that this exhaustive search is the only way we can // reliably guess masks for supernets // if ((dwAddress & pbte->BTE_Netmask) == (pbte->BTE_Address & pbte->BTE_Netmask)) { return pbte->BTE_Netmask; } dwGuessMask = pbte->BTE_Netmask; } // // return whatever has been our best guess so far // return dwGuessMask; } DWORD AddRtmRoute( RTM_ENTITY_HANDLE hRtmHandle, PRIP_IP_ROUTE prir, RTM_NEXTHOP_HANDLE hNextHop OPTIONAL, DWORD dwTimeOut, DWORD dwHoldTime, BOOL bActive ) /*++ Routine Description : This function adds a route to the RTMv2 database. In addition it creates the nexthop if one is not specified (via hNextHop), based on the next hop i/f and address specified in the RIP route. Parameters : hRtmHandle - Entity registration handle prir - RIP route to be added hNextHop - Handle to the next hop to be used for the route dwTimeout - Route timeout interval dwHoldTime - Route holddown interval (after delete) bActive - TRUE if the route being added is an active route, FALSE otherwise (in RIP's case for summary routes) Return Value : NO_ERROR - Success Rtm error code - Otherwise Environment : Invoked from ProcessRouteEntry and WriteSummaryRoutes --*/ { BOOL bRelDest = FALSE; DWORD dwErr, dwChangeFlags = 0; RTM_DEST_INFO rdi; RTM_NEXTHOP_INFO rni; RTM_ROUTE_INFO rri; RTM_NET_ADDRESS rna; CHAR szNetwork[20], szNetmask[20], szNextHop[20], szNextHopmask[20]; do { // // char strings used to print IP address/mask info // Used in error cases only // lstrcpy(szNetwork, INET_NTOA(prir-> RR_Network.N_NetNumber)); lstrcpy(szNetmask, INET_NTOA(prir-> RR_Network.N_NetMask)); lstrcpy(szNextHop, INET_NTOA(prir-> RR_NextHopAddress.N_NetNumber)); lstrcpy(szNextHopmask, INET_NTOA(prir-> RR_NextHopAddress.N_NetMask)); // // Zero out the next hop and route memory // ZeroMemory(&rni, sizeof(RTM_NEXTHOP_INFO)); ZeroMemory(&rri, sizeof(RTM_ROUTE_INFO)); if (hNextHop == NULL) { // // Find next hop. // rni.InterfaceIndex = prir-> RR_InterfaceID; RTM_IPV4_SET_ADDR_AND_MASK( &rni.NextHopAddress, prir-> RR_NextHopAddress.N_NetNumber, IPV4_SOURCE_MASK ); // // Save the nexthop mask in the entity specific info // *((PDWORD)&rni.EntitySpecificInfo) = prir-> RR_NextHopAddress.N_NetMask; rni.NextHopOwner = hRtmHandle; dwErr = RtmFindNextHop(hRtmHandle, &rni, &hNextHop, NULL); if (dwErr == ERROR_NOT_FOUND) { // // Next hop not found. Create one // dwErr = RtmAddNextHop( hRtmHandle, &rni, &hNextHop, &dwChangeFlags ); if (dwErr != NO_ERROR) { TRACE3( ROUTE, "error %d creating next hop %s %s", dwErr, szNextHop, szNextHopmask ); break; } } else if (dwErr != NO_ERROR) { TRACE3( ANY, "error %d finding next hop %s %s", dwErr, szNextHop, szNextHopmask ); break; } } // // Build route info structure // RTM_IPV4_SET_ADDR_AND_MASK( &rna, prir-> RR_Network.N_NetNumber, prir-> RR_Network.N_NetMask ); rri.PrefInfo.Metric = prir-> RR_FamilySpecificData.FSD_Metric1; rri.BelongsToViews = RTM_VIEW_MASK_UCAST | RTM_VIEW_MASK_MCAST; // // set entity specific info // SETRIPTAG(&rri, GETROUTETAG(prir)); SETRIPFLAG(&rri, GETROUTEFLAG(prir)); // // Set next hop info // rri.NextHopsList.NumNextHops = 1; rri.NextHopsList.NextHops[0] = hNextHop; rri.Neighbour = hNextHop; // // Call into router manager to set preference info // ig.IG_SupportFunctions.ValidateRoute(PROTO_IP_RIP, &rri, &rna); // // if this is an inactive route, // - set route flag to inactive. // - set the views for route to none // if ( !bActive ) { rri.Flags1 = 0; rri.Flags = RTM_ROUTE_FLAGS_INACTIVE; rri.BelongsToViews = 0; } // // Add route to dest, convert timeout to milliseconds // dwChangeFlags = RTM_ROUTE_CHANGE_FIRST; dwErr = RtmAddRouteToDest( hRtmHandle, NULL, &rna, &rri, dwTimeOut * 1000, NULL, 0, NULL, &dwChangeFlags ); if ( dwErr != NO_ERROR ) { TRACE4( ANY, "error %d adding route %s %s via %s", dwErr, szNetwork, szNetmask, szNextHop ); break; } if ( bActive ) { // // Hold destination if this is an active route // dwErr = RtmGetExactMatchDestination( hRtmHandle, &rna, RTM_BEST_PROTOCOL, RTM_VIEW_MASK_UCAST, &rdi ); if ( dwErr != NO_ERROR ) { TRACE3( ANY, "error %d getting just added destination %s:%s", dwErr, szNetwork, szNetmask ); break; } bRelDest = TRUE; dwErr = RtmHoldDestination( hRtmHandle, rdi.DestHandle, RTM_VIEW_MASK_UCAST, dwHoldTime * 1000 ); if ( dwErr != NO_ERROR ) { TRACE3( ANY, "error %d failed to hold destination %s %s", dwErr, szNetwork, szNetmask ); break; } } } while(FALSE); // // release acquired handles // if ( bRelDest ) { dwErr = RtmReleaseDestInfo( hRtmHandle, &rdi ); if ( dwErr != NO_ERROR ) { TRACE3( ANY, "error %d failed to relase just added destination %s %s", dwErr, szNetwork, szNetmask ); } } return dwErr; } DWORD GetRouteInfo( IN RTM_ROUTE_HANDLE hRoute, IN PRTM_ROUTE_INFO pInRouteInfo OPTIONAL, IN PRTM_DEST_INFO pInDestInfo OPTIONAL, OUT PRIP_IP_ROUTE pRoute ) /*++ Routine Description: Wrapper for filling out the OSPF_RTMv2_ROUTE by retrieving various RTM infos. Arguments: hRoute pInRouteInfo pInDestInfo pRoute Return Value: RTM error code --*/ { DWORD dwErr; RTM_ROUTE_INFO RouteInfo, *pRouteInfo; RTM_ENTITY_INFO EntityInfo, *pEntityInfo; RTM_DEST_INFO DestInfo, *pDestInfo; RTM_NEXTHOP_INFO NextHopInfo, *pNextHopInfo; pRouteInfo = NULL; pEntityInfo = NULL; pDestInfo = NULL; pNextHopInfo = NULL; do { ZeroMemory(pRoute, sizeof(RIP_IP_ROUTE)); // // If the user hasnt already given us the route info, get it // if ( pInRouteInfo == NULL ) { dwErr = RtmGetRouteInfo( ig.IG_RtmHandle, hRoute, &RouteInfo, NULL ); if ( dwErr != NO_ERROR ) { TRACE1( ANY, "GetRouteInfo: Error %d from RtmGetRouteInfo\n", dwErr ); break; } pRouteInfo = &RouteInfo; } else { pRouteInfo = pInRouteInfo; } // // If the user hasnt given us the dest info, get it // if ( pInDestInfo == NULL ) { dwErr = RtmGetDestInfo( ig.IG_RtmHandle, pRouteInfo->DestHandle, 0, RTM_VIEW_MASK_UCAST, &DestInfo ); if ( dwErr != NO_ERROR ) { TRACE1( ANY, "GetRouteInfo: Error %d from RtmGetDestInfo\n", dwErr ); break; } pDestInfo = &DestInfo; } else { pDestInfo = pInDestInfo; } // // Get owner info if the protocol is not us // if ( pRouteInfo-> RouteOwner != ig.IG_RtmHandle ) { dwErr = RtmGetEntityInfo( ig.IG_RtmHandle, pRouteInfo->RouteOwner, &EntityInfo ); if ( dwErr != NO_ERROR ) { TRACE1( ANY, "GetRouteInfo: Error %d from RtmGetEntityInfo\n", dwErr ); break; } pEntityInfo = &EntityInfo; } // // Get the info about the first next hop // dwErr = RtmGetNextHopInfo( ig.IG_RtmHandle, pRouteInfo->NextHopsList.NextHops[0], &NextHopInfo ); if ( dwErr != NO_ERROR ) { TRACE1( ANY, "GetRouteInfo: Error %d from RtmGetEntityInfo\n", dwErr ); break; } pNextHopInfo = &NextHopInfo; // // Now copy out all the info. // First, the route info // pRoute-> RR_FamilySpecificData.FSD_Metric1 = pRoute-> RR_FamilySpecificData.FSD_Metric = pRouteInfo-> PrefInfo.Metric; // // copy out the protocol id from the entity info // if ( pEntityInfo != NULL ) { pRoute-> RR_RoutingProtocol = pEntityInfo->EntityId.EntityProtocolId; } else { // // this is a RIP route // pRoute-> RR_RoutingProtocol = PROTO_IP_RIP; SETROUTEFLAG(pRoute, GETRIPFLAG(pRouteInfo)); SETROUTETAG(pRoute, GETRIPTAG(pRouteInfo)); } // // Copy out the dest info // RTM_IPV4_GET_ADDR_AND_MASK( pRoute->RR_Network.N_NetNumber, pRoute->RR_Network.N_NetMask, &(pDestInfo->DestAddress) ); pRoute-> hDest = pDestInfo-> DestHandle; // // Copy out the next hop info // RTM_IPV4_GET_ADDR_AND_MASK( pRoute->RR_NextHopAddress.N_NetNumber, pRoute->RR_NextHopAddress.N_NetMask, &(pNextHopInfo->NextHopAddress) ); // // retrive saved next hop mask // pRoute-> RR_NextHopAddress.N_NetMask = *((PDWORD)&pNextHopInfo-> EntitySpecificInfo); pRoute-> RR_InterfaceID = pNextHopInfo->InterfaceIndex; #if 0 { char szNet[20], szMask[20], szNextHop[20], szNextHopMask[20]; lstrcpy(szNet, INET_NTOA(pRoute-> RR_Network.N_NetNumber)); lstrcpy(szMask, INET_NTOA(pRoute-> RR_Network.N_NetMask)); lstrcpy(szNextHop, INET_NTOA(pRoute-> RR_NextHopAddress.N_NetNumber)); lstrcpy(szNextHopMask, INET_NTOA(pRoute-> RR_NextHopAddress.N_NetMask)); TRACE5( ROUTE, "GetRouteInfo : Route %s %s via %s %s on interface %d", szNet, szMask, szNextHop, szNextHopMask, pRoute-> RR_InterfaceID ); TRACE3( ROUTE, "Has metric %d, flag %x, tag %d", GETROUTEMETRIC(pRoute), GETROUTEFLAG(pRoute), GETROUTETAG(pRoute) ); TRACE2( ROUTE, "Protocol %d, original flag %d", pRoute-> RR_RoutingProtocol, GETRIPFLAG(pRouteInfo) ); } #endif } while( FALSE ); // // Release the relevant infos // if ( pNextHopInfo != NULL ) { RtmReleaseNextHopInfo( ig.IG_RtmHandle, pNextHopInfo ); } if ( pEntityInfo != NULL ) { RtmReleaseEntityInfo( ig.IG_RtmHandle, pEntityInfo ); } // // Release the route and dest infos only if we were not passed them // in AND we successfully retrieved them // if ( ( pInDestInfo == NULL ) && ( pDestInfo != NULL ) ) { RtmReleaseDestInfo( ig.IG_RtmHandle, pDestInfo ); } if( ( pInRouteInfo == NULL ) && ( pRouteInfo != NULL ) ) { RtmReleaseRouteInfo( ig.IG_RtmHandle, pRouteInfo ); } return NO_ERROR; }