You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5284 lines
156 KiB
5284 lines
156 KiB
//============================================================================
|
|
// Copyright (c) 2000, Microsoft Corporation
|
|
//
|
|
// File: kmddsp.c
|
|
//
|
|
// History:
|
|
// Dan Knudson (DanKn) 11-Apr-1995 Created
|
|
// Yi Sun (YiSun) June-29-2000 Rewriten
|
|
//
|
|
// Abstract:
|
|
//============================================================================
|
|
|
|
#include "nt.h"
|
|
#include "ntrtl.h"
|
|
#include "nturtl.h"
|
|
#include "windows.h"
|
|
#include "rtutils.h"
|
|
#include "winioctl.h"
|
|
#include "ntddndis.h"
|
|
#include "ndistapi.h"
|
|
#include "intrface.h"
|
|
|
|
//
|
|
// NOTE: the following are defined in both ndistapi.h & tapi.h (or tspi.h)
|
|
// and cause (more or less non-interesting) build warnings, so we
|
|
// undefine them after the first #include to do away with this
|
|
//
|
|
|
|
#undef LAST_LINEMEDIAMODE
|
|
#undef TSPI_MESSAGE_BASE
|
|
#undef LINE_NEWCALL
|
|
#undef LINE_CALLDEVSPECIFIC
|
|
#undef LINE_CREATE
|
|
|
|
#include "tapi.h"
|
|
#include "tspi.h"
|
|
#include "kmddsp.h"
|
|
|
|
#define OUTBOUND_CALL_KEY ((DWORD) 'OCAL')
|
|
#define INBOUND_CALL_KEY ((DWORD) 'ICAL')
|
|
#define LINE_KEY ((DWORD) 'KLIN')
|
|
#define ASYNCREQWRAPPER_KEY ((DWORD) 'ARWK')
|
|
#define INVALID_KEY ((DWORD) 'XXXX')
|
|
|
|
#define EVENT_BUFFER_SIZE 1024
|
|
|
|
typedef LONG (*POSTPROCESSPROC)(PASYNC_REQUEST_WRAPPER, LONG, PDWORD_PTR);
|
|
|
|
typedef struct _ASYNC_REQUEST_WRAPPER
|
|
{
|
|
// NOTE: overlapped must remain 1st field in this struct
|
|
OVERLAPPED Overlapped;
|
|
DWORD dwKey;
|
|
DWORD dwRequestID;
|
|
POSTPROCESSPROC pfnPostProcess;
|
|
CRITICAL_SECTION CritSec;
|
|
ULONG RefCount;
|
|
DWORD_PTR dwRequestSpecific;
|
|
// NOTE: NdisTapiRequest must follow a ptr to avoid alignment problem
|
|
NDISTAPI_REQUEST NdisTapiRequest;
|
|
} ASYNC_REQUEST_WRAPPER, *PASYNC_REQUEST_WRAPPER;
|
|
|
|
#define REF_ASYNC_REQUEST_WRAPPER(_pAsyncReqWrapper) \
|
|
{ \
|
|
EnterCriticalSection(&_pAsyncReqWrapper->CritSec); \
|
|
_pAsyncReqWrapper->RefCount++; \
|
|
LeaveCriticalSection(&_pAsyncReqWrapper->CritSec); \
|
|
}
|
|
|
|
#define DEREF_ASYNC_REQUEST_WRAPPER(_pAsyncReqWrapper) \
|
|
{ \
|
|
EnterCriticalSection(&_pAsyncReqWrapper->CritSec); \
|
|
if (--(_pAsyncReqWrapper->RefCount) == 0) { \
|
|
LeaveCriticalSection(&_pAsyncReqWrapper->CritSec); \
|
|
DeleteCriticalSection(&_pAsyncReqWrapper->CritSec); \
|
|
FreeRequest(_pAsyncReqWrapper); \
|
|
_pAsyncReqWrapper = NULL; \
|
|
} else { \
|
|
LeaveCriticalSection(&_pAsyncReqWrapper->CritSec); \
|
|
} \
|
|
}
|
|
|
|
typedef struct _ASYNC_EVENTS_THREAD_INFO
|
|
{
|
|
HANDLE hThread; // thread handle
|
|
PNDISTAPI_EVENT_DATA pBuf; // ptr to a buf for async events
|
|
DWORD dwBufSize; // size of the previous buffer
|
|
|
|
} ASYNC_EVENTS_THREAD_INFO, *PASYNC_EVENTS_THREAD_INFO;
|
|
|
|
|
|
typedef struct _DRVCALL
|
|
{
|
|
DWORD dwKey;
|
|
DWORD dwDeviceID;
|
|
HTAPICALL htCall; // TAPI's handle to the call
|
|
HDRVCALL hdCall; // TSP's handle to the call
|
|
HDRV_CALL hd_Call; // NDISTAPI's call handle
|
|
HDRVLINE hdLine; // TSP's handle to the line
|
|
union
|
|
{
|
|
struct _DRVCALL *pPrev; // for inbound calls only
|
|
DWORD dwPendingCallState; // for outbound calls only
|
|
};
|
|
union
|
|
{
|
|
struct _DRVCALL *pNext; // for inbound calls only
|
|
DWORD dwPendingCallStateMode; // for outbound calls only
|
|
};
|
|
union
|
|
{
|
|
HTAPI_CALL ht_Call; // for inbound calls only
|
|
DWORD dwPendingMediaMode; // for outbound calls only
|
|
};
|
|
BOOL bIncomplete;
|
|
BOOL bDropped;
|
|
BOOL bIdle;
|
|
} DRVCALL, *PDRVCALL;
|
|
|
|
|
|
typedef struct _DRVLINE
|
|
{
|
|
DWORD dwKey;
|
|
DWORD dwDeviceID;
|
|
HTAPILINE htLine; // TAPI's line handle
|
|
HDRV_LINE hd_Line; // NDISTAPI's line handle
|
|
PDRVCALL pInboundCalls; // inbound call list
|
|
|
|
// the following two related to PNP/POWER
|
|
GUID Guid;
|
|
NDIS_WAN_MEDIUM_SUBTYPE MediaType;
|
|
} DRVLINE, *PDRVLINE;
|
|
|
|
// globals
|
|
HANDLE ghDriverSync, ghDriverAsync, ghCompletionPort;
|
|
PASYNC_EVENTS_THREAD_INFO gpAsyncEventsThreadInfo;
|
|
DWORD gdwRequestID;
|
|
ASYNC_COMPLETION gpfnCompletionProc;
|
|
CRITICAL_SECTION gRequestIDCritSec;
|
|
LINEEVENT gpfnLineEvent;
|
|
HPROVIDER ghProvider;
|
|
OVERLAPPED gOverlappedTerminate;
|
|
// Dummy structure . Used by provider shutdown to notify
|
|
// AsyncEventsThread before closing completion port handle
|
|
|
|
|
|
//
|
|
// debug globals
|
|
//
|
|
#if DBG
|
|
DWORD gdwDebugLevel;
|
|
#endif // DBG
|
|
|
|
DWORD gdwTraceID = INVALID_TRACEID;
|
|
|
|
//
|
|
// creates a log using the RAS tracing utility
|
|
// also prints it onto the attached debugger
|
|
// if a debug build is running
|
|
//
|
|
VOID
|
|
TspLog(
|
|
IN DWORD dwDebugLevel,
|
|
IN PCHAR pchFormat,
|
|
...
|
|
)
|
|
{
|
|
va_list arglist;
|
|
CHAR chNewFmt[256];
|
|
|
|
va_start(arglist, pchFormat);
|
|
|
|
switch (dwDebugLevel)
|
|
{
|
|
case DL_ERROR:
|
|
strcpy(chNewFmt, "!!! ");
|
|
break;
|
|
|
|
case DL_WARNING:
|
|
strcpy(chNewFmt, "!! ");
|
|
break;
|
|
|
|
case DL_INFO:
|
|
strcpy(chNewFmt, "! ");
|
|
break;
|
|
|
|
case DL_TRACE:
|
|
strcpy(chNewFmt, " ");
|
|
break;
|
|
}
|
|
strcat(chNewFmt, pchFormat);
|
|
|
|
#if DBG
|
|
if (dwDebugLevel <= gdwDebugLevel)
|
|
{
|
|
#if 0
|
|
DbgPrint("++KMDDSP++ ");
|
|
DbgPrint(chNewFmt, arglist);
|
|
DbgPrint("\n");
|
|
#else
|
|
char szBuffer[256];
|
|
OutputDebugString("++KMDDSP++ ");
|
|
wvsprintf(szBuffer, chNewFmt, arglist);
|
|
OutputDebugString(szBuffer);
|
|
OutputDebugString("\n");
|
|
#endif
|
|
}
|
|
#endif // DBG
|
|
|
|
if (gdwTraceID != INVALID_TRACEID)
|
|
{
|
|
TraceVprintfEx(gdwTraceID,
|
|
(dwDebugLevel << 16) | TRACE_USE_MASK | TRACE_USE_MSEC,
|
|
chNewFmt,
|
|
arglist);
|
|
}
|
|
|
|
va_end(arglist);
|
|
|
|
#if DBG
|
|
if (DL_ERROR == dwDebugLevel)
|
|
{
|
|
//DebugBreak();
|
|
}
|
|
#endif // DBG
|
|
}
|
|
|
|
#if DBG
|
|
|
|
#define INSERTVARDATASTRING(a,b,c,d,e,f) InsertVarDataString(a,b,c,d,e,f)
|
|
|
|
void
|
|
PASCAL
|
|
InsertVarDataString(
|
|
LPVOID pStruct,
|
|
LPDWORD pdwXxxSize,
|
|
LPVOID pNewStruct,
|
|
LPDWORD pdwNewXxxSize,
|
|
DWORD dwFixedStructSize,
|
|
char *pszFieldName
|
|
)
|
|
|
|
#else
|
|
|
|
#define INSERTVARDATASTRING(a,b,c,d,e,f) InsertVarDataString(a,b,c,d,e)
|
|
|
|
void
|
|
PASCAL
|
|
InsertVarDataString(
|
|
LPVOID pStruct,
|
|
LPDWORD pdwXxxSize,
|
|
LPVOID pNewStruct,
|
|
LPDWORD pdwNewXxxSize,
|
|
DWORD dwFixedStructSize
|
|
)
|
|
|
|
#endif
|
|
{
|
|
DWORD dwXxxSize, dwTotalSize, dwXxxOffset;
|
|
|
|
|
|
//
|
|
// If the dwXxxSize field of the old struct is non-zero, then
|
|
// we need to do a ascii->unicode conversion on it. Check to
|
|
// make sure that the size/offset are valid (if not set the
|
|
// data size/offset in the new struct to 0) and then convert.
|
|
//
|
|
|
|
if ((dwXxxSize = *pdwXxxSize))
|
|
{
|
|
dwXxxOffset = *(pdwXxxSize + 1);
|
|
|
|
#if DBG
|
|
dwTotalSize = ((LPVARSTRING) pStruct)->dwTotalSize;
|
|
|
|
if (dwXxxSize > (dwTotalSize - dwFixedStructSize) ||
|
|
dwXxxOffset < dwFixedStructSize ||
|
|
dwXxxOffset >= dwTotalSize ||
|
|
(dwXxxSize + dwXxxOffset) > dwTotalSize)
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"INSERTVARDATASTRING: bad %s values - size(x%x), "\
|
|
"offset(x%x)",
|
|
pszFieldName, dwXxxSize, dwXxxOffset);
|
|
|
|
*pdwNewXxxSize = *(pdwNewXxxSize + 1) = 0;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
// make sure the string is NULL terminated
|
|
*(((LPBYTE)pStruct) + (dwXxxOffset + dwXxxSize - 1)) = '\0';
|
|
|
|
MultiByteToWideChar(
|
|
CP_ACP,
|
|
MB_PRECOMPOSED,
|
|
((LPBYTE) pStruct) + dwXxxOffset,
|
|
dwXxxSize,
|
|
(LPWSTR) (((LPBYTE) pNewStruct) +
|
|
((LPVARSTRING) pNewStruct)->dwUsedSize),
|
|
dwXxxSize
|
|
);
|
|
|
|
*pdwNewXxxSize = dwXxxSize * sizeof (WCHAR);
|
|
*(pdwNewXxxSize + 1) = ((LPVARSTRING) pNewStruct)->dwUsedSize; // offset
|
|
((LPVARSTRING) pNewStruct)->dwUsedSize += (dwXxxSize * sizeof (WCHAR));
|
|
}
|
|
}
|
|
|
|
|
|
#if DBG
|
|
|
|
#define INSERTVARDATA(a,b,c,d,e,f) InsertVarData(a,b,c,d,e,f)
|
|
|
|
void
|
|
PASCAL
|
|
InsertVarData(
|
|
LPVOID pStruct,
|
|
LPDWORD pdwXxxSize,
|
|
LPVOID pNewStruct,
|
|
LPDWORD pdwNewXxxSize,
|
|
DWORD dwFixedStructSize,
|
|
char *pszFieldName
|
|
)
|
|
|
|
#else
|
|
|
|
#define INSERTVARDATA(a,b,c,d,e,f) InsertVarData(a,b,c,d,e)
|
|
|
|
void
|
|
PASCAL
|
|
InsertVarData(
|
|
LPVOID pStruct,
|
|
LPDWORD pdwXxxSize,
|
|
LPVOID pNewStruct,
|
|
LPDWORD pdwNewXxxSize,
|
|
DWORD dwFixedStructSize
|
|
)
|
|
|
|
#endif
|
|
{
|
|
DWORD dwTotalSize, dwXxxSize, dwXxxOffset;
|
|
|
|
|
|
if ((dwXxxSize = *pdwXxxSize))
|
|
{
|
|
dwXxxOffset = *(pdwXxxSize + 1);
|
|
|
|
#if DBG
|
|
dwTotalSize = ((LPVARSTRING) pStruct)->dwTotalSize;
|
|
|
|
if (dwXxxSize > (dwTotalSize - dwFixedStructSize) ||
|
|
dwXxxOffset < dwFixedStructSize ||
|
|
dwXxxOffset >= dwTotalSize ||
|
|
(dwXxxSize + dwXxxOffset) > dwTotalSize)
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"INSERTVARDATA: bad %s values - size(x%x), offset(x%x)",
|
|
pszFieldName, dwXxxSize, dwXxxOffset);
|
|
|
|
*pdwNewXxxSize = *(pdwNewXxxSize + 1) = 0;
|
|
return;
|
|
}
|
|
#endif
|
|
CopyMemory(
|
|
((LPBYTE) pNewStruct) + ((LPVARSTRING) pNewStruct)->dwUsedSize,
|
|
((LPBYTE) pStruct) + dwXxxOffset,
|
|
dwXxxSize
|
|
);
|
|
|
|
*pdwNewXxxSize = dwXxxSize;
|
|
*(pdwNewXxxSize + 1) = ((LPVARSTRING) pNewStruct)->dwUsedSize; // offset
|
|
((LPVARSTRING) pNewStruct)->dwUsedSize += dwXxxSize;
|
|
}
|
|
}
|
|
|
|
static char *pszOidNames[] =
|
|
{
|
|
"Accept",
|
|
"Answer",
|
|
"Close",
|
|
"CloseCall",
|
|
"ConditionalMediaDetection",
|
|
"ConfigDialog",
|
|
"DevSpecific",
|
|
"Dial",
|
|
"Drop",
|
|
"GetAddressCaps",
|
|
"GetAddressID",
|
|
"GetAddressStatus",
|
|
"GetCallAddressID",
|
|
"GetCallInfo",
|
|
"GetCallStatus",
|
|
"GetDevCaps",
|
|
"GetDevConfig",
|
|
"GetExtensionID",
|
|
"GetID",
|
|
"GetLineDevStatus",
|
|
"MakeCall",
|
|
"NegotiateExtVersion",
|
|
"Open",
|
|
"ProviderInitialize",
|
|
"ProviderShutdown",
|
|
"SecureCall",
|
|
"SelectExtVersion",
|
|
"SendUserUserInfo",
|
|
"SetAppSpecific",
|
|
"StCallParams",
|
|
"StDefaultMediaDetection",
|
|
"SetDevConfig",
|
|
"SetMediaMode",
|
|
"SetStatusMessages"
|
|
};
|
|
|
|
// used to print the NDIS TAPI requests properly
|
|
typedef enum _TAPI_REQUEST_TYPE
|
|
{
|
|
TAPI_REQUEST_UNKNOWN = 0,
|
|
TAPI_REQUEST_NONE,
|
|
TAPI_REQUEST_HDCALL,
|
|
TAPI_REQUEST_HDLINE,
|
|
TAPI_REQUEST_DEVICEID
|
|
} TAPI_REQUEST_TYPE;
|
|
|
|
static TAPI_REQUEST_TYPE OidTypes[] =
|
|
{
|
|
TAPI_REQUEST_HDCALL, // "Accept"
|
|
TAPI_REQUEST_HDCALL, // "Answer"
|
|
TAPI_REQUEST_HDLINE, // "Close"
|
|
TAPI_REQUEST_HDCALL, // "CloseCall"
|
|
TAPI_REQUEST_HDLINE, // "ConditionalMediaDetection"
|
|
TAPI_REQUEST_DEVICEID, // "ConfigDialog"
|
|
TAPI_REQUEST_HDLINE, // "DevSpecific"
|
|
TAPI_REQUEST_HDCALL, // "Dial"
|
|
TAPI_REQUEST_HDCALL, // "Drop"
|
|
TAPI_REQUEST_DEVICEID, // "GetAddressCaps"
|
|
TAPI_REQUEST_HDLINE, // "GetAddressID"
|
|
TAPI_REQUEST_HDLINE, // "GetAddressStatus"
|
|
TAPI_REQUEST_HDCALL, // "GetCallAddressID"
|
|
TAPI_REQUEST_HDCALL, // "GetCallInfo"
|
|
TAPI_REQUEST_HDCALL, // "GetCallStatus"
|
|
TAPI_REQUEST_DEVICEID, // "GetDevCaps"
|
|
TAPI_REQUEST_DEVICEID, // "GetDevConfig"
|
|
TAPI_REQUEST_DEVICEID, // "GetExtensionID"
|
|
TAPI_REQUEST_HDLINE, // "GetID"
|
|
TAPI_REQUEST_HDLINE, // "GetLineDevStatus"
|
|
TAPI_REQUEST_HDLINE, // "MakeCall"
|
|
TAPI_REQUEST_DEVICEID, // "NegotiateExtVersion"
|
|
TAPI_REQUEST_DEVICEID, // "Open"
|
|
TAPI_REQUEST_DEVICEID, // "ProviderInitialize"
|
|
TAPI_REQUEST_NONE, // "ProviderShutdown"
|
|
TAPI_REQUEST_HDCALL, // "SecureCall"
|
|
TAPI_REQUEST_HDLINE, // "SelectExtVersion"
|
|
TAPI_REQUEST_HDCALL, // "SendUserUserInfo"
|
|
TAPI_REQUEST_HDCALL, // "SetAppSpecific"
|
|
TAPI_REQUEST_HDCALL, // "StCallParams"
|
|
TAPI_REQUEST_HDLINE, // "StDefaultMediaDetection"
|
|
TAPI_REQUEST_DEVICEID, // "SetDevConfig"
|
|
TAPI_REQUEST_HDCALL, // "SetMediaMode"
|
|
TAPI_REQUEST_HDLINE, // "SetStatusMessages"
|
|
};
|
|
|
|
|
|
//
|
|
// translates NDIS TAPI status codes into LINEERR_XXX
|
|
//
|
|
LONG
|
|
WINAPI
|
|
TranslateDriverResult(
|
|
ULONG ulRes
|
|
)
|
|
{
|
|
typedef struct _RESULT_LOOKUP
|
|
{
|
|
ULONG NdisTapiResult;
|
|
LONG TapiResult;
|
|
} RESULT_LOOKUP, *PRESULT_LOOKUP;
|
|
|
|
typedef ULONG NDIS_STATUS;
|
|
#define NDIS_STATUS_SUCCESS 0x00000000L
|
|
#define NDIS_STATUS_RESOURCES 0xC000009AL
|
|
#define NDIS_STATUS_FAILURE 0xC0000001L
|
|
#define NDIS_STATUS_INVALID_OID 0xC0010017L
|
|
|
|
static RESULT_LOOKUP aResults[] =
|
|
{
|
|
|
|
//
|
|
// Defined in NDIS.H
|
|
//
|
|
|
|
{ NDIS_STATUS_SUCCESS ,0 },
|
|
|
|
//
|
|
// These errors are defined in NDISTAPI.H
|
|
//
|
|
|
|
{ NDIS_STATUS_TAPI_ADDRESSBLOCKED ,LINEERR_ADDRESSBLOCKED },
|
|
{ NDIS_STATUS_TAPI_BEARERMODEUNAVAIL ,LINEERR_BEARERMODEUNAVAIL },
|
|
{ NDIS_STATUS_TAPI_CALLUNAVAIL ,LINEERR_CALLUNAVAIL },
|
|
{ NDIS_STATUS_TAPI_DIALBILLING ,LINEERR_DIALBILLING },
|
|
{ NDIS_STATUS_TAPI_DIALDIALTONE ,LINEERR_DIALDIALTONE },
|
|
{ NDIS_STATUS_TAPI_DIALPROMPT ,LINEERR_DIALPROMPT },
|
|
{ NDIS_STATUS_TAPI_DIALQUIET ,LINEERR_DIALQUIET },
|
|
{ NDIS_STATUS_TAPI_INCOMPATIBLEEXTVERSION,LINEERR_INCOMPATIBLEEXTVERSION},
|
|
{ NDIS_STATUS_TAPI_INUSE ,LINEERR_INUSE },
|
|
{ NDIS_STATUS_TAPI_INVALADDRESS ,LINEERR_INVALADDRESS },
|
|
{ NDIS_STATUS_TAPI_INVALADDRESSID ,LINEERR_INVALADDRESSID },
|
|
{ NDIS_STATUS_TAPI_INVALADDRESSMODE ,LINEERR_INVALADDRESSMODE },
|
|
{ NDIS_STATUS_TAPI_INVALBEARERMODE ,LINEERR_INVALBEARERMODE },
|
|
{ NDIS_STATUS_TAPI_INVALCALLHANDLE ,LINEERR_INVALCALLHANDLE },
|
|
{ NDIS_STATUS_TAPI_INVALCALLPARAMS ,LINEERR_INVALCALLPARAMS },
|
|
{ NDIS_STATUS_TAPI_INVALCALLSTATE ,LINEERR_INVALCALLSTATE },
|
|
{ NDIS_STATUS_TAPI_INVALDEVICECLASS ,LINEERR_INVALDEVICECLASS },
|
|
{ NDIS_STATUS_TAPI_INVALLINEHANDLE ,LINEERR_INVALLINEHANDLE },
|
|
{ NDIS_STATUS_TAPI_INVALLINESTATE ,LINEERR_INVALLINESTATE },
|
|
{ NDIS_STATUS_TAPI_INVALMEDIAMODE ,LINEERR_INVALMEDIAMODE },
|
|
{ NDIS_STATUS_TAPI_INVALRATE ,LINEERR_INVALRATE },
|
|
{ NDIS_STATUS_TAPI_NODRIVER ,LINEERR_NODRIVER },
|
|
{ NDIS_STATUS_TAPI_OPERATIONUNAVAIL ,LINEERR_OPERATIONUNAVAIL },
|
|
{ NDIS_STATUS_TAPI_RATEUNAVAIL ,LINEERR_RATEUNAVAIL },
|
|
{ NDIS_STATUS_TAPI_RESOURCEUNAVAIL ,LINEERR_RESOURCEUNAVAIL },
|
|
{ NDIS_STATUS_TAPI_STRUCTURETOOSMALL ,LINEERR_STRUCTURETOOSMALL },
|
|
{ NDIS_STATUS_TAPI_USERUSERINFOTOOBIG ,LINEERR_USERUSERINFOTOOBIG },
|
|
{ NDIS_STATUS_TAPI_ALLOCATED ,LINEERR_ALLOCATED },
|
|
{ NDIS_STATUS_TAPI_INVALADDRESSSTATE ,LINEERR_INVALADDRESSSTATE },
|
|
{ NDIS_STATUS_TAPI_INVALPARAM ,LINEERR_INVALPARAM },
|
|
{ NDIS_STATUS_TAPI_NODEVICE ,LINEERR_NODEVICE },
|
|
|
|
//
|
|
// These errors are defined in NDIS.H
|
|
//
|
|
|
|
{ NDIS_STATUS_RESOURCES ,LINEERR_NOMEM },
|
|
{ NDIS_STATUS_FAILURE ,LINEERR_OPERATIONFAILED },
|
|
{ NDIS_STATUS_INVALID_OID ,LINEERR_OPERATIONFAILED },
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
{ NDISTAPIERR_UNINITIALIZED ,LINEERR_OPERATIONFAILED },
|
|
{ NDISTAPIERR_BADDEVICEID ,LINEERR_OPERATIONFAILED },
|
|
{ NDISTAPIERR_DEVICEOFFLINE ,LINEERR_OPERATIONFAILED },
|
|
|
|
//
|
|
// The terminating fields
|
|
//
|
|
|
|
{ 0xffffffff, 0xffffffff }
|
|
|
|
};
|
|
|
|
int i;
|
|
|
|
for (i = 0; aResults[i].NdisTapiResult != 0xffffffff; i++)
|
|
{
|
|
if (ulRes == aResults[i].NdisTapiResult)
|
|
{
|
|
return (aResults[i].TapiResult);
|
|
}
|
|
}
|
|
|
|
TspLog(DL_WARNING, "TranslateDriverResult: unknown driver result(%x)",
|
|
ulRes);
|
|
|
|
return LINEERR_OPERATIONFAILED;
|
|
}
|
|
|
|
//
|
|
// NOTE: for functions that need to acquire (read, write) locks for both
|
|
// a line and a call, we enforce the order to be line first, call
|
|
// second to avoid potential DEADLOCK.
|
|
//
|
|
|
|
LONG
|
|
GetLineObjWithReadLock(
|
|
IN HDRVLINE hdLine,
|
|
OUT PDRVLINE *ppLine
|
|
)
|
|
{
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
|
|
lRes = GetObjWithReadLock((HANDLE)hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return LINEERR_INVALLINEHANDLE;
|
|
}
|
|
|
|
ASSERT(pLine != NULL);
|
|
if (pLine->dwKey != LINE_KEY)
|
|
{
|
|
TspLog(DL_WARNING, "GetLineObjWithReadLock: obj(%p) has bad key(%x)",
|
|
hdLine, pLine->dwKey);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return LINEERR_INVALLINEHANDLE;
|
|
}
|
|
|
|
*ppLine = pLine;
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
GetLineObjWithWriteLock(
|
|
IN HDRVLINE hdLine,
|
|
OUT PDRVLINE *ppLine
|
|
)
|
|
{
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
|
|
lRes = GetObjWithWriteLock((HANDLE)hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return LINEERR_INVALLINEHANDLE;
|
|
}
|
|
|
|
ASSERT(pLine != NULL);
|
|
if (pLine->dwKey != LINE_KEY)
|
|
{
|
|
TspLog(DL_WARNING, "GetLineObjWithWriteLock: obj(%p) has bad key(%x)",
|
|
hdLine, pLine->dwKey);
|
|
|
|
ReleaseObjWriteLock((HANDLE)hdLine);
|
|
return LINEERR_INVALLINEHANDLE;
|
|
}
|
|
|
|
*ppLine = pLine;
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
GetCallObjWithReadLock(
|
|
IN HDRVCALL hdCall,
|
|
OUT PDRVCALL *ppCall
|
|
)
|
|
{
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
|
|
lRes = GetObjWithReadLock((HANDLE)hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return LINEERR_INVALCALLHANDLE;
|
|
}
|
|
|
|
ASSERT(pCall != NULL);
|
|
if (pCall->dwKey != INBOUND_CALL_KEY &&
|
|
pCall->dwKey != OUTBOUND_CALL_KEY)
|
|
{
|
|
TspLog(DL_WARNING, "GetCallObjWithReadLock: obj(%p) has bad key(%x)",
|
|
hdCall, pCall->dwKey);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return LINEERR_INVALCALLHANDLE;
|
|
}
|
|
|
|
*ppCall = pCall;
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
GetCallObjWithWriteLock(
|
|
IN HDRVCALL hdCall,
|
|
OUT PDRVCALL *ppCall
|
|
)
|
|
{
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
|
|
lRes = GetObjWithWriteLock((HANDLE)hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return LINEERR_INVALCALLHANDLE;
|
|
}
|
|
|
|
ASSERT(pCall != NULL);
|
|
if (pCall->dwKey != INBOUND_CALL_KEY &&
|
|
pCall->dwKey != OUTBOUND_CALL_KEY)
|
|
{
|
|
TspLog(DL_WARNING, "GetCallObjWithWriteLock: obj(%p) has bad key(%x)",
|
|
hdCall, pCall->dwKey);
|
|
|
|
ReleaseObjWriteLock((HANDLE)hdCall);
|
|
return LINEERR_INVALCALLHANDLE;
|
|
}
|
|
|
|
*ppCall = pCall;
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
GetLineHandleFromCallHandle(
|
|
IN HDRVCALL hdCall,
|
|
OUT HDRVLINE *phdLine
|
|
)
|
|
{
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
|
|
lRes = GetObjWithReadLock((HANDLE)hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return LINEERR_INVALCALLHANDLE;
|
|
}
|
|
|
|
ASSERT(pCall != NULL);
|
|
if (pCall->dwKey != INBOUND_CALL_KEY &&
|
|
pCall->dwKey != OUTBOUND_CALL_KEY)
|
|
{
|
|
TspLog(DL_WARNING,
|
|
"GetLineHandleFromCallHandle: obj(%p) has bad key(%x)",
|
|
hdCall, pCall->dwKey);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return LINEERR_INVALCALLHANDLE;
|
|
}
|
|
|
|
*phdLine = pCall->hdLine;
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
GetLineAndCallObjWithReadLock(
|
|
HTAPI_LINE ht_Line,
|
|
HTAPI_CALL ht_Call,
|
|
PDRVLINE *ppLine,
|
|
PDRVCALL *ppCall
|
|
)
|
|
{
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
PDRVLINE pLine;
|
|
|
|
lRes = GetLineObjWithReadLock((HDRVLINE)ht_Line, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
*ppLine = pLine;
|
|
|
|
//
|
|
// figure out whether this is an inbound call or
|
|
// outbound call: for inbound calls, ht_Call is
|
|
// generated by NDISTAPI and bit 0 is 1;
|
|
// for outbound calls, ht_Call is a TSP handle
|
|
// and we make sure that bit 0 is 0
|
|
//
|
|
if (ht_Call & 0x1)
|
|
{
|
|
// inbound call: we need to walk the list
|
|
// of inbound calls on this line and
|
|
// find the right one
|
|
if ((pCall = pLine->pInboundCalls) != NULL)
|
|
{
|
|
while (pCall && (pCall->ht_Call != ht_Call))
|
|
{
|
|
pCall = pCall->pNext;
|
|
}
|
|
}
|
|
|
|
if (NULL == pCall || pCall->dwKey != INBOUND_CALL_KEY)
|
|
{
|
|
TspLog(DL_WARNING,
|
|
"GetLineAndCallObjWithReadLock: "\
|
|
"inbound ht_call(%p) closed already",
|
|
ht_Call);
|
|
|
|
ReleaseObjReadLock((HANDLE)ht_Line);
|
|
return LINEERR_INVALCALLHANDLE;
|
|
}
|
|
|
|
// call the following to increase the ref count
|
|
lRes = AcquireObjReadLock((HANDLE)pCall->hdCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)ht_Line);
|
|
return lRes;
|
|
}
|
|
|
|
*ppCall = pCall;
|
|
|
|
return TAPI_SUCCESS;
|
|
}
|
|
|
|
// ht_Call is a TSP handle and the call is OUTBOUND
|
|
lRes = GetObjWithReadLock((HANDLE)ht_Call, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)ht_Line);
|
|
return lRes;
|
|
}
|
|
|
|
ASSERT(pCall != NULL);
|
|
if (pCall->dwKey != OUTBOUND_CALL_KEY)
|
|
{
|
|
TspLog(DL_WARNING,
|
|
"GetLineAndCallObjWithReadLock: bad call handle(%p, %x)",
|
|
ht_Call, pCall->dwKey);
|
|
|
|
ReleaseObjReadLock((HANDLE)ht_Call);
|
|
ReleaseObjReadLock((HANDLE)ht_Line);
|
|
return LINEERR_INVALCALLHANDLE;
|
|
}
|
|
|
|
*ppCall = pCall;
|
|
|
|
return TAPI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// allocates mem for a NDISTAPI_REQUEST plus some initialization
|
|
//
|
|
LONG
|
|
WINAPI
|
|
PrepareSyncRequest(
|
|
ULONG Oid,
|
|
ULONG ulDeviceID,
|
|
DWORD dwDataSize,
|
|
PNDISTAPI_REQUEST *ppNdisTapiRequest
|
|
)
|
|
{
|
|
PNDISTAPI_REQUEST pNdisTapiRequest =
|
|
(PNDISTAPI_REQUEST)AllocRequest(dwDataSize + sizeof(NDISTAPI_REQUEST));
|
|
if (NULL == pNdisTapiRequest)
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"PrepareSyncRequest: failed to alloc sync req for oid(%x)",
|
|
Oid);
|
|
return LINEERR_NOMEM;
|
|
}
|
|
|
|
pNdisTapiRequest->Oid = Oid;
|
|
pNdisTapiRequest->ulDeviceID = ulDeviceID;
|
|
pNdisTapiRequest->ulDataSize = dwDataSize;
|
|
|
|
EnterCriticalSection(&gRequestIDCritSec);
|
|
|
|
// setting ulRequestId of NDIS_TAPI_xxxx
|
|
if ((*((ULONG *)pNdisTapiRequest->Data) = ++gdwRequestID) >= 0x7fffffff)
|
|
{
|
|
gdwRequestID = 1;
|
|
}
|
|
|
|
LeaveCriticalSection(&gRequestIDCritSec);
|
|
|
|
*ppNdisTapiRequest = pNdisTapiRequest;
|
|
|
|
return TAPI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// allocates mem for a ASYNC_REQUEST_WRAPPER plus some initialization
|
|
//
|
|
LONG
|
|
WINAPI
|
|
PrepareAsyncRequest(
|
|
ULONG Oid,
|
|
ULONG ulDeviceID,
|
|
DWORD dwRequestID,
|
|
DWORD dwDataSize,
|
|
PASYNC_REQUEST_WRAPPER *ppAsyncReqWrapper
|
|
)
|
|
{
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper;
|
|
|
|
// alloc & init an async request wrapper
|
|
pAsyncReqWrapper = (PASYNC_REQUEST_WRAPPER)
|
|
AllocRequest(dwDataSize + sizeof(ASYNC_REQUEST_WRAPPER));
|
|
if (NULL == pAsyncReqWrapper)
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"PrepareAsyncRequest: failed to alloc async req for oid(%x)",
|
|
Oid);
|
|
return LINEERR_NOMEM;
|
|
}
|
|
|
|
// don't need to create an event when using completion ports
|
|
pAsyncReqWrapper->Overlapped.hEvent = (HANDLE)NULL;
|
|
|
|
pAsyncReqWrapper->dwKey = ASYNCREQWRAPPER_KEY;
|
|
pAsyncReqWrapper->dwRequestID = dwRequestID;
|
|
pAsyncReqWrapper->pfnPostProcess = (POSTPROCESSPROC)NULL;
|
|
|
|
// initialize the critical section, ref the request wrapper.
|
|
// NOTE: this crit sec will be deleted by the last deref.
|
|
InitializeCriticalSection(&pAsyncReqWrapper->CritSec);
|
|
pAsyncReqWrapper->RefCount = 1;
|
|
|
|
// safely initialize the driver request
|
|
pNdisTapiRequest = &(pAsyncReqWrapper->NdisTapiRequest);
|
|
|
|
pNdisTapiRequest->Oid = Oid;
|
|
pNdisTapiRequest->ulDeviceID = ulDeviceID;
|
|
pNdisTapiRequest->ulDataSize = dwDataSize;
|
|
|
|
EnterCriticalSection(&gRequestIDCritSec);
|
|
|
|
if ((*((ULONG *)pNdisTapiRequest->Data) = ++gdwRequestID) >= 0x7fffffff)
|
|
{
|
|
gdwRequestID = 1;
|
|
}
|
|
|
|
LeaveCriticalSection(&gRequestIDCritSec);
|
|
|
|
*ppAsyncReqWrapper = pAsyncReqWrapper;
|
|
|
|
return TAPI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// makes a non-overlapped request to ndistapi.sys
|
|
// so it doesn't return until the req is completed
|
|
//
|
|
LONG
|
|
WINAPI
|
|
SyncDriverRequest(
|
|
DWORD dwIoControlCode,
|
|
PNDISTAPI_REQUEST pNdisTapiRequest
|
|
)
|
|
{
|
|
BOOL bRes;
|
|
DWORD cbReturned;
|
|
|
|
switch(OidTypes[pNdisTapiRequest->Oid - OID_TAPI_ACCEPT])
|
|
{
|
|
case TAPI_REQUEST_NONE:
|
|
TspLog(DL_INFO,
|
|
"SyncDriverRequest: oid(%s), devID(%x), reqID(%x)",
|
|
pszOidNames[pNdisTapiRequest->Oid - OID_TAPI_ACCEPT],
|
|
pNdisTapiRequest->ulDeviceID,
|
|
*((ULONG *)pNdisTapiRequest->Data));
|
|
break;
|
|
|
|
case TAPI_REQUEST_DEVICEID:
|
|
TspLog(DL_INFO,
|
|
"SyncDriverRequest: oid(%s), devID(%x), reqID(%x), deviceID(%x)",
|
|
pszOidNames[pNdisTapiRequest->Oid - OID_TAPI_ACCEPT],
|
|
pNdisTapiRequest->ulDeviceID,
|
|
*((ULONG *)pNdisTapiRequest->Data),
|
|
*(((ULONG *)pNdisTapiRequest->Data) + 1));
|
|
break;
|
|
|
|
case TAPI_REQUEST_HDCALL:
|
|
TspLog(DL_INFO,
|
|
"SyncDriverRequest: oid(%s), devID(%x), reqID(%x), hdCall(%p)",
|
|
pszOidNames[pNdisTapiRequest->Oid - OID_TAPI_ACCEPT],
|
|
pNdisTapiRequest->ulDeviceID,
|
|
*((ULONG *)pNdisTapiRequest->Data),
|
|
*((ULONG_PTR *)(pNdisTapiRequest->Data + sizeof(ULONG_PTR))));
|
|
|
|
break;
|
|
|
|
case TAPI_REQUEST_HDLINE:
|
|
TspLog(DL_INFO,
|
|
"SyncDriverRequest: oid(%s), devID(%x), reqID(%x), hdLine(%p)",
|
|
pszOidNames[pNdisTapiRequest->Oid - OID_TAPI_ACCEPT],
|
|
pNdisTapiRequest->ulDeviceID,
|
|
*((ULONG *)pNdisTapiRequest->Data),
|
|
*((ULONG_PTR *)(pNdisTapiRequest->Data + sizeof(ULONG_PTR))));
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
|
|
// mark the request as being processed by the driver
|
|
MarkRequest(pNdisTapiRequest);
|
|
|
|
bRes = DeviceIoControl(ghDriverSync,
|
|
dwIoControlCode,
|
|
pNdisTapiRequest,
|
|
(DWORD)(sizeof(NDISTAPI_REQUEST) +
|
|
pNdisTapiRequest->ulDataSize),
|
|
pNdisTapiRequest,
|
|
(DWORD)(sizeof(NDISTAPI_REQUEST) +
|
|
pNdisTapiRequest->ulDataSize),
|
|
&cbReturned,
|
|
0);
|
|
|
|
// unmark the request now that the ioctl is completed
|
|
UnmarkRequest(pNdisTapiRequest);
|
|
|
|
if (bRes != TRUE)
|
|
{
|
|
TspLog(DL_ERROR, "SyncDriverRequest: IoCtl(Oid %x) failed(%d)",
|
|
pNdisTapiRequest->Oid, GetLastError());
|
|
|
|
return (LINEERR_OPERATIONFAILED);
|
|
}
|
|
else
|
|
{
|
|
// the errors returned by ndistapi.sys don't match the TAPI
|
|
// LINEERR_'s, so return the translated values (but preserve
|
|
// the original driver return val so it's possible to distinguish
|
|
// between NDISTAPIERR_DEVICEOFFLINE & LINEERR_OPERATIONUNAVAIL,
|
|
// etc.)
|
|
if(pNdisTapiRequest->ulReturnValue != STATUS_SUCCESS)
|
|
{
|
|
TspLog(DL_WARNING, "SyncDriverRequest: (Oid %s) returns with NDIS status (%x)",
|
|
pszOidNames[pNdisTapiRequest->Oid - OID_TAPI_ACCEPT], pNdisTapiRequest->ulReturnValue);
|
|
}
|
|
|
|
return (TranslateDriverResult(pNdisTapiRequest->ulReturnValue));
|
|
}
|
|
}
|
|
|
|
//
|
|
// make an overlapped call
|
|
//
|
|
LONG
|
|
WINAPI
|
|
AsyncDriverRequest(
|
|
DWORD dwIoControlCode,
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper
|
|
)
|
|
{
|
|
BOOL bRes;
|
|
LONG lRes;
|
|
DWORD dwRequestSize, cbReturned, dwLastError;
|
|
|
|
TspLog(DL_INFO,
|
|
"AsyncDriverRequest: oid(%s), devID(%x), ReqID(%x), "
|
|
"reqID(%x), hdCall(%x)",
|
|
pszOidNames[pAsyncReqWrapper->NdisTapiRequest.Oid -
|
|
OID_TAPI_ACCEPT],
|
|
pAsyncReqWrapper->NdisTapiRequest.ulDeviceID,
|
|
pAsyncReqWrapper->dwRequestID,
|
|
*((ULONG *)pAsyncReqWrapper->NdisTapiRequest.Data),
|
|
*(((ULONG *)pAsyncReqWrapper->NdisTapiRequest.Data) + 1));
|
|
|
|
lRes = (LONG)pAsyncReqWrapper->dwRequestID;
|
|
|
|
dwRequestSize = sizeof(NDISTAPI_REQUEST) +
|
|
(pAsyncReqWrapper->NdisTapiRequest.ulDataSize - 1);
|
|
|
|
REF_ASYNC_REQUEST_WRAPPER(pAsyncReqWrapper);
|
|
|
|
// mark the request as being processed by the driver
|
|
MarkRequest(pAsyncReqWrapper);
|
|
|
|
bRes = DeviceIoControl(
|
|
ghDriverAsync,
|
|
dwIoControlCode,
|
|
&pAsyncReqWrapper->NdisTapiRequest,
|
|
dwRequestSize,
|
|
&pAsyncReqWrapper->NdisTapiRequest,
|
|
dwRequestSize,
|
|
&cbReturned,
|
|
&pAsyncReqWrapper->Overlapped
|
|
);
|
|
|
|
DEREF_ASYNC_REQUEST_WRAPPER(pAsyncReqWrapper);
|
|
|
|
if (bRes != TRUE) {
|
|
|
|
dwLastError = GetLastError();
|
|
|
|
if (dwLastError != ERROR_IO_PENDING) {
|
|
|
|
TspLog(DL_ERROR, "AsyncDriverRequest: IoCtl(oid %x) failed(%d)",
|
|
pAsyncReqWrapper->NdisTapiRequest.Oid, dwLastError);
|
|
|
|
// the ioctl failed and was not pended
|
|
// this does not trigger the completion port
|
|
// so we have to cleanup here.
|
|
(*gpfnCompletionProc)(pAsyncReqWrapper->dwRequestID,
|
|
LINEERR_OPERATIONFAILED);
|
|
|
|
DEREF_ASYNC_REQUEST_WRAPPER(pAsyncReqWrapper);
|
|
}
|
|
}
|
|
|
|
return lRes;
|
|
}
|
|
|
|
//
|
|
// reports to TAPI events that occur on the line or on calls on the line
|
|
//
|
|
VOID
|
|
WINAPI
|
|
ProcessEvent(
|
|
PNDIS_TAPI_EVENT pEvent
|
|
)
|
|
{
|
|
LONG lRes;
|
|
ULONG ulMsg = pEvent->ulMsg;
|
|
HTAPI_LINE ht_Line = (HTAPI_LINE)pEvent->htLine;
|
|
HTAPI_CALL ht_Call = (HTAPI_CALL)pEvent->htCall;
|
|
|
|
TspLog(DL_INFO,
|
|
"ProcessEvent: event(%p), msg(%x), ht_line(%p), ht_call(%p), "\
|
|
"p1(%p), p2(%p), p3(%p)",
|
|
pEvent, ulMsg, ht_Line, ht_Call,
|
|
pEvent->ulParam1, pEvent->ulParam2, pEvent->ulParam3);
|
|
|
|
switch (ulMsg)
|
|
{
|
|
case LINE_ADDRESSSTATE:
|
|
case LINE_CLOSE:
|
|
case LINE_DEVSPECIFIC:
|
|
case LINE_LINEDEVSTATE:
|
|
{
|
|
PDRVLINE pLine;
|
|
|
|
lRes = GetLineObjWithReadLock((HDRVLINE)ht_Line, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
TspLog(DL_INFO,
|
|
"PE::fnLineEvent: msg(%x), line(%p), p1(%p), p2(%p), p3(%p)",
|
|
ulMsg, pLine->htLine,
|
|
pEvent->ulParam1, pEvent->ulParam2, pEvent->ulParam3);
|
|
|
|
(*gpfnLineEvent)(pLine->htLine,
|
|
(HTAPICALL)NULL,
|
|
ulMsg,
|
|
(DWORD_PTR)pEvent->ulParam1,
|
|
(DWORD_PTR)pEvent->ulParam2,
|
|
(DWORD_PTR)pEvent->ulParam3);
|
|
|
|
ReleaseObjReadLock((HANDLE)ht_Line);
|
|
|
|
break;
|
|
}
|
|
case LINE_CALLDEVSPECIFIC:
|
|
case LINE_CALLINFO:
|
|
{
|
|
PDRVLINE pLine;
|
|
PDRVCALL pCall;
|
|
HDRVLINE hdLine;
|
|
|
|
lRes = GetLineAndCallObjWithReadLock(ht_Line, ht_Call, &pLine, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
hdLine = pCall->hdLine;
|
|
|
|
TspLog(DL_INFO,
|
|
"PE::fnLineEvent: msg(%x), htline(%p), htcall(%p), "\
|
|
"p1(%p), p2(%p), p3(%p)",
|
|
ulMsg, pLine->htLine, pCall->htCall,
|
|
pEvent->ulParam1, pEvent->ulParam2, pEvent->ulParam3);
|
|
|
|
(*gpfnLineEvent)(pLine->htLine,
|
|
pCall->htCall,
|
|
ulMsg,
|
|
(DWORD_PTR)pEvent->ulParam1,
|
|
(DWORD_PTR)pEvent->ulParam2,
|
|
(DWORD_PTR)pEvent->ulParam3);
|
|
|
|
ReleaseObjReadLock((HANDLE)pCall->hdCall);
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
|
|
break;
|
|
}
|
|
case LINE_CALLSTATE:
|
|
{
|
|
PDRVLINE pLine;
|
|
PDRVCALL pCall;
|
|
HDRVLINE hdLine;
|
|
|
|
lRes = GetLineAndCallObjWithReadLock(ht_Line, ht_Call, &pLine, &pCall);
|
|
// we may still receive a few events
|
|
// for calls that have been closed/dropped
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
hdLine = pCall->hdLine;
|
|
|
|
//
|
|
// for outbound calls there exists a race condition between
|
|
// receiving the first call state msg(s) and receiving the
|
|
// make call completion notification (if we pass a call state
|
|
// msg on to tapi for a call that hasn't been completed yet
|
|
// tapi will just discard the msg since the htCall really
|
|
// isn't valid at that point). So if htCall references a
|
|
// valid outbound call which hasn't completed yet, we'll save
|
|
// the call state params, and pass them on to tapi after we
|
|
// get & indicate a (successful) completion notification.
|
|
//
|
|
|
|
if ((OUTBOUND_CALL_KEY == pCall->dwKey) &&
|
|
(TRUE == pCall->bIncomplete))
|
|
{
|
|
TspLog(DL_INFO,
|
|
"ProcessEvent: incomplete outbound call, saving state");
|
|
|
|
pCall->dwPendingCallState = (DWORD)pEvent->ulParam1;
|
|
pCall->dwPendingCallStateMode = (DWORD)pEvent->ulParam2;
|
|
pCall->dwPendingMediaMode = (DWORD)pEvent->ulParam3;
|
|
|
|
ReleaseObjReadLock((HANDLE)pCall->hdCall);
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
break;
|
|
}
|
|
|
|
if (pCall->bIdle)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)pCall->hdCall);
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
break;
|
|
}
|
|
else if (LINECALLSTATE_DISCONNECTED == pEvent->ulParam1 ||
|
|
LINECALLSTATE_IDLE == pEvent->ulParam1)
|
|
{
|
|
HDRVCALL hdCall = pCall->hdCall;
|
|
|
|
// we need to acquire a write lock to update bIdle,
|
|
// make sure releasing the read lock before doing so.
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
|
|
lRes = AcquireObjWriteLock((HANDLE)hdCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
TspLog(DL_WARNING,
|
|
"ProcessEvent: failed to acquire write lock for call(%p)",
|
|
hdCall);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
break;
|
|
}
|
|
pCall->bIdle = TRUE;
|
|
|
|
ReleaseObjWriteLock((HANDLE)hdCall);
|
|
|
|
// reacquire the read lock
|
|
lRes = AcquireObjReadLock((HANDLE)hdCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
TspLog(DL_WARNING,
|
|
"ProcessEvent: failed to reacquire read lock for call(%p)",
|
|
hdCall);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
break;
|
|
}
|
|
}
|
|
|
|
TspLog(DL_INFO,
|
|
"PE::fnLineEvent(CALLSTATE): htline(%p), htcall(%p), "\
|
|
"p1(%p), p2(%p), p3(%p)",
|
|
pLine->htLine, pCall->htCall,
|
|
pEvent->ulParam1, pEvent->ulParam2, pEvent->ulParam3);
|
|
|
|
(*gpfnLineEvent)(pLine->htLine,
|
|
pCall->htCall,
|
|
ulMsg,
|
|
(DWORD_PTR)pEvent->ulParam1,
|
|
(DWORD_PTR)pEvent->ulParam2,
|
|
(DWORD_PTR)pEvent->ulParam3);
|
|
|
|
//
|
|
// For old style miniports we want to indicate an IDLE
|
|
// immediately following the disconnected (several of
|
|
// the initial NDIS WAN miniports did not indicate an
|
|
// IDLE call state due to doc confusion)
|
|
//
|
|
|
|
if (LINECALLSTATE_DISCONNECTED == pEvent->ulParam1)
|
|
{
|
|
TspLog(DL_INFO,
|
|
"PE::fnLineEvent(CALLSTATE_IDLE): htline(%p), htcall(%p), p3(%p)",
|
|
pLine->htLine, pCall->htCall, pEvent->ulParam3);
|
|
|
|
(*gpfnLineEvent)(pLine->htLine,
|
|
pCall->htCall,
|
|
ulMsg,
|
|
(DWORD_PTR)LINECALLSTATE_IDLE,
|
|
(DWORD_PTR)0,
|
|
(DWORD_PTR)pEvent->ulParam3);
|
|
}
|
|
|
|
ReleaseObjReadLock((HANDLE)pCall->hdCall);
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
break;
|
|
}
|
|
case LINE_NEWCALL:
|
|
{
|
|
HDRVCALL hdCall;
|
|
PDRVCALL pCall;
|
|
PDRVLINE pLine;
|
|
|
|
lRes = GetLineObjWithWriteLock((HDRVLINE)ht_Line, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// alloc & initialize a new DRVCALL object
|
|
if (pCall = AllocCallObj(sizeof(DRVCALL)))
|
|
{
|
|
pCall->dwKey = INBOUND_CALL_KEY;
|
|
pCall->hd_Call = (HDRV_CALL)pEvent->ulParam1;
|
|
pCall->ht_Call = (HTAPI_CALL)pEvent->ulParam2;
|
|
pCall->hdLine = (HDRVLINE)ht_Line;
|
|
pCall->bIncomplete = FALSE;
|
|
}
|
|
|
|
//
|
|
// if the new call object allocation failed above then we
|
|
// want to tell the driver to drop & close the call,
|
|
// then just break
|
|
//
|
|
|
|
if (NULL == pCall)
|
|
{
|
|
PNDISTAPI_REQUEST pNdisTapiRequestDrop;
|
|
PNDISTAPI_REQUEST pNdisTapiRequestCloseCall;
|
|
PNDIS_TAPI_DROP pNdisTapiDrop;
|
|
PNDIS_TAPI_CLOSE_CALL pNdisTapiCloseCall;
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_DROP, // opcode
|
|
pLine->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_DROP), // size of drve req data
|
|
&pNdisTapiRequestDrop // ptr to ptr to request buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjWriteLock((HANDLE)ht_Line);
|
|
break;
|
|
}
|
|
|
|
pNdisTapiDrop = (PNDIS_TAPI_DROP)pNdisTapiRequestDrop->Data;
|
|
|
|
pNdisTapiDrop->hdCall = (HDRV_CALL) pEvent->ulParam1;
|
|
pNdisTapiDrop->ulUserUserInfoSize = 0;
|
|
|
|
SyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pNdisTapiRequestDrop);
|
|
FreeRequest(pNdisTapiRequestDrop);
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_CLOSE_CALL, // opcode
|
|
pLine->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_CLOSE_CALL), // size of drve req data
|
|
&pNdisTapiRequestCloseCall // ptr to ptr to request buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjWriteLock((HANDLE)ht_Line);
|
|
break;
|
|
}
|
|
|
|
pNdisTapiCloseCall =
|
|
(PNDIS_TAPI_CLOSE_CALL)pNdisTapiRequestCloseCall->Data;
|
|
|
|
pNdisTapiCloseCall->hdCall = (HDRV_CALL) pEvent->ulParam1;
|
|
|
|
SyncDriverRequest(IOCTL_NDISTAPI_SET_INFO,
|
|
pNdisTapiRequestCloseCall);
|
|
|
|
FreeRequest(pNdisTapiRequestCloseCall);
|
|
|
|
ReleaseObjWriteLock((HANDLE)ht_Line);
|
|
break;
|
|
}
|
|
|
|
ASSERT(pCall != NULL);
|
|
|
|
pCall->dwDeviceID = pLine->dwDeviceID;
|
|
|
|
// make sure releasing write lock before calling OpenObjHandle()
|
|
// to avoid deadlock on acquiring write lock for the global mapper
|
|
ReleaseObjWriteLock((HANDLE)ht_Line);
|
|
|
|
lRes = OpenObjHandle(pCall, FreeCallObj, (HANDLE *)&hdCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"ProcessEvent: failed to map obj(%p) to handle",
|
|
pCall);
|
|
|
|
FreeCallObj(pCall);
|
|
break;
|
|
}
|
|
|
|
// reacquire the write lock
|
|
lRes = AcquireObjWriteLock((HANDLE)ht_Line);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"ProcessEvent: failed to reacquire write lock for obj(%p)",
|
|
ht_Line);
|
|
|
|
CloseObjHandle((HANDLE)hdCall);
|
|
break;
|
|
}
|
|
|
|
// save the TSP handle
|
|
pCall->hdCall = hdCall;
|
|
|
|
// send the LINE_NEWCALL to TAPI, getting back the TAPI call handle
|
|
TspLog(DL_INFO,
|
|
"PE::fnLineEvent(NEWCALL): htline(%p), call(%p)",
|
|
pLine->htLine, hdCall);
|
|
|
|
(*gpfnLineEvent)(pLine->htLine,
|
|
(HTAPICALL) NULL,
|
|
LINE_NEWCALL,
|
|
(DWORD_PTR)hdCall,
|
|
(DWORD_PTR)&pCall->htCall,
|
|
0);
|
|
|
|
//
|
|
// insert the new call into the line's inbound calls list
|
|
// regardless of the result of the LINE_NEWCALL
|
|
// if it failed, we'll destroy the call next, and
|
|
// TSPI_lineCloseCall will expect the call to be
|
|
// in the line's inbound call list
|
|
//
|
|
if ((pCall->pNext = pLine->pInboundCalls) != NULL)
|
|
{
|
|
pCall->pNext->pPrev = pCall;
|
|
}
|
|
pLine->pInboundCalls = pCall;
|
|
|
|
ReleaseObjWriteLock((HANDLE)ht_Line);
|
|
|
|
//
|
|
// if TAPI didn't create it's own representation of this
|
|
// cal (if pCall->htCall == NULL), then either:
|
|
//
|
|
// 1) the line is in the process of being closed, or
|
|
// 2) TAPI was unable to allocate the necessary resources
|
|
//
|
|
// ...so we'll close the call
|
|
//
|
|
if (NULL == pCall->htCall)
|
|
{
|
|
TspLog(DL_WARNING, "ProcessEvent: TAPI failed to create "
|
|
"its own handle for the new call, so we close the call");
|
|
TSPI_lineCloseCall(hdCall);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case LINE_CREATE:
|
|
|
|
TspLog(DL_INFO,
|
|
"PE::fnLineEvent(CREATE): ghProvider(%p), p2(%p), p3(%p)",
|
|
ghProvider, pEvent->ulParam2, pEvent->ulParam3);
|
|
|
|
(*gpfnLineEvent)((HTAPILINE) NULL,
|
|
(HTAPICALL) NULL,
|
|
ulMsg,
|
|
(DWORD_PTR)ghProvider,
|
|
(DWORD_PTR)pEvent->ulParam2,
|
|
(DWORD_PTR)pEvent->ulParam3);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
TspLog(DL_ERROR, "ProcessEvent: unknown msg(%x)", ulMsg);
|
|
|
|
break;
|
|
|
|
} // switch
|
|
}
|
|
|
|
//
|
|
// thread proc that retrieves and processes completed requests
|
|
// and async events
|
|
//
|
|
VOID
|
|
AsyncEventsThread(
|
|
LPVOID lpParams
|
|
)
|
|
{
|
|
OVERLAPPED overlapped;
|
|
DWORD cbReturned;
|
|
|
|
//
|
|
// send an IOCTL to retrieve async events
|
|
//
|
|
overlapped.hEvent = NULL; // don't need event when using completion ports
|
|
|
|
gpAsyncEventsThreadInfo->pBuf->ulTotalSize =
|
|
gpAsyncEventsThreadInfo->dwBufSize - sizeof(NDISTAPI_EVENT_DATA) + 1;
|
|
|
|
gpAsyncEventsThreadInfo->pBuf->ulUsedSize = 0;
|
|
|
|
if (DeviceIoControl(
|
|
ghDriverAsync,
|
|
IOCTL_NDISTAPI_GET_LINE_EVENTS,
|
|
gpAsyncEventsThreadInfo->pBuf,
|
|
sizeof(NDISTAPI_EVENT_DATA),
|
|
gpAsyncEventsThreadInfo->pBuf,
|
|
gpAsyncEventsThreadInfo->dwBufSize,
|
|
&cbReturned,
|
|
&overlapped
|
|
) != TRUE)
|
|
{
|
|
DWORD dwLastError = GetLastError();
|
|
if (dwLastError != ERROR_IO_PENDING)
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"AsyncEventsThread: IoCtl(GetEvent) failed(%d)",
|
|
dwLastError);
|
|
}
|
|
ASSERT(ERROR_IO_PENDING == dwLastError);
|
|
}
|
|
|
|
// loop waiting for completed requests and retrieving async events
|
|
while (1)
|
|
{
|
|
BOOL bRes;
|
|
LPOVERLAPPED lpOverlapped;
|
|
PNDIS_TAPI_EVENT pEvent;
|
|
|
|
// wait for a request to complete
|
|
while (1) {
|
|
DWORD dwNumBytesTransferred;
|
|
DWORD_PTR dwCompletionKey;
|
|
|
|
bRes = GetQueuedCompletionStatus(
|
|
ghCompletionPort,
|
|
&dwNumBytesTransferred,
|
|
&dwCompletionKey,
|
|
&lpOverlapped,
|
|
(DWORD)-1); // infinite wait
|
|
|
|
if (bRes)
|
|
{
|
|
//
|
|
// GetQueuedCompletion returned success so if our
|
|
// overlapped field is non-NULL then process the
|
|
// event. If the overlapped field is NULL try
|
|
// to get another event.
|
|
//
|
|
|
|
|
|
if (&gOverlappedTerminate==lpOverlapped)
|
|
{
|
|
|
|
TspLog(DL_WARNING, "AsyncEventsThread: Got "\
|
|
"exit message from TSPI_providerShutdown");
|
|
return;
|
|
}
|
|
|
|
if (lpOverlapped != NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
|
|
|
|
TspLog(DL_WARNING,
|
|
"AsyncEventsThread: GetQueuedCompletionStatus "\
|
|
"lpOverlapped == NULL!");
|
|
|
|
} else
|
|
{
|
|
|
|
DWORD dwErr = GetLastError();
|
|
|
|
if(ERROR_INVALID_HANDLE != dwErr)
|
|
{
|
|
|
|
// Error returned from GetQueuedCompletionStatus
|
|
|
|
TspLog(DL_ERROR,
|
|
"AsyncEventsThread: GetQueuedCompletionStatus "\
|
|
"failed(%d)", dwErr);
|
|
|
|
Sleep(1);
|
|
}
|
|
else
|
|
{
|
|
ExitThread(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// check the returned overlapped struct to determine if
|
|
// we have some events to process or a completed request
|
|
//
|
|
if (lpOverlapped == &overlapped)
|
|
{
|
|
DWORD i;
|
|
|
|
TspLog(DL_INFO, "AsyncEventsThread: got a line event");
|
|
|
|
// handle the events
|
|
pEvent = (PNDIS_TAPI_EVENT)gpAsyncEventsThreadInfo->pBuf->Data;
|
|
|
|
for (i = 0;
|
|
i < (gpAsyncEventsThreadInfo->pBuf->ulUsedSize /
|
|
sizeof(NDIS_TAPI_EVENT));
|
|
i++
|
|
)
|
|
{
|
|
ProcessEvent(pEvent);
|
|
pEvent++;
|
|
}
|
|
|
|
//
|
|
// send another IOCTL to retrieve new async events
|
|
//
|
|
overlapped.hEvent = NULL;
|
|
|
|
gpAsyncEventsThreadInfo->pBuf->ulTotalSize =
|
|
gpAsyncEventsThreadInfo->dwBufSize -
|
|
sizeof(NDISTAPI_EVENT_DATA) + 1;
|
|
|
|
gpAsyncEventsThreadInfo->pBuf->ulUsedSize = 0;
|
|
|
|
if (DeviceIoControl(
|
|
ghDriverAsync,
|
|
IOCTL_NDISTAPI_GET_LINE_EVENTS,
|
|
gpAsyncEventsThreadInfo->pBuf,
|
|
sizeof(NDISTAPI_EVENT_DATA),
|
|
gpAsyncEventsThreadInfo->pBuf,
|
|
gpAsyncEventsThreadInfo->dwBufSize,
|
|
&cbReturned,
|
|
&overlapped
|
|
) != TRUE)
|
|
{
|
|
DWORD dwLastError = GetLastError();
|
|
if (dwLastError != ERROR_IO_PENDING) {
|
|
TspLog(DL_ERROR,
|
|
"AsyncEventsThread: IoCtl(GetEvent) failed(%d)",
|
|
dwLastError);
|
|
|
|
ASSERT(ERROR_IO_PENDING == dwLastError);
|
|
Sleep(1);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LONG lRes;
|
|
DWORD dwRequestID;
|
|
DWORD_PTR callStateMsgParams[5];
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper =
|
|
(PASYNC_REQUEST_WRAPPER)lpOverlapped;
|
|
|
|
TspLog(DL_INFO, "AsyncEventsThread: got a completed req");
|
|
|
|
// verify that pointer is valid
|
|
if (pAsyncReqWrapper->dwKey != ASYNCREQWRAPPER_KEY) {
|
|
TspLog(DL_WARNING, "AsyncEventsThread: got a bogus req");
|
|
continue;
|
|
}
|
|
|
|
dwRequestID = pAsyncReqWrapper->dwRequestID;
|
|
|
|
// unmark the request now that the ioctl is completed
|
|
UnmarkRequest(pAsyncReqWrapper);
|
|
|
|
lRes = TranslateDriverResult(
|
|
pAsyncReqWrapper->NdisTapiRequest.ulReturnValue
|
|
);
|
|
|
|
TspLog(DL_INFO,
|
|
"AsyncEventsThread: req(%p) with reqID(%x) returned lRes(%x)",
|
|
pAsyncReqWrapper, dwRequestID, lRes);
|
|
|
|
// call the post processing proc if appropriate
|
|
callStateMsgParams[0] = 0;
|
|
if (pAsyncReqWrapper->pfnPostProcess)
|
|
{
|
|
(*pAsyncReqWrapper->pfnPostProcess)(
|
|
pAsyncReqWrapper,
|
|
lRes,
|
|
callStateMsgParams
|
|
);
|
|
}
|
|
|
|
// free the async request wrapper
|
|
DEREF_ASYNC_REQUEST_WRAPPER(pAsyncReqWrapper);
|
|
|
|
// call completion proc
|
|
TspLog(DL_TRACE,
|
|
"AsyncEventsThread: call compproc with ReqID(%x), lRes(%x)",
|
|
dwRequestID, lRes);
|
|
|
|
(*gpfnCompletionProc)(dwRequestID, lRes);
|
|
|
|
// when outbounding call completes, we need to
|
|
// report back the saved call state
|
|
if (callStateMsgParams[0])
|
|
{
|
|
TspLog(DL_INFO,
|
|
"AsyncEventsThread: report back the saved call state");
|
|
|
|
TspLog(DL_INFO,
|
|
"AET::fnLineEvent(CALLSTATE): htline(%p), htcall(%p), "\
|
|
"p1(%p), p2(%p), p3(%p)",
|
|
callStateMsgParams[0], callStateMsgParams[1],
|
|
callStateMsgParams[2], callStateMsgParams[3],
|
|
callStateMsgParams[4]);
|
|
|
|
(*gpfnLineEvent)((HTAPILINE)(callStateMsgParams[0]),
|
|
(HTAPICALL)(callStateMsgParams[1]),
|
|
LINE_CALLSTATE,
|
|
callStateMsgParams[2],
|
|
callStateMsgParams[3],
|
|
callStateMsgParams[4]);
|
|
}
|
|
}
|
|
} // while
|
|
}
|
|
|
|
HDRV_CALL
|
|
GetNdisTapiHandle(
|
|
PDRVCALL pCall,
|
|
LONG *plRes
|
|
)
|
|
{
|
|
HDRVCALL hdCall;
|
|
PDRVCALL pCallLocal = pCall;
|
|
LONG lRes;
|
|
|
|
ASSERT(pCallLocal != NULL);
|
|
|
|
hdCall = pCall->hdCall;
|
|
|
|
if(plRes != NULL)
|
|
{
|
|
*plRes = TAPI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// if the call is outbound, wait until the make call request
|
|
// has completed so we don't send a bad NDISTAPI handle down
|
|
// to the driver
|
|
//
|
|
if (OUTBOUND_CALL_KEY == pCallLocal->dwKey)
|
|
{
|
|
ASSERT(plRes != NULL);
|
|
|
|
if (pCallLocal->bIncomplete)
|
|
{
|
|
TspLog(DL_INFO,
|
|
"GetNdisTapiHandle: wait for the outbound call to complete...");
|
|
|
|
do
|
|
{
|
|
ASSERT(plRes != NULL);
|
|
|
|
//
|
|
// Release the lock before going to sleep.
|
|
// otherwise we get into a deadlock.
|
|
//
|
|
ReleaseObjReadLock((HANDLE) hdCall);
|
|
Sleep(250);
|
|
|
|
//
|
|
// ReAcquire Lock. break if we can't
|
|
//
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCallLocal);
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
*plRes = lRes;
|
|
break;
|
|
}
|
|
|
|
} while (pCallLocal->bIncomplete);
|
|
}
|
|
}
|
|
|
|
return pCall->hd_Call;
|
|
}
|
|
|
|
DWORD
|
|
GetDestAddressLength(
|
|
LPCWSTR lpszDestAddress,
|
|
DWORD dwOrgDALength,
|
|
UINT *pCodePage
|
|
)
|
|
{
|
|
DWORD dwLength;
|
|
|
|
ASSERT(lpszDestAddress != NULL);
|
|
ASSERT(pCodePage != NULL);
|
|
|
|
if (*pCodePage == CP_ACP)
|
|
{
|
|
// If code page is CP_ACP, return the original length to
|
|
// keep the old behavior.
|
|
dwLength = dwOrgDALength;
|
|
}
|
|
else
|
|
{
|
|
dwLength = WideCharToMultiByte(
|
|
*pCodePage,
|
|
0,
|
|
lpszDestAddress,
|
|
dwOrgDALength,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (dwLength == 0)
|
|
{
|
|
// WideCharToMultiByte() failed, use CP_ACP to show
|
|
// the old behavior.
|
|
*pCodePage = CP_ACP;
|
|
|
|
dwLength = dwOrgDALength;
|
|
}
|
|
}
|
|
|
|
return dwLength;
|
|
}
|
|
|
|
//
|
|
// TSPI_lineXXX functions
|
|
//
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineAccept(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVCALL hdCall,
|
|
LPCSTR lpsUserUserInfo,
|
|
DWORD dwSize
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper;
|
|
PNDIS_TAPI_ACCEPT pNdisTapiAccept;
|
|
|
|
TspLog(DL_TRACE, "lineAccept(%d): reqID(%x), call(%p)",
|
|
++dwSum, dwRequestID, hdCall);
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareAsyncRequest(
|
|
OID_TAPI_ACCEPT, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
dwRequestID, // request id
|
|
sizeof(NDIS_TAPI_ACCEPT) + dwSize, // size of drv request data
|
|
&pAsyncReqWrapper // ptr to ptr to request buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiAccept =
|
|
(PNDIS_TAPI_ACCEPT)pAsyncReqWrapper->NdisTapiRequest.Data;
|
|
|
|
pNdisTapiAccept->hdCall = GetNdisTapiHandle(pCall, NULL);
|
|
|
|
if ((pNdisTapiAccept->ulUserUserInfoSize = dwSize) != 0)
|
|
{
|
|
CopyMemory(pNdisTapiAccept->UserUserInfo, lpsUserUserInfo, dwSize);
|
|
}
|
|
|
|
lRes = AsyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pAsyncReqWrapper);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineAnswer(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVCALL hdCall,
|
|
LPCSTR lpsUserUserInfo,
|
|
DWORD dwSize
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper;
|
|
PNDIS_TAPI_ANSWER pNdisTapiAnswer;
|
|
|
|
TspLog(DL_TRACE, "lineAnswer(%d): reqID(%x), call(%p)",
|
|
++dwSum, dwRequestID, hdCall);
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareAsyncRequest(
|
|
OID_TAPI_ANSWER, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
dwRequestID, // request id
|
|
sizeof(NDIS_TAPI_ANSWER) + dwSize, // size of drv request data
|
|
&pAsyncReqWrapper // ptr to ptr to request buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiAnswer =
|
|
(PNDIS_TAPI_ANSWER)pAsyncReqWrapper->NdisTapiRequest.Data;
|
|
|
|
pNdisTapiAnswer->hdCall = GetNdisTapiHandle(pCall, NULL);
|
|
|
|
if ((pNdisTapiAnswer->ulUserUserInfoSize = dwSize) != 0)
|
|
{
|
|
CopyMemory(pNdisTapiAnswer->UserUserInfo, lpsUserUserInfo, dwSize);
|
|
}
|
|
|
|
lRes = AsyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pAsyncReqWrapper);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineClose(
|
|
HDRVLINE hdLine
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_CLOSE pNdisTapiClose;
|
|
|
|
TspLog(DL_TRACE, "lineClose(%d): line(%p)", ++dwSum, hdLine);
|
|
|
|
lRes = GetLineObjWithWriteLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_CLOSE, // opcode
|
|
pLine->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_CLOSE), // size of drve req data
|
|
&pNdisTapiRequest // ptr to ptr to request buffer
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjWriteLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiClose = (PNDIS_TAPI_CLOSE)pNdisTapiRequest->Data;
|
|
|
|
// mark line as invalid so any related events that show up
|
|
// will be discarded.
|
|
pLine->dwKey = INVALID_KEY;
|
|
|
|
pNdisTapiClose->hdLine = pLine->hd_Line;
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pNdisTapiRequest);
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
lRes = DecommitNegotiatedTSPIVersion(pLine->dwDeviceID);
|
|
}
|
|
|
|
ReleaseObjWriteLock((HANDLE)hdLine);
|
|
|
|
// release line resources
|
|
CloseObjHandle((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineCloseCall(
|
|
HDRVCALL hdCall
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
HDRVLINE hdLine;
|
|
PDRVLINE pLine;
|
|
PDRVCALL pCall;
|
|
PNDISTAPI_REQUEST pNdisTapiRequestCloseCall;
|
|
PNDIS_TAPI_CLOSE_CALL pNdisTapiCloseCall;
|
|
BOOL bInboundCall;
|
|
HDRV_CALL NdisTapiHandle;
|
|
|
|
TspLog(DL_TRACE, "lineCloseCall(%d): call(%p)", ++dwSum, hdCall);
|
|
|
|
lRes = GetLineHandleFromCallHandle(hdCall, &hdLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
//
|
|
// Initially we can't acquire the write lock directly
|
|
// because we might spin-wait in GetNdisTapiHandle so
|
|
// we grab the readlock instead.
|
|
//
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
bInboundCall = (INBOUND_CALL_KEY == pCall->dwKey);
|
|
|
|
NdisTapiHandle = GetNdisTapiHandle(pCall, &lRes);
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE) hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
|
|
//
|
|
// Now acquire the write lock
|
|
//
|
|
lRes = AcquireObjWriteLock((HANDLE)hdLine);
|
|
if (lRes != TAPI_SUCCESS) {
|
|
return lRes;
|
|
}
|
|
|
|
lRes = AcquireObjWriteLock((HANDLE)hdCall);
|
|
if (lRes != TAPI_SUCCESS) {
|
|
ReleaseObjWriteLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_CLOSE_CALL, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_CLOSE_CALL), // size of drve req data
|
|
&pNdisTapiRequestCloseCall // ptr to ptr to request buffer
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjWriteLock((HANDLE)hdCall);
|
|
ReleaseObjWriteLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
// @@@ for legacy NDISWAN ISDN miniports:
|
|
// since there's no more "automatic" call dropping in
|
|
// TAPI when an app has closed the line & there are
|
|
// existing non-IDLE calls, legacy NDIS WAN ISDN miniports
|
|
// rely on seeing an OID_TAPI_DROP, we need to synthesize
|
|
// this behavior if the call has not previously be dropped.
|
|
if (!pCall->bDropped)
|
|
{
|
|
PNDISTAPI_REQUEST pNdisTapiRequestDrop;
|
|
PNDIS_TAPI_DROP pNdisTapiDrop;
|
|
|
|
TspLog(DL_INFO, "lineCloseCall: synthesize DROP req");
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_DROP, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_DROP), // size of drve req data
|
|
&pNdisTapiRequestDrop // ptr to ptr to request buffer
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pNdisTapiRequestCloseCall);
|
|
|
|
ReleaseObjWriteLock((HANDLE)hdCall);
|
|
ReleaseObjWriteLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiDrop = (PNDIS_TAPI_DROP)pNdisTapiRequestDrop->Data;
|
|
|
|
pNdisTapiDrop->hdCall = NdisTapiHandle;
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pNdisTapiRequestDrop);
|
|
// done with the drop sync req
|
|
FreeRequest(pNdisTapiRequestDrop);
|
|
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pNdisTapiRequestCloseCall);
|
|
|
|
ReleaseObjWriteLock((HANDLE)hdCall);
|
|
ReleaseObjWriteLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
}
|
|
|
|
// mark the call as bad so any events get discarded
|
|
pCall->dwKey = INVALID_KEY;
|
|
|
|
// set up the params & call the driver
|
|
pNdisTapiCloseCall = (PNDIS_TAPI_CLOSE_CALL)pNdisTapiRequestCloseCall->Data;
|
|
pNdisTapiCloseCall->hdCall = NdisTapiHandle;
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_SET_INFO,
|
|
pNdisTapiRequestCloseCall);
|
|
FreeRequest(pNdisTapiRequestCloseCall);
|
|
|
|
// if inbound call, remove it from the list
|
|
if (bInboundCall)
|
|
{
|
|
if (pCall->pNext)
|
|
{
|
|
pCall->pNext->pPrev = pCall->pPrev;
|
|
}
|
|
if (pCall->pPrev)
|
|
{
|
|
pCall->pPrev->pNext = pCall->pNext;
|
|
}
|
|
else
|
|
{
|
|
pLine->pInboundCalls = pCall->pNext;
|
|
}
|
|
}
|
|
|
|
ReleaseObjWriteLock((HANDLE)hdCall);
|
|
ReleaseObjWriteLock((HANDLE)hdLine);
|
|
|
|
// free the call struct now that the call is closed
|
|
CloseObjHandle((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineConditionalMediaDetection(
|
|
HDRVLINE hdLine,
|
|
DWORD dwMediaModes,
|
|
LPLINECALLPARAMS const lpCallParams
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_CONDITIONAL_MEDIA_DETECTION pNdisTapiConditionalMediaDetection;
|
|
|
|
TspLog(DL_TRACE, "lineConditionalMediaDetection(%d): line(%p), mode(%x)",
|
|
++dwSum, hdLine, dwMediaModes);
|
|
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_CONDITIONAL_MEDIA_DETECTION, // opcode
|
|
pLine->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_CONDITIONAL_MEDIA_DETECTION) +
|
|
(lpCallParams->dwTotalSize - sizeof(LINE_CALL_PARAMS)),
|
|
&pNdisTapiRequest // ptr to ptr to
|
|
// req buffer
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiConditionalMediaDetection =
|
|
(PNDIS_TAPI_CONDITIONAL_MEDIA_DETECTION) pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiConditionalMediaDetection->hdLine = pLine->hd_Line;
|
|
pNdisTapiConditionalMediaDetection->ulMediaModes = dwMediaModes;
|
|
|
|
CopyMemory(
|
|
&pNdisTapiConditionalMediaDetection->LineCallParams,
|
|
lpCallParams,
|
|
lpCallParams->dwTotalSize
|
|
);
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pNdisTapiRequest);
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
PASCAL
|
|
TSPI_lineDevSpecific_postProcess(
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper,
|
|
LONG lRes,
|
|
PDWORD_PTR callStateMsgParams
|
|
)
|
|
{
|
|
TspLog(DL_TRACE, "lineDevSpecific_post: lRes(%x)", lRes);
|
|
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
PNDIS_TAPI_DEV_SPECIFIC pNdisTapiDevSpecific =
|
|
(PNDIS_TAPI_DEV_SPECIFIC)pAsyncReqWrapper->NdisTapiRequest.Data;
|
|
|
|
CopyMemory(
|
|
(LPVOID) pAsyncReqWrapper->dwRequestSpecific,
|
|
pNdisTapiDevSpecific->Params,
|
|
pNdisTapiDevSpecific->ulParamsSize
|
|
);
|
|
}
|
|
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineDevSpecific(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVLINE hdLine,
|
|
DWORD dwAddressID,
|
|
HDRVCALL hdCall,
|
|
LPVOID lpParams,
|
|
DWORD dwSize
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
PDRVCALL pCall = NULL;
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper;
|
|
PNDIS_TAPI_DEV_SPECIFIC pNdisTapiDevSpecific;
|
|
|
|
TspLog(DL_TRACE,
|
|
"lineDevSpecific(%d): reqID(%x), line(%p), addressID(%x), call(%p)",
|
|
++dwSum, dwRequestID, hdLine, dwAddressID, hdCall);
|
|
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareAsyncRequest(
|
|
OID_TAPI_DEV_SPECIFIC, // opcode
|
|
pLine->dwDeviceID, // device id
|
|
dwRequestID, // request id
|
|
sizeof(NDIS_TAPI_DEV_SPECIFIC) + // size of drv request data
|
|
(dwSize - 1),
|
|
&pAsyncReqWrapper // ptr to ptr to request buffer
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiDevSpecific =
|
|
(PNDIS_TAPI_DEV_SPECIFIC)pAsyncReqWrapper->NdisTapiRequest.Data;
|
|
|
|
pNdisTapiDevSpecific->hdLine = pLine->hd_Line;
|
|
pNdisTapiDevSpecific->ulAddressID = dwAddressID;
|
|
|
|
if (hdCall)
|
|
{
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pAsyncReqWrapper);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
pNdisTapiDevSpecific->hdCall = GetNdisTapiHandle(pCall, &lRes);
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pAsyncReqWrapper);
|
|
return lRes;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pNdisTapiDevSpecific->hdCall = (HDRV_CALL)NULL;
|
|
}
|
|
|
|
pNdisTapiDevSpecific->ulParamsSize = dwSize;
|
|
CopyMemory(pNdisTapiDevSpecific->Params, lpParams, dwSize);
|
|
|
|
pAsyncReqWrapper->dwRequestSpecific = (DWORD_PTR)lpParams;
|
|
pAsyncReqWrapper->pfnPostProcess = TSPI_lineDevSpecific_postProcess;
|
|
|
|
lRes = AsyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pAsyncReqWrapper);
|
|
|
|
if (pCall != NULL)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
}
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineDial(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVCALL hdCall,
|
|
LPCWSTR lpszDestAddress,
|
|
DWORD dwCountryCode
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
DWORD dwLength = lstrlenW (lpszDestAddress) + 1;
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper;
|
|
PNDIS_TAPI_DIAL pNdisTapiDial;
|
|
|
|
TspLog(DL_TRACE, "lineDial(%d): reqID(%x), call(%p)",
|
|
++dwSum, dwRequestID, hdCall);
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareAsyncRequest(
|
|
OID_TAPI_DIAL, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
dwRequestID, // request id
|
|
sizeof(NDIS_TAPI_DIAL) + dwLength, // size of driver req buffer
|
|
&pAsyncReqWrapper // ptr to ptr to req buffer
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiDial =
|
|
(PNDIS_TAPI_DIAL)pAsyncReqWrapper->NdisTapiRequest.Data;
|
|
|
|
pNdisTapiDial->hdCall = GetNdisTapiHandle(pCall, &lRes);
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pAsyncReqWrapper);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiDial->ulDestAddressSize = dwLength;
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, lpszDestAddress,
|
|
-1, (LPSTR)pNdisTapiDial->szDestAddress,
|
|
dwLength, NULL, NULL);
|
|
|
|
lRes = AsyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pAsyncReqWrapper);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
PASCAL
|
|
TSPI_lineDrop_postProcess(
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper,
|
|
LONG lRes,
|
|
PDWORD_PTR callStateMsgParams
|
|
)
|
|
{
|
|
BOOL bSendCallStateIdleMsg = FALSE;
|
|
LONG lSuc;
|
|
HDRVLINE hdLine;
|
|
HDRVCALL hdCall;
|
|
PDRVLINE pLine;
|
|
PDRVCALL pCall;
|
|
HTAPILINE htLine;
|
|
HTAPICALL htCall;
|
|
|
|
TspLog(DL_TRACE, "lineDrop_post: lRes(%x)", lRes);
|
|
|
|
hdCall = (HDRVCALL)(pAsyncReqWrapper->dwRequestSpecific);
|
|
|
|
lSuc = GetLineHandleFromCallHandle(hdCall, &hdLine);
|
|
if (lSuc != TAPI_SUCCESS)
|
|
{
|
|
return lSuc;
|
|
}
|
|
|
|
lSuc = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lSuc != TAPI_SUCCESS)
|
|
{
|
|
return lSuc;
|
|
}
|
|
|
|
lSuc = GetCallObjWithWriteLock(hdCall, &pCall);
|
|
if (lSuc != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lSuc;
|
|
}
|
|
|
|
//
|
|
// @@@ Some old-style miniports, notably pcimac, don't indicate
|
|
// IDLE msgs when they get a drop request- so we synthesize this
|
|
// for them (only if and IDLE hasn't already been sent)
|
|
//
|
|
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
ASSERT(INBOUND_CALL_KEY == pCall->dwKey ||
|
|
OUTBOUND_CALL_KEY == pCall->dwKey);
|
|
|
|
htCall = pCall->htCall;
|
|
htLine = pLine->htLine;
|
|
|
|
if (!pCall->bIdle)
|
|
{
|
|
pCall->bIdle = bSendCallStateIdleMsg = TRUE;
|
|
}
|
|
|
|
if (bSendCallStateIdleMsg)
|
|
{
|
|
TspLog(DL_INFO,
|
|
"postDrop::fnLineEvent(CALLSTATE_IDLE): htline(%p), htcall(%p)",
|
|
htLine, htCall);
|
|
|
|
(*gpfnLineEvent)(htLine,
|
|
htCall,
|
|
LINE_CALLSTATE,
|
|
LINECALLSTATE_IDLE,
|
|
0,
|
|
0);
|
|
}
|
|
}
|
|
|
|
ReleaseObjWriteLock((HANDLE)hdCall);
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineDrop(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVCALL hdCall,
|
|
LPCSTR lpsUserUserInfo,
|
|
DWORD dwSize
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper;
|
|
PNDIS_TAPI_DROP pNdisTapiDrop;
|
|
HDRV_CALL NdisTapiHandle;
|
|
|
|
TspLog(DL_TRACE, "lineDrop(%d): reqID(%x), call(%p)",
|
|
++dwSum, dwRequestID, hdCall);
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
NdisTapiHandle = GetNdisTapiHandle(pCall, &lRes);
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
|
|
lRes = AcquireObjWriteLock((HANDLE)hdCall);
|
|
if (lRes != TAPI_SUCCESS) {
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareAsyncRequest(
|
|
OID_TAPI_DROP, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
dwRequestID, // request id
|
|
sizeof(NDIS_TAPI_DROP) + dwSize, // size of driver req buffer
|
|
&pAsyncReqWrapper // ptr to ptr to req buffer
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjWriteLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiDrop =
|
|
(PNDIS_TAPI_DROP)pAsyncReqWrapper->NdisTapiRequest.Data;
|
|
|
|
pNdisTapiDrop->hdCall = NdisTapiHandle;
|
|
|
|
//
|
|
// @@@: the following is for legacy NDISWAN ISDN miniports
|
|
//
|
|
// Safely mark the call as dropped so the CloseCall code
|
|
// won't follow up with another "automatic" drop
|
|
//
|
|
pCall->bDropped = TRUE;
|
|
|
|
if ((pNdisTapiDrop->ulUserUserInfoSize = dwSize) != 0)
|
|
{
|
|
CopyMemory(pNdisTapiDrop->UserUserInfo, lpsUserUserInfo, dwSize);
|
|
}
|
|
|
|
pAsyncReqWrapper->dwRequestSpecific = (DWORD_PTR)hdCall;
|
|
pAsyncReqWrapper->pfnPostProcess = TSPI_lineDrop_postProcess;
|
|
|
|
ReleaseObjWriteLock((HANDLE)hdCall);
|
|
|
|
lRes = AsyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pAsyncReqWrapper);
|
|
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetAddressCaps(
|
|
DWORD dwDeviceID,
|
|
DWORD dwAddressID,
|
|
DWORD dwTSPIVersion,
|
|
DWORD dwExtVersion,
|
|
LPLINEADDRESSCAPS lpAddressCaps
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PLINE_ADDRESS_CAPS pCaps;
|
|
PNDIS_TAPI_GET_ADDRESS_CAPS pNdisTapiGetAddressCaps;
|
|
|
|
TspLog(DL_TRACE,
|
|
"lineGetAddressCaps(%d): deviceID(%x), addressID(%x), "\
|
|
"TSPIV(%x), ExtV(%x)",
|
|
++dwSum, dwDeviceID, dwAddressID);
|
|
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_GET_ADDRESS_CAPS, // opcode
|
|
dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_GET_ADDRESS_CAPS) + // size of req data
|
|
(lpAddressCaps->dwTotalSize - sizeof(LINE_ADDRESS_CAPS)),
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiGetAddressCaps =
|
|
(PNDIS_TAPI_GET_ADDRESS_CAPS)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiGetAddressCaps->ulDeviceID = dwDeviceID;
|
|
pNdisTapiGetAddressCaps->ulAddressID = dwAddressID;
|
|
pNdisTapiGetAddressCaps->ulExtVersion = dwExtVersion;
|
|
|
|
pCaps = &pNdisTapiGetAddressCaps->LineAddressCaps;
|
|
pCaps->ulTotalSize = lpAddressCaps->dwTotalSize;
|
|
pCaps->ulNeededSize = pCaps->ulUsedSize = sizeof (LINE_ADDRESS_CAPS);
|
|
|
|
ZeroMemory(
|
|
&pCaps->ulLineDeviceID,
|
|
sizeof(LINE_ADDRESS_CAPS) - 3 * sizeof(ULONG)
|
|
);
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
//
|
|
// Do some post processing to the returned data structure
|
|
// before passing it back to tapi:
|
|
// 1. Pad the area between the fixed 1.0 structure and the
|
|
// var data that the miniports pass back with 0's so a
|
|
// bad app that disregards the 1.0 version negotiation &
|
|
// references new 1.4 or 2.0 structure fields won't blow up
|
|
// 2. Convert ascii strings to unicode, & rebase all var data
|
|
//
|
|
|
|
//
|
|
// The real needed size is the sum of that requested by the
|
|
// underlying driver, plus padding for the new TAPI 1.4/2.0
|
|
// structure fields, plus the size of the var data returned
|
|
// by the driver to account for the ascii->unicode conversion.
|
|
// @@@ Granted, we are very liberal in computing the value for
|
|
// this last part, but at least this way it's fast & we'll
|
|
// never have too little buffer space.
|
|
//
|
|
|
|
lpAddressCaps->dwNeededSize =
|
|
pCaps->ulNeededSize +
|
|
(sizeof(LINEADDRESSCAPS) - // v2.0 struct
|
|
sizeof(LINE_ADDRESS_CAPS)) + // v1.0 struct
|
|
(pCaps->ulNeededSize - sizeof(LINE_ADDRESS_CAPS));
|
|
|
|
|
|
//
|
|
// Copy over the fixed fields that don't need changing, i.e.
|
|
// everything from dwAddressSharing to dwCallCompletionModes
|
|
//
|
|
|
|
lpAddressCaps->dwLineDeviceID = dwDeviceID;
|
|
|
|
CopyMemory(
|
|
&lpAddressCaps->dwAddressSharing,
|
|
&pCaps->ulAddressSharing,
|
|
sizeof(LINE_ADDRESS_CAPS) - (12 * sizeof(DWORD))
|
|
);
|
|
|
|
if (lpAddressCaps->dwNeededSize > lpAddressCaps->dwTotalSize)
|
|
{
|
|
lpAddressCaps->dwUsedSize =
|
|
(lpAddressCaps->dwTotalSize < sizeof(LINEADDRESSCAPS) ?
|
|
lpAddressCaps->dwTotalSize : sizeof(LINEADDRESSCAPS));
|
|
}
|
|
else
|
|
{
|
|
lpAddressCaps->dwUsedSize = sizeof(LINEADDRESSCAPS); // v2.0 struct
|
|
|
|
INSERTVARDATASTRING(
|
|
pCaps,
|
|
&pCaps->ulAddressSize,
|
|
lpAddressCaps,
|
|
&lpAddressCaps->dwAddressSize,
|
|
sizeof(LINE_ADDRESS_CAPS),
|
|
"LINE_ADDRESS_CAPS.Address"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pCaps,
|
|
&pCaps->ulDevSpecificSize,
|
|
lpAddressCaps,
|
|
&lpAddressCaps->dwDevSpecificSize,
|
|
sizeof(LINE_ADDRESS_CAPS),
|
|
"LINE_ADDRESS_CAPS.DevSpecific"
|
|
);
|
|
|
|
if (pCaps->ulCompletionMsgTextSize != 0)
|
|
{
|
|
// @@@ convert ComplMsgText to unicode???
|
|
INSERTVARDATA(
|
|
pCaps,
|
|
&pCaps->ulCompletionMsgTextSize,
|
|
lpAddressCaps,
|
|
&lpAddressCaps->dwCompletionMsgTextSize,
|
|
sizeof (LINE_ADDRESS_CAPS),
|
|
"LINE_ADDRESS_CAPS.CompletionMsgText"
|
|
);
|
|
|
|
lpAddressCaps->dwNumCompletionMessages =
|
|
pCaps->ulNumCompletionMessages;
|
|
lpAddressCaps->dwCompletionMsgTextEntrySize =
|
|
pCaps->ulCompletionMsgTextEntrySize;
|
|
}
|
|
|
|
// make sure dwNeededSize == dwUsedSize
|
|
lpAddressCaps->dwNeededSize = lpAddressCaps->dwUsedSize;
|
|
}
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetAddressID(
|
|
HDRVLINE hdLine,
|
|
LPDWORD lpdwAddressID,
|
|
DWORD dwAddressMode,
|
|
LPCWSTR lpsAddress,
|
|
DWORD dwSize
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_GET_ADDRESS_ID pNdisTapiGetAddressID;
|
|
|
|
TspLog(DL_TRACE, "lineGetAddressID(%d): line(%p), addressMode(%x)",
|
|
++dwSum, hdLine, dwAddressMode);
|
|
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_GET_ADDRESS_ID, // opcode
|
|
pLine->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_GET_ADDRESS_ID) + // size of req data
|
|
dwSize / 2 - 1,
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiGetAddressID = (PNDIS_TAPI_GET_ADDRESS_ID)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiGetAddressID->hdLine = pLine->hd_Line;
|
|
pNdisTapiGetAddressID->ulAddressMode = dwAddressMode;
|
|
pNdisTapiGetAddressID->ulAddressSize = dwSize / 2;
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, lpsAddress, dwSize,
|
|
(LPSTR)pNdisTapiGetAddressID->szAddress, dwSize / 2, NULL, NULL);
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
*lpdwAddressID = pNdisTapiGetAddressID->ulAddressID;
|
|
|
|
TspLog(DL_INFO, "lineGetAddressID: addressID(%x)", *lpdwAddressID);
|
|
}
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetAddressStatus(
|
|
HDRVLINE hdLine,
|
|
DWORD dwAddressID,
|
|
LPLINEADDRESSSTATUS lpAddressStatus
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PLINE_ADDRESS_STATUS pStatus;
|
|
PNDIS_TAPI_GET_ADDRESS_STATUS pNdisTapiGetAddressStatus;
|
|
|
|
TspLog(DL_TRACE, "lineGetAddressStatus(%d): line(%p), addressID(%x)",
|
|
++dwSum, hdLine, dwAddressID);
|
|
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_GET_ADDRESS_STATUS, // opcode
|
|
pLine->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_GET_ADDRESS_STATUS) + // size of req data
|
|
(lpAddressStatus->dwTotalSize - sizeof(LINE_ADDRESS_STATUS)),
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiGetAddressStatus =
|
|
(PNDIS_TAPI_GET_ADDRESS_STATUS)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiGetAddressStatus->hdLine = pLine->hd_Line;
|
|
pNdisTapiGetAddressStatus->ulAddressID = dwAddressID;
|
|
|
|
pStatus = &pNdisTapiGetAddressStatus->LineAddressStatus;
|
|
|
|
pStatus->ulTotalSize = lpAddressStatus->dwTotalSize;
|
|
pStatus->ulNeededSize = pStatus->ulUsedSize = sizeof(LINE_ADDRESS_STATUS);
|
|
|
|
ZeroMemory(&pStatus->ulNumInUse,
|
|
sizeof(LINE_ADDRESS_STATUS) - 3 * sizeof(ULONG));
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
CopyMemory(
|
|
lpAddressStatus,
|
|
&pNdisTapiGetAddressStatus->LineAddressStatus,
|
|
pNdisTapiGetAddressStatus->LineAddressStatus.ulUsedSize
|
|
);
|
|
}
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetCallAddressID(
|
|
HDRVCALL hdCall,
|
|
LPDWORD lpdwAddressID
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_GET_CALL_ADDRESS_ID pNdisTapiGetCallAddressID;
|
|
|
|
TspLog(DL_TRACE, "lineGetCallAddressID(%d): call(%p)", ++dwSum, hdCall);
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_GET_CALL_ADDRESS_ID, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_GET_CALL_ADDRESS_ID), // size of req data
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiGetCallAddressID =
|
|
(PNDIS_TAPI_GET_CALL_ADDRESS_ID)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiGetCallAddressID->hdCall = GetNdisTapiHandle(pCall, &lRes);
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
*lpdwAddressID = pNdisTapiGetCallAddressID->ulAddressID;
|
|
TspLog(DL_INFO, "lineGetCallAddressID: addressID(%x)", *lpdwAddressID);
|
|
}
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetCallInfo(
|
|
HDRVCALL hdCall,
|
|
LPLINECALLINFO lpCallInfo
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PLINE_CALL_INFO pInfo;
|
|
PNDIS_TAPI_GET_CALL_INFO pNdisTapiGetCallInfo;
|
|
|
|
TspLog(DL_TRACE, "lineGetCallInfo(%d): call(%p)", ++dwSum, hdCall);
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_GET_CALL_INFO, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_GET_CALL_INFO) + // size of req data
|
|
(lpCallInfo->dwTotalSize - sizeof(LINE_CALL_INFO)),
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiGetCallInfo = (PNDIS_TAPI_GET_CALL_INFO)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiGetCallInfo->hdCall = GetNdisTapiHandle(pCall, &lRes);
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
pInfo = &pNdisTapiGetCallInfo->LineCallInfo;
|
|
|
|
pInfo->ulTotalSize = lpCallInfo->dwTotalSize;
|
|
pInfo->ulNeededSize = pInfo->ulUsedSize = sizeof(LINE_CALL_INFO);
|
|
|
|
ZeroMemory(&pInfo->hLine, sizeof(LINE_CALL_INFO) - 3 * sizeof(ULONG));
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
//
|
|
// Do some post processing to the returned data structure
|
|
// before passing it back to tapi:
|
|
// 1. Pad the area between the fixed 1.0 structure and the
|
|
// var data that the miniports pass back with 0's so a
|
|
// bad app that disregards the 1.0 version negotiation &
|
|
// references new 1.4 or 2.0 structure fields won't blow up
|
|
// 2. Convert ascii strings to unicode, & rebase all var data
|
|
//
|
|
|
|
//
|
|
// The real needed size is the sum of that requested by the
|
|
// underlying driver, plus padding for the new TAPI 1.4/2.0
|
|
// structure fields, plus the size of the var data returned
|
|
// by the driver to account for the ascii->unicode conversion.
|
|
// @@@ Granted, we are very liberal in computing the value for
|
|
// this last part, but at least this way it's fast & we'll
|
|
// never have too little buffer space.
|
|
//
|
|
|
|
lpCallInfo->dwNeededSize =
|
|
pInfo->ulNeededSize +
|
|
(sizeof(LINECALLINFO) - // v2.0 struct
|
|
sizeof(LINE_CALL_INFO)) + // v1.0 struct
|
|
(pInfo->ulNeededSize - sizeof(LINE_CALL_INFO));
|
|
|
|
//
|
|
// Copy over the fixed fields that don't need changing,
|
|
// i.e. everything from dwLineDeviceID to dwTrunk
|
|
//
|
|
|
|
CopyMemory(
|
|
&lpCallInfo->dwLineDeviceID,
|
|
&pInfo->ulLineDeviceID,
|
|
23 * sizeof(DWORD)
|
|
);
|
|
|
|
if (lpCallInfo->dwNeededSize > lpCallInfo->dwTotalSize)
|
|
{
|
|
lpCallInfo->dwUsedSize =
|
|
(lpCallInfo->dwTotalSize < sizeof(LINECALLINFO) ?
|
|
lpCallInfo->dwTotalSize : sizeof(LINECALLINFO));
|
|
}
|
|
else
|
|
{
|
|
lpCallInfo->dwUsedSize = sizeof(LINECALLINFO); // v2.0 struct
|
|
|
|
lpCallInfo->dwCallerIDFlags = pInfo->ulCallerIDFlags;
|
|
|
|
INSERTVARDATASTRING(
|
|
pInfo,
|
|
&pInfo->ulCallerIDSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwCallerIDSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.CallerID"
|
|
);
|
|
|
|
INSERTVARDATASTRING(
|
|
pInfo,
|
|
&pInfo->ulCallerIDNameSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwCallerIDNameSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.CallerIDName"
|
|
);
|
|
|
|
lpCallInfo->dwCalledIDFlags = pInfo->ulCalledIDFlags;
|
|
|
|
INSERTVARDATASTRING(
|
|
pInfo,
|
|
&pInfo->ulCalledIDSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwCalledIDSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.CalledID"
|
|
);
|
|
|
|
INSERTVARDATASTRING(
|
|
pInfo,
|
|
&pInfo->ulCalledIDNameSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwCalledIDNameSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.CalledIDName"
|
|
);
|
|
|
|
lpCallInfo->dwConnectedIDFlags = pInfo->ulConnectedIDFlags;
|
|
|
|
INSERTVARDATASTRING(
|
|
pInfo,
|
|
&pInfo->ulConnectedIDSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwConnectedIDSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.ConnectID"
|
|
);
|
|
|
|
INSERTVARDATASTRING(
|
|
pInfo,
|
|
&pInfo->ulConnectedIDNameSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwConnectedIDNameSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.ConnectIDName"
|
|
);
|
|
|
|
lpCallInfo->dwRedirectionIDFlags = pInfo->ulRedirectionIDFlags;
|
|
|
|
INSERTVARDATASTRING(
|
|
pInfo,
|
|
&pInfo->ulRedirectionIDSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwRedirectionIDSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.RedirectionID"
|
|
);
|
|
|
|
INSERTVARDATASTRING(
|
|
pInfo,
|
|
&pInfo->ulRedirectionIDNameSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwRedirectionIDNameSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.RedirectionIDName"
|
|
);
|
|
|
|
lpCallInfo->dwRedirectingIDFlags = pInfo->ulRedirectingIDFlags;
|
|
|
|
INSERTVARDATASTRING(
|
|
pInfo,
|
|
&pInfo->ulRedirectingIDSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwRedirectingIDSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.RedirectingID"
|
|
);
|
|
|
|
INSERTVARDATASTRING(
|
|
pInfo,
|
|
&pInfo->ulRedirectingIDNameSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwRedirectingIDNameSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.RedirectingIDName"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pInfo,
|
|
&pInfo->ulDisplaySize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwDisplaySize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.Display"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pInfo,
|
|
&pInfo->ulUserUserInfoSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwUserUserInfoSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.UserUserInfo"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pInfo,
|
|
&pInfo->ulHighLevelCompSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwHighLevelCompSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.HighLevelComp"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pInfo,
|
|
&pInfo->ulLowLevelCompSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwLowLevelCompSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.LowLevelComp"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pInfo,
|
|
&pInfo->ulChargingInfoSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwChargingInfoSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.ChargingInfo"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pInfo,
|
|
&pInfo->ulTerminalModesSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwTerminalModesSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.TerminalModes"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pInfo,
|
|
&pInfo->ulDevSpecificSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwDevSpecificSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.DevSpecific"
|
|
);
|
|
|
|
// make sure that dwNeededSize == dwUsedSize
|
|
lpCallInfo->dwNeededSize = lpCallInfo->dwUsedSize;
|
|
}
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetCallStatus(
|
|
HDRVCALL hdCall,
|
|
LPLINECALLSTATUS lpCallStatus
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PLINE_CALL_STATUS pStatus;
|
|
PNDIS_TAPI_GET_CALL_STATUS pNdisTapiGetCallStatus;
|
|
|
|
TspLog(DL_TRACE, "lineGetCallStatus(%d): call(%p)", ++dwSum, hdCall);
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_GET_CALL_STATUS, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_GET_CALL_STATUS) + // size of req data
|
|
(lpCallStatus->dwTotalSize - sizeof(LINE_CALL_STATUS)),
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiGetCallStatus = (PNDIS_TAPI_GET_CALL_STATUS)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiGetCallStatus->hdCall = GetNdisTapiHandle(pCall, &lRes);
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
pStatus = &pNdisTapiGetCallStatus->LineCallStatus;
|
|
|
|
pStatus->ulTotalSize = lpCallStatus->dwTotalSize;
|
|
pStatus->ulNeededSize = pStatus->ulUsedSize = sizeof(LINE_CALL_STATUS);
|
|
|
|
ZeroMemory(&pStatus->ulCallState,
|
|
sizeof(LINE_CALL_STATUS) - 3 * sizeof(ULONG));
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
//
|
|
// Do some post processing to the returned data structure
|
|
// before passing it back to tapi:
|
|
// 1. Pad the area between the fixed 1.0 structure and the
|
|
// var data that the miniports pass back with 0's so a
|
|
// bad app that disregards the 1.0 version negotiation &
|
|
// references new 1.4 or 2.0 structure fields won't blow up
|
|
// (no embedded ascii strings to convert to unicode)
|
|
//
|
|
|
|
//
|
|
// The real needed size is the sum of that requested by the
|
|
// underlying driver, plus padding for the new TAPI 1.4/2.0
|
|
// structure fields. (There are no embedded ascii strings to
|
|
// convert to unicode, so no extra space needed for that.)
|
|
//
|
|
|
|
lpCallStatus->dwNeededSize =
|
|
pStatus->ulNeededSize +
|
|
(sizeof(LINECALLSTATUS) - // v2.0 struct
|
|
sizeof(LINE_CALL_STATUS)); // v1.0 struct
|
|
|
|
//
|
|
// Copy over the fixed fields that don't need changing,
|
|
// i.e. everything from dwLineDeviceID to dwCallCompletionModes
|
|
//
|
|
|
|
CopyMemory(
|
|
&lpCallStatus->dwCallState,
|
|
&pStatus->ulCallState,
|
|
4 * sizeof(DWORD)
|
|
);
|
|
|
|
if (lpCallStatus->dwNeededSize > lpCallStatus->dwTotalSize)
|
|
{
|
|
lpCallStatus->dwUsedSize =
|
|
(lpCallStatus->dwTotalSize < sizeof(LINECALLSTATUS) ?
|
|
lpCallStatus->dwTotalSize : sizeof(LINECALLSTATUS));
|
|
}
|
|
else
|
|
{
|
|
lpCallStatus->dwUsedSize = sizeof(LINECALLSTATUS);
|
|
// v2.0 struct
|
|
INSERTVARDATA(
|
|
pStatus,
|
|
&pStatus->ulDevSpecificSize,
|
|
lpCallStatus,
|
|
&lpCallStatus->dwDevSpecificSize,
|
|
sizeof(LINE_CALL_STATUS),
|
|
"LINE_CALL_STATUS.DevSpecific"
|
|
);
|
|
}
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
LINEDEVCAPS *
|
|
GetLineDevCaps(
|
|
IN DWORD dwDeviceID,
|
|
IN DWORD dwExtVersion
|
|
)
|
|
{
|
|
LONG lRes;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PLINE_DEV_CAPS pCaps;
|
|
PNDIS_TAPI_GET_DEV_CAPS pNdisTapiGetDevCaps;
|
|
DWORD dwNeededSize;
|
|
LINEDEVCAPS *pLineDevCaps;
|
|
DWORD dwTotalSize = sizeof(LINEDEVCAPS) + 0x80;
|
|
|
|
get_caps:
|
|
pLineDevCaps = (LINEDEVCAPS *)MALLOC(dwTotalSize);
|
|
if (NULL == pLineDevCaps)
|
|
{
|
|
TspLog(DL_ERROR, "GetLineDevCaps: failed to alloc mem of size(%x)",
|
|
dwTotalSize);
|
|
return NULL;
|
|
}
|
|
|
|
pLineDevCaps->dwTotalSize = dwTotalSize;
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_GET_DEV_CAPS, // opcode
|
|
dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_GET_DEV_CAPS) + // size of req data
|
|
(dwTotalSize - sizeof(LINE_DEV_CAPS)),
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
pNdisTapiGetDevCaps = (PNDIS_TAPI_GET_DEV_CAPS)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiGetDevCaps->ulDeviceID = dwDeviceID;
|
|
pNdisTapiGetDevCaps->ulExtVersion = dwExtVersion;
|
|
|
|
pCaps = &pNdisTapiGetDevCaps->LineDevCaps;
|
|
|
|
pCaps->ulTotalSize = dwTotalSize;
|
|
pCaps->ulNeededSize = pCaps->ulUsedSize = sizeof(LINE_DEV_CAPS);
|
|
|
|
ZeroMemory(&pCaps->ulProviderInfoSize,
|
|
sizeof(LINE_DEV_CAPS) - 3 * sizeof(ULONG));
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pNdisTapiRequest);
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// The real needed size is the sum of that requested by the
|
|
// underlying driver, plus padding for the new TAPI 1.4/2.0
|
|
// structure fields, plus the size of the var data returned
|
|
// by the driver to account for the ascii->unicode conversion.
|
|
// @@@ Granted, we are very liberal in computing the value for
|
|
// this last part, but at least this way it's fast & we'll
|
|
// never have too little buffer space.
|
|
//
|
|
TspLog(DL_TRACE,
|
|
"GetLineDevCaps: ulNeeded(%x), LINEDEVCAPS(%x), LINE_DEV_CAPS(%x)",
|
|
pCaps->ulNeededSize, sizeof(LINEDEVCAPS), sizeof(LINE_DEV_CAPS));
|
|
|
|
dwNeededSize =
|
|
pCaps->ulNeededSize +
|
|
(sizeof(LINEDEVCAPS) - // v2.0 struct
|
|
sizeof(LINE_DEV_CAPS)) + // v1.0 struct
|
|
(pCaps->ulNeededSize - sizeof(LINE_DEV_CAPS));
|
|
|
|
TspLog(DL_TRACE, "GetLineDevCaps: dwNeededSize(%x), dwTotalSize(%x)",
|
|
dwNeededSize, dwTotalSize);
|
|
|
|
if (dwNeededSize > dwTotalSize)
|
|
{
|
|
// free up the old req
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
// free the old buffer
|
|
FREE(pLineDevCaps);
|
|
|
|
// try again with a larger buffer
|
|
dwTotalSize = dwNeededSize;
|
|
goto get_caps;
|
|
}
|
|
|
|
ASSERT(dwNeededSize <= dwTotalSize);
|
|
|
|
//
|
|
// Copy over the fixed fields that don't need changing,
|
|
// i.e. everything from dwPermanentLineID to dwNumTerminals
|
|
//
|
|
CopyMemory(
|
|
&pLineDevCaps->dwPermanentLineID,
|
|
&pCaps->ulPermanentLineID,
|
|
sizeof(LINE_DEV_CAPS) - (14 * sizeof(DWORD))
|
|
);
|
|
|
|
// set the local flag to indicate that
|
|
// the line can't be used from remote machine
|
|
pLineDevCaps->dwDevCapFlags |= LINEDEVCAPFLAGS_LOCAL;
|
|
|
|
//
|
|
// Do some post processing to the returned data structure
|
|
// before passing it back to tapi:
|
|
// 1. Pad the area between the fixed 1.0 structure and the
|
|
// var data that the miniports pass back with 0's so a
|
|
// bad app that disregards the 1.0 version negotiation &
|
|
// references new 1.4 or 2.0 structure fields won't blow up
|
|
// 2. Convert ascii strings to unicode, & rebase all var data
|
|
//
|
|
|
|
pLineDevCaps->dwUsedSize = sizeof(LINEDEVCAPS); // v2.0 struct
|
|
|
|
INSERTVARDATASTRING(
|
|
pCaps,
|
|
&pCaps->ulProviderInfoSize,
|
|
pLineDevCaps,
|
|
&pLineDevCaps->dwProviderInfoSize,
|
|
sizeof(LINE_DEV_CAPS),
|
|
"LINE_DEV_CAPS.ProviderInfo"
|
|
);
|
|
|
|
INSERTVARDATASTRING(
|
|
pCaps,
|
|
&pCaps->ulSwitchInfoSize,
|
|
pLineDevCaps,
|
|
&pLineDevCaps->dwSwitchInfoSize,
|
|
sizeof(LINE_DEV_CAPS),
|
|
"LINE_DEV_CAPS.SwitchInfo"
|
|
);
|
|
|
|
INSERTVARDATASTRING(
|
|
pCaps,
|
|
&pCaps->ulLineNameSize,
|
|
pLineDevCaps,
|
|
&pLineDevCaps->dwLineNameSize,
|
|
sizeof(LINE_DEV_CAPS),
|
|
"LINE_DEV_CAPS.LineName"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pCaps,
|
|
&pCaps->ulTerminalCapsSize,
|
|
pLineDevCaps,
|
|
&pLineDevCaps->dwTerminalCapsSize,
|
|
sizeof(LINE_DEV_CAPS),
|
|
"LINE_DEV_CAPS.TerminalCaps"
|
|
);
|
|
|
|
// @@@ convert DevCaps.TermText to unicode???
|
|
|
|
pLineDevCaps->dwTerminalTextEntrySize =
|
|
pCaps->ulTerminalTextEntrySize;
|
|
|
|
INSERTVARDATA(
|
|
pCaps,
|
|
&pCaps->ulTerminalTextSize,
|
|
pLineDevCaps,
|
|
&pLineDevCaps->dwTerminalTextSize,
|
|
sizeof(LINE_DEV_CAPS),
|
|
"LINE_DEV_CAPS.TerminalText"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pCaps,
|
|
&pCaps->ulDevSpecificSize,
|
|
pLineDevCaps,
|
|
&pLineDevCaps->dwDevSpecificSize,
|
|
sizeof(LINE_DEV_CAPS),
|
|
"LINE_DEV_CAPS.DevSpecific"
|
|
);
|
|
|
|
// make sure dwNeededSize == dwUsedSize
|
|
pLineDevCaps->dwNeededSize = pLineDevCaps->dwUsedSize;
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
return pLineDevCaps;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetDevCaps(
|
|
DWORD dwDeviceID,
|
|
DWORD dwTSPIVersion,
|
|
DWORD dwExtVersion,
|
|
LPLINEDEVCAPS lpLineDevCaps
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
|
|
TspLog(DL_TRACE, "lineGetDevCaps(%d): deviceID(%x), TSPIV(%x), ExtV(%x)",
|
|
++dwSum, dwDeviceID, dwTSPIVersion, dwExtVersion);
|
|
|
|
lRes = GetDevCaps(dwDeviceID, dwTSPIVersion, dwExtVersion, lpLineDevCaps);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetDevConfig(
|
|
DWORD dwDeviceID,
|
|
LPVARSTRING lpDeviceConfig,
|
|
LPCWSTR lpszDeviceClass
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
DWORD dwLength = lstrlenW (lpszDeviceClass) + 1;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PVAR_STRING pConfig;
|
|
PNDIS_TAPI_GET_DEV_CONFIG pNdisTapiGetDevConfig;
|
|
|
|
TspLog(DL_TRACE, "lineGetDevConfig(%d): deviceID(%x)", ++dwSum, dwDeviceID);
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_GET_DEV_CONFIG, // opcode
|
|
dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_GET_DEV_CONFIG) + // size of req data
|
|
(lpDeviceConfig->dwTotalSize - sizeof(VAR_STRING)) + dwLength,
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiGetDevConfig = (PNDIS_TAPI_GET_DEV_CONFIG)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiGetDevConfig->ulDeviceID = dwDeviceID;
|
|
pNdisTapiGetDevConfig->ulDeviceClassSize = dwLength;
|
|
pNdisTapiGetDevConfig->ulDeviceClassOffset =
|
|
sizeof(NDIS_TAPI_GET_DEV_CONFIG) +
|
|
(lpDeviceConfig->dwTotalSize - sizeof(VAR_STRING));
|
|
|
|
pConfig = &pNdisTapiGetDevConfig->DeviceConfig;
|
|
pConfig->ulTotalSize = lpDeviceConfig->dwTotalSize;
|
|
pConfig->ulNeededSize = pConfig->ulUsedSize = sizeof(VAR_STRING);
|
|
|
|
pConfig->ulStringFormat =
|
|
pConfig->ulStringSize =
|
|
pConfig->ulStringOffset = 0;
|
|
|
|
// NOTE: old miniports expect strings to be ascii
|
|
WideCharToMultiByte(CP_ACP, 0, lpszDeviceClass, -1,
|
|
(LPSTR) (((LPBYTE) pNdisTapiGetDevConfig) +
|
|
pNdisTapiGetDevConfig->ulDeviceClassOffset),
|
|
dwLength, NULL, NULL);
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
CopyMemory(
|
|
lpDeviceConfig,
|
|
&pNdisTapiGetDevConfig->DeviceConfig,
|
|
pNdisTapiGetDevConfig->DeviceConfig.ulUsedSize
|
|
);
|
|
}
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetExtensionID(
|
|
DWORD dwDeviceID,
|
|
DWORD dwTSPIVersion,
|
|
LPLINEEXTENSIONID lpExtensionID
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_GET_EXTENSION_ID pNdisTapiGetExtensionID;
|
|
|
|
TspLog(DL_TRACE, "lineGetExtensionID(%d): deviceID(%x), TSPIV(%x)",
|
|
++dwSum, dwDeviceID, dwTSPIVersion);
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_GET_EXTENSION_ID, // opcode
|
|
dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_GET_EXTENSION_ID), // size of req data
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiGetExtensionID =
|
|
(PNDIS_TAPI_GET_EXTENSION_ID)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiGetExtensionID->ulDeviceID = dwDeviceID;
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
CopyMemory(
|
|
lpExtensionID,
|
|
&pNdisTapiGetExtensionID->LineExtensionID,
|
|
sizeof(LINE_EXTENSION_ID)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Rather than indicating a failure, we'll just zero out the
|
|
// ext id (implying driver doesn't support extensions) and
|
|
// return success to tapisrv so it'll complete the open ok
|
|
//
|
|
ZeroMemory(lpExtensionID, sizeof(LINE_EXTENSION_ID));
|
|
|
|
lRes = TAPI_SUCCESS;
|
|
}
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetID(
|
|
HDRVLINE hdLine,
|
|
DWORD dwAddressID,
|
|
HDRVCALL hdCall,
|
|
DWORD dwSelect,
|
|
LPVARSTRING lpDeviceID,
|
|
LPCWSTR lpszDeviceClass,
|
|
HANDLE hTargetProcess
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine = NULL;
|
|
PDRVCALL pCall = NULL;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
DWORD dwLength = lstrlenW(lpszDeviceClass) + 1;
|
|
DWORD dwDeviceID;
|
|
PUCHAR pchDest;
|
|
PVAR_STRING pID;
|
|
PNDIS_TAPI_GET_ID pNdisTapiGetID;
|
|
|
|
TspLog(DL_TRACE,
|
|
"lineGetID(%d): line(%p), call(%p), addressID(%x), select(%x)",
|
|
++dwSum, hdLine, hdCall, dwAddressID, dwSelect);
|
|
|
|
if(LINECALLSELECT_LINE != dwSelect &&
|
|
LINECALLSELECT_ADDRESS != dwSelect &&
|
|
LINECALLSELECT_CALL != dwSelect)
|
|
{
|
|
ASSERT(FALSE);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (LINECALLSELECT_LINE == dwSelect ||
|
|
LINECALLSELECT_ADDRESS == dwSelect)
|
|
{
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if ( (lRes != TAPI_SUCCESS)
|
|
|| (NULL == pLine))
|
|
{
|
|
return lRes;
|
|
}
|
|
}
|
|
|
|
if (LINECALLSELECT_CALL == dwSelect)
|
|
{
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Kmddsp will field this specific call on behalf of the
|
|
// wan miniports. It returns the guid and media string
|
|
// of the adapter that this line lives on
|
|
//
|
|
if (LINECALLSELECT_LINE == dwSelect &&
|
|
!wcscmp(lpszDeviceClass, L"LineGuid"))
|
|
{
|
|
lpDeviceID->dwNeededSize =
|
|
sizeof(VARSTRING) + sizeof(GUID) +
|
|
sizeof(pLine->MediaType) + sizeof('\0');
|
|
|
|
if (lpDeviceID->dwTotalSize < lpDeviceID->dwNeededSize)
|
|
{
|
|
if (pCall != NULL)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
}
|
|
if (pLine != NULL)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
}
|
|
return LINEERR_STRUCTURETOOSMALL;
|
|
}
|
|
|
|
lpDeviceID->dwUsedSize = lpDeviceID->dwNeededSize;
|
|
lpDeviceID->dwStringFormat = STRINGFORMAT_ASCII;
|
|
pchDest = (PUCHAR)lpDeviceID + sizeof(*lpDeviceID);
|
|
lpDeviceID->dwStringOffset = (DWORD)(pchDest - (PUCHAR)lpDeviceID);
|
|
lpDeviceID->dwStringSize =
|
|
sizeof(GUID) + sizeof(pLine->MediaType) +sizeof('\0');
|
|
|
|
MoveMemory(
|
|
pchDest,
|
|
(PUCHAR)&pLine->Guid,
|
|
sizeof(pLine->Guid)
|
|
);
|
|
|
|
pchDest += sizeof(pLine->Guid);
|
|
|
|
MoveMemory(
|
|
pchDest,
|
|
&pLine->MediaType,
|
|
sizeof(pLine->MediaType)
|
|
);
|
|
|
|
pchDest += sizeof(pLine->MediaType);
|
|
*pchDest = '\0';
|
|
|
|
TspLog(DL_INFO, "lineGetID: obj(%p)", hdLine);
|
|
|
|
if(pLine != NULL)
|
|
{
|
|
TspLog(
|
|
DL_INFO,
|
|
"Guid %4.4x-%2.2x-%2.2x-%1.1x%1.1x-%1.1x%1.1x%1.1x%1.1x%1.1x%1.1x",
|
|
pLine->Guid.Data1, pLine->Guid.Data2,
|
|
pLine->Guid.Data3, pLine->Guid.Data4[0],
|
|
pLine->Guid.Data4[1], pLine->Guid.Data4[2],
|
|
pLine->Guid.Data4[3], pLine->Guid.Data4[4],
|
|
pLine->Guid.Data4[5], pLine->Guid.Data4[6],
|
|
pLine->Guid.Data4[7]
|
|
);
|
|
}
|
|
|
|
TspLog(DL_INFO, "MediaType: %d", pLine->MediaType);
|
|
|
|
if (pCall != NULL)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
}
|
|
if (pLine != NULL)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
}
|
|
|
|
return TAPI_SUCCESS;
|
|
}
|
|
|
|
dwDeviceID = (LINECALLSELECT_CALL == dwSelect) ?
|
|
pCall->dwDeviceID : pLine->dwDeviceID;
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_GET_ID, // opcode
|
|
dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_GET_ID) + // size of req data
|
|
(lpDeviceID->dwTotalSize - sizeof(VAR_STRING)) + dwLength,
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
if (pCall != NULL)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
}
|
|
if (pLine != NULL)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
}
|
|
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiGetID = (PNDIS_TAPI_GET_ID)pNdisTapiRequest->Data;
|
|
|
|
if (LINECALLSELECT_LINE == dwSelect ||
|
|
LINECALLSELECT_ADDRESS == dwSelect)
|
|
{
|
|
pNdisTapiGetID->hdLine = pLine->hd_Line;
|
|
}
|
|
|
|
pNdisTapiGetID->ulAddressID = dwAddressID;
|
|
|
|
if (LINECALLSELECT_CALL == dwSelect)
|
|
{
|
|
pNdisTapiGetID->hdCall = GetNdisTapiHandle(pCall, &lRes);
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
if(pLine != NULL)
|
|
{
|
|
ReleaseObjReadLock((HANDLE) hdLine);
|
|
}
|
|
|
|
return lRes;
|
|
}
|
|
}
|
|
|
|
pNdisTapiGetID->ulSelect = dwSelect;
|
|
pNdisTapiGetID->ulDeviceClassSize = dwLength;
|
|
pNdisTapiGetID->ulDeviceClassOffset = sizeof(NDIS_TAPI_GET_ID) +
|
|
(lpDeviceID->dwTotalSize - sizeof(VAR_STRING));
|
|
|
|
pID = &pNdisTapiGetID->DeviceID;
|
|
|
|
pID->ulTotalSize = lpDeviceID->dwTotalSize;
|
|
pID->ulNeededSize = pID->ulUsedSize = sizeof(VAR_STRING);
|
|
pID->ulStringFormat = pID->ulStringSize = pID->ulStringOffset = 0;
|
|
|
|
// NOTE: old miniports expect strings to be ascii
|
|
WideCharToMultiByte(
|
|
CP_ACP, 0, lpszDeviceClass, -1,
|
|
(LPSTR) (((LPBYTE) pNdisTapiGetID) +
|
|
pNdisTapiGetID->ulDeviceClassOffset),
|
|
dwLength, NULL, NULL);
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
CopyMemory(
|
|
lpDeviceID,
|
|
&pNdisTapiGetID->DeviceID,
|
|
pNdisTapiGetID->DeviceID.ulUsedSize
|
|
);
|
|
}
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
if (pCall != NULL)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
}
|
|
if (pLine != NULL)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
}
|
|
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetLineDevStatus(
|
|
HDRVLINE hdLine,
|
|
LPLINEDEVSTATUS lpLineDevStatus
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PLINE_DEV_STATUS pStatus;
|
|
PNDIS_TAPI_GET_LINE_DEV_STATUS pNdisTapiGetLineDevStatus;
|
|
|
|
TspLog(DL_TRACE, "lineGetLineDevStatus(%d): line(%p)", ++dwSum, hdLine);
|
|
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_GET_LINE_DEV_STATUS, // opcode
|
|
pLine->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_GET_LINE_DEV_STATUS) + // size of req data
|
|
(lpLineDevStatus->dwTotalSize - sizeof(LINE_DEV_STATUS)),
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiGetLineDevStatus =
|
|
(PNDIS_TAPI_GET_LINE_DEV_STATUS)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiGetLineDevStatus->hdLine = pLine->hd_Line;
|
|
|
|
pStatus = &pNdisTapiGetLineDevStatus->LineDevStatus;
|
|
|
|
pStatus->ulTotalSize = lpLineDevStatus->dwTotalSize;
|
|
pStatus->ulNeededSize = pStatus->ulUsedSize = sizeof(LINE_DEV_STATUS);
|
|
|
|
ZeroMemory(&pStatus->ulNumOpens,
|
|
sizeof(LINE_DEV_STATUS) - 3 * sizeof(ULONG));
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
//
|
|
// Do some post processing to the returned data structure
|
|
// before passing it back to tapi:
|
|
// 1. Pad the area between the fixed 1.0 structure and the
|
|
// var data that the miniports pass back with 0's so a
|
|
// bad app that disregards the 1.0 version negotiation &
|
|
// references new 1.4 or 2.0 structure fields won't blow up
|
|
// (no embedded ascii strings to convert to unicode)
|
|
//
|
|
|
|
//
|
|
// The real needed size is the sum of that requested by the
|
|
// underlying driver, plus padding for the new TAPI 1.4/2.0
|
|
// structure fields. (There are no embedded ascii strings to
|
|
// convert to unicode, so no extra space needed for that.)
|
|
//
|
|
|
|
lpLineDevStatus->dwNeededSize =
|
|
pStatus->ulNeededSize +
|
|
(sizeof(LINEDEVSTATUS) - // v2.0 struct
|
|
sizeof(LINE_DEV_STATUS)); // v1.0 struct
|
|
|
|
//
|
|
// Copy over the fixed fields that don't need changing,
|
|
// i.e. everything from dwNumActiveCalls to dwDevStatusFlags
|
|
//
|
|
|
|
CopyMemory(
|
|
&lpLineDevStatus->dwNumActiveCalls,
|
|
&pStatus->ulNumActiveCalls,
|
|
sizeof(LINE_DEV_STATUS) - (9 * sizeof(DWORD))
|
|
);
|
|
|
|
if (lpLineDevStatus->dwNeededSize > lpLineDevStatus->dwTotalSize)
|
|
{
|
|
lpLineDevStatus->dwUsedSize =
|
|
(lpLineDevStatus->dwTotalSize < sizeof(LINEDEVSTATUS) ?
|
|
lpLineDevStatus->dwTotalSize : sizeof(LINEDEVSTATUS));
|
|
}
|
|
else
|
|
{
|
|
lpLineDevStatus->dwUsedSize = sizeof(LINEDEVSTATUS);
|
|
// v2.0 struct
|
|
INSERTVARDATA(
|
|
pStatus,
|
|
&pStatus->ulTerminalModesSize,
|
|
lpLineDevStatus,
|
|
&lpLineDevStatus->dwTerminalModesSize,
|
|
sizeof(LINE_DEV_STATUS),
|
|
"LINE_DEV_STATUS.TerminalModes"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pStatus,
|
|
&pStatus->ulDevSpecificSize,
|
|
lpLineDevStatus,
|
|
&lpLineDevStatus->dwDevSpecificSize,
|
|
sizeof(LINE_DEV_STATUS),
|
|
"LINE_DEV_STATUS.DevSpecific"
|
|
);
|
|
}
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetNumAddressIDs(
|
|
HDRVLINE hdLine,
|
|
LPDWORD lpdwNumAddressIDs
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
|
|
TspLog(DL_TRACE, "lineGetNumAddressIDs(%d): line(%p)", ++dwSum, hdLine);
|
|
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
lRes = GetNumAddressIDs(pLine->dwDeviceID, lpdwNumAddressIDs);
|
|
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
TspLog(DL_INFO, "lineGetNumAddressIDs: numAddressIDs(%x)",
|
|
*lpdwNumAddressIDs);
|
|
}
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
PASCAL
|
|
TSPI_lineMakeCall_postProcess(
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper,
|
|
LONG lRes,
|
|
PDWORD_PTR callStateMsgParams
|
|
)
|
|
{
|
|
LONG lSuc;
|
|
HDRVLINE hdLine;
|
|
PDRVLINE pLine;
|
|
HDRVCALL hdCall;
|
|
PDRVCALL pCall;
|
|
|
|
TspLog(DL_TRACE, "lineMakeCall_post: lRes(%x)", lRes);
|
|
|
|
hdCall = (HDRVCALL)(pAsyncReqWrapper->dwRequestSpecific);
|
|
|
|
lSuc = GetLineHandleFromCallHandle(hdCall, &hdLine);
|
|
if (lSuc != TAPI_SUCCESS)
|
|
{
|
|
return lSuc;
|
|
}
|
|
|
|
lSuc = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lSuc != TAPI_SUCCESS)
|
|
{
|
|
return lSuc;
|
|
}
|
|
|
|
lSuc = GetCallObjWithWriteLock(hdCall, &pCall);
|
|
if (lSuc != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lSuc;
|
|
}
|
|
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
PNDIS_TAPI_MAKE_CALL pNdisTapiMakeCall = (PNDIS_TAPI_MAKE_CALL)
|
|
pAsyncReqWrapper->NdisTapiRequest.Data;
|
|
|
|
// check to see if a call state msg was received before we had
|
|
// the chance to process the completion notification, & if so
|
|
// fill in the msg params
|
|
if (pCall->dwPendingCallState)
|
|
{
|
|
callStateMsgParams[0] = (DWORD_PTR)pLine->htLine;
|
|
callStateMsgParams[1] = (DWORD_PTR)pCall->htCall;
|
|
callStateMsgParams[2] = pCall->dwPendingCallState;
|
|
callStateMsgParams[3] = pCall->dwPendingCallStateMode;
|
|
callStateMsgParams[4] = pCall->dwPendingMediaMode;
|
|
}
|
|
pCall->hd_Call = pNdisTapiMakeCall->hdCall;
|
|
pCall->bIncomplete = FALSE;
|
|
|
|
ReleaseObjWriteLock((HANDLE)hdCall);
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
}
|
|
else
|
|
{
|
|
pCall->dwKey = INVALID_KEY;
|
|
|
|
ReleaseObjWriteLock((HANDLE)hdCall);
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
|
|
CloseObjHandle((HANDLE)hdCall);
|
|
}
|
|
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineMakeCall(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVLINE hdLine,
|
|
HTAPICALL htCall,
|
|
LPHDRVCALL lphdCall,
|
|
LPCWSTR lpszDestAddress,
|
|
DWORD dwCountryCode,
|
|
LPLINECALLPARAMS const lpCallParams
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
PDRVCALL pCall;
|
|
HDRVCALL hdCall;
|
|
DWORD dwDALength, dwCPLength, dwOrgDALength;
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper;
|
|
PNDIS_TAPI_MAKE_CALL pNdisTapiMakeCall;
|
|
UINT nCodePage;
|
|
|
|
TspLog(DL_TRACE, "lineMakeCall(%d): reqID(%x), line(%p)",
|
|
++dwSum, dwRequestID, hdLine);
|
|
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
// alloc & init a DRVCALL
|
|
if (!(pCall = AllocCallObj(sizeof(DRVCALL))))
|
|
{
|
|
TspLog(DL_ERROR, "lineMakeCall: failed to create call obj");
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return LINEERR_NOMEM;
|
|
}
|
|
pCall->dwKey = OUTBOUND_CALL_KEY;
|
|
pCall->dwDeviceID = pLine->dwDeviceID;
|
|
pCall->htCall = htCall;
|
|
pCall->hdLine = hdLine;
|
|
pCall->bIncomplete = TRUE;
|
|
|
|
// set nCodePage depending on the medium type
|
|
nCodePage = (pLine->MediaType == NdisWanMediumPppoe) ? CP_UTF8 : CP_ACP;
|
|
|
|
// init the request
|
|
dwOrgDALength = (lpszDestAddress ? (lstrlenW (lpszDestAddress) + 1) : 0);
|
|
|
|
dwDALength = (lpszDestAddress ?
|
|
GetDestAddressLength(lpszDestAddress, dwOrgDALength, &nCodePage) : 0);
|
|
|
|
dwCPLength = (lpCallParams ?
|
|
(lpCallParams->dwTotalSize - sizeof(LINE_CALL_PARAMS)) : 0);
|
|
|
|
if ((lRes = PrepareAsyncRequest(
|
|
OID_TAPI_MAKE_CALL, // opcode
|
|
pLine->dwDeviceID, // device id
|
|
dwRequestID, // request id
|
|
sizeof(NDIS_TAPI_MAKE_CALL) +
|
|
dwDALength + dwCPLength, // size
|
|
&pAsyncReqWrapper // ptr to ptr to request buffer
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
FreeCallObj(pCall);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiMakeCall = (PNDIS_TAPI_MAKE_CALL)
|
|
pAsyncReqWrapper->NdisTapiRequest.Data;
|
|
|
|
// make sure releasing read lock before calling OpenObjHandle()
|
|
// to avoid deadlock on acquiring write lock for the global mapper
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
|
|
lRes = OpenObjHandle(pCall, FreeCallObj, (HANDLE *)&hdCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"lineMakeCall: failed to map obj(%p) to handle",
|
|
pCall);
|
|
|
|
FreeRequest(pAsyncReqWrapper);
|
|
FreeCallObj(pCall);
|
|
return lRes;
|
|
}
|
|
|
|
// reacquire the read lock
|
|
lRes = AcquireObjReadLock((HANDLE)hdLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"lineMakeCall: failed to reacquire read lock for obj(%p)",
|
|
hdLine);
|
|
|
|
FreeRequest(pAsyncReqWrapper);
|
|
CloseObjHandle((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
// save the TSP handle
|
|
pCall->hdCall = hdCall;
|
|
|
|
pNdisTapiMakeCall->hdLine = pLine->hd_Line;
|
|
pNdisTapiMakeCall->htCall = (HTAPI_CALL)hdCall;
|
|
pNdisTapiMakeCall->ulDestAddressSize = dwDALength;
|
|
|
|
if (lpszDestAddress)
|
|
{
|
|
pNdisTapiMakeCall->ulDestAddressOffset =
|
|
sizeof(NDIS_TAPI_MAKE_CALL) + dwCPLength;
|
|
|
|
// old miniports expect strings to be ascii
|
|
WideCharToMultiByte(
|
|
nCodePage,
|
|
0,
|
|
lpszDestAddress,
|
|
dwOrgDALength,
|
|
(LPSTR) (((LPBYTE) pNdisTapiMakeCall) +
|
|
pNdisTapiMakeCall->ulDestAddressOffset),
|
|
dwDALength,
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|
|
else
|
|
{
|
|
pNdisTapiMakeCall->ulDestAddressOffset = 0;
|
|
}
|
|
|
|
if (lpCallParams)
|
|
{
|
|
pNdisTapiMakeCall->bUseDefaultLineCallParams = FALSE;
|
|
|
|
CopyMemory(
|
|
&pNdisTapiMakeCall->LineCallParams,
|
|
lpCallParams,
|
|
lpCallParams->dwTotalSize
|
|
);
|
|
|
|
if (lpCallParams->dwOrigAddressSize != 0)
|
|
{
|
|
WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
(LPCWSTR) (((LPBYTE) lpCallParams) +
|
|
lpCallParams->dwOrigAddressOffset),
|
|
lpCallParams->dwOrigAddressSize / sizeof (WCHAR),
|
|
(LPSTR) (((LPBYTE) &pNdisTapiMakeCall->LineCallParams) +
|
|
lpCallParams->dwOrigAddressOffset),
|
|
lpCallParams->dwOrigAddressSize,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
pNdisTapiMakeCall->LineCallParams.ulOrigAddressSize /= 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pNdisTapiMakeCall->bUseDefaultLineCallParams = TRUE;
|
|
}
|
|
|
|
pAsyncReqWrapper->dwRequestSpecific = (DWORD_PTR)hdCall;
|
|
pAsyncReqWrapper->pfnPostProcess = TSPI_lineMakeCall_postProcess;
|
|
|
|
*lphdCall = hdCall;
|
|
|
|
lRes = AsyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pAsyncReqWrapper);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineNegotiateExtVersion(
|
|
DWORD dwDeviceID,
|
|
DWORD dwTSPIVersion,
|
|
DWORD dwLowVersion,
|
|
DWORD dwHighVersion,
|
|
LPDWORD lpdwExtVersion
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_NEGOTIATE_EXT_VERSION pNdisTapiNegotiateExtVersion;
|
|
|
|
TspLog(DL_TRACE,
|
|
"lineNegotiateExtVersion(%d): deviceID(%x), TSPIV(%x), "\
|
|
"LowV(%x), HighV(%x)",
|
|
++dwSum, dwDeviceID, dwTSPIVersion, dwLowVersion, dwHighVersion);
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_NEGOTIATE_EXT_VERSION, // opcode
|
|
dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_NEGOTIATE_EXT_VERSION), // size of req data
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiNegotiateExtVersion =
|
|
(PNDIS_TAPI_NEGOTIATE_EXT_VERSION)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiNegotiateExtVersion->ulDeviceID = dwDeviceID;
|
|
pNdisTapiNegotiateExtVersion->ulLowVersion = dwLowVersion;
|
|
pNdisTapiNegotiateExtVersion->ulHighVersion = dwHighVersion;
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
*lpdwExtVersion = pNdisTapiNegotiateExtVersion->ulExtVersion;
|
|
|
|
// save version for future verification
|
|
lRes = SetNegotiatedExtVersion(dwDeviceID, *lpdwExtVersion);
|
|
}
|
|
else
|
|
{
|
|
TspLog(DL_WARNING, "lineNegotiateExtVersion: syncRequest returned(%x)",
|
|
lRes);
|
|
}
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineNegotiateTSPIVersion(
|
|
DWORD dwDeviceID,
|
|
DWORD dwLowVersion,
|
|
DWORD dwHighVersion,
|
|
LPDWORD lpdwTSPIVersion
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
|
|
TspLog(DL_TRACE, "lineNegotiateTSPIVersion(%d): deviceID(%x)",
|
|
++dwSum, dwDeviceID);
|
|
|
|
*lpdwTSPIVersion = 0x00010003; // until the ndistapi spec widened
|
|
|
|
// save version for future verification
|
|
lRes = SetNegotiatedTSPIVersion(dwDeviceID, 0x00010003);
|
|
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
TspLog(DL_INFO, "lineNegotiateTSPIVersion: TSPIVersion(%x)",
|
|
*lpdwTSPIVersion);
|
|
}
|
|
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineOpen(
|
|
DWORD dwDeviceID,
|
|
HTAPILINE htLine,
|
|
LPHDRVLINE lphdLine,
|
|
DWORD dwTSPIVersion,
|
|
LINEEVENT lpfnEventProc
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
HDRVLINE hdLine;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_OPEN pNdisTapiOpen;
|
|
GUID Guid;
|
|
NDIS_WAN_MEDIUM_SUBTYPE MediaType;
|
|
PNDISTAPI_OPENDATA OpenData;
|
|
|
|
|
|
TspLog(DL_TRACE, "lineOpen(%d): deviceID(%x), htLine(%p)",
|
|
++dwSum, dwDeviceID, htLine);
|
|
|
|
// alloc & init a DRVLINE
|
|
if (!(pLine = AllocLineObj(sizeof(DRVLINE))))
|
|
{
|
|
TspLog(DL_ERROR, "lineOpen: failed to create line obj");
|
|
return LINEERR_NOMEM;
|
|
}
|
|
pLine->dwKey = LINE_KEY;
|
|
pLine->dwDeviceID = dwDeviceID;
|
|
pLine->htLine = htLine;
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_OPEN, // opcode
|
|
dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_OPEN) +
|
|
sizeof(NDISTAPI_OPENDATA), // size
|
|
&pNdisTapiRequest // ptr to ptr to request buffer
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
FreeLineObj(pLine);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiOpen = (PNDIS_TAPI_OPEN)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiOpen->ulDeviceID = dwDeviceID;
|
|
|
|
lRes = OpenObjHandle(pLine, FreeLineObj, (HANDLE *)&hdLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
TspLog(DL_ERROR, "lineOpen: failed to map obj(%p) to handle", pLine);
|
|
FreeLineObj(pLine);
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
pNdisTapiOpen->htLine = (HTAPI_LINE)hdLine;
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
CloseObjHandle((HANDLE)hdLine);
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
OpenData = (PNDISTAPI_OPENDATA)
|
|
((PUCHAR)pNdisTapiOpen + sizeof(NDIS_TAPI_OPEN));
|
|
|
|
MoveMemory(&pLine->Guid,&OpenData->Guid, sizeof(pLine->Guid));
|
|
pLine->MediaType = OpenData->MediaType;
|
|
|
|
TspLog(DL_INFO, "lineOpen: obj(%p)", hdLine);
|
|
TspLog(
|
|
DL_INFO,
|
|
"Guid: %4.4x-%4.4x-%2.2x%2.2x-%1.1x%1.1x%1.1x%1.1x%1.1x%1.1x%1.1x",
|
|
pLine->Guid.Data1, pLine->Guid.Data2,
|
|
pLine->Guid.Data3, pLine->Guid.Data4[0],
|
|
pLine->Guid.Data4[1], pLine->Guid.Data4[2],
|
|
pLine->Guid.Data4[3], pLine->Guid.Data4[4],
|
|
pLine->Guid.Data4[5], pLine->Guid.Data4[6],
|
|
pLine->Guid.Data4[7]
|
|
);
|
|
|
|
TspLog(DL_INFO, "MediaType(%ld)", pLine->MediaType);
|
|
|
|
pLine->hd_Line = pNdisTapiOpen->hdLine;
|
|
*lphdLine = hdLine;
|
|
|
|
lRes = CommitNegotiatedTSPIVersion(dwDeviceID);
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSecureCall(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVCALL hdCall
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper;
|
|
PNDIS_TAPI_SECURE_CALL pNdisTapiSecureCall;
|
|
|
|
TspLog(DL_TRACE, "lineSecureCall(%d): reqID(%x), call(%p)",
|
|
++dwSum, dwRequestID, hdCall);
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareAsyncRequest(
|
|
OID_TAPI_SECURE_CALL, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
dwRequestID, // req id
|
|
sizeof(NDIS_TAPI_SECURE_CALL), // size
|
|
&pAsyncReqWrapper // ptr to ptr to request buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiSecureCall =
|
|
(PNDIS_TAPI_SECURE_CALL)pAsyncReqWrapper->NdisTapiRequest.Data;
|
|
|
|
pNdisTapiSecureCall->hdCall = GetNdisTapiHandle(pCall, &lRes);
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pAsyncReqWrapper);
|
|
return lRes;
|
|
}
|
|
|
|
lRes = AsyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pAsyncReqWrapper);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSelectExtVersion(
|
|
HDRVLINE hdLine,
|
|
DWORD dwExtVersion
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_SELECT_EXT_VERSION pNdisTapiSelectExtVersion;
|
|
|
|
TspLog(DL_TRACE, "lineSelectExtVersion(%d): line(%p), ExtV(%x)",
|
|
++dwSum, hdLine, dwExtVersion);
|
|
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_SELECT_EXT_VERSION, // opcode
|
|
pLine->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_SELECT_EXT_VERSION), // size
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiSelectExtVersion =
|
|
(PNDIS_TAPI_SELECT_EXT_VERSION)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiSelectExtVersion->hdLine = pLine->hd_Line;
|
|
pNdisTapiSelectExtVersion->ulExtVersion = dwExtVersion;
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pNdisTapiRequest);
|
|
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
lRes = SetSelectedExtVersion(pLine->dwDeviceID, dwExtVersion);
|
|
}
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSendUserUserInfo(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVCALL hdCall,
|
|
LPCSTR lpsUserUserInfo,
|
|
DWORD dwSize
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper;
|
|
PNDIS_TAPI_SEND_USER_USER_INFO pNdisTapiSendUserUserInfo;
|
|
|
|
TspLog(DL_TRACE, "lineSendUserUserInfo(%d): reqID(%x), call(%p)",
|
|
++dwSum, dwRequestID, hdCall);
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareAsyncRequest(
|
|
OID_TAPI_SEND_USER_USER_INFO, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
dwRequestID, // request id
|
|
sizeof(NDIS_TAPI_SEND_USER_USER_INFO) + dwSize,
|
|
&pAsyncReqWrapper // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiSendUserUserInfo = (PNDIS_TAPI_SEND_USER_USER_INFO)
|
|
pAsyncReqWrapper->NdisTapiRequest.Data;
|
|
|
|
pNdisTapiSendUserUserInfo->hdCall = GetNdisTapiHandle(pCall, &lRes);
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pAsyncReqWrapper);
|
|
return lRes;
|
|
}
|
|
|
|
if (pNdisTapiSendUserUserInfo->ulUserUserInfoSize = dwSize)
|
|
{
|
|
CopyMemory(
|
|
pNdisTapiSendUserUserInfo->UserUserInfo,
|
|
lpsUserUserInfo,
|
|
dwSize
|
|
);
|
|
}
|
|
|
|
lRes = AsyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pAsyncReqWrapper);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSetAppSpecific(
|
|
HDRVCALL hdCall,
|
|
DWORD dwAppSpecific
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_SET_APP_SPECIFIC pNdisTapiSetAppSpecific;
|
|
|
|
TspLog(DL_TRACE, "lineSetAppSpecific(%d): call(%p)", ++dwSum, hdCall);
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_SET_APP_SPECIFIC, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_SET_APP_SPECIFIC), // size
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiSetAppSpecific =
|
|
(PNDIS_TAPI_SET_APP_SPECIFIC)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiSetAppSpecific->hdCall = GetNdisTapiHandle(pCall, &lRes);
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiSetAppSpecific->ulAppSpecific = dwAppSpecific;
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pNdisTapiRequest);
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSetCallParams(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVCALL hdCall,
|
|
DWORD dwBearerMode,
|
|
DWORD dwMinRate,
|
|
DWORD dwMaxRate,
|
|
LPLINEDIALPARAMS const lpDialParams
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper;
|
|
PNDIS_TAPI_SET_CALL_PARAMS pNdisTapiSetCallParams;
|
|
|
|
TspLog(DL_TRACE, "lineSetCallParams(%d): reqID(%x), call(%p)",
|
|
++dwSum, dwRequestID, hdCall);
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareAsyncRequest(
|
|
OID_TAPI_SET_CALL_PARAMS, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
dwRequestID, // request id
|
|
sizeof(NDIS_TAPI_SET_CALL_PARAMS), // size
|
|
&pAsyncReqWrapper // ptr to ptr to request buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiSetCallParams =
|
|
(PNDIS_TAPI_SET_CALL_PARAMS)pAsyncReqWrapper->NdisTapiRequest.Data;
|
|
|
|
pNdisTapiSetCallParams->hdCall = GetNdisTapiHandle(pCall, &lRes);
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pAsyncReqWrapper);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiSetCallParams->ulBearerMode = dwBearerMode;
|
|
pNdisTapiSetCallParams->ulMinRate = dwMinRate;
|
|
pNdisTapiSetCallParams->ulMaxRate = dwMaxRate;
|
|
|
|
if (lpDialParams)
|
|
{
|
|
pNdisTapiSetCallParams->bSetLineDialParams = TRUE;
|
|
CopyMemory(
|
|
&pNdisTapiSetCallParams->LineDialParams,
|
|
lpDialParams,
|
|
sizeof(LINE_DIAL_PARAMS)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
pNdisTapiSetCallParams->bSetLineDialParams = FALSE;
|
|
}
|
|
|
|
lRes = AsyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pAsyncReqWrapper);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSetDefaultMediaDetection(
|
|
HDRVLINE hdLine,
|
|
DWORD dwMediaModes
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION pNdisTapiSetDefaultMediaDetection;
|
|
|
|
TspLog(DL_TRACE, "lineSetDefaultMediaDetection(%d): line(%p), mode(%x)",
|
|
++dwSum, hdLine, dwMediaModes);
|
|
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_SET_DEFAULT_MEDIA_DETECTION, // opcode
|
|
pLine->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION), // size
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiSetDefaultMediaDetection =
|
|
(PNDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION) pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiSetDefaultMediaDetection->hdLine = pLine->hd_Line;
|
|
pNdisTapiSetDefaultMediaDetection->ulMediaModes = dwMediaModes;
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pNdisTapiRequest);
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSetDevConfig(
|
|
DWORD dwDeviceID,
|
|
LPVOID const lpDeviceConfig,
|
|
DWORD dwSize,
|
|
LPCWSTR lpszDeviceClass
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
DWORD dwLength = lstrlenW(lpszDeviceClass) + 1;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_SET_DEV_CONFIG pNdisTapiSetDevConfig;
|
|
|
|
TspLog(DL_TRACE, "lineSetDevConfig(%d): deviceID(%x)", ++dwSum, dwDeviceID);
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_SET_DEV_CONFIG, // opcode
|
|
dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_SET_DEV_CONFIG) + dwLength + dwSize,
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiSetDevConfig = (PNDIS_TAPI_SET_DEV_CONFIG)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiSetDevConfig->ulDeviceID = dwDeviceID;
|
|
pNdisTapiSetDevConfig->ulDeviceClassSize = dwLength;
|
|
pNdisTapiSetDevConfig->ulDeviceClassOffset =
|
|
sizeof(NDIS_TAPI_SET_DEV_CONFIG) + dwSize - 1;
|
|
pNdisTapiSetDevConfig->ulDeviceConfigSize = dwSize;
|
|
|
|
CopyMemory(
|
|
pNdisTapiSetDevConfig->DeviceConfig,
|
|
lpDeviceConfig,
|
|
dwSize
|
|
);
|
|
|
|
// NOTE: old miniports expect strings to be ascii
|
|
WideCharToMultiByte(CP_ACP, 0, lpszDeviceClass, -1,
|
|
(LPSTR) (((LPBYTE) pNdisTapiSetDevConfig) +
|
|
pNdisTapiSetDevConfig->ulDeviceClassOffset),
|
|
dwLength, NULL, NULL);
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pNdisTapiRequest);
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSetMediaMode(
|
|
HDRVCALL hdCall,
|
|
DWORD dwMediaMode
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_SET_MEDIA_MODE pNdisTapiSetMediaMode;
|
|
|
|
TspLog(DL_TRACE, "lineSetMediaMode(%d): call(%p), mode(%x)",
|
|
++dwSum, hdCall, dwMediaMode);
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_SET_MEDIA_MODE, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_SET_MEDIA_MODE), // size
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiSetMediaMode = (PNDIS_TAPI_SET_MEDIA_MODE)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiSetMediaMode->hdCall = GetNdisTapiHandle(pCall, &lRes);
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiSetMediaMode->ulMediaMode = dwMediaMode;
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pNdisTapiRequest);
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSetStatusMessages(
|
|
HDRVLINE hdLine,
|
|
DWORD dwLineStates,
|
|
DWORD dwAddressStates
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_SET_STATUS_MESSAGES pNdisTapiSetStatusMessages;
|
|
|
|
TspLog(DL_TRACE, "lineSetStatusMessages(%d): line(%p)", ++dwSum, hdLine);
|
|
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_SET_STATUS_MESSAGES, // opcode
|
|
pLine->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_SET_STATUS_MESSAGES), // size
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiSetStatusMessages =
|
|
(PNDIS_TAPI_SET_STATUS_MESSAGES)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiSetStatusMessages->hdLine = pLine->hd_Line;
|
|
pNdisTapiSetStatusMessages->ulLineStates = dwLineStates;
|
|
pNdisTapiSetStatusMessages->ulAddressStates = dwAddressStates;
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pNdisTapiRequest);
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
//
|
|
// TAPI_providerXxx funcs
|
|
//
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_providerEnumDevices(
|
|
DWORD dwPermanentProviderID,
|
|
LPDWORD lpdwNumLines,
|
|
LPDWORD lpdwNumPhones,
|
|
HPROVIDER hProvider,
|
|
LINEEVENT lpfnLineCreateProc,
|
|
PHONEEVENT lpfnPhoneCreateProc
|
|
)
|
|
{
|
|
TspLog(DL_TRACE, "providerEnumDevices: permProvID(%x)",
|
|
dwPermanentProviderID);
|
|
|
|
//
|
|
// NOTE: We really enum devs in providerInit, see the
|
|
// special case note there
|
|
//
|
|
*lpdwNumLines = 0;
|
|
*lpdwNumPhones = 0;
|
|
|
|
gpfnLineEvent = lpfnLineCreateProc;
|
|
ghProvider = hProvider;
|
|
|
|
return 0;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_providerInit(
|
|
DWORD dwTSPIVersion,
|
|
DWORD dwPermanentProviderID,
|
|
DWORD dwLineDeviceIDBase,
|
|
DWORD dwPhoneDeviceIDBase,
|
|
DWORD_PTR dwNumLines,
|
|
DWORD_PTR dwNumPhones,
|
|
ASYNC_COMPLETION lpfnCompletionProc,
|
|
LPDWORD lpdwTSPIOptions
|
|
)
|
|
{
|
|
LONG lRes = LINEERR_OPERATIONFAILED;
|
|
char szDeviceName[] = "NDISTAPI";
|
|
char szTargetPath[] = "\\Device\\NdisTapi";
|
|
char szCompleteDeviceName[] = "\\\\.\\NDISTAPI";
|
|
DWORD cbReturned, dwThreadID;
|
|
DWORD adwConnectInfo[2];
|
|
|
|
TspLog(DL_TRACE, "providerInit: perfProvID(%x), lineDevIDBase(%x)",
|
|
dwPermanentProviderID, dwLineDeviceIDBase);
|
|
|
|
//
|
|
// inform tapisrv that we support multiple simultaneous requests
|
|
// (the WAN wrapper handles request serialization for miniports)
|
|
//
|
|
*lpdwTSPIOptions = 0;
|
|
|
|
//
|
|
// create symbolic link to the kernel-mode driver
|
|
//
|
|
DefineDosDevice(DDD_RAW_TARGET_PATH, szDeviceName, szTargetPath);
|
|
|
|
//
|
|
// open driver handles
|
|
//
|
|
if ((ghDriverSync = CreateFileA(
|
|
szCompleteDeviceName,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL, // no security attrs
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL // no template file
|
|
)) == INVALID_HANDLE_VALUE)
|
|
{
|
|
TspLog(DL_ERROR, "providerInit: CreateFile(%s, sync) failed(%ld)",
|
|
szCompleteDeviceName, GetLastError());
|
|
|
|
goto providerInit_error0;
|
|
}
|
|
|
|
if ((ghDriverAsync = CreateFileA(
|
|
szCompleteDeviceName,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL, // no security attrs
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
|
|
NULL // no template file
|
|
)) == INVALID_HANDLE_VALUE)
|
|
{
|
|
TspLog(DL_ERROR, "providerInit: CreateFile(%s, async) failed(%ld)",
|
|
szCompleteDeviceName, GetLastError());
|
|
|
|
goto providerInit_error1;
|
|
}
|
|
|
|
//
|
|
// create io completion port
|
|
//
|
|
if ((ghCompletionPort = CreateIoCompletionPort(ghDriverAsync, NULL, 0, 0))
|
|
== INVALID_HANDLE_VALUE)
|
|
{
|
|
TspLog(DL_ERROR, "providerInit: CreateIoCompletionPort failed(%ld)",
|
|
GetLastError());
|
|
|
|
goto providerInit_error2;
|
|
}
|
|
|
|
//
|
|
// connect to driver- we send it a device ID base & it returns
|
|
// the number of devices it supports
|
|
//
|
|
{
|
|
adwConnectInfo[0] = dwLineDeviceIDBase;
|
|
adwConnectInfo[1] = 1;
|
|
|
|
if (!DeviceIoControl(
|
|
ghDriverSync,
|
|
IOCTL_NDISTAPI_CONNECT,
|
|
adwConnectInfo,
|
|
2 * sizeof(DWORD),
|
|
adwConnectInfo,
|
|
2 * sizeof(DWORD),
|
|
&cbReturned,
|
|
(LPOVERLAPPED)NULL
|
|
) ||
|
|
(cbReturned < sizeof(DWORD)))
|
|
{
|
|
TspLog(DL_ERROR, "providerInit: CONNECT failed(%ld)",
|
|
GetLastError());
|
|
|
|
goto providerInit_error3;
|
|
}
|
|
}
|
|
|
|
// init mapper, allocator and dev list
|
|
if (InitializeMapper() != TAPI_SUCCESS)
|
|
{
|
|
goto providerInit_error3_5;
|
|
}
|
|
|
|
InitAllocator();
|
|
|
|
//
|
|
// alloc the resources needed by the AsyncEventThread, and then
|
|
// create the thread
|
|
//
|
|
if ((gpAsyncEventsThreadInfo = (PASYNC_EVENTS_THREAD_INFO)
|
|
MALLOC(sizeof(ASYNC_EVENTS_THREAD_INFO))) == NULL)
|
|
{
|
|
TspLog(DL_ERROR, "providerInit: failed to alloc thread info");
|
|
goto providerInit_error4;
|
|
}
|
|
|
|
gpAsyncEventsThreadInfo->dwBufSize = EVENT_BUFFER_SIZE;
|
|
|
|
if ((gpAsyncEventsThreadInfo->pBuf = (PNDISTAPI_EVENT_DATA)
|
|
MALLOC(EVENT_BUFFER_SIZE)) == NULL)
|
|
{
|
|
TspLog(DL_ERROR, "providerInit: failed to alloc event buf");
|
|
goto providerInit_error5;
|
|
}
|
|
|
|
if ((gpAsyncEventsThreadInfo->hThread = CreateThread(
|
|
(LPSECURITY_ATTRIBUTES)NULL, // no security attrs
|
|
0, // default stack size
|
|
(LPTHREAD_START_ROUTINE) // func addr
|
|
AsyncEventsThread,
|
|
(LPVOID)NULL, // thread param
|
|
0, // create flags
|
|
&dwThreadID // thread id
|
|
)) == NULL)
|
|
{
|
|
TspLog(DL_ERROR, "providerInit: CreateThread failed(%ld)",
|
|
GetLastError());
|
|
|
|
goto providerInit_error7;
|
|
}
|
|
|
|
gdwRequestID = 1;
|
|
|
|
//
|
|
// !!! Special case for KMDDSP.TSP only !!!
|
|
//
|
|
// For KMDDSP.TSP only, TAPISRV.EXE will pass pointers in the
|
|
// dwNumLines/dwNumPhones variables rather than an actual
|
|
// number of lines/phones, thereby allowing the driver to tell
|
|
// TAPISRV.EXE how many devices are currently registered.
|
|
//
|
|
// This is really due to a design/interface problem in NDISTAPI.SYS.
|
|
// Since the current CONNECT IOCTLS expects both a device ID base &
|
|
// returns the num devs, we can't really do this in
|
|
// TSPI_providerEnumDevices as the device ID base is unknown
|
|
// at that point
|
|
//
|
|
*((LPDWORD)dwNumLines) = adwConnectInfo[0];
|
|
*((LPDWORD)dwNumPhones) = 0;
|
|
|
|
//
|
|
// if here success
|
|
//
|
|
gpfnCompletionProc = lpfnCompletionProc;
|
|
lRes = TAPI_SUCCESS;
|
|
|
|
goto providerInit_return;
|
|
|
|
//
|
|
// clean up resources if an error occured & then return
|
|
//
|
|
providerInit_error7:
|
|
|
|
FREE(gpAsyncEventsThreadInfo->pBuf);
|
|
|
|
providerInit_error5:
|
|
|
|
FREE(gpAsyncEventsThreadInfo);
|
|
|
|
providerInit_error4:
|
|
UninitAllocator();
|
|
UninitializeMapper();
|
|
|
|
providerInit_error3_5:
|
|
providerInit_error3:
|
|
|
|
CloseHandle(ghCompletionPort);
|
|
|
|
providerInit_error2:
|
|
|
|
CloseHandle(ghDriverAsync);
|
|
|
|
providerInit_error1:
|
|
|
|
CloseHandle(ghDriverSync);
|
|
|
|
providerInit_error0:
|
|
|
|
DefineDosDevice(DDD_REMOVE_DEFINITION, szDeviceName, NULL);
|
|
|
|
providerInit_return:
|
|
|
|
TspLog(DL_INFO, "providerInit: lRes(%x)", lRes);
|
|
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_providerCreateLineDevice(
|
|
DWORD_PTR dwTempID,
|
|
DWORD dwDeviceID
|
|
)
|
|
{
|
|
DWORD cbReturned;
|
|
NDISTAPI_CREATE_INFO CreateInfo;
|
|
|
|
CreateInfo.TempID = dwTempID;
|
|
CreateInfo.DeviceID = dwDeviceID;
|
|
|
|
TspLog(DL_TRACE, "providerCreateLineDevice: tempID(%x), deviceID(%x)",
|
|
dwTempID, dwDeviceID);
|
|
|
|
if (!DeviceIoControl(
|
|
ghDriverSync,
|
|
IOCTL_NDISTAPI_CREATE,
|
|
&CreateInfo,
|
|
sizeof(CreateInfo),
|
|
&CreateInfo,
|
|
sizeof(CreateInfo),
|
|
&cbReturned,
|
|
(LPOVERLAPPED)NULL
|
|
))
|
|
{
|
|
TspLog(DL_ERROR, "providerCreateLineDevice: failed(%ld) to create",
|
|
GetLastError());
|
|
return LINEERR_OPERATIONFAILED;
|
|
}
|
|
|
|
return TAPI_SUCCESS;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_providerShutdown(
|
|
DWORD dwTSPIVersion,
|
|
DWORD dwPermanentProviderID
|
|
)
|
|
{
|
|
char deviceName[] = "NDISTAPI";
|
|
ASYNC_REQUEST_WRAPPER asyncRequestWrapper;
|
|
|
|
TspLog(DL_TRACE, "providerShutdown: perfProvID(%x)", dwPermanentProviderID);
|
|
|
|
// @@@ all we ought to have to do here is send a DISCONNECT IOCTL
|
|
|
|
//
|
|
// Close the driver & remove the symbolic link
|
|
//
|
|
|
|
CancelIo(ghDriverSync);
|
|
CancelIo(ghDriverAsync);
|
|
CloseHandle (ghDriverSync);
|
|
|
|
TspLog(DL_WARNING, "providerShutdown: Calling PostQueuedCompletionStatus");
|
|
if( !PostQueuedCompletionStatus
|
|
( ghCompletionPort, 0, 0,(LPOVERLAPPED) &gOverlappedTerminate) )
|
|
{
|
|
|
|
TspLog(DL_ERROR, "providerShutdown: PostQueuedCompletionStatus "\
|
|
"failed");
|
|
}
|
|
else
|
|
{
|
|
WaitForSingleObject(gpAsyncEventsThreadInfo->hThread, INFINITE);
|
|
}
|
|
CloseHandle (ghDriverAsync);
|
|
CloseHandle (ghCompletionPort);
|
|
DefineDosDevice (DDD_REMOVE_DEFINITION, deviceName, NULL);
|
|
|
|
CloseHandle(gpAsyncEventsThreadInfo->hThread);
|
|
FREE(gpAsyncEventsThreadInfo->pBuf);
|
|
FREE(gpAsyncEventsThreadInfo);
|
|
|
|
UninitAllocator();
|
|
UninitializeMapper();
|
|
|
|
return TAPI_SUCCESS;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
DllMain(
|
|
HANDLE hDLL,
|
|
DWORD dwReason,
|
|
LPVOID lpReserved
|
|
)
|
|
{
|
|
switch (dwReason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
{
|
|
#if DBG
|
|
{
|
|
HKEY hKey;
|
|
DWORD dwDataSize, dwDataType;
|
|
TCHAR szTelephonyKey[] =
|
|
"Software\\Microsoft\\Windows\\CurrentVersion\\Telephony";
|
|
TCHAR szKmddspDebugLevel[] = "KmddspDebugLevel";
|
|
|
|
RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
szTelephonyKey,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hKey
|
|
);
|
|
|
|
dwDataSize = sizeof(DWORD);
|
|
gdwDebugLevel = DL_WARNING;
|
|
|
|
RegQueryValueEx(
|
|
hKey,
|
|
szKmddspDebugLevel,
|
|
0,
|
|
&dwDataType,
|
|
(LPBYTE)&gdwDebugLevel,
|
|
&dwDataSize
|
|
);
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
#endif
|
|
gdwTraceID = TraceRegisterA("KMDDSP");
|
|
ASSERT(gdwTraceID != INVALID_TRACEID);
|
|
|
|
TspLog(DL_TRACE, "DLL_PROCESS_ATTACH");
|
|
|
|
//
|
|
// Init global sync objects
|
|
//
|
|
InitializeCriticalSection(&gRequestIDCritSec);
|
|
|
|
InitLineDevList();
|
|
|
|
break;
|
|
}
|
|
case DLL_PROCESS_DETACH:
|
|
{
|
|
TspLog(DL_TRACE, "DLL_PROCESS_DETACH");
|
|
|
|
UninitLineDevList();
|
|
|
|
DeleteCriticalSection(&gRequestIDCritSec);
|
|
|
|
TraceDeregisterA(gdwTraceID);
|
|
|
|
break;
|
|
}
|
|
} // switch
|
|
|
|
return TRUE;
|
|
}
|