/*******************************************************************/ /* Copyright(c) 1992 Microsoft Corporation */ /*******************************************************************/ //*** // // Filename: closehnd.c // // Description: This module contains auxiliary procedures for the // supervisor's procedure-driven state machine that // handles device closing events. // // Author: Stefan Solomon (stefans) June 1, 1992. // //*** #include "ddm.h" #include "handlers.h" #include "objects.h" #include #include #include #include "rasmanif.h" #include "isdn.h" #include "timer.h" #include #include #include //*** // // Function: DevStartClosing // // Descr: // //*** VOID DevStartClosing( IN PDEVICE_OBJECT pDeviceObj ) { PCONNECTION_OBJECT pConnObj; DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM, "DevStartClosing: Entered, hPort=%d", pDeviceObj->hPort); // // Was this a failure for a BAP callback? // if ( pDeviceObj->fFlags & DEV_OBJ_BAP_CALLBACK ) { PppDdmBapCallbackResult( pDeviceObj->hBapConnection, ERROR_PORT_DISCONNECTED ); pDeviceObj->fFlags &= ~DEV_OBJ_BAP_CALLBACK; } // // If not disconnected, disconnect the line. // if( pDeviceObj->ConnectionState != DISCONNECTED ) { if(( gblDDMConfigInfo.pServiceStatus->dwCurrentState == SERVICE_STOP_PENDING) && (!IsPortOwned(pDeviceObj))) { // // RAS service is stopping and we do not own the port // so just mark the state as DISCONNECTED // pDeviceObj->ConnectionState = DISCONNECTED; DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM, "DevStartClosing:Disconnect not posted for biplx port%d", pDeviceObj->hPort); } else { RmDisconnect( pDeviceObj ); } } // // If we are doing security dialog. // if ( pDeviceObj->SecurityState == DEV_OBJ_SECURITY_DIALOG_ACTIVE ) { DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM, "DevStartClosing:Notifying sec. dll to Disconnect"); // // If this fails then we assume that this port has been cleaned up // if ( (*gblDDMConfigInfo.lpfnRasEndSecurityDialog)( pDeviceObj->hPort ) != NO_ERROR ) { pDeviceObj->SecurityState = DEV_OBJ_SECURITY_DIALOG_INACTIVE; } else { pDeviceObj->SecurityState = DEV_OBJ_SECURITY_DIALOG_STOPPING; } } // // If authentication is active, stop it // pDeviceObj->fFlags &= (~DEV_OBJ_AUTH_ACTIVE); if ( ( pConnObj = ConnObjGetPointer( pDeviceObj->hConnection ) ) != NULL ) { // // If our previous state has been active, get the time the user has been // active and log the result. // if (pDeviceObj->DeviceState == DEV_OBJ_ACTIVE) { LogConnectionEvent( pConnObj, pDeviceObj ); } } // // If receive frame was active, stop it. // if ( pDeviceObj->fFlags & DEV_OBJ_RECEIVE_ACTIVE ) { pDeviceObj->fFlags &= (~DEV_OBJ_RECEIVE_ACTIVE ); } // // Stop timers. If no timer active, StopTimer still returns OK // TimerQRemove( (HANDLE)pDeviceObj->hPort, SvDiscTimeout ); TimerQRemove( (HANDLE)pDeviceObj->hPort, SvAuthTimeout ); TimerQRemove( (HANDLE)pDeviceObj->hPort, SvSecurityTimeout ); // // Finally, change the state to closing // pDeviceObj->DeviceState = DEV_OBJ_CLOSING; // // If any any resources are still active, closing will have to wait // until all resources are released. // Check if everything has closed // DevCloseComplete( pDeviceObj ); } //*** // // Function: DevCloseComplete // // Description: Checks if there are still resources allocated. // If all cleaned up goes to next state // //*** VOID DevCloseComplete( IN PDEVICE_OBJECT pDeviceObj ) { BOOL fAuthClosed = FALSE; BOOL fRecvClosed = FALSE; BOOL fConnClosed = FALSE; BOOL fSecurityClosed = FALSE; BOOL fPppClosed = FALSE; PCONNECTION_OBJECT pConnObj = ConnObjGetPointer( pDeviceObj->hConnection ); if ( !( pDeviceObj->fFlags & DEV_OBJ_AUTH_ACTIVE ) ) { fAuthClosed = TRUE; } if ( !( pDeviceObj->fFlags & DEV_OBJ_RECEIVE_ACTIVE ) ) { fRecvClosed = TRUE; } if ( !( pDeviceObj->fFlags & DEV_OBJ_PPP_IS_ACTIVE ) ) { fPppClosed = TRUE; } // // Was this is the last link in the connection // if (pDeviceObj->ConnectionState == DISCONNECTED ) { fConnClosed = TRUE; } if (pDeviceObj->SecurityState == DEV_OBJ_SECURITY_DIALOG_INACTIVE ) { fSecurityClosed = TRUE; } DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM, "DevCloseComplete:hPort=%d,Auth=%d,Rcv=%d,Conn=%d %d,Sec=%d %d,Ppp=%d", pDeviceObj->hPort, !fAuthClosed, !fRecvClosed, pConnObj ? 0 : 1, !fConnClosed, pDeviceObj->ConnectionState, pDeviceObj->SecurityState, !fPppClosed ); if ( fAuthClosed && fRecvClosed && fConnClosed && fSecurityClosed && fPppClosed ) { // // Was this the last link in the bundle? If it was we clean up // if ( pConnObj != NULL ) { HPORT hPortConnected; // // Remove this link from the connection // ConnObjRemoveLink( pDeviceObj->hConnection, pDeviceObj ); // // If admin module is loaded, notify it of a link disconnection // if ( ( pDeviceObj->fFlags & DEV_OBJ_NOTIFY_OF_DISCONNECTION ) && ( gblDDMConfigInfo.lpfnRasAdminLinkHangupNotification != NULL)) { RAS_PORT_0 RasPort0; RAS_PORT_1 RasPort1; VOID (*MprAdminLinkHangupNotification)(RAS_PORT_0 *, RAS_PORT_1*); if ((GetRasPort0Data(pDeviceObj,&RasPort0) == NO_ERROR) && (GetRasPort1Data(pDeviceObj,&RasPort1) == NO_ERROR)) { MprAdminLinkHangupNotification = (VOID (*)( RAS_PORT_0 *, RAS_PORT_1 * )) gblDDMConfigInfo.lpfnRasAdminLinkHangupNotification; MprAdminLinkHangupNotification( &RasPort0, &RasPort1 ); } } // // Confirm with RASMAN that there are no more ports in this // bundle. It may be that there is one but DDM has not gotten // a NewLink message from PPP yet. // if ( ( RasBundleGetPort( NULL, pConnObj->hConnection, &hPortConnected ) != NO_ERROR ) && ( pConnObj->cActiveDevices == 0 ) ) { // // If admin module is loaded, notify it of disconnection // if ( pConnObj->fFlags & CONN_OBJ_NOTIFY_OF_DISCONNECTION ) { ConnectionHangupNotification( pConnObj ); } // // Remove the interface object if it is not a full router. // if ( pConnObj->hDIMInterface != INVALID_HANDLE_VALUE ) { ROUTER_INTERFACE_OBJECT * pIfObject; EnterCriticalSection( &(gblpInterfaceTable->CriticalSection)); pIfObject = IfObjectGetPointer( pConnObj->hDIMInterface ); if ( pIfObject != NULL ) { IfObjectDisconnected( pIfObject ); if ( pIfObject->IfType != ROUTER_IF_TYPE_FULL_ROUTER ) { IfObjectDeleteInterface( pIfObject ); IfObjectRemove( pConnObj->hDIMInterface ); } } LeaveCriticalSection( &(gblpInterfaceTable->CriticalSection)); } // // Remove the Connection Object // ConnObjRemoveAndDeAllocate( pDeviceObj->hConnection ); } } // // Release the media (if any) used by this port // if ( pDeviceObj->fFlags & DEV_OBJ_MARKED_AS_INUSE ) { pDeviceObj->fFlags &= ~DEV_OBJ_MARKED_AS_INUSE; gblDeviceTable.NumDevicesInUse--; // // Increase media count for this device // if ( pDeviceObj->fFlags & DEV_OBJ_ALLOW_ROUTERS ) { MediaObjAddToTable( pDeviceObj->wchDeviceType ); } // // Possibly need to notify router managers of reachability // change // EnterCriticalSection( &(gblpInterfaceTable->CriticalSection) ); IfObjectNotifyAllOfReachabilityChange( TRUE, INTERFACE_OUT_OF_RESOURCES ); LeaveCriticalSection( &(gblpInterfaceTable->CriticalSection) ); } // // Release any RasMan buffers if we have allocated them // if ( pDeviceObj->pRasmanSendBuffer != NULL ) { RasFreeBuffer( pDeviceObj->pRasmanSendBuffer ); pDeviceObj->pRasmanSendBuffer = NULL; } if ( pDeviceObj->pRasmanRecvBuffer != NULL ) { RasFreeBuffer( pDeviceObj->pRasmanRecvBuffer ); pDeviceObj->pRasmanRecvBuffer = NULL; } RasSetRouterUsage( pDeviceObj->hPort, FALSE ); // // If we have gotten a PnP remove message, then discard this port // if ( pDeviceObj->fFlags & DEV_OBJ_PNP_DELETE ) { // // We do this in a worker thread since this thread may be // walking the device list, hence we cannot modify it here. // RtlQueueWorkItem( DeviceObjRemoveFromTable, pDeviceObj->hPort, WT_EXECUTEDEFAULT ); return; } else { // // Reset fields in this port device // pDeviceObj->hConnection = (HCONN)INVALID_HANDLE_VALUE; pDeviceObj->wchUserName[0] = (WCHAR)NULL; pDeviceObj->wchDomainName[0] = (WCHAR)NULL; pDeviceObj->wchCallbackNumber[0] = (WCHAR)NULL; pDeviceObj->fFlags &= (~DEV_OBJ_IS_PPP); } // // switch to next state (based on the present service state) // switch ( gblDDMConfigInfo.pServiceStatus->dwCurrentState ) { case SERVICE_RUNNING: case SERVICE_START_PENDING: // // post a listen on the device // pDeviceObj->DeviceState = DEV_OBJ_LISTENING; RmListen(pDeviceObj); break; case SERVICE_PAUSED: // // wait for the service to be running again // pDeviceObj->DeviceState = DEV_OBJ_CLOSED; break; case SERVICE_STOP_PENDING: // // this device has terminated. Announce the closure to // the central stop service coordinator // pDeviceObj->DeviceState = DEV_OBJ_CLOSED; DDMServiceStopComplete(); break; default: RTASSERT(FALSE); break; } } }