490 lines
9.6 KiB
C
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;
|
|
}
|