windows-nt/Source/XPSP1/NT/net/rras/ip/bootp/table.c

1434 lines
32 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
//============================================================================
// 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;
}