|
|
/*++
Copyright (c) 1999, Microsoft Corporation
Module Name:
sample\networkmanager.c
Abstract:
The file contains network configuration related functions, implementing the network manager.
NOTE: The network manager should never take the configuration entry lock (g_ce.rwlLock). . the protocol manager never modifies any g_ce field protected by it . the network manager never modifies any g_ce field protected by it . the configuration manager never cleans up any g_ce field as long as there are active threads
--*/
#include "pchsample.h"
#pragma hdrstop
BOOL ValidateInterfaceConfig ( IN PIPSAMPLE_IF_CONFIG piic) /*++
Routine Description Checks to see if the interface configuration is OK. It is good practice to do this because a corrupt registry can change configuration causing all sorts of debugging headaches if it is not found early
Locks None
Arguments piic pointer to ip sample interface's configuration
Return Value TRUE if the configuration is good FALSE o/w
--*/ { DWORD dwErr = NO_ERROR;
do // breakout loop
{ if (piic is NULL) { dwErr = ERROR_INVALID_PARAMETER; TRACE0(NETWORK, "Error null interface config");
break; }
//
// check range of each field
//
// ensure that the metric is within bounds
if (piic->ulMetric > IPSAMPLE_METRIC_INFINITE) { dwErr = ERROR_INVALID_PARAMETER; TRACE0(NETWORK, "Error metric out of range");
break; }
// ensure that protocol flags are fine, for now they'll always be
// add more here...
} while (FALSE);
if (!(dwErr is NO_ERROR)) { TRACE0(NETWORK, "Error corrupt interface config"); LOGERR0(CORRUPT_INTERFACE_CONFIG, dwErr);
return FALSE; }
return TRUE; }
////////////////////////////////////////
// CALLBACKFUNCTIONS
////////////////////////////////////////
VOID WINAPI NM_CallbackNetworkEvent ( IN PVOID pvContext, IN BOOLEAN bTimerOrWaitFired) /*++
Routine Description Processes a network event on the specified interface. NOTE: The interface might have been deleted.
Locks Acquires shared (g_ce.pneNetworkEntry)->rwlLock Releases (g_ce.pneNetworkEntry)->rwlLock
Arguments pvContext dwIfIndex
Return Value None
--*/ { DWORD dwErr = NO_ERROR; DWORD dwIfIndex = 0; PINTERFACE_ENTRY pieInterfaceEntry = NULL; PACKET Packet;
dwIfIndex = (DWORD) pvContext; TRACE1(ENTER, "Entering NM_CallbackNetworkEvent: %u", dwIfIndex);
if (!ENTER_SAMPLE_API()) { return; } // cannot return anything
ACQUIRE_READ_LOCK(&((g_ce.pneNetworkEntry)->rwlLock));
do // breakout loop
{ // fail if the interface does not exist
dwErr = IE_Get(dwIfIndex, &pieInterfaceEntry); if (dwErr != NO_ERROR) break;
// fail if interface is inactive
if (!INTERFACE_IS_ACTIVE(pieInterfaceEntry)) { TRACE1(NETWORK, "Error interface %u is inactive", dwIfIndex); break; }
RTASSERT(pieInterfaceEntry->sRawSocket != INVALID_SOCKET); if (SocketReceiveEvent(pieInterfaceEntry->sRawSocket)) { if (SocketReceive(pieInterfaceEntry->sRawSocket, &Packet) is NO_ERROR) PacketDisplay(&Packet); } else { TRACE1(NETWORK, "Error interface %u false alarm", dwIfIndex); break; }
} while (FALSE);
// reregister ReceiveWait if the interface exists
if (pieInterfaceEntry) { if (!RegisterWaitForSingleObject(&pieInterfaceEntry->hReceiveWait, pieInterfaceEntry->hReceiveEvent, NM_CallbackNetworkEvent, (PVOID) pieInterfaceEntry->dwIfIndex, INFINITE, WT_EXECUTEONLYONCE)) { dwErr = GetLastError(); TRACE2(NETWORK, "Error %u registering wait for %u, continuing", dwErr, pieInterfaceEntry->dwIfIndex); LOGERR0(REGISTER_WAIT_FAILED, dwErr); } }
RELEASE_READ_LOCK(&((g_ce.pneNetworkEntry)->rwlLock));
LEAVE_SAMPLE_API();
TRACE0(LEAVE, "Leaving NM_CallbackNetworkEvent"); }
VOID WINAPI NM_CallbackPeriodicTimer ( IN PVOID pvContext, IN BOOLEAN bTimerOrWaitFired) /*++
Routine Description Processes a periodic timeout event on the specified interface. NOTE: The interface might have been deleted.
Locks Acquires shared (g_ce.pneNetworkEntry)->rwlLock Releases (g_ce.pneNetworkEntry)->rwlLock
Arguments pvContext dwIfIndex
Return Value None
--*/ { DWORD dwErr = NO_ERROR; DWORD dwIfIndex = 0; PINTERFACE_ENTRY pieInterfaceEntry = NULL; PPACKET pPacket; dwIfIndex = (DWORD) pvContext; TRACE1(ENTER, "Entering NM_CallbackPeriodicTimer: %u", dwIfIndex);
if (!ENTER_SAMPLE_API()) { return; } // cannot return anything
ACQUIRE_READ_LOCK(&((g_ce.pneNetworkEntry)->rwlLock));
do // breakout loop
{ // fail if the interface does not exist
dwErr = IE_Get(dwIfIndex, &pieInterfaceEntry); if (dwErr != NO_ERROR) break;
// fail if interface is inactive
if (!INTERFACE_IS_ACTIVE(pieInterfaceEntry)) break;
RTASSERT(pieInterfaceEntry->sRawSocket != INVALID_SOCKET);
// fail if packet cannot be created
if (PacketCreate(&pPacket) != NO_ERROR) break;
PacketDisplay(pPacket); dwErr = SocketSend(pieInterfaceEntry->sRawSocket, SAMPLE_PROTOCOL_MULTICAST_GROUP, pPacket); if (dwErr != NO_ERROR) { PacketDestroy(pPacket); break; }
// update interface statistics
InterlockedIncrement(&(pieInterfaceEntry->iisStats.ulNumPackets)); } while (FALSE);
// restart timer if the interface exists and is active
if ((pieInterfaceEntry) and INTERFACE_IS_ACTIVE(pieInterfaceEntry)) { RESTART_TIMER(pieInterfaceEntry->hPeriodicTimer, PERIODIC_INTERVAL, &dwErr); }
RELEASE_READ_LOCK(&((g_ce.pneNetworkEntry)->rwlLock));
LEAVE_SAMPLE_API();
TRACE0(LEAVE, "Leaving NM_CallbackPeriodicTimer"); }
////////////////////////////////////////
// APIFUNCTIONS
////////////////////////////////////////
DWORD NM_AddInterface ( IN LPWSTR pwszInterfaceName, IN DWORD dwInterfaceIndex, IN WORD wAccessType, IN PVOID pvInterfaceInfo) /*++
Routine Description Add an interface with the given configuration to IPSAMPLE. Interface is created UNBOUND and DISABLED.
Locks Acquires exclusively (g_ce.pneNetworkEntry)->rwlLock Releases (g_ce.pneNetworkEntry)->rwlLock
Arguments pwszInterfaceName the name of the interface, used for logging. dwInterfaceIndex the positive integer used to refer to this interface. wAccessType access type... MULTIACCESS or POINTTOPOINT pvInterfaceInfo our config for this interface
Return Value NO_ERROR if successfully initiailzed Failure code o/w
--*/ { DWORD dwErr = NO_ERROR; PIPSAMPLE_IF_CONFIG piic = NULL; PINTERFACE_ENTRY pieEntry = NULL; if (!ENTER_SAMPLE_API()) { return ERROR_CAN_NOT_COMPLETE; }
ACQUIRE_WRITE_LOCK(&((g_ce.pneNetworkEntry)->rwlLock)); do // breakout loop
{ piic = (PIPSAMPLE_IF_CONFIG) pvInterfaceInfo;
// validate the configuration parameters
if (!ValidateInterfaceConfig(piic)) { dwErr = ERROR_INVALID_PARAMETER; break; }
// fail if the interface exists
if (IE_IsPresent(dwInterfaceIndex)) { dwErr = ERROR_INVALID_PARAMETER; TRACE2(NETWORK, "Error interface %S (%u) already exists", pwszInterfaceName, dwInterfaceIndex); LOGERR0(INTERFACE_PRESENT, dwErr);
break; }
// create an interface entry
dwErr = IE_Create(pwszInterfaceName, dwInterfaceIndex, wAccessType, &pieEntry); if (dwErr != NO_ERROR) break;
// initialize interface configuration fields
pieEntry->ulMetric = piic->ulMetric;
// insert the interface in all access structures
dwErr = IE_Insert(pieEntry); RTASSERT(dwErr is NO_ERROR); // no reason to fail!
// update global statistics
InterlockedIncrement(&(g_ce.igsStats.ulNumInterfaces)); } while (FALSE); RELEASE_WRITE_LOCK(&((g_ce.pneNetworkEntry)->rwlLock));
LEAVE_SAMPLE_API();
return dwErr; }
DWORD NM_DeleteInterface ( IN DWORD dwInterfaceIndex) /*++
Routine Description Remove an interface with the given index, deactivating it if required.
Locks Acquires exclusively (g_ce.pneNetworkEntry)->rwlLock Releases (g_ce.pneNetworkEntry)->rwlLock
Arguments dwInterfaceIndex the positive integer used to identify the interface.
Return Value NO_ERROR if successfully initiailzed Failure code o/w
--*/ { DWORD dwErr = NO_ERROR; PINTERFACE_ENTRY pieInterfaceEntry = NULL;
if (!ENTER_SAMPLE_API()) { return ERROR_CAN_NOT_COMPLETE; }
do // breakout loop
{ // remove from all tables, lists...
ACQUIRE_WRITE_LOCK(&((g_ce.pneNetworkEntry)->rwlLock));
dwErr = IE_Delete(dwInterfaceIndex, &pieInterfaceEntry);
RELEASE_WRITE_LOCK(&((g_ce.pneNetworkEntry)->rwlLock));
// fail if the interface does not exist
if (dwErr != NO_ERROR) { TRACE1(NETWORK, "Error interface %u does not exist", dwInterfaceIndex); break; }
// destroy the interface entry, deregisters ReceiveWait
// hence best not to hold any locks to prevent deadlocks.
IE_Destroy(pieInterfaceEntry);
// update global statistics
InterlockedDecrement(&(g_ce.igsStats.ulNumInterfaces)); } while (FALSE);
LEAVE_SAMPLE_API();
return dwErr; }
DWORD NM_InterfaceStatus ( IN DWORD dwInterfaceIndex, IN BOOL bInterfaceActive, IN DWORD dwStatusType, IN PVOID pvStatusInfo) /*++
Routine Description
Locks Acquires exclusively (g_ce.pneNetworkEntry)->rwlLock Releases (g_ce.pneNetworkEntry)->rwlLock
Arguments dwInterfaceIndex The index of the interface in question bInterfaceActive Whether the interface can send and receive data dwStatusType RIS_INTERFACE_[ADDRESS_CHANGED|ENABLED|DISABLED] pvStatusInfo Pointer to IP_ADAPTER_BINDING_INFO containing info about the addresses on the interface
Return Value NO_ERROR if successfully initiailzed Failure code o/w --*/ { DWORD dwErr = NO_ERROR; PINTERFACE_ENTRY pieInterfaceEntry = NULL; PIP_ADAPTER_BINDING_INFO pBinding = NULL; BOOL bBindingChanged = FALSE;
if (!ENTER_SAMPLE_API()) { return ERROR_CAN_NOT_COMPLETE; }
ACQUIRE_WRITE_LOCK(&((g_ce.pneNetworkEntry)->rwlLock));
do // breakout loop
{ // fail if the interface does not exist
dwErr = IE_Get(dwInterfaceIndex, &pieInterfaceEntry); if (dwErr != NO_ERROR) break;
// the only status we care about is a change in interface binding
if (dwStatusType is RIS_INTERFACE_ADDRESS_CHANGE) { // destroy existing binding
if (INTERFACE_IS_BOUND(pieInterfaceEntry)) { bBindingChanged = TRUE; dwErr = IE_UnBindInterface(pieInterfaceEntry); RTASSERT(dwErr is NO_ERROR); }
// create new binding
pBinding = (PIP_ADAPTER_BINDING_INFO) pvStatusInfo; if(pBinding->AddressCount) { bBindingChanged = TRUE; dwErr = IE_BindInterface(pieInterfaceEntry, pBinding); if (dwErr != NO_ERROR) break; } }
// interface needs to be deactivated even when the binding changes!
// this restriction is due to the fact that the socket is bound to
// the interface address and not the interface index...
if (INTERFACE_IS_ACTIVE(pieInterfaceEntry) and (bBindingChanged or !bInterfaceActive)) { dwErr = IE_DeactivateInterface(pieInterfaceEntry); if (dwErr != NO_ERROR) break; }
// activate interface only when a binding exists!
// i.e. we do not support unnumbered interfaces for now...
if (INTERFACE_IS_INACTIVE(pieInterfaceEntry) and INTERFACE_IS_BOUND(pieInterfaceEntry) and bInterfaceActive) { dwErr = IE_ActivateInterface(pieInterfaceEntry); if (dwErr != NO_ERROR) break; } } while (FALSE); RELEASE_WRITE_LOCK(&((g_ce.pneNetworkEntry)->rwlLock));
LEAVE_SAMPLE_API();
return dwErr; }
DWORD NM_GetInterfaceInfo ( IN DWORD dwInterfaceIndex, IN PVOID pvInterfaceInfo, IN OUT PULONG pulBufferSize, OUT PULONG pulStructureVersion, OUT PULONG pulStructureSize, OUT PULONG pulStructureCount) /*++
Routine Description See if there's space enough to return ip sample interface config. If yes, we return it, otherwise return the size needed.
Locks Acquires shared (g_ce.pneNetworkEntry)->rwlLock Releases (g_ce.pneNetworkEntry)->rwlLock
Arguments dwInterfaceIndex the interface whose configuration is needed pvInterfaceInfo pointer to allocated buffer to store our config pulBufferSize IN size of buffer received OUT size of our interface config
Return Value NO_ERROR if success Failure code o/w
--*/ { DWORD dwErr = NO_ERROR; PIPSAMPLE_IF_CONFIG piic; ULONG ulSize = sizeof(IPSAMPLE_IF_CONFIG); PINTERFACE_ENTRY pieInterfaceEntry = NULL;
if (!ENTER_SAMPLE_API()) { return ERROR_CAN_NOT_COMPLETE; }
ACQUIRE_READ_LOCK(&((g_ce.pneNetworkEntry)->rwlLock));
do // breakout loop
{ // fail if the interface does not exist
dwErr = IE_Get(dwInterfaceIndex, &pieInterfaceEntry); if (dwErr != NO_ERROR) break;
// fail if the size was too small or there was no storage
if((*pulBufferSize < ulSize) or (pvInterfaceInfo is NULL)) { TRACE1(NETWORK, "NM_GetInterfaceInfo: *ulBufferSize %u", *pulBufferSize);
*pulBufferSize = ulSize; dwErr = ERROR_INSUFFICIENT_BUFFER; break; }
// set the OUT parameters
*pulBufferSize = ulSize; if (pulStructureVersion) *pulStructureVersion = 1; if (pulStructureSize) *pulStructureSize = ulSize; if (pulStructureCount) *pulStructureCount = 1;
// copy out the interface configuration
piic = (PIPSAMPLE_IF_CONFIG) pvInterfaceInfo; piic->ulMetric = pieInterfaceEntry->ulMetric; } while (FALSE);
RELEASE_READ_LOCK(&((g_ce.pneNetworkEntry)->rwlLock));
LEAVE_SAMPLE_API();
return dwErr; }
DWORD NM_SetInterfaceInfo ( IN DWORD dwInterfaceIndex, IN PVOID pvInterfaceInfo) /*++
Routine Description Set ip sample interface's configuration.
Locks Acquires exclusively (g_ce.pneNetworkEntry)->rwlLock Releases (g_ce.pneNetworkEntry)->rwlLock
Arguments dwInterfaceIndex the interface whose configuration is to be set pvInterfaceInfo buffer with new interface config
Return Value NO_ERROR if success Failure code o/w
--*/ { DWORD dwErr = NO_ERROR; PIPSAMPLE_IF_CONFIG piic; PINTERFACE_ENTRY pieInterfaceEntry = NULL;
if (!ENTER_SAMPLE_API()) { return ERROR_CAN_NOT_COMPLETE; }
ACQUIRE_WRITE_LOCK(&((g_ce.pneNetworkEntry)->rwlLock));
do // breakout loop
{ // fail if the interface does not exist
dwErr = IE_Get(dwInterfaceIndex, &pieInterfaceEntry); if (dwErr != NO_ERROR) break;
// fail if the configuration is invalid
piic = (PIPSAMPLE_IF_CONFIG) pvInterfaceInfo; if(!ValidateInterfaceConfig(piic)) { dwErr = ERROR_INVALID_PARAMETER; break; }
// update our configuration
pieInterfaceEntry->ulMetric = piic->ulMetric;
// might need additional processing depending on the state change
// caused by the updated interface configuration and the protocol
// behavior. for instance, sockets may need to be created/shutdown
} while (FALSE);
RELEASE_WRITE_LOCK(&((g_ce.pneNetworkEntry)->rwlLock));
LEAVE_SAMPLE_API();
return dwErr; }
DWORD NM_DoUpdateRoutes ( IN DWORD dwInterfaceIndex ) /*++
Routine Description Updates routes over a demand dial interface.
Locks Acquires exclusively (g_ce.pneNetworkEntry)->rwlLock Releases (g_ce.pneNetworkEntry)->rwlLock
Arguments dwInterfaceIndex the relevant interface index
Return Value NO_ERROR if success Failure code o/w
--*/ { DWORD dwErr = NO_ERROR; PINTERFACE_ENTRY pieInterfaceEntry = NULL; MESSAGE mMessage; if (!ENTER_SAMPLE_API()) { return ERROR_CAN_NOT_COMPLETE; }
ACQUIRE_READ_LOCK(&((g_ce.pneNetworkEntry)->rwlLock));
do // breakout loop
{ // fail if the interface does not exist
dwErr = IE_Get(dwInterfaceIndex, &pieInterfaceEntry); if (dwErr != NO_ERROR) break;
// ensure interface is active
if (INTERFACE_IS_INACTIVE(pieInterfaceEntry)) { dwErr = ERROR_CAN_NOT_COMPLETE; TRACE1(NETWORK, "Error, interface %u inactive", dwInterfaceIndex); break; }
// here we do protocol specific processing,
// for sample nothing :)
} while (FALSE);
RELEASE_READ_LOCK(&((g_ce.pneNetworkEntry)->rwlLock));
mMessage.UpdateCompleteMessage.InterfaceIndex = dwInterfaceIndex; mMessage.UpdateCompleteMessage.UpdateType = RF_DEMAND_UPDATE_ROUTES; mMessage.UpdateCompleteMessage.UpdateStatus = dwErr; if (EnqueueEvent(UPDATE_COMPLETE, mMessage) is NO_ERROR) SetEvent(g_ce.hMgrNotificationEvent); LEAVE_SAMPLE_API();
return dwErr; }
DWORD NM_ProcessRouteChange ( VOID) /*++
Routine Description Handle messages from RTM about route changes.
Locks None Arguments None Return Value NO_ERROR success Error Code o/w --*/ { DWORD dwErr = NO_ERROR; RTM_DEST_INFO rdiDestination; // 1 view registered for change
BOOL bDone = FALSE; UINT uiNumDests; if (!ENTER_SAMPLE_API()) { return ERROR_CAN_NOT_COMPLETE; }
// loop dequeueing messages until RTM says there are no more left
while (!bDone) { // retrieve route changes
uiNumDests = 1; dwErr = RTM_GetChangedDests( g_ce.hRtmHandle, // my RTMv2 handle
g_ce.hRtmNotificationHandle, // my notification handle
&uiNumDests, // IN # dest info's required
// OUT # dest info's supplied
&rdiDestination); // OUT buffer for dest info's
switch (dwErr) { case ERROR_NO_MORE_ITEMS: bDone = TRUE; dwErr = NO_ERROR; if (uiNumDests < 1) break; // else continue below to process the last destination
case NO_ERROR: RTASSERT(uiNumDests is 1); RTM_DisplayDestInfo(&rdiDestination); // release the destination info
if (RTM_ReleaseChangedDests( g_ce.hRtmHandle, // my RTMv2 handle
g_ce.hRtmNotificationHandle,// my notif handle
uiNumDests, // 1
&rdiDestination // released dest info
) != NO_ERROR) TRACE0(NETWORK, "Error releasing changed dests");
break;
default: bDone = TRUE; TRACE1(NETWORK, "Error %u RtmGetChangedDests", dwErr); break; } } // while
LEAVE_SAMPLE_API();
return dwErr; }
|