|
|
/*++
Copyright (c) 1998, Microsoft Corporation
Module Name:
rmdhcp.c
Abstract:
This module contains routines for the DHCP allocator module's interface to the IP router-manager. (See ROUTPROT.H for details).
Author:
Abolade Gbadegesin (aboladeg) 4-Mar-1998
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
COMPONENT_REFERENCE DhcpComponentReference;
PCHAR DhcpDomainName = NULL;
PIP_AUTO_DHCP_GLOBAL_INFO DhcpGlobalInfo;
CRITICAL_SECTION DhcpGlobalInfoLock;
HANDLE DhcpNotificationEvent;
ULONG DhcpProtocolStopped = 0;
const MPR_ROUTING_CHARACTERISTICS DhcpRoutingCharacteristics = { MS_ROUTER_VERSION, MS_IP_DHCP_ALLOCATOR, RF_ROUTING|RF_ADD_ALL_INTERFACES, DhcpRmStartProtocol, DhcpRmStartComplete, DhcpRmStopProtocol, DhcpRmGetGlobalInfo, DhcpRmSetGlobalInfo, NULL, NULL, DhcpRmAddInterface, DhcpRmDeleteInterface, DhcpRmInterfaceStatus, DhcpRmGetInterfaceInfo, DhcpRmSetInterfaceInfo, DhcpRmGetEventMessage, NULL, NULL, NULL, NULL, NULL, DhcpRmMibCreate, DhcpRmMibDelete, DhcpRmMibGet, DhcpRmMibSet, DhcpRmMibGetFirst, DhcpRmMibGetNext, NULL, NULL };
IP_AUTO_DHCP_STATISTICS DhcpStatistics; SUPPORT_FUNCTIONS DhcpSupportFunctions;
extern "C" LPSTR WINAPI DnsGetPrimaryDomainName_A( VOID );
VOID DhcpCleanupModule( VOID )
/*++
Routine Description:
This routine is invoked to cleanup the DHCP module.
Arguments:
none.
Return Value:
none.
Environment:
Invoked from within a 'DllMain' routine on 'DLL_PROCESS_DETACH'.
--*/
{ DeleteCriticalSection(&DhcpGlobalInfoLock); DhcpShutdownInterfaceManagement(); DeleteComponentReference(&DhcpComponentReference);
} // DhcpCleanupModule
VOID DhcpCleanupProtocol( VOID )
/*++
Routine Description:
This routine is invoked to cleanup the DHCP protocol-component after a 'StopProtocol'. It runs when the last reference to the DHCP component is released. (See 'COMPREF.H').
Arguments:
none.
Return Value:
none.
Environment:
Invoked from within an arbitrary context with no locks held.
--*/
{ PROFILE("DhcpCleanupProtocol");
#if 1
if (DhcpDomainName) { LocalFree(DhcpDomainName); DhcpDomainName = NULL; } #else
if (DhcpDomainName) { NH_FREE(DhcpDomainName); DhcpDomainName = NULL; } #endif
if (DhcpGlobalInfo) { NH_FREE(DhcpGlobalInfo); DhcpGlobalInfo = NULL; } InterlockedExchange(reinterpret_cast<LPLONG>(&DhcpProtocolStopped), 1); SetEvent(DhcpNotificationEvent); ResetComponentReference(&DhcpComponentReference);
} // DhcpCleanupProtocol
BOOLEAN DhcpInitializeModule( VOID )
/*++
Routine Description:
This routine is invoked to initialize the DHCP module.
Arguments:
none.
Return Value:
BOOLEAN - TRUE if initialization succeeded, FALSE otherwise
Environment:
Invoked in the context of a 'DllMain' routine on 'DLL_PROCESS_ATTACH'.
--*/
{ if (InitializeComponentReference( &DhcpComponentReference, DhcpCleanupProtocol )) { return FALSE; } else if (DhcpInitializeInterfaceManagement()) { DeleteComponentReference(&DhcpComponentReference); return FALSE; } else { __try { InitializeCriticalSection(&DhcpGlobalInfoLock); } __except(EXCEPTION_EXECUTE_HANDLER) { DeleteComponentReference(&DhcpComponentReference); return FALSE; } }
return TRUE;
} // DhcpInitializeModule
ULONG APIENTRY DhcpRmStartProtocol( HANDLE NotificationEvent, PSUPPORT_FUNCTIONS SupportFunctions, PVOID GlobalInfo, ULONG StructureVersion, ULONG StructureSize, ULONG StructureCount )
/*++
Routine Description:
This routine is invoked to indicate the component's operation should begin.
Arguments:
NotificationEvent - event on which we notify the router-manager about asynchronous occurrences
SupportFunctions - functions for initiating router-related operations
GlobalInfo - configuration for the component
Return Value:
ULONG - Win32 status code.
Environment:
The routine runs in the context of an IP router-manager thread.
--*/
{ ULONG Error = NO_ERROR; ULONG Size;
PROFILE("DhcpRmStartProtocol");
REFERENCE_DHCP_OR_RETURN(ERROR_CAN_NOT_COMPLETE);
if (!GlobalInfo) { DEREFERENCE_DHCP_AND_RETURN(ERROR_INVALID_PARAMETER); }
do {
//
// Create a copy of the global configuration
//
Size = sizeof(*DhcpGlobalInfo) + ((PIP_AUTO_DHCP_GLOBAL_INFO)GlobalInfo)->ExclusionCount * sizeof(ULONG); DhcpGlobalInfo = reinterpret_cast<PIP_AUTO_DHCP_GLOBAL_INFO>(NH_ALLOCATE(Size));
if (!DhcpGlobalInfo) { NhTrace( TRACE_FLAG_INIT, "DhcpRmStartProtocol: cannot allocate global info" ); NhErrorLog( IP_AUTO_DHCP_LOG_ALLOCATION_FAILED, 0, "%d", Size ); Error = ERROR_NOT_ENOUGH_MEMORY; break; }
CopyMemory(DhcpGlobalInfo, GlobalInfo, Size);
//
// Save the notification event
//
DhcpNotificationEvent = NotificationEvent;
//
// Save the support functions
//
if (!SupportFunctions) { ZeroMemory(&DhcpSupportFunctions, sizeof(DhcpSupportFunctions)); } else { CopyMemory( &DhcpSupportFunctions, SupportFunctions, sizeof(*SupportFunctions) ); }
InterlockedExchange(reinterpret_cast<LPLONG>(&DhcpProtocolStopped), 0);
} while (FALSE);
DEREFERENCE_DHCP_AND_RETURN(Error);
} // DhcpRmStartProtocol
ULONG APIENTRY DhcpRmStartComplete( VOID )
/*++
Routine Description:
This routine is invoked when the router has finished adding the initial configuration
Arguments:
none.
Return Value:
ULONG - Win32 status code
Environment:
The routine runs in the context of an IP router-manager thread.
--*/
{ return NO_ERROR; } // DhcpRmStartComplete
ULONG APIENTRY DhcpRmStopProtocol( VOID )
/*++
Routine Description:
This routine is invoked to stop the protocol.
Arguments:
none.
Return Value:
ULONG - Win32 status code
Environment:
The routine runs in the context of an IP router-manager thread.
--*/
{ PROFILE("DhcpStopProtocol");
//
// Reference the module to make sure it's running
//
REFERENCE_DHCP_OR_RETURN(ERROR_CAN_NOT_COMPLETE);
//
// Drop the initial reference to cause a cleanup
//
ReleaseInitialComponentReference(&DhcpComponentReference);
return DEREFERENCE_DHCP() ? NO_ERROR : ERROR_PROTOCOL_STOP_PENDING;
} // DhcpRmStopProtocol
ULONG APIENTRY DhcpRmAddInterface( PWCHAR Name, ULONG Index, NET_INTERFACE_TYPE Type, ULONG MediaType, USHORT AccessType, USHORT ConnectionType, PVOID InterfaceInfo, ULONG StructureVersion, ULONG StructureSize, ULONG StructureCount )
/*++
Routine Description:
This routine is invoked to add an interface to the component.
Arguments:
Name - the name of the interface (unused)
Index - the index of the interface
Type - the type of the interface
InterfaceInfo - the configuration information for the interface
Return Value:
ULONG - Win32 status code.
Environment:
The routine runs in the context of an IP router-manager thread.
--*/
{ ULONG Error; PROFILE("DhcpRmAddInterface");
if (Type != PERMANENT) { return NO_ERROR; }
REFERENCE_DHCP_OR_RETURN(ERROR_CAN_NOT_COMPLETE);
Error = DhcpCreateInterface( Index, Type, (PIP_AUTO_DHCP_INTERFACE_INFO)InterfaceInfo, NULL );
DEREFERENCE_DHCP_AND_RETURN(Error);
} // DhcpRmAddInterface
ULONG APIENTRY DhcpRmDeleteInterface( ULONG Index )
/*++
Routine Description:
This routine is invoked to delete an interface from the component.
Arguments:
Index - the index of the interface
Return Value:
ULONG - Win32 status code
Environment:
The routine runs in the context of an IP router-manager thread.
--*/
{ ULONG Error; PROFILE("DhcpRmDeleteInterface");
REFERENCE_DHCP_OR_RETURN(ERROR_CAN_NOT_COMPLETE);
Error = DhcpDeleteInterface( Index );
DEREFERENCE_DHCP_AND_RETURN(Error);
} // DhcpRmDeleteInterface
ULONG APIENTRY DhcpRmGetEventMessage( OUT ROUTING_PROTOCOL_EVENTS* Event, OUT MESSAGE* Result )
/*++
Routine Description:
This routine is invoked to retrieve an event message from the component. The only event message we generate is the 'ROUTER_STOPPED' message.
Arguments:
Event - receives the generated event
Result - receives the associated result
Return Value:
ULONG - Win32 status code.
--*/
{ PROFILE("DhcpRmGetEventMessage");
if (InterlockedExchange(reinterpret_cast<LPLONG>(&DhcpProtocolStopped), 0)) { *Event = ROUTER_STOPPED; return NO_ERROR; }
return ERROR_NO_MORE_ITEMS;
} // DhcpRmGetEventMessage
ULONG APIENTRY DhcpRmGetInterfaceInfo( ULONG Index, PVOID InterfaceInfo, IN OUT PULONG InterfaceInfoSize, IN OUT PULONG StructureVersion, IN OUT PULONG StructureSize, IN OUT PULONG StructureCount )
/*++
Routine Description:
This routine is invoked to retrieve the component's per-interface configuration.
Arguments:
Index - the index of the interface to be queried
InterfaceInfo - receives the query results
InterfaceInfoSize - receives the amount of data retrieved
Return Value:
ULONG - Win32 status code.
--*/
{ ULONG Error; PROFILE("DhcpRmGetInterfaceInfo");
REFERENCE_DHCP_OR_RETURN(ERROR_CAN_NOT_COMPLETE);
Error = DhcpQueryInterface( Index, (PIP_AUTO_DHCP_INTERFACE_INFO)InterfaceInfo, InterfaceInfoSize );
*StructureSize = *InterfaceInfoSize; if (StructureCount) {*StructureCount = 1;} DEREFERENCE_DHCP_AND_RETURN(Error);
} // DhcpRmGetInterfaceInfo
ULONG APIENTRY DhcpRmSetInterfaceInfo( ULONG Index, PVOID InterfaceInfo, ULONG StructureVersion, ULONG StructureSize, ULONG StructureCount )
/*++
Routine Description:
This routine is invoked to change the component's per-interface configuration.
Arguments:
Index - the index of the interface to be updated
InterfaceInfo - supplies the new configuration
Return Value:
ULONG - Win32 status code.
--*/
{ ULONG Error; PROFILE("DhcpRmSetInterfaceInfo");
REFERENCE_DHCP_OR_RETURN(ERROR_CAN_NOT_COMPLETE);
Error = DhcpConfigureInterface( Index, (PIP_AUTO_DHCP_INTERFACE_INFO)InterfaceInfo );
DEREFERENCE_DHCP_AND_RETURN(Error);
} // DhcpRmSetInterfaceInfo
ULONG APIENTRY DhcpRmInterfaceStatus( ULONG Index, BOOL InterfaceActive, ULONG StatusType, PVOID StatusInfo )
/*++
Routine Description:
This routine is invoked to bind/unbind, enable/disable an interface
Arguments:
Index - the interface to be bound
InterfaceActive - whether the interface is active
StatusType - type of status being changed (bind or enabled)
StatusInfo - Info pertaining to the state being changed
Return Value:
ULONG - Win32 Status code
Environment:
The routine runs in the context of an IP router-manager thread. --*/
{ ULONG Error = NO_ERROR;
switch(StatusType) { case RIS_INTERFACE_ADDRESS_CHANGE: { PIP_ADAPTER_BINDING_INFO BindInfo = (PIP_ADAPTER_BINDING_INFO)StatusInfo;
if (BindInfo->AddressCount) { Error = DhcpRmBindInterface(Index, StatusInfo); } else { Error = DhcpRmUnbindInterface(Index); } break; }
case RIS_INTERFACE_ENABLED: { Error = DhcpRmEnableInterface(Index); break; }
case RIS_INTERFACE_DISABLED: { Error = DhcpRmDisableInterface(Index); break; } }
return Error; } // DhcpRmInterfaceStatus
ULONG DhcpRmBindInterface( ULONG Index, PVOID BindingInfo )
/*++
Routine Description:
This routine is invoked to bind an interface to its IP address(es).
Arguments:
Index - the interface to be bound
BindingInfo - the addressing information
Return Value:
ULONG - Win32 status code.
Environment:
The routine runs in the context of an IP router-manager thread.
--*/
{ PCHAR DomainName; ULONG Error; NTSTATUS status;
PROFILE("DhcpRmBindInterface");
REFERENCE_DHCP_OR_RETURN(ERROR_CAN_NOT_COMPLETE);
Error = DhcpBindInterface( Index, (PIP_ADAPTER_BINDING_INFO)BindingInfo );
//
// Re-read the domain name in case it changed
//
EnterCriticalSection(&DhcpGlobalInfoLock);
#if 1
DomainName = DnsGetPrimaryDomainName_A(); if (DomainName) { if (DhcpDomainName && lstrcmpiA(DomainName, DhcpDomainName) == 0) { LocalFree(DomainName); } else { if (DhcpDomainName) { LocalFree(DhcpDomainName); } DhcpDomainName = DomainName; } } #else
status = NhQueryDomainName(&DomainName);
if (NT_SUCCESS(status)) { if (DhcpDomainName && lstrcmpiA(DomainName, DhcpDomainName) == 0) { NH_FREE(DomainName); } else { NH_FREE(DhcpDomainName); if (DhcpDomainName) { NH_FREE(DhcpDomainName); } DhcpDomainName = DomainName; } } #endif
LeaveCriticalSection(&DhcpGlobalInfoLock);
DEREFERENCE_DHCP_AND_RETURN(Error);
} // DhcpRmBindInterface
ULONG DhcpRmUnbindInterface( ULONG Index )
/*++
Routine Description:
This routine is invoked to unbind an interface from its IP address(es).
Arguments:
Index - the interface to be unbound
Return Value:
ULONG - Win32 status code.
Environment:
The routine runs in the context of an IP router-manager thread.
--*/
{ ULONG Error; PROFILE("DhcpRmUnbindInterface");
REFERENCE_DHCP_OR_RETURN(ERROR_CAN_NOT_COMPLETE);
Error = DhcpUnbindInterface( Index );
DEREFERENCE_DHCP_AND_RETURN(Error);
} // DhcpRmUnbindInterface
ULONG DhcpRmEnableInterface( ULONG Index )
/*++
Routine Description:
This routine is invoked to enable operation on an interface.
Arguments:
Index - the interface to be enabled.
Return Value:
ULONG - Win32 status code.
Environment:
The routine runs in the context of an IP router-manager thread.
--*/
{ ULONG Error; PROFILE("DhcpRmEnableInterface");
REFERENCE_DHCP_OR_RETURN(ERROR_CAN_NOT_COMPLETE);
Error = DhcpEnableInterface( Index );
DEREFERENCE_DHCP_AND_RETURN(Error);
} // DhcpRmEnableInterface
ULONG DhcpRmDisableInterface( ULONG Index )
/*++
Routine Description:
This routine is invoked to disable operation on an interface.
Arguments:
Index - the interface to be disabled.
Return Value:
ULONG - Win32 status code.
Environment:
The routine runs in the context of an IP router-manager thread.
--*/
{ ULONG Error; PROFILE("DhcpRmDisableInterface");
REFERENCE_DHCP_OR_RETURN(ERROR_CAN_NOT_COMPLETE);
Error = DhcpDisableInterface( Index );
DEREFERENCE_DHCP_AND_RETURN(Error);
} // DhcpRmDisableInterface
ULONG APIENTRY DhcpRmGetGlobalInfo( PVOID GlobalInfo, IN OUT PULONG GlobalInfoSize, PULONG StructureVersion, IN OUT PULONG StructureSize, IN OUT PULONG StructureCount )
/*++
Routine Description:
This routine is invoked to retrieve the configuration for the component.
Arguments:
GlobalInfo - receives the configuration
GlobalInfoSize - receives the size of the configuration
Return Value:
ULONG - Win32 status code
Environment:
The routine runs in the context of an IP router-manager thread.
--*/
{ ULONG Size; PROFILE("DhcpRmGetGlobalInfo");
REFERENCE_DHCP_OR_RETURN(ERROR_CAN_NOT_COMPLETE);
if (!GlobalInfoSize || (*GlobalInfoSize && !GlobalInfo)) { DEREFERENCE_DHCP_AND_RETURN(ERROR_INVALID_PARAMETER); }
EnterCriticalSection(&DhcpGlobalInfoLock); Size = sizeof(*DhcpGlobalInfo) + DhcpGlobalInfo->ExclusionCount * sizeof(ULONG); if (*GlobalInfoSize < Size) { LeaveCriticalSection(&DhcpGlobalInfoLock); *StructureSize = *GlobalInfoSize = Size; if (StructureCount) {*StructureCount = 1;} DEREFERENCE_DHCP_AND_RETURN(ERROR_INSUFFICIENT_BUFFER); } CopyMemory(GlobalInfo, DhcpGlobalInfo, Size); LeaveCriticalSection(&DhcpGlobalInfoLock); *StructureSize = *GlobalInfoSize = Size; if (StructureCount) {*StructureCount = 1;} DEREFERENCE_DHCP_AND_RETURN(NO_ERROR); } // DhcpRmGetGlobalInfo
ULONG APIENTRY DhcpRmSetGlobalInfo( PVOID GlobalInfo, ULONG StructureVersion, ULONG StructureSize, ULONG StructureCount )
/*++
Routine Description:
This routine is invoked to change the configuration for the component.
Arguments:
GlobalInfo - the new configuration
Return Value:
ULONG - Win32 status code
Environment:
The routine runs in the context of an IP router-manager thread.
--*/
{ PIP_AUTO_DHCP_GLOBAL_INFO NewInfo; ULONG NewScope; ULONG OldScope; ULONG Size; PROFILE("DhcpRmSetGlobalInfo");
REFERENCE_DHCP_OR_RETURN(ERROR_CAN_NOT_COMPLETE);
if (!GlobalInfo) { DEREFERENCE_DHCP_AND_RETURN(ERROR_INVALID_PARAMETER); }
Size = sizeof(*DhcpGlobalInfo) + ((PIP_AUTO_DHCP_GLOBAL_INFO)GlobalInfo)->ExclusionCount * sizeof(ULONG); NewInfo = reinterpret_cast<PIP_AUTO_DHCP_GLOBAL_INFO>(NH_ALLOCATE(Size)); if (!NewInfo) { NhTrace( TRACE_FLAG_INIT, "DhcpRmSetGlobalInfo: error reallocating global info" ); NhErrorLog( IP_AUTO_DHCP_LOG_ALLOCATION_FAILED, 0, "%d", Size ); DEREFERENCE_DHCP_AND_RETURN(ERROR_NOT_ENOUGH_MEMORY); } CopyMemory(NewInfo, GlobalInfo, Size);
EnterCriticalSection(&DhcpGlobalInfoLock); OldScope = DhcpGlobalInfo->ScopeNetwork & DhcpGlobalInfo->ScopeMask; NH_FREE(DhcpGlobalInfo); DhcpGlobalInfo = NewInfo; NewScope = DhcpGlobalInfo->ScopeNetwork & DhcpGlobalInfo->ScopeMask; LeaveCriticalSection(&DhcpGlobalInfoLock);
if (OldScope != NewScope) { DhcpReactivateEveryInterface(); }
DEREFERENCE_DHCP_AND_RETURN(NO_ERROR); } // DhcpRmSetGlobalInfo
ULONG APIENTRY DhcpRmMibCreate( ULONG InputDataSize, PVOID InputData ) { return ERROR_NOT_SUPPORTED; }
ULONG APIENTRY DhcpRmMibDelete( ULONG InputDataSize, PVOID InputData ) { return ERROR_NOT_SUPPORTED; }
ULONG APIENTRY DhcpRmMibGet( ULONG InputDataSize, PVOID InputData, OUT PULONG OutputDataSize, OUT PVOID OutputData )
/*++
Routine Description:
The DHCP allocator only exposes one item to the MIB; its statistics.
Arguments:
InputDataSize - the MIB query data size
InputData - specifies the MIB object to be retrieved
OutputDataSize - the MIB response data size
OutputData - receives the MIB object retrieved
Return Value:
ULONG - Win32 status code.
--*/
{ ULONG Error; PIP_AUTO_DHCP_MIB_QUERY Oidp;
PROFILE("DhcpRmMibGet");
REFERENCE_DHCP_OR_RETURN(ERROR_CAN_NOT_COMPLETE);
if (InputDataSize < sizeof(*Oidp) || !OutputDataSize) { Error = ERROR_INVALID_PARAMETER; } else { Oidp = (PIP_AUTO_DHCP_MIB_QUERY)InputData; switch(Oidp->Oid) { case IP_AUTO_DHCP_STATISTICS_OID: { if (*OutputDataSize < sizeof(*Oidp) + sizeof(DhcpStatistics)) { *OutputDataSize = sizeof(*Oidp) + sizeof(DhcpStatistics); Error = ERROR_INSUFFICIENT_BUFFER; } else { *OutputDataSize = sizeof(*Oidp) + sizeof(DhcpStatistics); Oidp = (PIP_AUTO_DHCP_MIB_QUERY)OutputData; Oidp->Oid = IP_AUTO_DHCP_STATISTICS_OID; CopyMemory( Oidp->Data, &DhcpStatistics, sizeof(DhcpStatistics) ); Error = NO_ERROR; } break; } default: { NhTrace( TRACE_FLAG_DHCP, "DhcpRmMibGet: oid %d invalid", Oidp->Oid ); Error = ERROR_INVALID_PARAMETER; break; } } }
DEREFERENCE_DHCP_AND_RETURN(Error); }
ULONG APIENTRY DhcpRmMibSet( ULONG InputDataSize, PVOID InputData ) { return ERROR_NOT_SUPPORTED; }
ULONG APIENTRY DhcpRmMibGetFirst( ULONG InputDataSize, PVOID InputData, OUT PULONG OutputDataSize, OUT PVOID OutputData ) { return ERROR_NOT_SUPPORTED; }
ULONG APIENTRY DhcpRmMibGetNext( ULONG InputDataSize, PVOID InputData, OUT PULONG OutputDataSize, OUT PVOID OutputData ) { return ERROR_NOT_SUPPORTED; }
|