//============================================================================ // Copyright (c) 1995, Microsoft Corporation // // File: table.c // // History: // Abolade Gbadegesin August 31, 1995 Created // // Interface table and stats tables management routines //============================================================================ #include "pchbootp.h" //---------------------------------------------------------------------------- // Function: CreateIfTable // // Initializes an interface table. //---------------------------------------------------------------------------- DWORD CreateIfTable( PIF_TABLE pTable ) { DWORD dwErr; PLIST_ENTRY ple, plend; // // return an error if the table is already created // if ( IF_TABLE_CREATED(pTable) ) { TRACE0( IF, "interface table already initialized" ); return ERROR_ALREADY_EXISTS; } // // initialize the by-address and by-index lists of interfaces // InitializeListHead( &pTable->IT_ListByAddress ); InitializeListHead(&pTable->IT_ListByIndex); // // initialize the by-index hash-table of interfaces // plend = pTable->IT_HashTableByIndex + IF_HASHTABLE_SIZE; for ( ple = pTable->IT_HashTableByIndex; ple < plend; ple++ ) { InitializeListHead( ple ); } // // initialize the lock which will protect the table // dwErr = NO_ERROR; try { CREATE_READ_WRITE_LOCK( &pTable->IT_RWL ); } except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = GetExceptionCode( ); TRACE1( IF, "error %d initializing interface table lock", dwErr ); } if ( dwErr == NO_ERROR ) { pTable->IT_Created = 0x12345678; } return dwErr; } //---------------------------------------------------------------------------- // Function: DeleteIfTable // // Deinitializes an interface table, and releases all resources used. // Assumes the table is locked exclusively //---------------------------------------------------------------------------- DWORD DeleteIfTable( PIF_TABLE pTable ) { DWORD dwErr; PIF_TABLE_ENTRY pite; PLIST_ENTRY ple, plend, phead; // // clear the creation flag on the table // pTable->IT_Created = 0; // // free memory used by all entries // plend = pTable->IT_HashTableByIndex + IF_HASHTABLE_SIZE; for ( phead = pTable->IT_HashTableByIndex; phead < plend; phead++ ) { while ( !IsListEmpty( phead ) ) { ple = RemoveHeadList( phead ); pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_HTLinkByIndex); if (IF_IS_BOUND(pite)) { DeleteIfSocket(pite); if (IF_IS_ENABLED(pite)) { RemoveEntryList(&pite->ITE_LinkByAddress); } BOOTP_FREE(pite->ITE_Binding); } if (pite->ITE_Config) { BOOTP_FREE(pite->ITE_Config); } BOOTP_FREE( pite ); } } dwErr = NO_ERROR; try { DELETE_READ_WRITE_LOCK( &pTable->IT_RWL ); } except( EXCEPTION_EXECUTE_HANDLER ) { dwErr = GetExceptionCode( ); TRACE1( IF, "error %d deleting interface table lock", dwErr ); } return dwErr; } //---------------------------------------------------------------------------- // Function: CreateIfEntry // // Allocates and initializes an entry for an interface in the table, // using the supplied configuration. Assumes table is locked exclusively. //---------------------------------------------------------------------------- DWORD CreateIfEntry( PIF_TABLE pTable, DWORD dwIndex, PVOID pConfig ) { DWORD dwErr, dwSize; PIF_TABLE_ENTRY pite; PLIST_ENTRY ple, phead; PIPBOOTP_IF_CONFIG picsrc, picdst; dwErr = NO_ERROR; do { // error breakout loop // // see if the interface already exists // pite = GetIfByIndex( pTable, dwIndex ); if ( pite != NULL ) { TRACE1( IF, "interface %d already exists", dwIndex ); dwErr = ERROR_ALREADY_EXISTS; pite = NULL; break; } // // now allocate memory for the interface // pite = BOOTP_ALLOC( sizeof(IF_TABLE_ENTRY) ); if ( pite == NULL ) { dwErr = GetLastError( ); TRACE2( IF, "error %d allocating %d bytes for interface entry", dwErr, sizeof(IF_TABLE_ENTRY) ); LOGERR0(HEAP_ALLOC_FAILED, dwErr); break; } // // initialize struct fields // pite->ITE_Index = dwIndex; // // We come up in disabled state // pite->ITE_Flags = 0; pite->ITE_Sockets = NULL; pite->ITE_Config = NULL; // // get the size of the configuration block // picsrc = (PIPBOOTP_IF_CONFIG)pConfig; dwSize = IC_SIZEOF( picsrc ); // // validate the configuration parameters // dwErr = ValidateIfConfig(pConfig); if (dwErr != NO_ERROR) { TRACE1(IF, "invalid config specified for interface %d", dwIndex); break; } // // allocate space for the configuration // picdst = BOOTP_ALLOC( dwSize ); if ( picdst == NULL ) { dwErr = GetLastError( ); TRACE2( IF, "error %d allocating %d bytes for interface configuration", dwErr, dwSize ); LOGERR0(HEAP_ALLOC_FAILED, dwErr); pite->ITE_Config = NULL; break; } // // copy the configuration // CopyMemory(picdst, picsrc, dwSize); pite->ITE_Config = picdst; // // initialize binding information and interface stats // pite->ITE_Binding = NULL; ZeroMemory(&pite->ITE_Stats, sizeof(IPBOOTP_IF_STATS)); // // insert the interface in the hash table // phead = pTable->IT_HashTableByIndex + IF_HASHVALUE( dwIndex ); InsertHeadList( phead, &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); } while( FALSE ); if ( dwErr != NO_ERROR && pite != NULL ) { if ( pite->ITE_Config != NULL ) { BOOTP_FREE( pite->ITE_Config ); } BOOTP_FREE( pite ); } return dwErr; } //---------------------------------------------------------------------------- // Function: DeleteIfEntry // // Removes an interface from the interface table. // Assumes the table is locked exclusively. //---------------------------------------------------------------------------- DWORD DeleteIfEntry( PIF_TABLE pTable, DWORD dwIndex ) { DWORD dwErr; PIF_TABLE_ENTRY pite; // // make certain the interface exists // pite = GetIfByIndex( pTable, dwIndex ); if ( pite == NULL ) { TRACE1( IF, "deleting interface: interface %d not found", 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); } BOOTP_FREE(pite->ITE_Binding); } // // remove the entry from the hash table and the list sorted by index // RemoveEntryList( &pite->ITE_HTLinkByIndex ); RemoveEntryList( &pite->ITE_LinkByIndex ); BOOTP_FREE( pite->ITE_Config ); BOOTP_FREE( pite ); return NO_ERROR; } //---------------------------------------------------------------------------- // Function: ValidateIfConfig // // Validates the contents of the specified IPBOOTP_IF_CONFIG structure. //---------------------------------------------------------------------------- DWORD ValidateIfConfig( PIPBOOTP_IF_CONFIG pic ) { CHAR szStr[12]; if (pic->IC_RelayMode != IPBOOTP_RELAY_ENABLED && pic->IC_RelayMode != IPBOOTP_RELAY_DISABLED) { TRACE1( IF, "Invalid value for relay mode %d", pic->IC_RelayMode ); _ltoa(pic->IC_RelayMode, szStr, 10); LOGERR2( INVALID_IF_CONFIG, "Relay Mode", szStr, ERROR_INVALID_PARAMETER ); return ERROR_INVALID_PARAMETER; } if (pic->IC_MaxHopCount > IPBOOTP_MAX_HOP_COUNT) { TRACE1( IF, "Invalid value for max hop count %d", pic->IC_MaxHopCount ); _ltoa(pic->IC_MaxHopCount, szStr, 10); LOGERR2( INVALID_IF_CONFIG, "Max Hop Count", szStr, ERROR_INVALID_PARAMETER ); return ERROR_INVALID_PARAMETER; } return NO_ERROR; } //---------------------------------------------------------------------------- // Function: CreateIfSocket // // Initializes the socket for an interface. Assumes the interface table lock // is held exclusively. //---------------------------------------------------------------------------- DWORD CreateIfSocket( PIF_TABLE_ENTRY pITE ) { SOCKADDR_IN sinaddr; PIPBOOTP_IF_BINDING pib; PIPBOOTP_IP_ADDRESS paddr; DWORD i, dwErr, dwOption; pib = pITE->ITE_Binding; paddr = IPBOOTP_IF_ADDRESS_TABLE(pib); // // allocate memory for the array of sockets // pITE->ITE_Sockets = BOOTP_ALLOC(pib->IB_AddrCount * sizeof(SOCKET)); if (pITE->ITE_Sockets == NULL) { dwErr = GetLastError(); TRACE3( IF, "error %d allocating %d bytes for sockets on interface %d", dwErr, pib->IB_AddrCount * sizeof(SOCKET), pITE->ITE_Index ); LOGERR0(HEAP_ALLOC_FAILED, dwErr); return dwErr; } // // initialize the array // for (i = 0; i < pib->IB_AddrCount; i++) { pITE->ITE_Sockets[i] = INVALID_SOCKET; } // // go through the table of addresses in the binding, // creating a socket for each address // for (i = 0; i < pib->IB_AddrCount; i++, paddr++) { // // create a socket // pITE->ITE_Sockets[i] = WSASocket( AF_INET, SOCK_DGRAM, 0, NULL, 0, 0 ); if (pITE->ITE_Sockets[i] == INVALID_SOCKET) { LPSTR lpszAddr; dwErr = WSAGetLastError( ); lpszAddr = INET_NTOA( paddr->IA_Address ); TRACE3( IF, "error %d creating socket for interface %d (%s)", dwErr, pITE->ITE_Index, lpszAddr ); LOGERR1(CREATE_SOCKET_FAILED, lpszAddr, dwErr); break; } // // enable address re-use on this socket // dwOption = 1; dwErr = setsockopt( pITE->ITE_Sockets[i], SOL_SOCKET, SO_REUSEADDR, (PBYTE)&dwOption, sizeof( DWORD ) ); if ( dwErr == SOCKET_ERROR ) { // // this is a non-fatal error, so print a warning, // but continue initializing the socket // dwErr = WSAGetLastError( ); TRACE3( IF, "error %d enabling address re-use for interface %d (%s)", dwErr, pITE->ITE_Index, INET_NTOA( paddr->IA_Address ) ); } // // enable broadcasting on the socket // dwOption = 1; dwErr = setsockopt( pITE->ITE_Sockets[i], SOL_SOCKET, SO_BROADCAST, (PBYTE)&dwOption, sizeof( DWORD ) ); if ( dwErr == SOCKET_ERROR ) { LPSTR lpszAddr; dwErr = WSAGetLastError( ); lpszAddr = INET_NTOA( paddr->IA_Address ); TRACE3( IF, "error %d enabling broadcast for interface %d (%s)", dwErr, pITE->ITE_Index, lpszAddr ); LOGERR1(ENABLE_BROADCAST_FAILED, lpszAddr, dwErr); break; } // // bind to the address and the BOOTP Server port // sinaddr.sin_port = htons( IPBOOTP_SERVER_PORT ); sinaddr.sin_family = AF_INET; sinaddr.sin_addr.s_addr = paddr->IA_Address; dwErr = bind( pITE->ITE_Sockets[i], (PSOCKADDR)&sinaddr, sizeof(SOCKADDR_IN) ); if ( dwErr == SOCKET_ERROR ) { dwErr = WSAGetLastError( ); TRACE3( IF, "error %d binding interface %d (%s) to BOOTP port", dwErr, pITE->ITE_Index, INET_NTOA( paddr->IA_Address ) ); break; } dwErr = NO_ERROR; } if ( i < pib->IB_AddrCount ) { // // an error occurred, so clean up // DeleteIfSocket( pITE ); } return dwErr; } //---------------------------------------------------------------------------- // Function: DeleteIfSocket // // This function closes the socket used by an interface. // It assumes the interface table lock is held exclusively. //---------------------------------------------------------------------------- DWORD DeleteIfSocket( PIF_TABLE_ENTRY pITE ) { DWORD i, dwErr = NO_ERROR; PIPBOOTP_IF_BINDING pib; PIPBOOTP_IP_ADDRESS paddr; pib = pITE->ITE_Binding; if (!pib) { return ERROR_INVALID_PARAMETER; } paddr = IPBOOTP_IF_ADDRESS_TABLE(pib); for (i = 0; i < pib->IB_AddrCount; i++) { if ( pITE->ITE_Sockets[i] == INVALID_SOCKET ) { continue; } dwErr = closesocket( pITE->ITE_Sockets[i] ); if ( dwErr == SOCKET_ERROR ) { dwErr = WSAGetLastError( ); TRACE3( IF, "error %d closing socket for interface %d (%s)", dwErr, pITE->ITE_Index, INET_NTOA( paddr->IA_Address ) ); } } BOOTP_FREE(pITE->ITE_Sockets); pITE->ITE_Sockets = NULL; return dwErr; } //---------------------------------------------------------------------------- // Function: BindIfEntry // // This function updates the binding information for an interface. // It assumes the interface table is locked for writing. //---------------------------------------------------------------------------- DWORD BindIfEntry( PIF_TABLE pTable, DWORD dwIndex, PIP_ADAPTER_BINDING_INFO pBinding ) { DWORD i, dwErr = NO_ERROR, dwSize; PIF_TABLE_ENTRY pite = (PIF_TABLE_ENTRY) NULL; PIPBOOTP_IF_BINDING pib = (PIPBOOTP_IF_BINDING) NULL; PIPBOOTP_IP_ADDRESS paddr = (PIPBOOTP_IP_ADDRESS) NULL; do { // // retrieve the interface to be bound // pite = GetIfByIndex( pTable, dwIndex ); if ( pite == NULL ) { TRACE1( IF, "binding interface: interface %d not found", dwIndex ); dwErr = ERROR_INVALID_PARAMETER; break; } // // make sure the interface is not bound // if ( IF_IS_BOUND(pite) ) { TRACE1( IF, "interface %d is already bound", dwIndex ); break; } // // make sure there is at least one address // if (pBinding->AddressCount == 0) { break; } dwSize = sizeof(IPBOOTP_IF_BINDING) + pBinding->AddressCount * sizeof(IPBOOTP_IP_ADDRESS); // // allocate memory to store the binding // in our format // pib = BOOTP_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 = IPBOOTP_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; dwErr = CreateIfSocket(pite); if (dwErr != NO_ERROR) { break; } pite->ITE_Flags |= ITEFLAG_BOUND; // // if the interface is also enabled, it is now active // so we put it on the active list // 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; } // // request notification of input events from Winsock // paddr = IPBOOTP_IF_ADDRESS_TABLE(pib); for (i = 0; i < pib->IB_AddrCount; i++, paddr++) { dwErr = WSAEventSelect( pite->ITE_Sockets[i], ig.IG_InputEvent, FD_READ ); if (dwErr != NO_ERROR) { LPSTR lpszAddr = INET_NTOA(paddr->IA_Address); TRACE3( IF, "WSAEventSelect returned %d for interface %d (%s)", dwErr, dwIndex, lpszAddr ); LOGERR1(EVENTSELECT_FAILED, lpszAddr, dwErr); RemoveEntryList(&pite->ITE_LinkByAddress); pite->ITE_Flags &= ~ITEFLAG_BOUND; DeleteIfSocket( pite ); break; } } if (i < pib->IB_AddrCount) { break; } } } while(FALSE); if (dwErr != NO_ERROR) { if (pib) { BOOTP_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; dwErr = NO_ERROR; do { // // retrieve the interface to be unbound // pite = GetIfByIndex( pTable, dwIndex ); if ( pite == NULL ) { TRACE1(IF, "unbinding interface: interface %d not found", dwIndex); return ERROR_INVALID_PARAMETER; } // // quit if interface is already unbound // if ( IF_IS_UNBOUND( pite ) ) { TRACE1( IF, "interface %d is already unbound", dwIndex ); break; } // // if the interface was active (i.e. bound and enabled) // it is no longer, so remove it from the active list // if ( IF_IS_ENABLED( pite ) ) { RemoveEntryList( &pite->ITE_LinkByAddress ); } pite->ITE_Flags &= ~ITEFLAG_BOUND; DeleteIfSocket( pite ); BOOTP_FREE(pite->ITE_Binding); pite->ITE_Binding = NULL; } while(FALSE); return dwErr; } //---------------------------------------------------------------------------- // Function: EnableIfEntry // // This function initiates BOOTP relay activity on the specified interface. // It assumes the interface table lock is held exclusively. //---------------------------------------------------------------------------- DWORD EnableIfEntry( PIF_TABLE pTable, DWORD dwIndex ) { DWORD i, dwErr; PIF_TABLE_ENTRY pite; PIPBOOTP_IF_BINDING pib; PIPBOOTP_IP_ADDRESS paddr; dwErr = NO_ERROR; do { // // make certain the interface exists // pite = GetIfByIndex( pTable, dwIndex ); if ( pite == NULL ) { TRACE1( IF, "enabling interface: interface %d not found", dwIndex ); dwErr = ERROR_INVALID_PARAMETER; break; } // // make certain the interface is disabled // if ( IF_IS_ENABLED( pite ) ) { TRACE1( IF, "interface %d is already enabled", dwIndex ); // // He shouldnt call us twice but we will still handle it // break; } pite->ITE_Flags |= ITEFLAG_ENABLED; // // if the interface was already bound, it is now active, // so place it on the active list // if ( IF_IS_BOUND( pite ) ) { // // insert the interface in the by-address list of 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; } pib = pite->ITE_Binding; paddr = IPBOOTP_IF_ADDRESS_TABLE(pib); // // request notification of input events from Winsock // for (i = 0; i < pib->IB_AddrCount; i++, paddr++) { dwErr = WSAEventSelect( pite->ITE_Sockets[i], ig.IG_InputEvent, FD_READ ); if (dwErr != NO_ERROR) { INT j; LPSTR lpszAddr = INET_NTOA(paddr->IA_Address); TRACE3( IF, "WSAEventSelect returned %d for interface %d (%s)", dwErr, dwIndex, lpszAddr ); LOGERR1(EVENTSELECT_FAILED, lpszAddr, dwErr); RemoveEntryList(&pite->ITE_LinkByAddress); pite->ITE_Flags &= ~ITEFLAG_ENABLED; // // clear the requests for events // for (j = i - 1; j >= 0; j--) { dwErr = WSAEventSelect( pite->ITE_Sockets[j], ig.IG_InputEvent, 0 ); } break; } } if (i < pib->IB_AddrCount) { break; } } } 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, PVOID pConfig ) { DWORD dwErr, dwSize; PIF_TABLE_ENTRY pite; PIPBOOTP_IF_CONFIG picsrc, picdst; // // retrieve the interface to be reconfigured // pite = GetIfByIndex(pTable, dwIndex); if (pite == NULL) { TRACE1( IF, "configuring interface: interface %d not found", dwIndex ); return ERROR_INVALID_PARAMETER; } do { // breakout loop // // compute the size needed to store the new configuration // picsrc = (PIPBOOTP_IF_CONFIG)pConfig; dwSize = IC_SIZEOF(picsrc); // // make sure the new parameters are valid // dwErr = ValidateIfConfig(pConfig); if (dwErr != NO_ERROR) { TRACE1(IF, "invalid config specified for interface %d", dwIndex); break; } // // allocate space for the new configuration // picdst = BOOTP_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; } CopyMemory(picdst, picsrc, dwSize); if (pite->ITE_Config) { BOOTP_FREE(pite->ITE_Config); } pite->ITE_Config = picdst; dwErr = NO_ERROR; } while(FALSE); return dwErr; } //---------------------------------------------------------------------------- // Function: DisableIfEntry // // This function stops RIP activaty on the specified interface. // It assumes the interface table is locked for writing. //---------------------------------------------------------------------------- DWORD DisableIfEntry( PIF_TABLE pTable, DWORD dwIndex ) { DWORD i, dwErr; PIF_TABLE_ENTRY pite; PIPBOOTP_IF_BINDING pib; PIPBOOTP_IP_ADDRESS paddr; dwErr = NO_ERROR; do { // // make certain the interface exists // pite = GetIfByIndex( pTable, dwIndex ); if ( pite == NULL ) { TRACE1( IF, "disabling interface: interface %d not found", dwIndex ); dwErr = ERROR_INVALID_PARAMETER; break; } // // make certain the interface is enabled // if ( IF_IS_DISABLED( pite ) ) { TRACE1( IF, "interface %d is already disabled", dwIndex ); // // This is NOT AN ERROR. // break; } // // if the interface was active (i.e. bound and enabled) // it isn't anymore, so deactivate it here. // if ( IF_IS_BOUND( pite ) ) { // // remove the interface from the by-address list // RemoveEntryList( &pite->ITE_LinkByAddress ); // // tell Winsock to stop notifying us of input events // pib = pite->ITE_Binding; paddr = IPBOOTP_IF_ADDRESS_TABLE(pib); for (i = 0; i < pib->IB_AddrCount; i++) { WSAEventSelect(pite->ITE_Sockets[i], ig.IG_InputEvent, 0); } } // // clear the enabled flag on the interface // pite->ITE_Flags &= ~ITEFLAG_ENABLED; } while(FALSE); return dwErr; } //---------------------------------------------------------------------------- // Function: GetIfByIndex // // returns the interface with the given index. // Assumes the table is locked. //---------------------------------------------------------------------------- PIF_TABLE_ENTRY GetIfByIndex( PIF_TABLE pTable, DWORD dwIndex ) { DWORD dwErr; PIF_TABLE_ENTRY pite, pitefound = NULL; PLIST_ENTRY ple, phead; 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 ) { pitefound = pite; break; } } return pitefound; } //---------------------------------------------------------------------------- // Function: GetIfByAddress // // Returns the interface bound with the given address. // Assumes the table is locked for reading or writing. //---------------------------------------------------------------------------- PIF_TABLE_ENTRY GetIfByAddress( PIF_TABLE pTable, DWORD dwAddress, PDWORD pdwAddrIndex ) { INT cmp; DWORD i, dwErr; PLIST_ENTRY ple, phead; PIPBOOTP_IF_BINDING pib; PIPBOOTP_IP_ADDRESS paddr; PIF_TABLE_ENTRY pite, pitefound = NULL; if ( pdwAddrIndex ) { *pdwAddrIndex = 0; } phead = &pTable->IT_ListByAddress; for ( ple = phead->Flink; ple != phead; ple = ple->Flink ) { pite = CONTAINING_RECORD(ple, IF_TABLE_ENTRY, ITE_LinkByAddress); pib = pite->ITE_Binding; paddr = IPBOOTP_IF_ADDRESS_TABLE(pib); for (i = 0; i < pib->IB_AddrCount; i++, paddr++) { if ( dwAddress == paddr->IA_Address ) { pitefound = pite; break; } } if (pitefound) { if (pdwAddrIndex) { *pdwAddrIndex = i; } break; } } return pitefound; } //---------------------------------------------------------------------------- // 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) { 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 // // This function inserts an interface in the list sorted by index // Assumes the table is locked for writing. //---------------------------------------------------------------------------- DWORD InsertIfByAddress( PIF_TABLE pTable, PIF_TABLE_ENTRY pITE ) { INT cmp; PIF_TABLE_ENTRY pite; PIPBOOTP_IF_BINDING pib; PIPBOOTP_IP_ADDRESS paddr; PLIST_ENTRY pfl, phead; DWORD dwAddress, dwEntryAddr; if ( pITE == NULL || pITE->ITE_Binding == NULL ) { return ERROR_INVALID_PARAMETER; } pib = pITE->ITE_Binding; paddr = IPBOOTP_IF_ADDRESS_TABLE(pib); dwAddress = paddr->IA_Address; phead = &pTable->IT_ListByAddress; for ( pfl = phead->Flink; pfl != phead; pfl = pfl->Flink ) { pite = CONTAINING_RECORD( pfl, IF_TABLE_ENTRY, ITE_LinkByAddress ); paddr = IPBOOTP_IF_ADDRESS_TABLE(pite->ITE_Binding); dwEntryAddr = paddr->IA_Address; if ( INET_CMP( dwAddress, dwEntryAddr, cmp ) < 0 ) { break; } else if (cmp == 0) { return ERROR_ALREADY_EXISTS; } } InsertTailList( pfl, &pITE->ITE_LinkByAddress ); return NO_ERROR; }