|
|
//****************************************************************************
//
// Terminal Server CDmodem
//
//
// Copyright 1996, Citrix Systems Inc.
// Copyright (C) 1994-95 Microsft Corporation. All rights reserved.
//
// Filename: init.c
//
// Revision History
//
// Nov 1998 updated by Qunbiao Guo for terminal server
// Mar 28 1992 Gurdeep Singh Pall Created for RASMAN
//
// Description: This file contains init code for cdmodem
//
//****************************************************************************
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <tapi.h>
#include <rasndis.h>
#include <wanioctl.h>
#include <rasman.h>
#include <raserror.h>
#include <eventlog.h>
#include <media.h>
#include <device.h>
#include <rasmxs.h>
#include <isdn.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include "rastapi.h"
#ifdef CITRIX
#include <winstaw.h>
#include <icadd.h>
#include <icaapi.h>
#include "cdmodem.h"
#endif // CITRIX
#ifdef CITRIX
#ifdef DBG
#define DBGPRINT(_arg) DbgPrint _arg
#else
#define DBGPRINT(_arg) { }
#endif
#endif // CITRIX
#pragma warning (error:4312)
HLINEAPP RasLine = 0 ; HINSTANCE RasInstance = 0 ; TapiLineInfo *RasTapiLineInfo ; DWORD TotalLines = 0 ; DWORD TotalPorts ; TapiPortControlBlock *RasPorts ; TapiPortControlBlock *RasPortsEnd ; //DWORD NegotiatedApiVersion ;
//DWORD NegotiatedExtVersion ;
HANDLE RasTapiMutex ; BOOL Initialized = FALSE ; DWORD TapiThreadId ; HANDLE TapiThreadHandle; DWORD LoaderThreadId; DWORD ValidPorts = 0; DWORD NumberOfRings = 1 ;
HANDLE ghAsyMac = INVALID_HANDLE_VALUE ;
//DWORD EnumerateTapiPorts () ;
BOOL ReadUsageInfoFromRegistry() ; TapiLineInfo *FindLineByHandle (HLINE) ; TapiPortControlBlock *FindPortByRequestId (DWORD) ; TapiPortControlBlock *FindPortByAddressId (TapiLineInfo *, DWORD) ; TapiPortControlBlock *FindPortByAddress (CHAR *) ; DWORD InitiatePortDisconnection (TapiPortControlBlock *hIOPort) ; TapiPortControlBlock *FindPortByAddressAndName (CHAR *address, CHAR *name) ;
//* InitTapi()
//
//
//*
BOOL InitRasTapi (HANDLE hInst, DWORD ul_reason_being_called, LPVOID lpReserved) { STARTUPINFO startupinfo ; DWORD dwErr; static BOOLEAN DllInitialized = FALSE ;
DBGPRINT(( "CDMODEM: InitRasTapi: hInst 0x%x, reason 0x%x\n", hInst, ul_reason_being_called ));
switch (ul_reason_being_called) {
case DLL_PROCESS_ATTACH:
if (RasPorts != 0) return 1 ;
RasInstance = hInst ;
ReadUsageInfoFromRegistry();
if ((RasTapiMutex = CreateMutex (NULL, FALSE, NULL)) == NULL) return 0 ;
DllInitialized = TRUE ;
break ;
case DLL_PROCESS_DETACH:
//
// If DLL did not successfully initialize for this process dont try to clean up
//
if (!DllInitialized) break ;
lineShutdown (RasLine) ; PostThreadMessage (TapiThreadId, WM_QUIT, 0, 0) ; break ;
case DLL_THREAD_ATTACH: break;
case DLL_THREAD_DETACH: #ifndef CITRIX
//
// If the thread that has created the TAPI
// message queue thread via EnumerateTapiPorts
// is exiting, also clean up the TAPI message
// queue thread at this time.
//
// NOTE: We cannot do an explicit WaitForSingleObject()
// on the TAPI message queue thread because we are
// in a DLL init proc. This would cause a deadlock,
// since the exiting thread has to execute this DLL
// init proc before exiting. The TAPI message queue
// thread actually takes care of the final DLL unload.
// See EnumerateTapiPorts below.
//
if (GetCurrentThreadId() == LoaderThreadId) PostThreadMessage (TapiThreadId, WM_QUIT, 0, 0) ;
#endif // CITRIX
break;
}
return 1 ; }
//* EnumerateTapiPorts()
//
// Function: First we call line initialize and construct a TLI for each line
// Then for each line we enumerate addresses and go through each address
// If the address is configured to be used with RAS we fill in the
// approp. info into the TPCB for the address (now port).
//
// Return: GetLastError(), SUCCESS
//
//*
DWORD EnumerateTapiPorts (HANDLE event) { WORD i, k ; TapiLineInfo *nextline ; DWORD lines = 0 ; BYTE buffer[800] ; LINEADDRESSCAPS *lineaddrcaps ; LINEDEVCAPS *linedevcaps ; CHAR address[40] ; CHAR devicetype[MAX_DEVICETYPE_NAME] = {0}; DWORD devicetypelength; CHAR devicename[MAX_DEVICE_NAME] = {0}; DWORD devicenamelength; CHAR szregkey[128]; LINEEXTENSIONID extensionid ; DWORD totaladdresses ; #ifndef CITRIX
TapiPortControlBlock *nextport ; #else // CITRIX
DWORD addresses ; TapiPortControlBlock *nextport = NULL, *port ; #endif // CITRIX
MSG msg ; HINSTANCE hInst; TapiPortControlBlock *pports ; LINEINITIALIZEEXPARAMS param ; DWORD version = HIGH_VERSION ;
memset (¶m, 0, sizeof (LINEINITIALIZEEXPARAMS)) ; param.dwOptions = LINEINITIALIZEEXOPTION_USEHIDDENWINDOW ; param.dwTotalSize = sizeof(param) ;
#ifdef CITRIX
DBGPRINT(( "CDMODEM: EnumerateTapiPorts: Entry\n" )); #endif // CITRIX
if (lineInitializeEx (&RasLine, RasInstance, (LINECALLBACK) RasTapiCallback, REMOTEACCESS_APP, &lines, &version, ¶m) ) goto error ;
if (lines == 0) { goto error; }
nextline = RasTapiLineInfo = LocalAlloc (LPTR, sizeof (TapiLineInfo) * lines) ;
if (nextline == NULL) goto error ;
TotalLines = lines ; #ifdef CITRIX
totaladdresses = 0; #endif // CITRIX
for (i=0; i<lines; i++) { // for all lines get the addresses -> ports
if (lineNegotiateAPIVersion(RasLine, i, LOW_VERSION, HIGH_VERSION, &nextline->NegotiatedApiVersion, &extensionid) ) { #ifdef CITRIX
totaladdresses++; #endif // CITRIX
nextline->TLI_LineState = PS_UNINITIALIZED ; nextline++ ; continue ; }
if (lineNegotiateExtVersion(RasLine, i, nextline->NegotiatedApiVersion, LOW_EXT_VERSION, HIGH_EXT_VERSION, &nextline->NegotiatedExtVersion)) {
nextline->NegotiatedExtVersion = 0; }
memset (buffer, 0, sizeof(buffer)) ;
linedevcaps = (LINEDEVCAPS *)buffer ; linedevcaps->dwTotalSize = sizeof (buffer) ;
// Get a count of all addresses across all lines
//
if (lineGetDevCaps (RasLine, i, nextline->NegotiatedApiVersion, nextline->NegotiatedExtVersion, linedevcaps)) { #ifdef CITRIX
totaladdresses += linedevcaps->dwNumAddresses; #endif // CITRIX
nextline->TLI_LineState = PS_UNINITIALIZED ; nextline++ ; continue ; }
#ifdef CITRIX
totaladdresses++; #endif // CITRIX
nextline->TLI_LineId = i ; // fill TLI struct. id.
nextline->TLI_LineState = PS_CLOSED ;
nextline++ ; } #ifdef CITRIX
DBGPRINT(( "CDMODEM: ETP: totaladdresses %d\n", totaladdresses)); #endif // CITRIX
// Now that we know the number of lines and number of addresses per line
// we now fillin the TPCB structure per address
//
for (i=0, nextline = RasTapiLineInfo; i<TotalLines ; i++, nextline++) {
BOOL fModem = FALSE ;
if (RasTapiLineInfo[i].TLI_LineState == PS_UNINITIALIZED) continue ;
memset (buffer, 0, sizeof(buffer)) ;
linedevcaps = (LINEDEVCAPS *)buffer ; linedevcaps->dwTotalSize = sizeof(buffer) ;
// Get a count of all addresses across all lines
//
if (lineGetDevCaps (RasLine, i, nextline->NegotiatedApiVersion, nextline->NegotiatedExtVersion, linedevcaps))
goto error ;
// Figure out if this is a unimodem device or not
//
if (nextline->NegotiatedApiVersion == HIGH_VERSION) {
// first convert all nulls in the device class string to non nulls.
//
DWORD j ; char *temp ;
for (j=0, temp = (CHAR *)linedevcaps+linedevcaps->dwDeviceClassesOffset; j<linedevcaps->dwDeviceClassesSize; j++, temp++)
if (*temp == '\0') *temp = ' ' ;
#ifdef CITRIX
DBGPRINT(( "CDMODEM: HIGH VERSION provider: %s, line name: %s \n", (char*) linedevcaps+linedevcaps->dwProviderInfoOffset, (CHAR *)linedevcaps+linedevcaps->dwLineNameOffset)); #endif
// select only those devices that have comm/datamodem as a device class
//
if ( (strstr((CHAR *)linedevcaps+linedevcaps->dwDeviceClassesOffset, "comm/datamodem") != NULL) || (strstr((CHAR *)linedevcaps+linedevcaps->dwProviderInfoOffset, "Modem") != NULL) ) {
DWORD stringlen = (linedevcaps->dwLineNameSize > MAX_DEVICE_NAME - 1 ? MAX_DEVICE_NAME - 1 : linedevcaps->dwLineNameSize) ;
strcpy (devicetype, DEVICETYPE_UNIMODEM) ; strncpy (devicename, (CHAR *)linedevcaps+linedevcaps->dwLineNameOffset, stringlen) ; devicename[stringlen] = '\0' ;
lstrcpynA(szregkey, (CHAR *)linedevcaps+linedevcaps->dwDevSpecificOffset+(2*sizeof(DWORD)), linedevcaps->dwDevSpecificSize); szregkey[linedevcaps->dwDevSpecificSize] = '\0';
fModem = TRUE ; }
} else {
// Provider info is of the following format
// <media name>\0<device name>\0
// where - media name is - ISDN, SWITCH56, FRAMERELAY, etc.
// device name is Digiboard PCIMAC, Cirel, Intel, etc.
//
// Since this format is used only by NDISWAN miniports this may not be present if the TSP
// is a non unimodem and a non NDISWAN miniport. The following code (carefully) tries to
// parse the
//
DWORD copylen ; DWORD providerinfosize = linedevcaps->dwProviderInfoSize + 2; BYTE* providerinfo = LocalAlloc (LPTR, providerinfosize) ; if (providerinfo == NULL) goto error ; memcpy (providerinfo, (CHAR *)linedevcaps+linedevcaps->dwProviderInfoOffset, linedevcaps->dwProviderInfoSize) ; providerinfo[providerinfosize-1] = '\0' ; providerinfo[providerinfosize-2] = '\0' ;
#ifdef CITRIX
DBGPRINT(( "CDMODEM: None High Version, version: %d \n",nextline->NegotiatedApiVersion)); #endif
if (strlen (providerinfo) > MAX_DEVICETYPE_NAME) {
//
// If this name is longer than specified for a devicetype name then this is not a
// wan miniport device. In this case copy the provider info into the devicename
//
copylen = (strlen(providerinfo) > MAX_DEVICE_NAME ? MAX_DEVICE_NAME : strlen(providerinfo)) ;
strcpy (devicetype, "XXXX") ; // put in a dummy device type - this will get skipped.
strncpy (devicename, providerinfo, copylen) ;
} else {
//
// treat this case as the the properly formatted name
//
strcpy (devicetype, providerinfo) ; copylen = (strlen(providerinfo+strlen(providerinfo)+1) > MAX_DEVICE_NAME ? MAX_DEVICE_NAME : strlen(providerinfo+strlen(providerinfo)+1)) ; strncpy (devicename, providerinfo+strlen(providerinfo)+1, copylen) ; devicename[copylen] = '\0' ; } }
#ifndef CITRIX
totaladdresses = linedevcaps->dwNumAddresses ;
for (k=0; k < totaladdresses; k++) { #else // CITRIX
for (k=0; k < linedevcaps->dwNumAddresses; k++) { #endif // CITRIX
if (!fModem) {
memset (buffer, 0, sizeof(buffer)) ;
lineaddrcaps = (LINEADDRESSCAPS*) buffer ; lineaddrcaps->dwTotalSize = sizeof (buffer) ;
if (lineGetAddressCaps (RasLine, i, k, nextline->NegotiatedApiVersion, nextline->NegotiatedExtVersion, lineaddrcaps)) { DBGPRINT(( "CDMODEM: ETP: linegetaddresecaps error\n" )); continue; }
memcpy (address, (CHAR *)lineaddrcaps + lineaddrcaps->dwAddressOffset, sizeof (address) -1 ) ;
#ifndef CITRIX
if ((nextport = FindPortByAddress(address)) == NULL) continue ; // this address not configured for remoteaccess
#endif // CITRIX
} else {
GetAssociatedPortName (szregkey, address) ;
#ifndef CITRIX
if ((nextport = FindPortByAddressAndName(address, devicename)) == NULL) continue ; // this address not configured for remoteaccess
#endif // CITRIX
}
#ifndef CITRIX
// nextport is the TPCB for this address
nextport->TPCB_Line = &RasTapiLineInfo[i] ; nextport->TPCB_State = PS_CLOSED ; nextport->TPCB_Endpoint = 0xffffffff ; nextport->TPCB_AddressId = k ;
// Copy over the devicetype and devicename
strcpy (nextport->TPCB_DeviceType, devicetype) ; #else // CITRIX
// Under RAS, the TPCB was allocated and partially
// set up in the function ReadUsageInfoFromRegistry,
// since WinFrame doesn't have this info convienently
// sectioned off in the Registry it is built here
// from the info garnered from TAPI itself. This
// potentially could add lines to the table that
// WinFrame has no interest in, but it will do no
// harm, since the lines are only acted upon when
// an upper-level WinFrame API is called for a true
// WinFrame-configured line. (Bruce Fortune, Citrix)
//
if (nextport == NULL) { int i;
// Allocate the linear list of TPCBs based on the number
// of addresses. This may be wasteful, and a better
// solution would be to cull the info from WinFrame's
// registry info. (Bruce Fortune, Citrix)
//
TotalPorts = totaladdresses; port = nextport = RasPorts = LocalAlloc (LPTR, sizeof (TapiPortControlBlock) * TotalPorts) ; if (!port) { goto error; } RasPortsEnd = RasPorts + TotalPorts ; while (port < RasPortsEnd) { DBGPRINT(( "CDMODEM: ETP: TPCB init loop\n" )); port->TPCB_State = PS_UNINITIALIZED; port++; } port = nextport++; } else {
// Look for this address in the table, just in case
// of duplicates. If the lookup fails, use the
// next TPCB in the linear list.
//
if ((port = FindPortByAddress(address)) == NULL) { port = nextport++; // use next available entry
if (port >= RasPortsEnd) { DbgPrint("CDMODEM: ETP: Insufficient TPCB.\n"); DbgBreakPoint(); } } }
port->TPCB_Signature = CONTROLBLOCKSIGNATURE ; port->TPCB_Line = &RasTapiLineInfo[i] ; port->TPCB_State = PS_CLOSED ; port->TPCB_Endpoint = 0xffffffff ; port->TPCB_AddressId = k ; port->TPCB_Usage = CALL_IN_OUT;
strcpy (port->TPCB_DeviceType, devicetype) ; strncpy (port->TPCB_Name, devicename, sizeof(port->TPCB_Name)-1 ) ; port->TPCB_Name[sizeof(port->TPCB_Name)-1] = 0; strncpy (port->TPCB_Address, address, sizeof(port->TPCB_Address)-1) ; port->TPCB_Address[sizeof(port->TPCB_Address)-1] = 0; #endif // CITRIX
// For unimodem devices we need to fix up names
//
if (fModem) {
// Device Name is of the form "COM1: Hayes"
//
DBGPRINT(("CDMODEM: address %s, devicename %s \n", address, devicename)); strcpy (port->TPCB_DeviceName, address) ; strcpy (port->TPCB_DeviceName, ":") ; strcpy (port->TPCB_DeviceName, devicename) ;
strncpy (port->TPCB_Name, address, sizeof(port->TPCB_Name)-1) ; port->TPCB_Name[sizeof(port->TPCB_Name)-1] = 0;
} else {
if (devicename[0] != '\0') strcpy (port->TPCB_DeviceName, devicename) ; // default
} DBGPRINT(( "CDMODEM: ETP: p 0x%x, DN \"%s\", a \"%s\"\n", port, port->TPCB_DeviceName, port->TPCB_Name )); }
}
#ifndef CITRIX
//
// Calculate the number of valid ports
//
for (pports = RasPorts, i=0; i < TotalPorts; i++, pports++) { if (pports->TPCB_State == PS_UNINITIALIZED) continue ; ValidPorts++; } #else // CITRIX
//
// Okay, if this DLL got loaded, then at least one TAPI port
// is being used by WinFrame. Since this is all we know,
// ValidPorts will be used here just to indicate that
// there is *at least* one port worth doing this for...
//
ValidPorts = 1; #endif // CITRIX
//
// Increase the reference count on our DLL
// so it won't get unloaded out from under us.
//
hInst = LoadLibrary("cdmodem.dll");
// Notify the api that the initialization is done
//
SetEvent (event) ;
//
// If there are ports, then we hang around until
// we are shut down. Otherwise, we exit immediately.
//
if (ValidPorts) { while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg) ; }
DBGPRINT(( "CDMODEM: ETP: WM_QUIT Message received, shutting down\n" )); }
lineShutdown (RasLine) ;
//
// The following call atomically unloads our
// DLL and terminates this thread.
//
FreeLibraryAndExitThread(hInst, SUCCESS);
error:
if (RasLine) { lineShutdown (RasLine) ; }
RasLine = 0 ;
SetEvent (event) ;
return ((DWORD)-1) ; }
//* ReadUsageInfoFromRegistry()
//
//
//
//
//
//*
BOOL ReadUsageInfoFromRegistry() { DWORD size; DWORD type; HKEY hkey;
//
// Read the number of rings key from the registry
//
if (RegOpenKey (HKEY_LOCAL_MACHINE, TEXT("System\\CurrentControlSet\\Services\\Rasman\\Parameters"), &hkey)) return FALSE;
size = sizeof(DWORD) ; if (RegQueryValueEx (hkey, TEXT("NumberOfRings"), NULL, &type, (LPBYTE)&NumberOfRings, &size)) NumberOfRings = 1 ;
if ((NumberOfRings < 1) || (NumberOfRings > 20)) NumberOfRings = 1 ;
RegCloseKey (hkey) ;
return TRUE; } //* RasTapiCallback()
//
// Function: Callback entrypoint for TAPI.
//
// Returns: Nothing.
//*
VOID FAR PASCAL RasTapiCallback (HANDLE context, DWORD msg, DWORD instance, DWORD param1, DWORD param2, DWORD param3) { LINECALLINFO *linecallinfo ; BYTE buffer [1000] ; HCALL hcall ; HLINE linehandle ; TapiLineInfo *line ; TapiPortControlBlock *port ; DWORD i ; DWORD retcode ;
// **** Exclusion Begin ****
GetMutex (RasTapiMutex, INFINITE) ;
DBGPRINT(( "RasTapiCallback: Ctx 0x%x, Msg: %d, Inst 0x%x, Param1: %d\n", context, msg, instance, param1 ));
switch (msg) {
case LINE_CALLSTATE:
hcall = (HCALL) (ULONG_PTR) context ; line = ULongToPtr(instance);
// If line is closed dont bother
//
if (line->TLI_LineState == PS_CLOSED) break ;
memset (buffer, 0, sizeof(buffer)) ; linecallinfo = (LINECALLINFO *) buffer ; linecallinfo->dwTotalSize = sizeof(buffer) ;
// If line get call info fails return.
//
if (lineGetCallInfo (hcall, linecallinfo) > 0x80000000) break ;
// Locate the ras port for this call
//
if ((port = FindPortByAddressId (line, linecallinfo->dwAddressID)) == NULL) {
// Did not find a ras port for the call. Ignore it.
//
break ; }
DBGPRINT(("RasTapiCallBack: LINE_CALLSTATE check param1 \n")); // A new call is coming in
//
if (param1 == LINECALLSTATE_OFFERING) {
if ((line->TLI_LineState == PS_LISTENING) && (port->TPCB_State == PS_LISTENING)) {
port->TPCB_CallHandle = hcall ;
//
// for unimodem devices wait for the specified number of rings
//
if (_stricmp (port->TPCB_DeviceType, DEVICETYPE_UNIMODEM) == 0) {
//
// call has already been answered by somebody else and is being offered to me
//
if (linecallinfo->dwCallStates == LINECALLSTATE_CONNECTED) {
port->TPCB_ListenState = LS_COMPLETE ;
//
// Complete event so that rasman calls DeviceWork to proceed the listen state machine.
//
SetEvent (port->TPCB_ReqNotificationHandle) ;
} else {
port->TPCB_ListenState = LS_RINGING ; port->TPCB_NumberOfRings = NumberOfRings ;
}
} else {
//
// For other devices make transition to next listening state
//
port->TPCB_ListenState = LS_ACCEPT ;
//
// Complete event so that rasman calls DeviceWork to proceed the listen state machine.
//
SetEvent (port->TPCB_ReqNotificationHandle) ;
}
} else {
//
// We were not expecting the call. Make transition to next listening state
//
port->TPCB_ListenState = LS_ERROR ; port->TPCB_CallHandle = hcall ;
//
// not interested in call, drop it.
//
InitiatePortDisconnection (port) ;
}
break ; }
// Call connected.
//
if (param1 == LINECALLSTATE_CONNECTED ) {
DBGPRINT((" RasTapiCallBack: LINECALLSTATE_CONNECTED \n"));
if (port->TPCB_State == PS_CONNECTING) {
//
// We were requesting the call. Complete event so that rasman calls DeviceWork() to complete the
// connection process.
//
SetEvent (port->TPCB_ReqNotificationHandle) ;
} else {
port->TPCB_CallHandle = hcall ;
// This is a call we are asnwering. Now we can indicate to rasman that the call has come in.
//
// Setting listen state to LS_COMPLETE may be redundant but handles the case where the answer
// completes *after* the connection is indicated
//
port->TPCB_ListenState = LS_COMPLETE ;
//
// Complete event so that rasman knows of incoming call and calls devicework.
//
SetEvent (port->TPCB_ReqNotificationHandle) ; }
}
//
// Failure of sorts.
//
if ((param1 == LINECALLSTATE_BUSY) || (param1 == LINECALLSTATE_SPECIALINFO)) {
// If we were connecting, notify rasman to call devicework so that the connection attempt can
// be gracefully failed.
//
if (port->TPCB_State == PS_CONNECTING) SetEvent (port->TPCB_ReqNotificationHandle) ;
// Can this be received for the answering case?
//
}
//
// Disconnection happened
//
if (param1 == LINECALLSTATE_DISCONNECTED) {
// If we were connecting, notify rasman to call devicework so that the connection attempt can
// be gracefully failed.
//
if (port->TPCB_State == PS_CONNECTING) {
if (param2 == LINEDISCONNECTMODE_BUSY) port->TPCB_AsyncErrorCode = ERROR_LINE_BUSY ; else if (param2 == LINEDISCONNECTMODE_NOANSWER) port->TPCB_AsyncErrorCode = ERROR_NO_ANSWER ; else if (param2 == LINEDISCONNECTMODE_NODIALTONE) port->TPCB_AsyncErrorCode = ERROR_NO_DIALTONE ; else if (param2 == LINEDISCONNECTMODE_CANCELLED) port->TPCB_AsyncErrorCode = ERROR_USER_DISCONNECTION;
SetEvent (port->TPCB_ReqNotificationHandle) ;
} else if (port->TPCB_State != PS_CLOSED) {
// If we were connected and got a disconnect notification then this could be hardware failure or
// a remote disconnection. Determine this and save the reason away.
//
if (port->TPCB_State == PS_CONNECTED) { LINECALLSTATUS *pcallstatus ; BYTE buffer[200] ;
memset (buffer, 0, sizeof(buffer)) ; pcallstatus = (LINECALLSTATUS *) buffer ; pcallstatus->dwTotalSize = sizeof (buffer) ; lineGetCallStatus (port->TPCB_CallHandle, pcallstatus) ; if (pcallstatus->dwCallState == LINECALLSTATE_DISCONNECTED) port->TPCB_DisconnectReason = SS_LINKDROPPED ; else port->TPCB_DisconnectReason = SS_HARDWAREFAILURE ;
} else port->TPCB_DisconnectReason = 0 ;
//
// This means that we got a disconnect indication in one of the other states (listening, connected, etc.)
// We initiate our disconnect state machine.
//
if (InitiatePortDisconnection (port) != PENDING) {
// Disconnection succeeded or failed. Both are end states for the disconnect state machine so notify
// rasman that a disconnection has happened.
//
// DbgPrint("SignalDisc: 1\n") ;
SetEvent (port->TPCB_DiscNotificationHandle) ; } } }
//
// A busy call state - our attempt to dialout failed
//
if (param1 == LINECALLSTATE_BUSY) {
if (port->TPCB_State == PS_CONNECTING) { port->TPCB_AsyncErrorCode = ERROR_LINE_BUSY ; SetEvent (port->TPCB_ReqNotificationHandle) ; } }
// Idle indication is useful to complete the disconnect state machine.
//
if (param1 == LINECALLSTATE_IDLE) {
// DbgPrint ("I, State = %d\n", port->TPCB_State) ;
if ((port->TPCB_State == PS_DISCONNECTING) && (port->TPCB_RequestId == INFINITE)) {
// IDLE notification came after LineDrop Succeeded so safe to
// deallocate the call
//
port->TPCB_State = PS_OPEN ; lineDeallocateCall (port->TPCB_CallHandle) ; // DbgPrint ("D + Signal Disc\n") ;
port->TPCB_CallHandle = (HCALL) 0xffffffff ; line->IdleReceived = FALSE; SetEvent (port->TPCB_DiscNotificationHandle) ; } else {
// We have not yet disconnected so do not deallocate call
// yet. This will be done when the disconnect completes.
//
line->IdleReceived = TRUE; // DbgPrint ("IdleNoAction\n") ;
} }
break ;
case LINE_REPLY:
// This message is sent to indicate completion of an asynchronous API.
//
DbgPrint ("LineReply: ReqId:%d", param1) ;
// Find for which port the async request succeeded. This is done by searching for pending
// request id that is also provided in this message.
//
if ((port = FindPortByRequestId (param1)) == NULL) { DbgPrint ("\n") ;
break ;
} else
DbgPrint (" State = %d\n", port->TPCB_State) ;
// Set request id to invalid.
//
port->TPCB_RequestId = INFINITE ;
if (port->TPCB_State == PS_DISCONNECTING) {
// lineDrop completed. Note that we ignore the return code in param2. This is
// because we cant do anything else.
//
if (port->TPCB_Line->IdleReceived) {
// We received IDLE notification before/during disconnect
// so deallocate this call
//
port->TPCB_Line->IdleReceived = FALSE; port->TPCB_State = PS_OPEN ; lineDeallocateCall (port->TPCB_CallHandle) ; // DbgPrint ("D + SignalDisc\n") ;
port->TPCB_CallHandle = (HCALL) 0xffffffff ; SetEvent (port->TPCB_DiscNotificationHandle) ;
} else {
// wait for idle message before signalling disconnect
//
; // DbgPrint ("DropCompNoAction\n") ;
}
break ; }
// Some other api completed
//
if (param2 == SUCCESS) {
// Success means take no action - unless we are listening
// in which case it means move to the next state - we simply
// set the event that will result in a call to DeviceWork() to
// make the actual call for the next state
//
if (port->TPCB_State != PS_LISTENING) break ;
// Proceed to the next listening sub-state
//
if (port->TPCB_ListenState == LS_ACCEPT) {
port->TPCB_ListenState = LS_ANSWER ; SetEvent (port->TPCB_ReqNotificationHandle) ;
} else if (port->TPCB_ListenState == LS_ANSWER) {
port->TPCB_ListenState = LS_COMPLETE ; }
} else {
// For connecting and listening ports this means the attempt failed
// because of some error
//
if (port->TPCB_State == PS_CONNECTING) {
port->TPCB_AsyncErrorCode = ERROR_PORT_OR_DEVICE ; SetEvent (port->TPCB_ReqNotificationHandle) ;
} else if (port->TPCB_State == PS_LISTENING) {
// Because ACCEPT may not be supported by the device - treat error as success
//
if (port->TPCB_ListenState == LS_ACCEPT) port->TPCB_ListenState = LS_ANSWER ; else port->TPCB_ListenState = LS_ERROR ;
SetEvent (port->TPCB_ReqNotificationHandle) ; }
// Some other API failed, we dont know and we dont care. Ignore.
//
else if (port->TPCB_State != PS_CLOSED) {
; // DbgPrint ("RASTAPI: LINE_REPLY failed. Ignored.\n") ;
} }
break ;
case LINE_CLOSE:
// Typically sent when things go really wrong.
//
DbgPrint ("RASTAPI: received LINE_CLOSE message\n") ;
// Find which line is indication came for.
//
line = ULongToPtr(instance) ;
// if line not found or if it is closed just return
//
if ((line == NULL) || (line->TLI_LineState == PS_CLOSED)) break ;
// For every port that is on the line - open the line again and signal
// hw failure
//
for (port = RasPorts, i = 0; i < TotalPorts; i++, port++) {
// Skip ports that arent initialized
//
if (port->TPCB_State == PS_UNINITIALIZED) continue ;
if (port->TPCB_Line == line) {
if (retcode = lineOpen (RasLine, port->TPCB_Line->TLI_LineId, &port->TPCB_Line->TLI_LineHandle, port->TPCB_Line->NegotiatedApiVersion, port->TPCB_Line->NegotiatedExtVersion, (ULONG) (ULONG_PTR) port->TPCB_Line, LINECALLPRIVILEGE_OWNER, port->TPCB_MediaMode, NULL)); //
// Set monitoring of rings
//
lineSetStatusMessages (port->TPCB_Line->TLI_LineHandle, LINEDEVSTATE_RINGING, 0) ;
// If the port is listening - then we do not need to do anything since the listen is
// posted implicitly,
//
if (port->TPCB_State != PS_LISTENING) { //
// These settings should cause connections and connect attempts to
// fail.
//
port->TPCB_AsyncErrorCode = ERROR_FROM_DEVICE ; port->TPCB_CallHandle = (HCALL) 0xffffffff ; port->TPCB_ListenState = LS_ERROR ;
// Signal hardware failure to rasman.
//
// DbgPrint ("SignalDisc: 3\n") ;
SetEvent (port->TPCB_DiscNotificationHandle) ; } } } break ;
case LINE_LINEDEVSTATE:
//
// we are only interested in ringing message
//
if (param1 != LINEDEVSTATE_RINGING) break ;
// Find which line is indication came for.
//
line = ULongToPtr(instance) ;
// if line not found or if it is closed just return
//
if ((line == NULL) || (line->TLI_LineState == PS_CLOSED)) break ;
// get the port from the line
//
for (port = RasPorts, i = 0; i < TotalPorts; i++, port++) {
// Skip ports that arent initialized
//
if (port->TPCB_State == PS_UNINITIALIZED) continue ;
if ((port->TPCB_Line == line) && (port->TPCB_State == PS_LISTENING) && (port->TPCB_ListenState == LS_RINGING)) {
//
// count down the rings
//
port->TPCB_NumberOfRings -= 1 ; // DbgPrint ("Ring count = %d\n", port->TPCB_NumberOfRings) ;
//
// if the ring count has gone down to zero this means that we should pick up the call.
//
if (port->TPCB_NumberOfRings == 0) {
port->TPCB_ListenState = LS_ACCEPT ;
//
// Complete event so that rasman calls DeviceWork to proceed the listen state machine.
//
SetEvent (port->TPCB_ReqNotificationHandle) ; }
break ; } }
break ;
case LINE_ADDRESSSTATE: case LINE_CALLINFO: case LINE_CREATE: case LINE_DEVSPECIFIC: case LINE_DEVSPECIFICFEATURE: case LINE_GATHERDIGITS: case LINE_GENERATE:
case LINE_MONITORDIGITS: case LINE_MONITORMEDIA: case LINE_MONITORTONE: case LINE_REQUEST: default: // All unhandled unsolicited messages.
//
; }
// **** Exclusion End ****
FreeMutex (RasTapiMutex) ; }
//* FindPortByAddressId()
//
//
//
//
//*
TapiPortControlBlock * FindPortByAddressId (TapiLineInfo *line, DWORD addid) { DWORD i ; TapiPortControlBlock *port ;
for (i=0, port=RasPorts; i<TotalPorts; i++, port++) {
if ((port->TPCB_AddressId == addid) && (port->TPCB_Line == line)) return port ;
}
return NULL ; }
//* FindPortByAddress()
//
//
//
//
//*
TapiPortControlBlock * FindPortByAddress (CHAR *address) { DWORD i ; TapiPortControlBlock *port ;
for (i=0, port=RasPorts; i<TotalPorts; i++, port++) {
if (_stricmp (port->TPCB_Address, address) == 0) return port ;
}
return NULL ; }
//* FindPortByAddress()
//
//
//
//
//*
TapiPortControlBlock * FindPortByAddressAndName (CHAR *address, CHAR *name) { DWORD i ; TapiPortControlBlock *port ;
for (i=0, port=RasPorts; i<TotalPorts; i++, port++) {
if ((_stricmp (port->TPCB_Address, address) == 0) && (_strnicmp (port->TPCB_Name, name, MAX_PORT_NAME-1) == 0)) return port ;
}
return NULL ; }
//* FindPortByRequestId()
//
//
//
//
//*
TapiPortControlBlock * FindPortByRequestId (DWORD reqid) { DWORD i ; TapiPortControlBlock *port ;
for (i=0, port=RasPorts; i<TotalPorts; i++, port++) {
if (port->TPCB_RequestId == reqid) return port ;
}
return NULL ; }
//* FindLineByHandle()
//
//
//
//
//*
TapiLineInfo * FindLineByHandle (HLINE linehandle) { DWORD i ; TapiLineInfo *line ;
for (i=0, line=RasTapiLineInfo; i<TotalLines; i++, line++) {
if (line->TLI_LineHandle == linehandle) return line ;
}
return NULL ; }
#define VALNAME_ATTACHEDTO "AttachedTo"
BOOL GetAssociatedPortName( char * szKeyName, CHAR * szPortName) /*
* Given the registry key name 'szRegistryKeyName' corresponding to the modem entry, fills in * 'wszAddress' with the associated port like COM1, .. * */ { HKEY hKeyModem; DWORD dwType; DWORD cbValueBuf; #if 0
char buf[256]; #endif
#if 0
wsprintfA(buf,"RegistryKey -> %s \n", szKeyName); OutputDebugStringA(buf); #endif
if ( RegOpenKeyExA(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_READ, &hKeyModem ) ) { return( FALSE ); }
cbValueBuf = 40 ;
if ( RegQueryValueExA(hKeyModem, VALNAME_ATTACHEDTO, NULL, &dwType, (LPBYTE)szPortName, &cbValueBuf )) { return ( FALSE ); }
RegCloseKey( hKeyModem );
return ( TRUE ); }
|