windows-nt/Source/XPSP1/NT/net/rras/ip/sample/networkentry.c
2020-09-26 16:20:57 +08:00

1318 lines
32 KiB
C

/*++
Copyright (c) 1999, Microsoft Corporation
Module Name:
sample\networkentry.c
Abstract:
The file contains functions to deal with the network entry and its
associated data structures.
--*/
#include "pchsample.h"
#pragma hdrstop
DWORD
BE_CreateTable (
IN PIP_ADAPTER_BINDING_INFO pBinding,
OUT PBINDING_ENTRY *ppbeBindingTable,
OUT PIPADDRESS pipLowestAddress)
/*++
Routine Description
Creates a table of binding entries and returns the binding with the
lowest ip address. Ensures that there is atleast one binding.
Locks
None
Arguments
pBinding structure containing info about addresses bindings
ppbeBindingTable pointer to the binding table address
pipLowestAddress pointer to the lowest ip address in the binding
Return Value
NO_ERROR if success
Failure code o/w
--*/
{
ULONG i;
DWORD dwErr = NO_ERROR;
PBINDING_ENTRY pbe; // scratch
// validate parameters
if (!pBinding or !ppbeBindingTable or !pipLowestAddress)
return ERROR_INVALID_PARAMETER;
// a binding already exists
if (*ppbeBindingTable != NULL)
return ERROR_INVALID_PARAMETER;
IP_ASSIGN(pipLowestAddress, IP_HIGHEST);
do // breakout loop
{
if (pBinding->AddressCount is 0)
{
dwErr = ERROR_INVALID_PARAMETER;
TRACE0(NETWORK, "Error, no bindings specified");
break;
}
for (i = 0; i < pBinding->AddressCount; i++)
if (!IP_VALID((pBinding->Address)[i].Address))
break;
if (i != pBinding->AddressCount)
{
dwErr = ERROR_INVALID_PARAMETER;
TRACE0(NETWORK, "Error, an invalid binding specified");
break;
}
// allocate the binding table
MALLOC(&pbe, pBinding->AddressCount * sizeof(BINDING_ENTRY), &dwErr);
if (dwErr != NO_ERROR)
break;
for (i = 0; i < pBinding->AddressCount; i++)
{
// initialize fields
IP_ASSIGN(&(pbe[i].ipAddress), (pBinding->Address)[i].Address);
IP_ASSIGN(&(pbe[i].ipMask), pBinding->Address[i].Mask);
// update lowest ip address
if (IP_COMPARE(pbe[i].ipAddress, *pipLowestAddress) is -1)
IP_ASSIGN(pipLowestAddress,pbe[i].ipAddress);
}
*ppbeBindingTable = pbe;
} while (FALSE);
return dwErr;
}
DWORD
BE_DestroyTable (
IN PBINDING_ENTRY pbeBindingTable)
/*++
Routine Description
Destroys a binding table.
Locks
None.
Arguments
pbeBindingTable pointer to the table of binding entries
Return Value
NO_ERROR always
--*/
{
if (!pbeBindingTable)
return NO_ERROR;
FREE(pbeBindingTable);
return NO_ERROR;
}
#ifdef DEBUG
DWORD
BE_DisplayTable (
IN PBINDING_ENTRY pbeBindingTable,
IN ULONG ulNumBindings)
/*++
Routine Description
Displays a binding entry.
Locks
None.
Arguments
pbeBindingTable pointer to the table of binding entries
ulNumBindings # binding entries in the table
Return Value
NO_ERROR always
--*/
{
ULONG i;
if (!pbeBindingTable)
return NO_ERROR;
for (i = 0; i < ulNumBindings; i++)
{
TRACE1(NETWORK, "ipAddress %s",
INET_NTOA(pbeBindingTable[i].ipAddress));
TRACE1(NETWORK, "ipMask %s",
INET_NTOA(pbeBindingTable[i].ipMask));
}
return NO_ERROR;
}
#endif // DEBUG
#ifdef DEBUG
static
VOID
DisplayInterfaceEntry (
IN PLIST_ENTRY pleEntry)
/*++
Routine Description
Displays an INTERFACE_ENTRY object.
Locks
None
Arguments
pleEntry address of the 'leInterfaceTableLink' field
Return Value
None
--*/
{
IE_Display(CONTAINING_RECORD(pleEntry,
INTERFACE_ENTRY,
leInterfaceTableLink));
}
#else
#define DisplayInterfaceEntry NULL
#endif // DEBUG
static
VOID
FreeInterfaceEntry (
IN PLIST_ENTRY pleEntry)
/*++
Routine Description
Called by HT_Destroy, the destructor of the primary access structure.
Removes an INTERFACE_ENTRY object from all secondary access structures.
Locks
None
Arguments
pleEntry address of the 'leInterfaceTableLink' field
Return Value
None
--*/
{
PINTERFACE_ENTRY pie = NULL;
pie = CONTAINING_RECORD(pleEntry, INTERFACE_ENTRY, leInterfaceTableLink);
// remove from all secondary access structures.
RemoveEntryList(&(pie->leIndexSortedListLink));
// initialize pointers to indicate that the entry has been deleted
InitializeListHead(&(pie->leInterfaceTableLink));
InitializeListHead(&(pie->leIndexSortedListLink));
IE_Destroy(pie);
}
static
ULONG
HashInterfaceEntry (
IN PLIST_ENTRY pleEntry)
/*++
Routine Description
Computes the hash value of an INTERFACE_ENTRY object.
Locks
None
Arguments
pleEntry address of the 'leInterfaceTableLink' field
Return Value
None
--*/
{
PINTERFACE_ENTRY pie = CONTAINING_RECORD(pleEntry,
INTERFACE_ENTRY,
leInterfaceTableLink);
return (pie->dwIfIndex % INTERFACE_TABLE_BUCKETS);
}
static
LONG
CompareInterfaceEntry (
IN PLIST_ENTRY pleKeyEntry,
IN PLIST_ENTRY pleTableEntry)
/*++
Routine Description
Compares the interface indices of two INTERFACE_ENTRY objects.
Locks
None
Arguments
pleTableEntry address of the 'leInterfaceTableLink' fields
pleKeyEntry within the two objects
Return Value
None
--*/
{
PINTERFACE_ENTRY pieA, pieB;
pieA = CONTAINING_RECORD(pleKeyEntry,
INTERFACE_ENTRY,
leInterfaceTableLink);
pieB = CONTAINING_RECORD(pleTableEntry,
INTERFACE_ENTRY,
leInterfaceTableLink);
if (pieA->dwIfIndex < pieB->dwIfIndex)
return -1;
else if (pieA->dwIfIndex is pieB->dwIfIndex)
return 0;
else
return 1;
}
#ifdef DEBUG
static
VOID
DisplayIndexInterfaceEntry (
IN PLIST_ENTRY pleEntry)
/*++
Routine Description
Displays an INTERFACE_ENTRY object.
Locks
None
Arguments
pleEntry address of the 'leIndexSortedListLink' field
Return Value
None
--*/
{
IE_Display(CONTAINING_RECORD(pleEntry,
INTERFACE_ENTRY,
leIndexSortedListLink));
}
#else
#define DisplayIndexInterfaceEntry NULL
#endif // DEBUG
static
LONG
CompareIndexInterfaceEntry (
IN PLIST_ENTRY pleKeyEntry,
IN PLIST_ENTRY pleTableEntry)
/*++
Routine Description
Compares the interface indices of two INTERFACE_ENTRY objects.
Locks
None
Arguments
pleTableEntry address of the 'leIndexSortedListLink' fields
pleKeyEntry within the two objects
Return Value
None
--*/
{
PINTERFACE_ENTRY pieA, pieB;
pieA = CONTAINING_RECORD(pleKeyEntry,
INTERFACE_ENTRY,
leIndexSortedListLink);
pieB = CONTAINING_RECORD(pleTableEntry,
INTERFACE_ENTRY,
leIndexSortedListLink);
if (pieA->dwIfIndex < pieB->dwIfIndex)
return -1;
else if (pieA->dwIfIndex is pieB->dwIfIndex)
return 0;
else
return 1;
}
DWORD
IE_Create (
IN PWCHAR pwszIfName,
IN DWORD dwIfIndex,
IN WORD wAccessType,
OUT PINTERFACE_ENTRY *ppieInterfaceEntry)
/*++
Routine Description
Creates an interface entry.
Locks
None
Arguments
ppieInterfaceEntry pointer to the interface entry address
Return Value
NO_ERROR if success
Failure code o/w
--*/
{
DWORD dwErr = NO_ERROR;
ULONG ulNameLength;
PINTERFACE_ENTRY pieEntry; // scratch
// validate parameters
if (!ppieInterfaceEntry)
return ERROR_INVALID_PARAMETER;
*ppieInterfaceEntry = NULL;
do // breakout loop
{
// allocate and zero out the interface entry structure
MALLOC(&pieEntry, sizeof(INTERFACE_ENTRY), &dwErr);
if (dwErr != NO_ERROR)
break;
// initialize fields with default values
InitializeListHead(&(pieEntry->leInterfaceTableLink));
InitializeListHead(&(pieEntry->leIndexSortedListLink));
// pieEntry->pwszIfName = NULL;
pieEntry->dwIfIndex = dwIfIndex;
// pieEntry->ulNumBindings = 0;
// pieEntry->pbeBindingTable = NULL;
// pieEntry->dwFlags = 0; // disabled unbound pointtopoint
if (wAccessType is IF_ACCESS_BROADCAST)
pieEntry->dwFlags |= IEFLAG_MULTIACCESS;
IP_ASSIGN(&(pieEntry->ipAddress), IP_LOWEST);
pieEntry->sRawSocket = INVALID_SOCKET;
// pieEntry->hReceiveEvent = NULL;
// pieEntry->hReceiveWait = NULL;
// pieEntry->hPeriodicTimer = NULL;
// pieEntry->ulMetric = 0;
// pieEntry->iisStats zero'ed out
// initialize name
ulNameLength = wcslen(pwszIfName) + 1;
MALLOC(&(pieEntry->pwszIfName), ulNameLength * sizeof(WCHAR), &dwErr);
if(dwErr != NO_ERROR)
break;
wcscpy(pieEntry->pwszIfName, pwszIfName);
// initialize ReceiveEvent (signalled when input arrives).
// Auto-Reset Event: state automatically reset to nonsignaled after
// a single waiting thread is released. Initially non signalled
pieEntry->hReceiveEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (pieEntry->hReceiveEvent is NULL)
{
dwErr = GetLastError();
TRACE1(NETWORK, "Error %u creating Receive Event", dwErr);
LOGERR0(CREATE_EVENT_FAILED, dwErr);
break;
}
// register ReceiveWait for this interface
if (!RegisterWaitForSingleObject(&(pieEntry->hReceiveWait),
pieEntry->hReceiveEvent,
NM_CallbackNetworkEvent,
(PVOID) dwIfIndex,
INFINITE,
WT_EXECUTEONLYONCE))
{
dwErr = GetLastError();
TRACE1(NETWORK, "Error %u registering ReceiveWait", dwErr);
LOGERR0(REGISTER_WAIT_FAILED, dwErr);
break;
}
*ppieInterfaceEntry = pieEntry; // all's well :)
} while (FALSE);
if (dwErr != NO_ERROR)
{
// something went wrong, so cleanup.
TRACE2(NETWORK, "Failed to create interface entry for %S (%u)",
pwszIfName, dwIfIndex);
IE_Destroy(pieEntry);
}
return dwErr;
}
DWORD
IE_Destroy (
IN PINTERFACE_ENTRY pieInterfaceEntry)
/*++
Routine Description
Destroys an interface entry.
Locks
Assumes exclusive access to the entry by virute of it having been
removed from all access data structures (lists, tables, ...)
NOTE: Should NOT be called with g_ce.neNetworkEntry.rwlLock held! The
call to UnregisterWaitEx blocks till all queued callbacks for
pieInterfaceEntry->hReceiveEvent finish execution. These callbacks may
acquire g_ce.neNetworkEntry.rwlLock, causing deadlock.
Arguments
pieInterfaceEntry pointer to the interface entry
Return Value
NO_ERROR always
--*/
{
if (!pieInterfaceEntry)
return NO_ERROR;
if (INTERFACE_IS_BOUND(pieInterfaceEntry))
IE_UnBindInterface(pieInterfaceEntry);
if (INTERFACE_IS_ACTIVE(pieInterfaceEntry))
IE_DeactivateInterface(pieInterfaceEntry);
// PeriodicTimer should have been destroyed
RTASSERT(pieInterfaceEntry->hPeriodicTimer is NULL);
// deregister ReceiveWait
if (pieInterfaceEntry->hReceiveWait)
UnregisterWaitEx(pieInterfaceEntry->hReceiveWait,
INVALID_HANDLE_VALUE);
// delete ReceiveEvent
if (pieInterfaceEntry->hReceiveEvent)
CloseHandle(pieInterfaceEntry->hReceiveEvent);
// BindingTable and RawSocket should have been destroyed
RTASSERT(pieInterfaceEntry->pbeBindingTable is NULL);
RTASSERT(pieInterfaceEntry->sRawSocket is INVALID_SOCKET);
// delete IfName
FREE(pieInterfaceEntry->pwszIfName);
// Entry should have been removed from all access structures
RTASSERT(IsListEmpty(&(pieInterfaceEntry->leInterfaceTableLink)));
RTASSERT(IsListEmpty(&(pieInterfaceEntry->leIndexSortedListLink)));
// deallocate the interface entry structure
FREE(pieInterfaceEntry);
return NO_ERROR;
}
#ifdef DEBUG
DWORD
IE_Display (
IN PINTERFACE_ENTRY pieInterfaceEntry)
/*++
Routine Description
Displays an interface entry.
Locks
Assumes the interface entry is locked for reading.
Arguments
pieInterfaceEntry pointer to the interface entry to be displayed
Return Value
NO_ERROR always
--*/
{
if (!pieInterfaceEntry)
return NO_ERROR;
TRACE3(NETWORK,
"IfName %S, IfIndex %u, AccessType %u",
pieInterfaceEntry->pwszIfName,
pieInterfaceEntry->dwIfIndex,
INTERFACE_IS_MULTIACCESS(pieInterfaceEntry));
TRACE1(NETWORK, "NumBindings %u", pieInterfaceEntry->ulNumBindings);
BE_DisplayTable(pieInterfaceEntry->pbeBindingTable,
pieInterfaceEntry->ulNumBindings);
TRACE2(NETWORK,
"IfAddress %s Flags %u",
INET_NTOA(pieInterfaceEntry->ipAddress),
pieInterfaceEntry->dwFlags);
TRACE2(NETWORK,
"Metric %u, NumPackets %u",
pieInterfaceEntry->ulMetric,
pieInterfaceEntry->iisStats.ulNumPackets);
return NO_ERROR;
}
#endif // DEBUG
DWORD
IE_Insert (
IN PINTERFACE_ENTRY pieIfEntry)
/*++
Routine Description
Inserts an interface entry in all access structures,
primary and secondary.
Locks
Assumes exclusive access to the interface table and index sorted list
i.e. (g_ce.pneNetworkEntry)->rwlLock held in write mode.
Arguments
pieIfEntry pointer to the interface entry
Return Value
NO_ERROR success
ERROR_INVALID_PARAMETER o/w (interface entry already exists)
--*/
{
DWORD dwErr = NO_ERROR;
do // breakout loop
{
dwErr = HT_InsertEntry((g_ce.pneNetworkEntry)->phtInterfaceTable,
&(pieIfEntry->leInterfaceTableLink));
if (dwErr != NO_ERROR)
{
TRACE2(NETWORK, "Error interface %S (%u) already exists",
pieIfEntry->pwszIfName, pieIfEntry->dwIfIndex);
LOGERR0(INTERFACE_PRESENT, dwErr);
break;
}
// insert in all tables, lists...
InsertSortedList(&((g_ce.pneNetworkEntry)->leIndexSortedList),
&(pieIfEntry->leIndexSortedListLink),
CompareIndexInterfaceEntry);
} while (FALSE);
return dwErr;
}
DWORD
IE_Delete (
IN DWORD dwIfIndex,
OUT PINTERFACE_ENTRY *ppieIfEntry)
/*++
Routine Description
Deletes an interface entry from all access structures,
primary and secondary.
Locks
Assumes exclusive access to the interface table and index sorted list
i.e. (g_ce.pneNetworkEntry)->rwlLock held in write mode.
Arguments
dwIfIndex the positive integer used to identify the interface.
ppieIfEntry address of the pointer to the interface entry
Return Value
NO_ERROR success
ERROR_INVALID_PARAMETER o/w (interface entry does not exist)
--*/
{
DWORD dwErr = NO_ERROR;
INTERFACE_ENTRY ieKey;
PLIST_ENTRY pleListEntry = NULL;
*ppieIfEntry = NULL;
do // breakout loop
{
// remove from interface table (primary)
ZeroMemory(&ieKey, sizeof(INTERFACE_ENTRY));
ieKey.dwIfIndex = dwIfIndex;
dwErr = HT_DeleteEntry((g_ce.pneNetworkEntry)->phtInterfaceTable,
&(ieKey.leInterfaceTableLink),
&pleListEntry);
if (dwErr != NO_ERROR)
{
TRACE1(NETWORK, "Error interface %u has vanished", dwIfIndex);
LOGWARN0(INTERFACE_ABSENT, dwErr);
break;
}
*ppieIfEntry = CONTAINING_RECORD(pleListEntry,
INTERFACE_ENTRY,
leInterfaceTableLink);
// remove from all other tables, lists... (secondary)
RemoveEntryList(&((*ppieIfEntry)->leIndexSortedListLink));
// initialize pointers to indicate that the entry has been deleted
InitializeListHead(&((*ppieIfEntry)->leInterfaceTableLink));
InitializeListHead(&((*ppieIfEntry)->leIndexSortedListLink));
} while (FALSE);
return dwErr;
}
BOOL
IE_IsPresent (
IN DWORD dwIfIndex)
/*++
Routine Description
Is interface entry present in interface table?
Locks
Assumes shared access to the interface table
i.e. (g_ce.pneNetworkEntry)->rwlLock held in read mode.
Arguments
dwIfIndex the positive integer used to identify the interface.
Return Value
TRUE entry present
FALSE o/w
--*/
{
DWORD dwErr = NO_ERROR;
INTERFACE_ENTRY ieKey;
ZeroMemory(&ieKey, sizeof(INTERFACE_ENTRY));
ieKey.dwIfIndex = dwIfIndex;
return HT_IsPresentEntry((g_ce.pneNetworkEntry)->phtInterfaceTable,
&(ieKey.leInterfaceTableLink));
}
DWORD
IE_Get (
IN DWORD dwIfIndex,
OUT PINTERFACE_ENTRY *ppieIfEntry)
/*++
Routine Description
Retrieves an interface entry from the interface table,
the primary address strucutre.
Locks
Assumes shared access to the interface table
i.e. (g_ce.pneNetworkEntry)->rwlLock held in read mode.
Arguments
dwIfIndex the positive integer used to identify the interface.
ppieIfEntry address of the pointer to the interface entry
Return Value
NO_ERROR success
ERROR_INVALID_PARAMETER o/w (interface entry does not exist)
--*/
{
DWORD dwErr = NO_ERROR;
INTERFACE_ENTRY ieKey;
PLIST_ENTRY pleListEntry = NULL;
*ppieIfEntry = NULL;
do // breakout loop
{
ZeroMemory(&ieKey, sizeof(INTERFACE_ENTRY));
ieKey.dwIfIndex = dwIfIndex;
dwErr = HT_GetEntry((g_ce.pneNetworkEntry)->phtInterfaceTable,
&(ieKey.leInterfaceTableLink),
&pleListEntry);
if (dwErr != NO_ERROR)
{
TRACE1(NETWORK, "Error interface %u has vanished", dwIfIndex);
LOGWARN0(INTERFACE_ABSENT, dwErr);
break;
}
*ppieIfEntry = CONTAINING_RECORD(pleListEntry,
INTERFACE_ENTRY,
leInterfaceTableLink);
} while (FALSE);
return dwErr;
}
DWORD
IE_GetIndex (
IN DWORD dwIfIndex,
IN MODE mMode,
OUT PINTERFACE_ENTRY *ppieIfEntry)
/*++
Routine Description
Retrieves an interface entry from the index sorted list,
the secondary address strucutre.
Locks
Assumes shared access to the index sorted list
i.e. (g_ce.pneNetworkEntry)->rwlLock held in read mode.
Arguments
dwIfIndex the positive integer used to identify the interface.
mMode mode of access (GET_EXACT, GET_FIRST, GET_NEXT)
ppieIfEntry address of the pointer to the interface entry
Return Value
NO_ERROR success
ERROR_NO_MORE_ITEMS o/w
--*/
{
INTERFACE_ENTRY ieKey;
PLIST_ENTRY pleHead = NULL, pleEntry = NULL;
*ppieIfEntry = NULL;
pleHead = &((g_ce.pneNetworkEntry)->leIndexSortedList);
if (IsListEmpty(pleHead))
return ERROR_NO_MORE_ITEMS;
ZeroMemory(&ieKey, sizeof(INTERFACE_ENTRY));
ieKey.dwIfIndex = (mMode is GET_FIRST) ? 0 : dwIfIndex;
// this either gets the exact match or the next entry
FindSortedList(pleHead,
&(ieKey.leIndexSortedListLink),
&pleEntry,
CompareIndexInterfaceEntry);
// reached end of list
if (pleEntry is NULL)
{
RTASSERT(mMode != GET_FIRST); // should have got the first entry
return ERROR_NO_MORE_ITEMS;
}
*ppieIfEntry = CONTAINING_RECORD(pleEntry,
INTERFACE_ENTRY,
leIndexSortedListLink);
switch (mMode)
{
case GET_FIRST:
return NO_ERROR;
case GET_EXACT:
// found an exact match
if ((*ppieIfEntry)->dwIfIndex is dwIfIndex)
return NO_ERROR;
else
{
*ppieIfEntry = NULL;
return ERROR_NO_MORE_ITEMS;
}
case GET_NEXT:
// found an exact match
if ((*ppieIfEntry)->dwIfIndex is dwIfIndex)
{
pleEntry = pleEntry->Flink; // get next entry
if (pleEntry is pleHead) // end of list
{
*ppieIfEntry = NULL;
return ERROR_NO_MORE_ITEMS;
}
*ppieIfEntry = CONTAINING_RECORD(pleEntry,
INTERFACE_ENTRY,
leIndexSortedListLink);
}
return NO_ERROR;
default:
RTASSERT(FALSE); // never reached
}
}
DWORD
IE_BindInterface (
IN PINTERFACE_ENTRY pie,
IN PIP_ADAPTER_BINDING_INFO pBinding)
/*++
Routine Description
Binds an interface.
Locks
Assumes the interface entry is locked for writing.
Arguments
pie pointer to the interface entry
pBinding info about the addresses on the interface
Return Value
NO_ERROR success
Error Code o/w
--*/
{
DWORD dwErr = NO_ERROR;
ULONG i, j;
do // breakout loop
{
// fail if the interface is already bound
if (INTERFACE_IS_BOUND(pie))
{
dwErr = ERROR_INVALID_PARAMETER;
TRACE2(NETWORK, "Error interface %S (%u) is already bound",
pie->pwszIfName, pie->dwIfIndex);
break;
}
dwErr = BE_CreateTable (pBinding,
&(pie->pbeBindingTable),
&(pie->ipAddress));
if (dwErr != NO_ERROR)
break;
pie->ulNumBindings = pBinding->AddressCount;
// set the "bound" flag
pie->dwFlags |= IEFLAG_BOUND;
} while (FALSE);
return dwErr;
}
DWORD
IE_UnBindInterface (
IN PINTERFACE_ENTRY pie)
/*++
Routine Description
UnBinds an interface.
Locks
Assumes the interface entry is locked for writing.
Arguments
pie pointer to the interface entry
Return Value
NO_ERROR success
Error Code o/w
--*/
{
DWORD dwErr = NO_ERROR;
do // breakout loop
{
// fail if the interface is already unbound
if (INTERFACE_IS_UNBOUND(pie))
{
dwErr = ERROR_INVALID_PARAMETER;
TRACE2(NETWORK, "interface %S (%u) already unbound",
pie->pwszIfName, pie->dwIfIndex);
break;
}
// clear the "bound" flag
pie->dwFlags &= ~IEFLAG_BOUND;
IP_ASSIGN(&(pie->ipAddress), IP_LOWEST);
BE_DestroyTable(pie->pbeBindingTable);
pie->pbeBindingTable = NULL;
pie->ulNumBindings = 0;
} while (FALSE);
return dwErr;
}
DWORD
IE_ActivateInterface (
IN PINTERFACE_ENTRY pie)
/*++
Routine Description
Activates an interface by creating a socket and starting a timer.
The socket is bound to the interface address.
Interface is assumed to have atleast one binding.
Locks
Assumes the interface entry is locked for writing.
Arguments
pie pointer to the interface entry
Return Value
NO_ERROR success
Error Code o/w
--*/
{
DWORD dwErr = NO_ERROR;
do // breakout loop
{
// fail if the interface is already active
if (INTERFACE_IS_ACTIVE(pie))
{
dwErr = ERROR_INVALID_PARAMETER;
TRACE0(NETWORK, "Interface already active");
break;
}
// set the "active" flag
pie->dwFlags |= IEFLAG_ACTIVE;
// create a socket for the interface
dwErr = SocketCreate(pie->ipAddress,
pie->hReceiveEvent,
&(pie->sRawSocket));
if (dwErr != NO_ERROR)
{
TRACE1(NETWORK, "Error creating socket for %s",
INET_NTOA(pie->ipAddress));
break;
}
// start timer for sending protocol packets
CREATE_TIMER(&pie->hPeriodicTimer ,
NM_CallbackPeriodicTimer,
(PVOID) pie->dwIfIndex,
PERIODIC_INTERVAL,
&dwErr);
if (dwErr != NO_ERROR)
break;
} while (FALSE);
if (dwErr != NO_ERROR)
{
TRACE3(NETWORK, "Error %u activating interface %S (%u)",
dwErr, pie->pwszIfName, pie->dwIfIndex);
IE_DeactivateInterface(pie);
}
return dwErr;
}
DWORD
IE_DeactivateInterface (
IN PINTERFACE_ENTRY pie)
/*++
Routine Description
Deactivates an interface by stopping the timer and destroying the socket.
Locks
Assumes the interface entry is locked for writing.
Arguments
pie pointer to the interface entry
Return Value
NO_ERROR success
Error Code o/w
--*/
{
DWORD dwErr = NO_ERROR;
do // breakout loop
{
// fail if the interface is already inactive
if (INTERFACE_IS_INACTIVE(pie))
{
dwErr = ERROR_INVALID_PARAMETER;
TRACE2(NETWORK, "interface %S (%u) already inactive",
pie->pwszIfName, pie->dwIfIndex);
break;
}
// stop the timer
if (pie->hPeriodicTimer)
DELETE_TIMER(pie->hPeriodicTimer, &dwErr);
pie->hPeriodicTimer = NULL;
// destroy the socket for the interface
dwErr = SocketDestroy(pie->sRawSocket);
pie->sRawSocket = INVALID_SOCKET;
// clear the "active" flag
pie->dwFlags &= ~IEFLAG_ACTIVE;
} while (FALSE);
return dwErr;
}
DWORD
NE_Create (
OUT PNETWORK_ENTRY *ppneNetworkEntry)
/*++
Routine Description
Creates a network entry.
Locks
None
Arguments
ppneNetworkEntry pointer to the network entry address
Return Value
NO_ERROR if success
Failure code o/w
--*/
{
DWORD dwErr = NO_ERROR;
PNETWORK_ENTRY pneEntry; // scratch
// validate parameters
if (!ppneNetworkEntry)
return ERROR_INVALID_PARAMETER;
*ppneNetworkEntry = NULL;
do // breakout loop
{
// allocate and zero out the network entry structure
MALLOC(&pneEntry, sizeof(NETWORK_ENTRY), &dwErr);
if (dwErr != NO_ERROR)
break;
// initialize fields with default values
// pneEntry->rwlLock zero'ed out
// pneEntry->phtInterfaceTable = NULL;
InitializeListHead(&(pneEntry->leIndexSortedList));
// initialize the read-write lock
dwErr = CREATE_READ_WRITE_LOCK(&(pneEntry->rwlLock));
if (dwErr != NO_ERROR)
{
TRACE1(NETWORK, "Error %u creating read-write-lock", dwErr);
LOGERR0(CREATE_RWL_FAILED, dwErr);
break;
}
// allocate the interface table
dwErr = HT_Create(GLOBAL_HEAP,
INTERFACE_TABLE_BUCKETS,
DisplayInterfaceEntry,
FreeInterfaceEntry,
HashInterfaceEntry,
CompareInterfaceEntry,
&(pneEntry->phtInterfaceTable));
if (dwErr != NO_ERROR)
{
TRACE1(NETWORK, "Error %u creating hash-table", dwErr);
LOGERR0(CREATE_HASHTABLE_FAILED, dwErr);
break;
}
*ppneNetworkEntry = pneEntry;
} while (FALSE);
if (dwErr != NO_ERROR)
{
// something went wrong, so cleanup.
TRACE0(NETWORK, "Failed to create nework entry");
NE_Destroy(pneEntry);
pneEntry = NULL;
}
return dwErr;
}
DWORD
NE_Destroy (
IN PNETWORK_ENTRY pneNetworkEntry)
/*++
Routine Description
Destroys a network entry.
Locks
Assumes exclusive access to rwlLock by virtue of of no competing threads.
Arguments
pneNetworkEntry pointer to the network entry
Return Value
NO_ERROR always
--*/
{
if (!pneNetworkEntry)
return NO_ERROR;
// deallocate the interface table...
// this removes the interface entries from all secondary access
// structures (IndexSortedList, ...) as well since all of them
// share interface entries by containing pointers to the same object.
HT_Destroy(GLOBAL_HEAP, pneNetworkEntry->phtInterfaceTable);
pneNetworkEntry->phtInterfaceTable = NULL;
RTASSERT(IsListEmpty(&(pneNetworkEntry->leIndexSortedList)));
// delete read-write-lock
if (READ_WRITE_LOCK_CREATED(&(pneNetworkEntry->rwlLock)))
DELETE_READ_WRITE_LOCK(&(pneNetworkEntry->rwlLock));
// deallocate the network entry structure
FREE(pneNetworkEntry);
return NO_ERROR;
}
#ifdef DEBUG
DWORD
NE_Display (
IN PNETWORK_ENTRY pneNetworkEntry)
/*++
Routine Description
Displays a network entry.
Locks
Acquires shared pneNetworkEntry->rwlLock
Releases pneNetworkEntry->rwlLock
Arguments
pne pointer to the network entry to be displayed
Return Value
NO_ERROR always
--*/
{
if (!pneNetworkEntry)
return NO_ERROR;
ACQUIRE_READ_LOCK(&(pneNetworkEntry->rwlLock));
TRACE0(NETWORK, "Network Entry...");
TRACE1(NETWORK,
"Interface Table Size %u",
HT_Size(pneNetworkEntry->phtInterfaceTable));
TRACE0(NETWORK, "Interface Table...");
HT_Display(pneNetworkEntry->phtInterfaceTable);
TRACE0(NETWORK, "Index Sorted List...");
MapCarList(&(pneNetworkEntry->leIndexSortedList),
DisplayIndexInterfaceEntry);
RELEASE_READ_LOCK(&(pneNetworkEntry->rwlLock));
return NO_ERROR;
}
#endif // DEBUG