windows-nt/Source/XPSP1/NT/net/rras/ipx/rtrmgr/update.c
2020-09-26 16:20:57 +08:00

490 lines
9.6 KiB
C

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
update.c
Abstract:
The auto-static update routines
Author:
Stefan Solomon 05/18/1995
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
VOID
SaveUpdate(PVOID InterfaceIndex);
VOID
RestoreInterface (PVOID InterfaceIndex);
/*++
Function: RequestUpdate
Descr: Called to initiate an auto static update of routes and
services on the specified interface.
--*/
DWORD
RequestUpdate(IN HANDLE InterfaceIndex,
IN HANDLE hEvent)
{
PICB icbp;
DWORD rc;
BOOL RoutesUpdateStarted = FALSE;
BOOL ServicesUpdateStarted = FALSE;
Trace(UPDATE_TRACE, "RequestUpdate: Entered for if # %d\n", InterfaceIndex);
ACQUIRE_DATABASE_LOCK;
if(RouterOperState != OPER_STATE_UP) {
RELEASE_DATABASE_LOCK;
return ERROR_CAN_NOT_COMPLETE;
}
if((icbp = GetInterfaceByIndex(PtrToUlong(InterfaceIndex))) == NULL) {
RELEASE_DATABASE_LOCK;
Trace(UPDATE_TRACE, "RequestUpdate: Nonexistent interface with # %d\n", InterfaceIndex);
return ERROR_INVALID_HANDLE;
}
SS_ASSERT(!memcmp(&icbp->Signature, InterfaceSignature, 4));
// check if the interface is bound to a connected adapter
if(icbp->OperState != OPER_STATE_UP) {
RELEASE_DATABASE_LOCK;
Trace(UPDATE_TRACE, "RequestUpdate: adapter not connected on if # %d\n", InterfaceIndex);
return ERROR_NOT_CONNECTED;
}
// check if an update is already pending
if(IsUpdateRequestPending(icbp)) {
RELEASE_DATABASE_LOCK;
Trace(UPDATE_TRACE, "RequestUpdate: update already pending on if # %d\n", InterfaceIndex);
return ERROR_UPDATE_IN_PROGRESS;
}
//
// *** Start a new update ***
//
icbp->DIMUpdateEvent = hEvent;
if((rc = RtProtRequestRoutesUpdate(icbp->InterfaceIndex)) == NO_ERROR) {
icbp->UpdateReq.RoutesReqStatus = UPDATE_PENDING;
}
else
{
Trace(UPDATE_TRACE, "RequestUpdate: Routing Update is Disabled\n");
}
if((rc = RtProtRequestServicesUpdate(icbp->InterfaceIndex)) == NO_ERROR) {
icbp->UpdateReq.ServicesReqStatus = UPDATE_PENDING;
}
else
{
Trace(UPDATE_TRACE, "RequestUpdate: Services Update is Disabled\n");
}
// if at least one of the protocols initiated the update, we qualify
// the request as successfull, else it failed.
if(!IsUpdateRequestPending(icbp)) {
RELEASE_DATABASE_LOCK;
return ERROR_CAN_NOT_COMPLETE;
}
RELEASE_DATABASE_LOCK;
return PENDING;
}
/*++
Function: UpdateCompleted
Descr: Invoked by the router manager worker when the routing protocol
signals completion of the update request
--*/
VOID
UpdateCompleted(PUPDATE_COMPLETE_MESSAGE ucmsgp)
{
PICB icbp;
BOOL UpdateDone;
ULONG InterfaceIndex;
HANDLE hDIMInterface;
#if DBG
char *updttype;
#endif
Trace(UPDATE_TRACE, "UpdateCompleted: Entered\n");
UpdateDone = FALSE;
ACQUIRE_DATABASE_LOCK;
if((icbp = GetInterfaceByIndex(ucmsgp->InterfaceIndex)) == NULL) {
RELEASE_DATABASE_LOCK;
Trace(UPDATE_TRACE, "UpdateCompleted: Nonexistent interface with # %d\n",
ucmsgp->InterfaceIndex);
return;
}
InterfaceIndex = icbp->InterfaceIndex;
// check if we have requested one, if not just discard
if(!IsUpdateRequestPending(icbp)) {
RELEASE_DATABASE_LOCK;
return;
}
// fill in the result and check if we're done
if(ucmsgp->UpdateType == DEMAND_UPDATE_ROUTES) {
// ROUTES UPDATE
Trace(UPDATE_TRACE, "UpdateCompleted: Routes update req done for if # %d with status %d\n",
ucmsgp->InterfaceIndex,
ucmsgp->UpdateStatus);
if(ucmsgp->UpdateStatus == NO_ERROR) {
icbp->UpdateReq.RoutesReqStatus = UPDATE_SUCCESSFULL;
// if the update was successfull we delete all the static routes
// for this interface, and then CONVERT all the routes added by the
// protocol which did the update on this interface to static routes.
DeleteAllStaticRoutes(icbp->InterfaceIndex);
ConvertAllProtocolRoutesToStatic(icbp->InterfaceIndex, UpdateRoutesProtId);
}
else
{
icbp->UpdateReq.RoutesReqStatus = UPDATE_FAILURE;
}
if(icbp->UpdateReq.ServicesReqStatus != UPDATE_PENDING) {
// we are done
UpdateDone = TRUE;
}
}
else
{
// SERVICES UPDATE
Trace(UPDATE_TRACE, "UpdateCompleted: Services update req done for if # %d with status %d\n",
ucmsgp->InterfaceIndex,
ucmsgp->UpdateStatus);
if(ucmsgp->UpdateStatus == NO_ERROR) {
icbp->UpdateReq.ServicesReqStatus = UPDATE_SUCCESSFULL;
// we delete all the static services for this interface and then
// CONVERT all the services added by the protocol which did the
// update routes on this interface to static services
DeleteAllStaticServices(InterfaceIndex);
ConvertAllServicesToStatic(InterfaceIndex);
}
else
{
icbp->UpdateReq.ServicesReqStatus = UPDATE_FAILURE;
}
if(icbp->UpdateReq.RoutesReqStatus != UPDATE_PENDING) {
// we are done
UpdateDone = TRUE;
}
}
if(UpdateDone) {
if((icbp->UpdateReq.RoutesReqStatus == UPDATE_SUCCESSFULL) &&
(icbp->UpdateReq.ServicesReqStatus == UPDATE_SUCCESSFULL)) {
icbp->UpdateResult = NO_ERROR;
}
else
{
if((icbp->UpdateReq.RoutesReqStatus == UPDATE_FAILURE) ||
(icbp->UpdateReq.ServicesReqStatus == UPDATE_FAILURE)) {
icbp->UpdateResult = ERROR_CAN_NOT_COMPLETE;
}
else
{
// this is for the case when one or both protocols couldn't
// do updates because they were not configured to update.
icbp->UpdateResult = NO_ERROR;
}
}
ResetUpdateRequest(icbp);
if(icbp->MIBInterfaceType != IF_TYPE_ROUTER_WORKSTATION_DIALOUT) {
SetEvent(icbp->DIMUpdateEvent);
CloseHandle (icbp->DIMUpdateEvent);
icbp->DIMUpdateEvent = NULL;
}
}
// complete the update action by signaling DIM the final result
// and saving the update result on disk
if(UpdateDone &&
(icbp->MIBInterfaceType != IF_TYPE_ROUTER_WORKSTATION_DIALOUT)) {
InterfaceIndex = icbp->InterfaceIndex;
if(RtlQueueWorkItem((icbp->UpdateResult == NO_ERROR) ? SaveUpdate : RestoreInterface,
(PVOID)UlongToPtr(InterfaceIndex), 0) == STATUS_SUCCESS) {
WorkItemsPendingCounter++;
}
}
RELEASE_DATABASE_LOCK;
}
/*++
Function: SaveUpdate
Descr: Saves the new interface configuration on permanent storage
--*/
VOID
SaveUpdate(PVOID InterfaceIndex)
{
LPVOID InterfaceInfop = NULL;
ULONG InterfaceInfoSize = 0;
DWORD rc;
HANDLE hDIMInterface;
PICB icbp;
if(RouterOperState != OPER_STATE_UP) {
goto Exit;
}
rc = GetInterfaceInfo((HANDLE)InterfaceIndex,
InterfaceInfop,
&InterfaceInfoSize);
if(rc != ERROR_INSUFFICIENT_BUFFER) {
// !!! log an error !!!
goto Exit;
}
InterfaceInfop = GlobalAlloc(GPTR, InterfaceInfoSize);
if(InterfaceInfop == NULL) {
// !!! log error !!!
goto Exit;
}
rc = GetInterfaceInfo((HANDLE)InterfaceIndex,
InterfaceInfop,
&InterfaceInfoSize);
if(rc != NO_ERROR) {
// !!! log error !!!
GlobalFree(InterfaceInfop);
goto Exit;
}
ACQUIRE_DATABASE_LOCK;
if((icbp = GetInterfaceByIndex(PtrToUlong(InterfaceIndex))) == NULL) {
RELEASE_DATABASE_LOCK;
goto Exit;
}
hDIMInterface = icbp->hDIMInterface;
RELEASE_DATABASE_LOCK;
// save the info on disk
rc = SaveInterfaceInfo(hDIMInterface,
PID_IPX,
InterfaceInfop,
InterfaceInfoSize);
SS_ASSERT(rc == NO_ERROR);
GlobalFree(InterfaceInfop);
Exit:
ACQUIRE_DATABASE_LOCK;
WorkItemsPendingCounter--;
RELEASE_DATABASE_LOCK;
}
/*++
Function: RestoreInterface
Descr: Restore interface configuration from permanent storage
--*/
VOID
RestoreInterface (PVOID InterfaceIndex)
{
LPVOID InterfaceInfop = NULL;
ULONG InterfaceInfoSize = 0;
DWORD rc;
HANDLE hDIMInterface;
PICB icbp;
if(RouterOperState != OPER_STATE_UP) {
goto Exit;
}
ACQUIRE_DATABASE_LOCK;
if((icbp = GetInterfaceByIndex(PtrToUlong(InterfaceIndex))) == NULL) {
RELEASE_DATABASE_LOCK;
goto Exit;
}
hDIMInterface = icbp->hDIMInterface;
RELEASE_DATABASE_LOCK;
// get the info from disk
InterfaceInfoSize = 0;
InterfaceInfop = NULL;
rc = RestoreInterfaceInfo (hDIMInterface,
PID_IPX,
InterfaceInfop,
&InterfaceInfoSize);
if (rc==ERROR_BUFFER_TOO_SMALL) {
InterfaceInfop = GlobalAlloc (GMEM_FIXED, InterfaceInfoSize);
if (InterfaceInfop!=NULL) {
rc = RestoreInterfaceInfo(hDIMInterface,
PID_IPX,
InterfaceInfop,
&InterfaceInfoSize);
}
else
rc = GetLastError ();
}
if (rc == NO_ERROR)
rc = SetInterfaceInfo (InterfaceIndex, InterfaceInfop);
if (InterfaceInfop!=NULL)
GlobalFree(InterfaceInfop);
Exit:
ACQUIRE_DATABASE_LOCK;
WorkItemsPendingCounter--;
RELEASE_DATABASE_LOCK;
}
/*++
Function: GetDIMUpdateResult
Descr: Called by DDM to retrieve a message posted for it
--*/
DWORD
GetDIMUpdateResult(IN HANDLE InterfaceIndex,
OUT LPDWORD UpdateResultp)
{
PLIST_ENTRY lep;
PICB icbp;
ACQUIRE_DATABASE_LOCK;
if(RouterOperState != OPER_STATE_UP) {
RELEASE_DATABASE_LOCK;
return ERROR_CAN_NOT_COMPLETE;
}
if((icbp = GetInterfaceByIndex(PtrToUlong(InterfaceIndex))) == NULL) {
RELEASE_DATABASE_LOCK;
return ERROR_INVALID_PARAMETER;
}
// check that the update is not pending
if(IsUpdateRequestPending(icbp)) {
RELEASE_DATABASE_LOCK;
return ERROR_CAN_NOT_COMPLETE;
}
*UpdateResultp = icbp->UpdateResult;
RELEASE_DATABASE_LOCK;
return NO_ERROR;
}