mirror of https://github.com/lianthony/NT4.0
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.
4792 lines
128 KiB
4792 lines
128 KiB
/*++ BUILD Version: 0000 // Increment this if a change has global effects
|
|
|
|
Copyright (c) 1995-1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
kmddsp.c
|
|
|
|
Abstract:
|
|
|
|
This module contains
|
|
|
|
Author:
|
|
|
|
Dan Knudson (DanKn) 11-Apr-1995
|
|
|
|
Revision History:
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
1. NdisTapi.sys needs to be modified to support IOCTL_DISCONNECT so we
|
|
don't have to close all the driver handles etc each time we get a
|
|
providerShutdown request (ideally we ought only have to close handles,
|
|
etc on a dll process detach).
|
|
|
|
2. There's the hack in TSPI_providerInit where tapisrv has to pass in
|
|
pointer to dwNumLines & dwNumPhones, becuase we determine the # of
|
|
devs when we send the CONNECT IOCTL
|
|
|
|
3. Ndistapi.h is not in sync w/ tapi.h & tspi.h, so make sure to use
|
|
the definitions in ndistapi.h as appropriate (like LINE_DEV_CAPS
|
|
instead of LINEDEVCAPS).
|
|
|
|
4. A slight perf gain might be realized by caching dev caps info for
|
|
each line (but can/will it chg on the fly?)
|
|
|
|
5. To keep bad 2.0 apps from blowing up if they try to look at version
|
|
1.4 or 2.0 structure fields we pad the area between the end of the
|
|
1.0 structure and the variable-length data with 0's. This is done
|
|
in GetAddrCaps, GetCallInfo, GetCallStatus, GetDevCaps, &
|
|
GetLineDevStatus.
|
|
|
|
6. Since TAPI 2.0 service providers are required to be 100% unicode,
|
|
kmddsp munge all incoming unicode strings to ascii before passing
|
|
them to an underlying driver, and also converts all returned ascii
|
|
strings (embedded in structures) to unicode.
|
|
|
|
--*/
|
|
|
|
|
|
#include "windows.h"
|
|
#include "winioctl.h"
|
|
#include "stdarg.h"
|
|
#include "stdio.h"
|
|
#define ULONGLONG DWORDLONG
|
|
#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
|
|
|
|
#include "tapi.h"
|
|
#include "tspi.h"
|
|
#include "kmddsp.h"
|
|
|
|
|
|
#define MYHACK
|
|
|
|
|
|
void
|
|
AsyncEventsThread(
|
|
LPVOID lpParams
|
|
);
|
|
|
|
LONG
|
|
WINAPI
|
|
TranslateDriverResult(
|
|
ULONG ulResult
|
|
);
|
|
|
|
//BOOL
|
|
//WINAPI
|
|
//_CRT_INIT(
|
|
// HINSTANCE hDLL,
|
|
// DWORD dwReason,
|
|
// LPVOID lpReserved
|
|
// );
|
|
|
|
#if DBG
|
|
|
|
#define DBGOUT(arg) DbgPrt arg
|
|
|
|
VOID
|
|
DbgPrt(
|
|
IN DWORD dwDbgLevel,
|
|
IN PUCHAR DbgMessage,
|
|
IN ...
|
|
);
|
|
|
|
DWORD gdwDebugLevel;
|
|
|
|
#else
|
|
|
|
#define DBGOUT(arg)
|
|
|
|
#endif
|
|
|
|
LPVOID
|
|
WINAPI
|
|
DrvAlloc(
|
|
DWORD dwSize
|
|
);
|
|
|
|
VOID
|
|
WINAPI
|
|
DrvFree(
|
|
LPVOID lp
|
|
);
|
|
|
|
void
|
|
WINAPI
|
|
ProcessEvent(
|
|
PNDIS_TAPI_EVENT pEvent
|
|
);
|
|
|
|
LONG
|
|
WINAPI
|
|
PrepareSyncRequest(
|
|
ULONG Oid,
|
|
LPDWORD lphWidget,
|
|
DWORD dwWidgetType,
|
|
PNDISTAPI_REQUEST *ppNdisTapiRequest,
|
|
DWORD dwDataSize
|
|
);
|
|
|
|
LONG
|
|
WINAPI
|
|
PrepareAsyncRequest(
|
|
ULONG Oid,
|
|
LPDWORD lphWidget,
|
|
DWORD dwWidgetType,
|
|
DWORD dwRequestID,
|
|
PASYNC_REQUEST_WRAPPER *ppAsyncRequestWrapper,
|
|
DWORD dwDataSize
|
|
);
|
|
|
|
LONG
|
|
WINAPI
|
|
SyncDriverRequest(
|
|
DWORD dwIoControlCode,
|
|
PNDISTAPI_REQUEST pNdisTapiRequest
|
|
);
|
|
|
|
LONG
|
|
WINAPI
|
|
AsyncDriverRequest(
|
|
DWORD dwIoControlCode,
|
|
PASYNC_REQUEST_WRAPPER pAsyncRequestWrapper
|
|
);
|
|
|
|
|
|
//
|
|
// Global vars
|
|
//
|
|
|
|
DWORD gdwTlsIndex, gdwRequestID;
|
|
HANDLE ghDriverSync, ghDriverAsync, ghCompletionPort;
|
|
LINEEVENT gpfnLineEvent;
|
|
ASYNC_COMPLETION gpfnCompletionProc;
|
|
PASYNC_EVENTS_THREAD_INFO gpAsyncEventsThreadInfo;
|
|
CRITICAL_SECTION gInboundCallsCritSec, gRequestIDCritSec;
|
|
|
|
|
|
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",
|
|
szKmddspDebugLevel[] = "KmddspDebugLevel";
|
|
|
|
|
|
RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
szTelephonyKey,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hKey
|
|
);
|
|
|
|
dwDataSize = sizeof (DWORD);
|
|
gdwDebugLevel=0;
|
|
|
|
RegQueryValueEx(
|
|
hKey,
|
|
szKmddspDebugLevel,
|
|
0,
|
|
&dwDataType,
|
|
(LPBYTE) &gdwDebugLevel,
|
|
&dwDataSize
|
|
);
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
#endif
|
|
|
|
// if (!_CRT_INIT (hDLL, dwReason, lpReserved))
|
|
// {
|
|
// return FALSE;
|
|
// }
|
|
|
|
DBGOUT((4, "DLL_PROCESS_ATTACH"));
|
|
|
|
|
|
//
|
|
// Get a thread local storage entry
|
|
//
|
|
|
|
if ((gdwTlsIndex = TlsAlloc()) == 0xffffffff)
|
|
{
|
|
DBGOUT((1, "TlsAlloc() failed"));
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Init global sync objects
|
|
//
|
|
|
|
InitializeCriticalSection (&gInboundCallsCritSec);
|
|
InitializeCriticalSection (&gRequestIDCritSec);
|
|
|
|
break;
|
|
}
|
|
case DLL_PROCESS_DETACH:
|
|
{
|
|
//
|
|
// Free resources
|
|
//
|
|
|
|
PREQUEST_THREAD_INFO pRequestThreadInfo;
|
|
|
|
|
|
DBGOUT((4, "DLL_PROCESS_DETACH"));
|
|
|
|
if ((pRequestThreadInfo = TlsGetValue (gdwTlsIndex)))
|
|
{
|
|
DrvFree (pRequestThreadInfo->pBuf);
|
|
DrvFree (pRequestThreadInfo);
|
|
}
|
|
|
|
TlsFree (gdwTlsIndex);
|
|
|
|
DeleteCriticalSection (&gInboundCallsCritSec);
|
|
DeleteCriticalSection (&gRequestIDCritSec);
|
|
|
|
// _CRT_INIT (hDLL, dwReason, lpReserved);
|
|
|
|
break;
|
|
}
|
|
case DLL_THREAD_ATTACH:
|
|
{
|
|
PREQUEST_THREAD_INFO pRequestThreadInfo;
|
|
|
|
|
|
// if (!_CRT_INIT (hDLL, dwReason, lpReserved))
|
|
// {
|
|
// DBGOUT((1, "DLL_THREAD_ATTACH, _CRT_INIT failed"));
|
|
// }
|
|
|
|
TlsSetValue (gdwTlsIndex, NULL);
|
|
|
|
break;
|
|
}
|
|
case DLL_THREAD_DETACH:
|
|
{
|
|
//
|
|
// Free resources
|
|
//
|
|
|
|
PREQUEST_THREAD_INFO pRequestThreadInfo;
|
|
|
|
|
|
if ((pRequestThreadInfo = TlsGetValue (gdwTlsIndex)))
|
|
{
|
|
DrvFree (pRequestThreadInfo->pBuf);
|
|
DrvFree (pRequestThreadInfo);
|
|
}
|
|
|
|
// _CRT_INIT (hDLL, dwReason, lpReserved);
|
|
|
|
break;
|
|
}
|
|
} // switch
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
#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)
|
|
{
|
|
DBGOUT((
|
|
0,
|
|
"ERROR! bad %s values, size=x%x, offset=x%x",
|
|
pszFieldName,
|
|
dwXxxSize,
|
|
dwXxxOffset
|
|
));
|
|
|
|
*pdwNewXxxSize = *(pdwNewXxxSize + 1) = 0;
|
|
return;
|
|
}
|
|
//#endif
|
|
|
|
MultiByteToWideChar(
|
|
CP_ACP,
|
|
MB_PRECOMPOSED,
|
|
((LPBYTE) pStruct) + dwXxxOffset,
|
|
dwXxxSize,
|
|
(LPWSTR) (((LPBYTE) pNewStruct) +
|
|
((LPVARSTRING) pNewStruct)->dwUsedSize),
|
|
dwXxxSize * sizeof (WCHAR)
|
|
);
|
|
|
|
*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)
|
|
{
|
|
DBGOUT((
|
|
0,
|
|
"ERROR! 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;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// TSPI_lineXxx funcs
|
|
//
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineAccept(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVCALL hdCall,
|
|
LPCSTR lpsUserUserInfo,
|
|
DWORD dwSize
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PASYNC_REQUEST_WRAPPER pAsyncRequestWrapper;
|
|
|
|
|
|
if ((lResult = PrepareAsyncRequest(
|
|
OID_TAPI_ACCEPT, // opcode
|
|
(LPDWORD) &hdCall, // target handle
|
|
HT_HDCALL, // target handle type
|
|
dwRequestID, // request id
|
|
&pAsyncRequestWrapper, // ptr to ptr to request buffer
|
|
sizeof(NDIS_TAPI_ACCEPT) + dwSize // size of drv request data
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PNDIS_TAPI_ACCEPT pNdisTapiAccept =
|
|
(PNDIS_TAPI_ACCEPT) pAsyncRequestWrapper->NdisTapiRequest.Data;
|
|
|
|
|
|
pNdisTapiAccept->hdCall = (HDRV_CALL) hdCall;
|
|
|
|
if ((pNdisTapiAccept->ulUserUserInfoSize = (ULONG) dwSize))
|
|
{
|
|
CopyMemory(
|
|
pNdisTapiAccept->UserUserInfo,
|
|
lpsUserUserInfo,
|
|
dwSize
|
|
);
|
|
}
|
|
|
|
lResult = AsyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_SET_INFO,
|
|
pAsyncRequestWrapper
|
|
);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineAnswer(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVCALL hdCall,
|
|
LPCSTR lpsUserUserInfo,
|
|
DWORD dwSize
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PASYNC_REQUEST_WRAPPER pAsyncRequestWrapper;
|
|
|
|
|
|
if ((lResult = PrepareAsyncRequest(
|
|
OID_TAPI_ANSWER, // opcode
|
|
(LPDWORD) &hdCall, // target handle
|
|
HT_HDCALL, // target handle type
|
|
dwRequestID, // request id
|
|
&pAsyncRequestWrapper, // ptr to ptr to request buffer
|
|
sizeof(NDIS_TAPI_ANSWER) + dwSize // size of drv request data
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PNDIS_TAPI_ANSWER pNdisTapiAnswer =
|
|
(PNDIS_TAPI_ANSWER) pAsyncRequestWrapper->NdisTapiRequest.Data;
|
|
|
|
|
|
pNdisTapiAnswer->hdCall = (HDRV_CALL) hdCall;
|
|
|
|
if ((pNdisTapiAnswer->ulUserUserInfoSize = (ULONG) dwSize))
|
|
{
|
|
CopyMemory(
|
|
pNdisTapiAnswer->UserUserInfo,
|
|
lpsUserUserInfo,
|
|
dwSize
|
|
);
|
|
}
|
|
|
|
lResult = AsyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_SET_INFO,
|
|
pAsyncRequestWrapper
|
|
);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineClose(
|
|
HDRVLINE hdLine
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PDRVLINE pLine = (PDRVLINE) hdLine;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
|
|
|
|
if ((lResult = PrepareSyncRequest(
|
|
OID_TAPI_CLOSE, // opcode
|
|
(LPDWORD) &hdLine, // target handle
|
|
HT_HDLINE, // target handle type
|
|
&pNdisTapiRequest, // ptr to ptr to request buffer
|
|
sizeof(NDIS_TAPI_CLOSE) // size of drve req data
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
//
|
|
// Note that this is a command rather than a request, in that
|
|
// TAPI considers the line closed regardless of the request result.
|
|
//
|
|
|
|
PNDIS_TAPI_CLOSE 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 = (HDRV_LINE) hdLine;
|
|
|
|
lResult = SyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_SET_INFO,
|
|
pNdisTapiRequest
|
|
);
|
|
|
|
|
|
//
|
|
// Clean up our pLine. Make sure to clean up any calls in the
|
|
// inbound list that may not have been explicitly closed
|
|
// (i.e. new calls that showed up after TAPI had already
|
|
// started closing down this line)
|
|
//
|
|
|
|
EnterCriticalSection (&gInboundCallsCritSec);
|
|
|
|
{
|
|
PDRVCALL pCall;
|
|
|
|
|
|
while ((pCall = pLine->pInboundCalls))
|
|
{
|
|
pLine->pInboundCalls = pCall->pNext;
|
|
|
|
DrvFree (pCall);
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection (&gInboundCallsCritSec);
|
|
|
|
DrvFree (pLine);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineCloseCall(
|
|
HDRVCALL hdCall
|
|
)
|
|
{
|
|
LONG lResult;
|
|
HDRVCALL hdCallDrop = hdCall;
|
|
PDRVCALL pCall = (PDRVCALL) hdCall;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
|
|
|
|
if ((lResult = PrepareSyncRequest(
|
|
OID_TAPI_CLOSE_CALL, // opcode
|
|
(LPDWORD) &hdCall, // target handle
|
|
HT_HDCALL, // target handle type
|
|
&pNdisTapiRequest, // ptr to ptr to request buffer
|
|
sizeof (NDIS_TAPI_CLOSE_CALL) // size of drve req data
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
//
|
|
// Note that this is a command rather than a request, in that
|
|
// TAPI considers the call closed regardless of the request
|
|
// result.
|
|
//
|
|
|
|
BOOL bInboundCall;
|
|
PNDIS_TAPI_CLOSE_CALL pNdisTapiCloseCall;
|
|
|
|
|
|
//
|
|
// Safely determine if call is inbound or outbound, & if the
|
|
// latter then if necessary wait until the make call request
|
|
// has completed so we don't send a bad hdCall down to the
|
|
// driver with the close call request.
|
|
//
|
|
// We'll just return 0 if the call is bad or we AV (meaning
|
|
// a make call request failed & call struct was freed in post
|
|
// processing).
|
|
//
|
|
|
|
try
|
|
{
|
|
bInboundCall = (pCall->dwKey == INBOUND_CALL_KEY ? TRUE : FALSE);
|
|
|
|
if (bInboundCall == FALSE)
|
|
{
|
|
while (pCall->dwKey == OUTBOUND_CALL_KEY)
|
|
{
|
|
if (pCall->bIncomplete == FALSE)
|
|
{
|
|
hdCall = (HDRVCALL) pCall->hd_Call;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
Sleep (0);
|
|
}
|
|
}
|
|
|
|
if (pCall->dwKey != OUTBOUND_CALL_KEY)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
// we expect some AVs and alignment faults
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// HACKHACK: the following is for legacy ndis wan 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,
|
|
// and 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.
|
|
//
|
|
// Note: we do a sync rather than an async drop here
|
|
//
|
|
|
|
if (pCall->bDropped == FALSE)
|
|
{
|
|
HDRVCALL hdCallClose2 = hdCallDrop;
|
|
PNDISTAPI_REQUEST pNdisTapiRequestDrop;
|
|
|
|
|
|
if (PrepareSyncRequest(
|
|
OID_TAPI_DROP, // opcode
|
|
(LPDWORD) &hdCallDrop, // target handle
|
|
HT_HDCALL, // target handle type
|
|
&pNdisTapiRequestDrop, // ptr to ptr to request buffer
|
|
sizeof (NDIS_TAPI_DROP) // size of driver request data
|
|
|
|
) == TAPI_SUCCESS)
|
|
{
|
|
PNDIS_TAPI_DROP pNdisTapiDrop = (PNDIS_TAPI_DROP)
|
|
pNdisTapiRequestDrop->Data;
|
|
|
|
|
|
//
|
|
// Mark the call as bad so any events get discarded
|
|
//
|
|
|
|
pCall->dwKey = INVALID_KEY;
|
|
|
|
pNdisTapiDrop->hdCall = (HDRV_CALL) hdCallDrop;
|
|
|
|
SyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_SET_INFO,
|
|
pNdisTapiRequestDrop
|
|
);
|
|
}
|
|
|
|
if ((lResult = PrepareSyncRequest(
|
|
OID_TAPI_CLOSE_CALL, // opcode
|
|
(LPDWORD) &hdCallClose2, // target handle
|
|
HT_HDCALL, // target handle type
|
|
&pNdisTapiRequest, // ptr to ptr to request buffer
|
|
sizeof (NDIS_TAPI_CLOSE_CALL) // size of drve req data
|
|
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
return lResult;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// 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) pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiCloseCall->hdCall = (HDRV_CALL) hdCall;
|
|
|
|
lResult = SyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_SET_INFO,
|
|
pNdisTapiRequest
|
|
);
|
|
|
|
|
|
//
|
|
// Clean up our drv call
|
|
//
|
|
|
|
if (bInboundCall)
|
|
{
|
|
PDRVLINE pLine = (PDRVLINE) pCall->pLine;
|
|
|
|
|
|
EnterCriticalSection (&gInboundCallsCritSec);
|
|
|
|
if (pCall->pNext)
|
|
{
|
|
pCall->pNext->pPrev = pCall->pPrev;
|
|
}
|
|
|
|
if (pCall->pPrev)
|
|
{
|
|
pCall->pPrev->pNext = pCall->pNext;
|
|
}
|
|
else
|
|
{
|
|
pLine->pInboundCalls = pCall->pNext;
|
|
}
|
|
|
|
LeaveCriticalSection (&gInboundCallsCritSec);
|
|
}
|
|
|
|
DrvFree (pCall);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineConditionalMediaDetection(
|
|
HDRVLINE hdLine,
|
|
DWORD dwMediaModes,
|
|
LPLINECALLPARAMS const lpCallParams
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
|
|
|
|
if ((lResult = PrepareSyncRequest(
|
|
OID_TAPI_CONDITIONAL_MEDIA_DETECTION, // opcode
|
|
(LPDWORD) &hdLine, // target handle
|
|
HT_HDLINE, // target handle type
|
|
&pNdisTapiRequest, // ptr to ptr to req buffer
|
|
// size of drv request data
|
|
sizeof(NDIS_TAPI_CONDITIONAL_MEDIA_DETECTION) +
|
|
(lpCallParams->dwTotalSize - sizeof(LINE_CALL_PARAMS))
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PNDIS_TAPI_CONDITIONAL_MEDIA_DETECTION
|
|
pNdisTapiConditionalMediaDetection =
|
|
(PNDIS_TAPI_CONDITIONAL_MEDIA_DETECTION) pNdisTapiRequest->Data;
|
|
|
|
|
|
pNdisTapiConditionalMediaDetection->hdLine = (HDRV_LINE) hdLine;
|
|
pNdisTapiConditionalMediaDetection->ulMediaModes = (ULONG)
|
|
dwMediaModes;
|
|
|
|
CopyMemory(
|
|
&pNdisTapiConditionalMediaDetection->LineCallParams,
|
|
lpCallParams,
|
|
lpCallParams->dwTotalSize
|
|
);
|
|
|
|
lResult = SyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_SET_INFO,
|
|
pNdisTapiRequest
|
|
);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
PASCAL
|
|
TSPI_lineDevSpecific_postProcess(
|
|
PASYNC_REQUEST_WRAPPER pAsyncRequestWrapper,
|
|
LONG lResult,
|
|
LPDWORD callStateMsgParams
|
|
)
|
|
{
|
|
if (lResult == TAPI_SUCCESS)
|
|
{
|
|
PNDIS_TAPI_DEV_SPECIFIC pNdisTapiDevSpecific =(PNDIS_TAPI_DEV_SPECIFIC)
|
|
pAsyncRequestWrapper->NdisTapiRequest.Data;
|
|
|
|
|
|
CopyMemory(
|
|
(LPVOID) pAsyncRequestWrapper->dwRequestSpecific,
|
|
pNdisTapiDevSpecific->Params,
|
|
pNdisTapiDevSpecific->ulParamsSize
|
|
);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineDevSpecific(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVLINE hdLine,
|
|
DWORD dwAddressID,
|
|
HDRVCALL hdCall,
|
|
LPVOID lpParams,
|
|
DWORD dwSize
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PASYNC_REQUEST_WRAPPER pAsyncRequestWrapper;
|
|
|
|
|
|
//
|
|
// Init the request
|
|
//
|
|
|
|
if ((lResult = PrepareAsyncRequest(
|
|
OID_TAPI_DEV_SPECIFIC, // opcode
|
|
(LPDWORD) &hdLine, // target handle
|
|
HT_HDLINE, // target handle type
|
|
dwRequestID, // request id
|
|
&pAsyncRequestWrapper, // ptr to ptr to request buffer
|
|
sizeof(NDIS_TAPI_DEV_SPECIFIC)+ // size of drv request data
|
|
(dwSize - 1)
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PNDIS_TAPI_DEV_SPECIFIC pNdisTapiDevSpecific =(PNDIS_TAPI_DEV_SPECIFIC)
|
|
pAsyncRequestWrapper->NdisTapiRequest.Data;
|
|
|
|
|
|
pNdisTapiDevSpecific->hdLine = (HDRV_LINE) hdLine;
|
|
pNdisTapiDevSpecific->ulAddressID = (ULONG) dwAddressID;
|
|
|
|
if (hdCall)
|
|
{
|
|
LONG lResult = 0;
|
|
|
|
|
|
try
|
|
{
|
|
pNdisTapiDevSpecific->hdCall = ((PDRVCALL)(hdCall))->hd_Call;
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
// we expect some AVs and alignment faults
|
|
{
|
|
lResult = LINEERR_INVALCALLHANDLE;
|
|
}
|
|
|
|
if (lResult)
|
|
{
|
|
DrvFree (pAsyncRequestWrapper);
|
|
return lResult;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pNdisTapiDevSpecific->hdCall = (HDRV_CALL) NULL;
|
|
}
|
|
|
|
pNdisTapiDevSpecific->ulParamsSize = (ULONG) dwSize;
|
|
|
|
CopyMemory (pNdisTapiDevSpecific->Params, lpParams, dwSize);
|
|
|
|
pAsyncRequestWrapper->dwRequestSpecific = (DWORD) lpParams;
|
|
pAsyncRequestWrapper->pfnPostProcess =
|
|
TSPI_lineDevSpecific_postProcess;
|
|
|
|
lResult = AsyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_QUERY_INFO,
|
|
pAsyncRequestWrapper
|
|
);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineDial(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVCALL hdCall,
|
|
LPCWSTR lpszDestAddress,
|
|
DWORD dwCountryCode
|
|
)
|
|
{
|
|
LONG lResult;
|
|
DWORD dwLength = lstrlenW (lpszDestAddress) + 1;
|
|
PASYNC_REQUEST_WRAPPER pAsyncRequestWrapper;
|
|
|
|
|
|
if ((lResult = PrepareAsyncRequest(
|
|
OID_TAPI_DIAL, // opcode
|
|
(LPDWORD) &hdCall, // target handle
|
|
HT_HDCALL, // target handle type
|
|
dwRequestID, // request id
|
|
&pAsyncRequestWrapper, // ptr to ptr to request buffer
|
|
sizeof(NDIS_TAPI_DIAL) + dwLength // size of driver request data
|
|
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PNDIS_TAPI_DIAL pNdisTapiDial =
|
|
(PNDIS_TAPI_DIAL) pAsyncRequestWrapper->NdisTapiRequest.Data;
|
|
|
|
|
|
pNdisTapiDial->hdCall = (HDRV_CALL) hdCall;
|
|
pNdisTapiDial->ulDestAddressSize = (ULONG) dwLength;
|
|
|
|
|
|
//
|
|
// Note: old miniports expect strings to be ascii
|
|
//
|
|
|
|
WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
lpszDestAddress,
|
|
-1,
|
|
(LPSTR) pNdisTapiDial->szDestAddress,
|
|
dwLength,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
|
|
lResult = AsyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_SET_INFO,
|
|
pAsyncRequestWrapper
|
|
);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
PASCAL
|
|
TSPI_lineDrop_postProcess(
|
|
PASYNC_REQUEST_WRAPPER pAsyncRequestWrapper,
|
|
LONG lResult,
|
|
LPDWORD callStateMsgParams
|
|
)
|
|
{
|
|
PDRVCALL pCall = (PDRVCALL) pAsyncRequestWrapper->dwRequestSpecific;
|
|
HTAPICALL htCall;
|
|
HTAPILINE htLine;
|
|
|
|
|
|
//
|
|
// HACK ALERT!!!
|
|
//
|
|
// Some old-style miniports, notably pcimac, don't indicate IDLE msgs
|
|
// when they get a drop request- so we synthesize this for them.
|
|
//
|
|
|
|
if (lResult == TAPI_SUCCESS)
|
|
{
|
|
try
|
|
{
|
|
htCall = pCall->htCall;
|
|
htLine = ((PDRVLINE) pCall->pLine)->htLine;
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
// we expect some AVs and alignment faults
|
|
{
|
|
return lResult;
|
|
}
|
|
|
|
(*gpfnLineEvent)(
|
|
htLine,
|
|
htCall,
|
|
LINE_CALLSTATE,
|
|
LINECALLSTATE_IDLE,
|
|
0,
|
|
0
|
|
);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineDrop(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVCALL hdCall,
|
|
LPCSTR lpsUserUserInfo,
|
|
DWORD dwSize
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PDRVCALL pCall = (PDRVCALL) hdCall;
|
|
PASYNC_REQUEST_WRAPPER pAsyncRequestWrapper;
|
|
|
|
|
|
if ((lResult = PrepareAsyncRequest(
|
|
OID_TAPI_DROP, // opcode
|
|
(LPDWORD) &hdCall, // target handle
|
|
HT_HDCALL, // target handle type
|
|
dwRequestID, // request id
|
|
&pAsyncRequestWrapper, // ptr to ptr to request buffer
|
|
sizeof(NDIS_TAPI_DROP) + dwSize // size of driver request data
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PNDIS_TAPI_DROP pNdisTapiDrop =
|
|
(PNDIS_TAPI_DROP) pAsyncRequestWrapper->NdisTapiRequest.Data;
|
|
|
|
|
|
//
|
|
// HACKHACK: the following is for legacy ndis wan isdn miniports
|
|
//
|
|
// Safely mark the call as dropped so the CloseCall code won't follow
|
|
// up with another "automatic" drop
|
|
//
|
|
|
|
try
|
|
{
|
|
pCall->bDropped = TRUE;
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
// we expect some AVs and alignment faults
|
|
{
|
|
lResult = LINEERR_INVALCALLHANDLE;
|
|
}
|
|
|
|
if (lResult == 0)
|
|
{
|
|
pNdisTapiDrop->hdCall = (HDRV_CALL) hdCall;
|
|
|
|
if ((pNdisTapiDrop->ulUserUserInfoSize = (ULONG) dwSize))
|
|
{
|
|
CopyMemory(
|
|
pNdisTapiDrop->UserUserInfo,
|
|
lpsUserUserInfo,
|
|
dwSize
|
|
);
|
|
}
|
|
|
|
pAsyncRequestWrapper->dwRequestSpecific = (DWORD) pCall;
|
|
pAsyncRequestWrapper->pfnPostProcess = TSPI_lineDrop_postProcess;
|
|
|
|
lResult = AsyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_SET_INFO,
|
|
pAsyncRequestWrapper
|
|
);
|
|
}
|
|
else
|
|
{
|
|
DrvFree (pAsyncRequestWrapper);
|
|
}
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetAddressCaps(
|
|
DWORD dwDeviceID,
|
|
DWORD dwAddressID,
|
|
DWORD dwTSPIVersion,
|
|
DWORD dwExtVersion,
|
|
LPLINEADDRESSCAPS lpAddressCaps
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
|
|
|
|
if ((lResult = PrepareSyncRequest(
|
|
OID_TAPI_GET_ADDRESS_CAPS, // opcode
|
|
&dwDeviceID, // target handle
|
|
HT_DEVICEID, // target handle type
|
|
&pNdisTapiRequest, // ptr to ptr to request buffer
|
|
sizeof(NDIS_TAPI_GET_ADDRESS_CAPS) + // size of drv request data
|
|
(lpAddressCaps->dwTotalSize - sizeof(LINE_ADDRESS_CAPS))
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PLINE_ADDRESS_CAPS pCaps;
|
|
PNDIS_TAPI_GET_ADDRESS_CAPS pNdisTapiGetAddressCaps =
|
|
(PNDIS_TAPI_GET_ADDRESS_CAPS) pNdisTapiRequest->Data;
|
|
|
|
|
|
pNdisTapiGetAddressCaps->ulDeviceID = (ULONG) dwDeviceID;
|
|
pNdisTapiGetAddressCaps->ulAddressID = (ULONG) dwAddressID;
|
|
pNdisTapiGetAddressCaps->ulExtVersion = (ULONG) 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)
|
|
);
|
|
|
|
if ((lResult = SyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_QUERY_INFO,
|
|
pNdisTapiRequest
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
//
|
|
// 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)
|
|
{
|
|
// BUGBUG TSPI_lineGetAddressCaps: 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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetAddressID(
|
|
HDRVLINE hdLine,
|
|
LPDWORD lpdwAddressID,
|
|
DWORD dwAddressMode,
|
|
LPCWSTR lpsAddress,
|
|
DWORD dwSize
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
|
|
|
|
// BUGBUG unicode
|
|
|
|
if ((lResult = PrepareSyncRequest(
|
|
OID_TAPI_GET_ADDRESS_ID, // opcode
|
|
(LPDWORD) &hdLine, // target handle
|
|
HT_HDLINE, // target handle type
|
|
&pNdisTapiRequest, // ptr to ptr to request buffer
|
|
sizeof(NDIS_TAPI_GET_ADDRESS_ID) + // size of drv request data
|
|
dwSize/2 - 1
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PNDIS_TAPI_GET_ADDRESS_ID pNdisTapiGetAddressID =
|
|
(PNDIS_TAPI_GET_ADDRESS_ID) pNdisTapiRequest->Data;
|
|
|
|
|
|
pNdisTapiGetAddressID->hdLine = (HDRV_LINE) hdLine;
|
|
pNdisTapiGetAddressID->ulAddressMode = (ULONG) dwAddressMode;
|
|
pNdisTapiGetAddressID->ulAddressSize = (ULONG) dwSize/2;
|
|
|
|
WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
lpsAddress,
|
|
dwSize,
|
|
(LPSTR) pNdisTapiGetAddressID->szAddress,
|
|
dwSize/2,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if ((lResult = SyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_QUERY_INFO,
|
|
pNdisTapiRequest
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
*lpdwAddressID = pNdisTapiGetAddressID->ulAddressID;
|
|
}
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetAddressStatus(
|
|
HDRVLINE hdLine,
|
|
DWORD dwAddressID,
|
|
LPLINEADDRESSSTATUS lpAddressStatus
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
|
|
|
|
if ((lResult = PrepareSyncRequest(
|
|
OID_TAPI_GET_ADDRESS_STATUS, // opcode
|
|
(LPDWORD) &hdLine, // target handle
|
|
HT_HDLINE, // target handle type
|
|
&pNdisTapiRequest, // ptr to ptr to request buffer
|
|
sizeof(NDIS_TAPI_GET_ADDRESS_STATUS) + // size of drv request data
|
|
(lpAddressStatus->dwTotalSize - sizeof(LINE_ADDRESS_STATUS))
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PLINE_ADDRESS_STATUS pStatus;
|
|
PNDIS_TAPI_GET_ADDRESS_STATUS pNdisTapiGetAddressStatus =
|
|
(PNDIS_TAPI_GET_ADDRESS_STATUS) pNdisTapiRequest->Data;
|
|
|
|
|
|
pNdisTapiGetAddressStatus->hdLine = (HDRV_LINE) hdLine;
|
|
pNdisTapiGetAddressStatus->ulAddressID = (ULONG) dwAddressID;
|
|
|
|
pStatus = &pNdisTapiGetAddressStatus->LineAddressStatus;
|
|
|
|
pStatus->ulTotalSize = (ULONG) lpAddressStatus->dwTotalSize;
|
|
pStatus->ulNeededSize =
|
|
pStatus->ulUsedSize = sizeof (LINE_ADDRESS_STATUS);
|
|
|
|
ZeroMemory(
|
|
&pStatus->ulNumInUse,
|
|
sizeof (LINE_ADDRESS_STATUS) - 3 * sizeof (ULONG)
|
|
);
|
|
|
|
if ((lResult = SyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_QUERY_INFO,
|
|
pNdisTapiRequest
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
CopyMemory(
|
|
lpAddressStatus,
|
|
&pNdisTapiGetAddressStatus->LineAddressStatus,
|
|
pNdisTapiGetAddressStatus->LineAddressStatus.ulUsedSize
|
|
);
|
|
}
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetCallAddressID(
|
|
HDRVCALL hdCall,
|
|
LPDWORD lpdwAddressID
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
|
|
|
|
if ((lResult = PrepareSyncRequest(
|
|
OID_TAPI_GET_CALL_ADDRESS_ID, // opcode
|
|
(LPDWORD) &hdCall, // target handle
|
|
HT_HDCALL, // target handle type
|
|
&pNdisTapiRequest, // ptr to ptr to request buffer
|
|
sizeof(NDIS_TAPI_GET_CALL_ADDRESS_ID) // size of drv request data
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PNDIS_TAPI_GET_CALL_ADDRESS_ID pNdisTapiGetCallAddressID =
|
|
(PNDIS_TAPI_GET_CALL_ADDRESS_ID) pNdisTapiRequest->Data;
|
|
|
|
|
|
pNdisTapiGetCallAddressID->hdCall = (HDRV_CALL) hdCall;
|
|
|
|
if ((lResult = SyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_QUERY_INFO,
|
|
pNdisTapiRequest
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
*lpdwAddressID = (DWORD) pNdisTapiGetCallAddressID->ulAddressID;
|
|
}
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetCallInfo(
|
|
HDRVCALL hdCall,
|
|
LPLINECALLINFO lpCallInfo
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
|
|
|
|
if ((lResult = PrepareSyncRequest(
|
|
OID_TAPI_GET_CALL_INFO, // opcode
|
|
(LPDWORD) &hdCall, // target handle
|
|
HT_HDCALL, // target handle type
|
|
&pNdisTapiRequest, // ptr to ptr to request buffer
|
|
sizeof(NDIS_TAPI_GET_CALL_INFO) + // size of driver request data
|
|
(lpCallInfo->dwTotalSize - sizeof(LINE_CALL_INFO))
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PLINE_CALL_INFO pInfo;
|
|
PNDIS_TAPI_GET_CALL_INFO pNdisTapiGetCallInfo =
|
|
(PNDIS_TAPI_GET_CALL_INFO) pNdisTapiRequest->Data;
|
|
|
|
|
|
pNdisTapiGetCallInfo->hdCall = (HDRV_CALL) hdCall;
|
|
|
|
pInfo = &pNdisTapiGetCallInfo->LineCallInfo;
|
|
|
|
pInfo->ulTotalSize = (ULONG) lpCallInfo->dwTotalSize;
|
|
pInfo->ulNeededSize =
|
|
pInfo->ulUsedSize = sizeof (LINE_CALL_INFO);
|
|
|
|
ZeroMemory(
|
|
&pInfo->hLine,
|
|
sizeof (LINE_CALL_INFO) - 3 * sizeof (ULONG)
|
|
);
|
|
|
|
if ((lResult = SyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_QUERY_INFO,
|
|
pNdisTapiRequest
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
//
|
|
// 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"
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetCallStatus(
|
|
HDRVCALL hdCall,
|
|
LPLINECALLSTATUS lpCallStatus
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
|
|
|
|
if ((lResult = PrepareSyncRequest(
|
|
OID_TAPI_GET_CALL_STATUS, // opcode
|
|
(LPDWORD) &hdCall, // target handle
|
|
HT_HDCALL, // target handle type
|
|
&pNdisTapiRequest, // ptr to ptr to request buffer
|
|
sizeof(NDIS_TAPI_GET_CALL_STATUS) + // size of driver request data
|
|
(lpCallStatus->dwTotalSize - sizeof(LINE_CALL_STATUS))
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PLINE_CALL_STATUS pStatus;
|
|
PNDIS_TAPI_GET_CALL_STATUS pNdisTapiGetCallStatus =
|
|
(PNDIS_TAPI_GET_CALL_STATUS) pNdisTapiRequest->Data;
|
|
|
|
|
|
pNdisTapiGetCallStatus->hdCall = (HDRV_CALL) hdCall;
|
|
|
|
pStatus = &pNdisTapiGetCallStatus->LineCallStatus;
|
|
|
|
pStatus->ulTotalSize = (ULONG) lpCallStatus->dwTotalSize;
|
|
pStatus->ulNeededSize =
|
|
pStatus->ulUsedSize = sizeof (LINE_CALL_STATUS);
|
|
|
|
ZeroMemory(
|
|
&pStatus->ulCallState,
|
|
sizeof (LINE_CALL_STATUS) - 3 * sizeof (ULONG)
|
|
);
|
|
|
|
if ((lResult = SyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_QUERY_INFO,
|
|
pNdisTapiRequest
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
//
|
|
// 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"
|
|
);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetDevCaps(
|
|
DWORD dwDeviceID,
|
|
DWORD dwTSPIVersion,
|
|
DWORD dwExtVersion,
|
|
LPLINEDEVCAPS lpLineDevCaps
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
|
|
|
|
if ((lResult = PrepareSyncRequest(
|
|
OID_TAPI_GET_DEV_CAPS, // opcode
|
|
&dwDeviceID, // target handle
|
|
HT_DEVICEID, // target handle type
|
|
&pNdisTapiRequest, // ptr to ptr to request buffer
|
|
sizeof(NDIS_TAPI_GET_DEV_CAPS) + // size of driver request data
|
|
(lpLineDevCaps->dwTotalSize - sizeof(LINE_DEV_CAPS))
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PLINE_DEV_CAPS pCaps;
|
|
PNDIS_TAPI_GET_DEV_CAPS pNdisTapiGetDevCaps =
|
|
(PNDIS_TAPI_GET_DEV_CAPS) pNdisTapiRequest->Data;
|
|
|
|
|
|
pNdisTapiGetDevCaps->ulDeviceID = (ULONG) dwDeviceID;
|
|
pNdisTapiGetDevCaps->ulExtVersion = (ULONG) dwExtVersion;
|
|
|
|
pCaps = &pNdisTapiGetDevCaps->LineDevCaps;
|
|
|
|
pCaps->ulTotalSize = (ULONG) lpLineDevCaps->dwTotalSize;
|
|
pCaps->ulNeededSize =
|
|
pCaps->ulUsedSize = sizeof (LINE_DEV_CAPS);
|
|
|
|
ZeroMemory(
|
|
&pCaps->ulProviderInfoSize,
|
|
sizeof (LINE_DEV_CAPS) - 3 * sizeof (ULONG)
|
|
);
|
|
|
|
if ((lResult = SyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_QUERY_INFO,
|
|
pNdisTapiRequest
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
lpLineDevCaps->dwNeededSize =
|
|
pCaps->ulNeededSize +
|
|
(sizeof (LINEDEVCAPS) - // v2.0 struct
|
|
sizeof (LINE_DEV_CAPS)) + // v1.0 struct
|
|
(pCaps->ulNeededSize - sizeof (LINE_DEV_CAPS));
|
|
|
|
|
|
//
|
|
// Copy over the fixed fields that don't need changing,
|
|
// i.e. everything from dwPermanentLineID to dwNumTerminals
|
|
//
|
|
|
|
CopyMemory(
|
|
&lpLineDevCaps->dwPermanentLineID,
|
|
&pCaps->ulPermanentLineID,
|
|
sizeof (LINE_DEV_CAPS) - (14 * sizeof (DWORD))
|
|
);
|
|
|
|
if (lpLineDevCaps->dwNeededSize > lpLineDevCaps->dwTotalSize)
|
|
{
|
|
lpLineDevCaps->dwUsedSize =
|
|
(lpLineDevCaps->dwTotalSize < sizeof (LINEDEVCAPS) ?
|
|
lpLineDevCaps->dwTotalSize : sizeof (LINEDEVCAPS));
|
|
|
|
lpLineDevCaps->dwLineNameSize =
|
|
lpLineDevCaps->dwLineNameOffset = 0;
|
|
}
|
|
else
|
|
{
|
|
lpLineDevCaps->dwUsedSize = sizeof (LINEDEVCAPS);
|
|
// v2.0 struct
|
|
|
|
INSERTVARDATASTRING(
|
|
pCaps,
|
|
&pCaps->ulProviderInfoSize,
|
|
lpLineDevCaps,
|
|
&lpLineDevCaps->dwProviderInfoSize,
|
|
sizeof (LINE_DEV_CAPS),
|
|
"LINE_DEV_CAPS.ProviderInfo"
|
|
);
|
|
|
|
INSERTVARDATASTRING(
|
|
pCaps,
|
|
&pCaps->ulSwitchInfoSize,
|
|
lpLineDevCaps,
|
|
&lpLineDevCaps->dwSwitchInfoSize,
|
|
sizeof (LINE_DEV_CAPS),
|
|
"LINE_DEV_CAPS.SwitchInfo"
|
|
);
|
|
|
|
INSERTVARDATASTRING(
|
|
pCaps,
|
|
&pCaps->ulLineNameSize,
|
|
lpLineDevCaps,
|
|
&lpLineDevCaps->dwLineNameSize,
|
|
sizeof (LINE_DEV_CAPS),
|
|
"LINE_DEV_CAPS.LineName"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pCaps,
|
|
&pCaps->ulTerminalCapsSize,
|
|
lpLineDevCaps,
|
|
&lpLineDevCaps->dwTerminalCapsSize,
|
|
sizeof (LINE_DEV_CAPS),
|
|
"LINE_DEV_CAPS.TerminalCaps"
|
|
);
|
|
|
|
// BUGBUG TSPI_lineGetDevCaps: convert DevCaps.TermText to unicode???
|
|
|
|
lpLineDevCaps->dwTerminalTextEntrySize =
|
|
pCaps->ulTerminalTextEntrySize;
|
|
|
|
INSERTVARDATA(
|
|
pCaps,
|
|
&pCaps->ulTerminalTextSize,
|
|
lpLineDevCaps,
|
|
&lpLineDevCaps->dwTerminalTextSize,
|
|
sizeof (LINE_DEV_CAPS),
|
|
"LINE_DEV_CAPS.TerminalText"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pCaps,
|
|
&pCaps->ulDevSpecificSize,
|
|
lpLineDevCaps,
|
|
&lpLineDevCaps->dwDevSpecificSize,
|
|
sizeof (LINE_DEV_CAPS),
|
|
"LINE_DEV_CAPS.DevSpecific"
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetDevConfig(
|
|
DWORD dwDeviceID,
|
|
LPVARSTRING lpDeviceConfig,
|
|
LPCWSTR lpszDeviceClass
|
|
)
|
|
{
|
|
LONG lResult;
|
|
DWORD dwLength = lstrlenW (lpszDeviceClass) + 1;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
|
|
|
|
if ((lResult = PrepareSyncRequest(
|
|
OID_TAPI_GET_DEV_CONFIG, // opcode
|
|
&dwDeviceID, // target handle
|
|
HT_DEVICEID, // target handle type
|
|
&pNdisTapiRequest, // ptr to ptr to request buffer
|
|
sizeof(NDIS_TAPI_GET_DEV_CONFIG) + // size of driver request data
|
|
(lpDeviceConfig->dwTotalSize - sizeof(VAR_STRING)) + dwLength
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PVAR_STRING pConfig;
|
|
PNDIS_TAPI_GET_DEV_CONFIG pNdisTapiGetDevConfig =
|
|
(PNDIS_TAPI_GET_DEV_CONFIG) pNdisTapiRequest->Data;
|
|
|
|
|
|
pNdisTapiGetDevConfig->ulDeviceID = (ULONG) dwDeviceID;
|
|
pNdisTapiGetDevConfig->ulDeviceClassSize = (ULONG) dwLength;
|
|
pNdisTapiGetDevConfig->ulDeviceClassOffset = (ULONG)
|
|
sizeof(NDIS_TAPI_GET_DEV_CONFIG) +
|
|
(lpDeviceConfig->dwTotalSize - sizeof(VAR_STRING));
|
|
|
|
pConfig = &pNdisTapiGetDevConfig->DeviceConfig;
|
|
|
|
pConfig->ulTotalSize = (ULONG) 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
|
|
);
|
|
|
|
if ((lResult = SyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_QUERY_INFO,
|
|
pNdisTapiRequest
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
CopyMemory(
|
|
lpDeviceConfig,
|
|
&pNdisTapiGetDevConfig->DeviceConfig,
|
|
pNdisTapiGetDevConfig->DeviceConfig.ulUsedSize
|
|
);
|
|
}
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetExtensionID(
|
|
DWORD dwDeviceID,
|
|
DWORD dwTSPIVersion,
|
|
LPLINEEXTENSIONID lpExtensionID
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
|
|
|
|
if ((lResult = PrepareSyncRequest(
|
|
OID_TAPI_GET_EXTENSION_ID, // opcode
|
|
&dwDeviceID, // target handle
|
|
HT_DEVICEID, // target handle type
|
|
&pNdisTapiRequest, // ptr to ptr to request buffer
|
|
sizeof(NDIS_TAPI_GET_EXTENSION_ID) // size of driver request data
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PNDIS_TAPI_GET_EXTENSION_ID pNdisTapiGetExtensionID =
|
|
(PNDIS_TAPI_GET_EXTENSION_ID) pNdisTapiRequest->Data;
|
|
|
|
|
|
pNdisTapiGetExtensionID->ulDeviceID = (ULONG) dwDeviceID;
|
|
|
|
if ((lResult = SyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_QUERY_INFO,
|
|
pNdisTapiRequest
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
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)
|
|
);
|
|
|
|
lResult = TAPI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetID(
|
|
HDRVLINE hdLine,
|
|
DWORD dwAddressID,
|
|
HDRVCALL hdCall,
|
|
DWORD dwSelect,
|
|
LPVARSTRING lpDeviceID,
|
|
LPCWSTR lpszDeviceClass,
|
|
HANDLE hTargetProcess
|
|
)
|
|
{
|
|
LONG lResult;
|
|
DWORD dwLength = lstrlenW (lpszDeviceClass) + 1;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
|
|
|
|
if ((lResult = PrepareSyncRequest(
|
|
OID_TAPI_GET_ID, // opcode
|
|
(LPDWORD)(dwSelect == LINECALLSELECT_CALL ? // target handle
|
|
(LPDWORD) &hdCall : (LPDWORD) &hdLine),
|
|
(dwSelect == LINECALLSELECT_CALL ? // target handle type
|
|
HT_HDCALL : HT_HDLINE),
|
|
&pNdisTapiRequest, // ptr to ptr to request buffer
|
|
sizeof(NDIS_TAPI_GET_ID) + // size of driver request data
|
|
(lpDeviceID->dwTotalSize - sizeof(VAR_STRING)) + dwLength
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PVAR_STRING pID;
|
|
PNDIS_TAPI_GET_ID pNdisTapiGetID =
|
|
(PNDIS_TAPI_GET_ID) pNdisTapiRequest->Data;
|
|
|
|
|
|
pNdisTapiGetID->hdLine = (HDRV_LINE) hdLine;
|
|
pNdisTapiGetID->ulAddressID = (ULONG) dwAddressID;
|
|
pNdisTapiGetID->hdCall = (HDRV_CALL) hdCall;
|
|
pNdisTapiGetID->ulSelect = (ULONG) dwSelect;
|
|
pNdisTapiGetID->ulDeviceClassSize = (ULONG) dwLength;
|
|
pNdisTapiGetID->ulDeviceClassOffset = (ULONG)
|
|
sizeof(NDIS_TAPI_GET_ID) +
|
|
(lpDeviceID->dwTotalSize - sizeof(VAR_STRING));
|
|
|
|
pID = &pNdisTapiGetID->DeviceID;
|
|
|
|
pID->ulTotalSize = (ULONG) 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
|
|
);
|
|
|
|
if ((lResult = SyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_QUERY_INFO,
|
|
pNdisTapiRequest
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
CopyMemory(
|
|
lpDeviceID,
|
|
&pNdisTapiGetID->DeviceID,
|
|
pNdisTapiGetID->DeviceID.ulUsedSize
|
|
);
|
|
}
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetLineDevStatus(
|
|
HDRVLINE hdLine,
|
|
LPLINEDEVSTATUS lpLineDevStatus
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
|
|
|
|
if ((lResult = PrepareSyncRequest(
|
|
OID_TAPI_GET_LINE_DEV_STATUS, // opcode
|
|
(LPDWORD) &hdLine, // target handle
|
|
HT_HDLINE, // target handle type
|
|
&pNdisTapiRequest, // ptr to ptr to request buffer
|
|
sizeof(NDIS_TAPI_GET_LINE_DEV_STATUS) + // size of drv request data
|
|
(lpLineDevStatus->dwTotalSize - sizeof(LINE_DEV_STATUS))
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PLINE_DEV_STATUS pStatus;
|
|
PNDIS_TAPI_GET_LINE_DEV_STATUS pNdisTapiGetLineDevStatus =
|
|
(PNDIS_TAPI_GET_LINE_DEV_STATUS) pNdisTapiRequest->Data;
|
|
|
|
|
|
pNdisTapiGetLineDevStatus->hdLine = (HDRV_LINE) hdLine;
|
|
|
|
pStatus = &pNdisTapiGetLineDevStatus->LineDevStatus;
|
|
|
|
pStatus->ulTotalSize = (ULONG) lpLineDevStatus->dwTotalSize;
|
|
pStatus->ulNeededSize =
|
|
pStatus->ulUsedSize = sizeof (LINE_DEV_STATUS);
|
|
|
|
ZeroMemory(
|
|
&pStatus->ulNumOpens,
|
|
sizeof (LINE_DEV_STATUS) - 3 * sizeof (ULONG)
|
|
);
|
|
|
|
if ((lResult = SyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_QUERY_INFO,
|
|
pNdisTapiRequest
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
//
|
|
// 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"
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetNumAddressIDs(
|
|
HDRVLINE hdLine,
|
|
LPDWORD lpdwNumAddressIDs
|
|
)
|
|
{
|
|
//
|
|
// Since there isn't an OID_TAPI_GET_NUM_ADDRESS_IDS at this point
|
|
// we need to synthesize it by getting the dev caps and looking at
|
|
// the dwNumAddresses field of that structure. We first do this
|
|
// with a fixed size (+) structure, then if that doesn't cut it
|
|
// (i.e. the provider hasn't chg'd the dwNumAddresses field) we
|
|
// alloc a larger buffer (as per the returned dwNeededSize field)
|
|
// and try again. If we get an error along the way we just return
|
|
// 1 address- kludgy, but say "la vee".
|
|
//
|
|
// Note that we use the (P)LINE_DEV_CAPS types from ndistapi.h.
|
|
//
|
|
|
|
BOOL bTryAgain = TRUE;
|
|
DWORD dwTotalSize = sizeof (LINE_DEV_CAPS) + 128;
|
|
PDRVLINE pLine = (PDRVLINE) hdLine;
|
|
PLINE_DEV_CAPS pLineDevCaps;
|
|
|
|
|
|
TSPI_lineGetNumAddressIDs_allocBuffer:
|
|
|
|
if ((pLineDevCaps = DrvAlloc (dwTotalSize)))
|
|
{
|
|
pLineDevCaps->ulTotalSize = dwTotalSize;
|
|
pLineDevCaps->ulNeededSize =
|
|
pLineDevCaps->ulUsedSize = sizeof (LINE_DEV_CAPS);
|
|
|
|
if (TSPI_lineGetDevCaps(
|
|
pLine->dwDeviceID,
|
|
0x10003,
|
|
0,
|
|
(LPLINEDEVCAPS) pLineDevCaps
|
|
|
|
) == 0)
|
|
{
|
|
DWORD dwNumAddresses = (DWORD) pLineDevCaps->ulNumAddresses,
|
|
dwNeededSize = (DWORD) pLineDevCaps->ulNeededSize;
|
|
|
|
|
|
DrvFree (pLineDevCaps);
|
|
|
|
if (dwNumAddresses != 0)
|
|
{
|
|
*lpdwNumAddressIDs = dwNumAddresses;
|
|
|
|
return 0;
|
|
}
|
|
else if (bTryAgain && (dwNeededSize > dwTotalSize))
|
|
{
|
|
dwTotalSize = dwNeededSize;
|
|
|
|
bTryAgain = FALSE;
|
|
|
|
goto TSPI_lineGetNumAddressIDs_allocBuffer;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DrvFree (pLineDevCaps);
|
|
}
|
|
}
|
|
|
|
*lpdwNumAddressIDs = 1; // if here an error occured, default to 1 addr
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
LONG
|
|
PASCAL
|
|
TSPI_lineMakeCall_postProcess(
|
|
PASYNC_REQUEST_WRAPPER pAsyncRequestWrapper,
|
|
LONG lResult,
|
|
LPDWORD callStateMsgParams
|
|
)
|
|
{
|
|
PDRVCALL pCall = (PDRVCALL) pAsyncRequestWrapper->dwRequestSpecific;
|
|
|
|
|
|
if (lResult == TAPI_SUCCESS)
|
|
{
|
|
PNDIS_TAPI_MAKE_CALL pNdisTapiMakeCall = (PNDIS_TAPI_MAKE_CALL)
|
|
pAsyncRequestWrapper->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) ((PDRVLINE) pCall->pLine)->htLine;
|
|
callStateMsgParams[1] = (DWORD) pCall->htCall;
|
|
callStateMsgParams[2] = pCall->dwPendingCallState;
|
|
callStateMsgParams[3] = pCall->dwPendingCallStateMode;
|
|
callStateMsgParams[4] = pCall->dwPendingMediaMode;
|
|
}
|
|
|
|
pCall->hd_Call = pNdisTapiMakeCall->hdCall;
|
|
pCall->bIncomplete = FALSE;
|
|
}
|
|
else
|
|
{
|
|
pCall->dwKey = INVALID_KEY;
|
|
DrvFree (pCall);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineMakeCall(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVLINE hdLine,
|
|
HTAPICALL htCall,
|
|
LPHDRVCALL lphdCall,
|
|
LPCWSTR lpszDestAddress,
|
|
DWORD dwCountryCode,
|
|
LPLINECALLPARAMS const lpCallParams
|
|
)
|
|
{
|
|
LONG lResult;
|
|
DWORD dwLength;
|
|
PDRVCALL pCall;
|
|
PASYNC_REQUEST_WRAPPER pAsyncRequestWrapper;
|
|
|
|
|
|
//
|
|
// First alloc & init a DRVCALL
|
|
//
|
|
|
|
if (!(pCall = DrvAlloc (sizeof(DRVCALL))))
|
|
{
|
|
return LINEERR_NOMEM;
|
|
}
|
|
|
|
pCall->dwKey = OUTBOUND_CALL_KEY;
|
|
pCall->dwDeviceID = ((PDRVLINE) hdLine)->dwDeviceID;
|
|
pCall->htCall = htCall;
|
|
pCall->pLine = (LPVOID) hdLine;
|
|
pCall->bIncomplete = TRUE;
|
|
|
|
|
|
//
|
|
// Init the request
|
|
//
|
|
|
|
dwLength = (lpszDestAddress ? lstrlenW (lpszDestAddress) + 1 : 0);
|
|
|
|
if ((lResult = PrepareAsyncRequest(
|
|
OID_TAPI_MAKE_CALL, // opcode
|
|
(LPDWORD) &hdLine, // target handle
|
|
HT_HDLINE, // target handle type
|
|
dwRequestID, // request id
|
|
&pAsyncRequestWrapper, // ptr to ptr to request buffer
|
|
sizeof(NDIS_TAPI_MAKE_CALL) + // size of drv request data
|
|
dwLength + (lpCallParams ?
|
|
(lpCallParams->dwTotalSize - sizeof(LINE_CALL_PARAMS)) : 0)
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PNDIS_TAPI_MAKE_CALL pNdisTapiMakeCall = (PNDIS_TAPI_MAKE_CALL)
|
|
pAsyncRequestWrapper->NdisTapiRequest.Data;
|
|
|
|
|
|
pNdisTapiMakeCall->hdLine = (HDRV_LINE) hdLine;
|
|
pNdisTapiMakeCall->htCall = (HTAPI_CALL) pCall;
|
|
|
|
pNdisTapiMakeCall->ulDestAddressSize = (ULONG) dwLength;
|
|
|
|
if (lpszDestAddress)
|
|
{
|
|
pNdisTapiMakeCall->ulDestAddressOffset =
|
|
sizeof(NDIS_TAPI_MAKE_CALL) +
|
|
(lpCallParams ? (lpCallParams->dwTotalSize -
|
|
sizeof(LINE_CALL_PARAMS)) : 0);
|
|
|
|
//
|
|
// Note: old miniports expect strings to be ascii
|
|
//
|
|
|
|
WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
lpszDestAddress,
|
|
dwLength,
|
|
(LPSTR) (((LPBYTE) pNdisTapiMakeCall) +
|
|
pNdisTapiMakeCall->ulDestAddressOffset),
|
|
dwLength,
|
|
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;
|
|
}
|
|
|
|
pAsyncRequestWrapper->dwRequestSpecific = (DWORD) pCall;
|
|
pAsyncRequestWrapper->pfnPostProcess = TSPI_lineMakeCall_postProcess;
|
|
|
|
*lphdCall = (HDRVCALL) pCall;
|
|
|
|
lResult = AsyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_QUERY_INFO,
|
|
pAsyncRequestWrapper
|
|
);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineNegotiateExtVersion(
|
|
DWORD dwDeviceID,
|
|
DWORD dwTSPIVersion,
|
|
DWORD dwLowVersion,
|
|
DWORD dwHighVersion,
|
|
LPDWORD lpdwExtVersion
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
|
|
|
|
if ((lResult = PrepareSyncRequest(
|
|
OID_TAPI_NEGOTIATE_EXT_VERSION, // opcode
|
|
(LPDWORD) &dwDeviceID, // target handle
|
|
HT_DEVICEID, // target handle type
|
|
&pNdisTapiRequest, // ptr to ptr to request buffer
|
|
sizeof(NDIS_TAPI_NEGOTIATE_EXT_VERSION) // size of drv req data
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PNDIS_TAPI_NEGOTIATE_EXT_VERSION pNdisTapiNegotiateExtVersion =
|
|
(PNDIS_TAPI_NEGOTIATE_EXT_VERSION) pNdisTapiRequest->Data;
|
|
|
|
|
|
pNdisTapiNegotiateExtVersion->ulDeviceID = (ULONG) dwDeviceID;
|
|
pNdisTapiNegotiateExtVersion->ulLowVersion = (ULONG) dwLowVersion;
|
|
pNdisTapiNegotiateExtVersion->ulHighVersion = (ULONG) dwHighVersion;
|
|
|
|
|
|
if ((lResult = SyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_QUERY_INFO,
|
|
pNdisTapiRequest
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
*lpdwExtVersion = pNdisTapiNegotiateExtVersion->ulExtVersion;
|
|
}
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineNegotiateTSPIVersion(
|
|
DWORD dwDeviceID,
|
|
DWORD dwLowVersion,
|
|
DWORD dwHighVersion,
|
|
LPDWORD lpdwTSPIVersion
|
|
)
|
|
{
|
|
*lpdwTSPIVersion = 0x00010003; // until the ndistapi spec widened
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineOpen(
|
|
DWORD dwDeviceID,
|
|
HTAPILINE htLine,
|
|
LPHDRVLINE lphdLine,
|
|
DWORD dwTSPIVersion,
|
|
LINEEVENT lpfnEventProc
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PDRVLINE pLine;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
|
|
|
|
|
|
//
|
|
// First alloc & init a DRVLINE
|
|
//
|
|
|
|
if (!(pLine = DrvAlloc (sizeof(DRVLINE))))
|
|
{
|
|
return LINEERR_NOMEM;
|
|
}
|
|
|
|
pLine->dwKey = LINE_KEY;
|
|
pLine->dwDeviceID = dwDeviceID;
|
|
pLine->htLine = htLine;
|
|
|
|
|
|
//
|
|
// Init the request
|
|
//
|
|
|
|
if ((lResult = PrepareSyncRequest(
|
|
OID_TAPI_OPEN, // opcode
|
|
(LPDWORD) &dwDeviceID, // target handle
|
|
HT_DEVICEID, // target handle type
|
|
&pNdisTapiRequest, // ptr to ptr to request buffer
|
|
sizeof(NDIS_TAPI_OPEN) // size of drve req data
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PNDIS_TAPI_OPEN pNdisTapiOpen =
|
|
(PNDIS_TAPI_OPEN) pNdisTapiRequest->Data;
|
|
|
|
|
|
pNdisTapiOpen->ulDeviceID = (ULONG) dwDeviceID;
|
|
pNdisTapiOpen->htLine = (HTAPI_LINE) pLine;
|
|
|
|
|
|
if ((lResult = SyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_QUERY_INFO,
|
|
pNdisTapiRequest
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
pLine->hd_Line = pNdisTapiOpen->hdLine;
|
|
|
|
*lphdLine = (HDRVLINE) pLine;
|
|
}
|
|
else
|
|
{
|
|
DrvFree (pLine);
|
|
}
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSecureCall(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVCALL hdCall
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PASYNC_REQUEST_WRAPPER pAsyncRequestWrapper;
|
|
|
|
|
|
if ((lResult = PrepareAsyncRequest(
|
|
OID_TAPI_SECURE_CALL, // opcode
|
|
(LPDWORD) &hdCall, // target handle
|
|
HT_HDCALL, // target handle type
|
|
dwRequestID, // request id
|
|
&pAsyncRequestWrapper, // ptr to ptr to request buffer
|
|
sizeof(NDIS_TAPI_SECURE_CALL) // size of drv request data
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PNDIS_TAPI_SECURE_CALL pNdisTapiSecureCall =
|
|
(PNDIS_TAPI_SECURE_CALL)
|
|
pAsyncRequestWrapper->NdisTapiRequest.Data;
|
|
|
|
|
|
pNdisTapiSecureCall->hdCall = (HDRV_CALL) hdCall;
|
|
|
|
lResult = AsyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_SET_INFO,
|
|
pAsyncRequestWrapper
|
|
);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSelectExtVersion(
|
|
HDRVLINE hdLine,
|
|
DWORD dwExtVersion
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
|
|
|
|
if ((lResult = PrepareSyncRequest(
|
|
OID_TAPI_SELECT_EXT_VERSION, // opcode
|
|
(LPDWORD) &hdLine, // target handle
|
|
HT_HDLINE, // target handle type
|
|
&pNdisTapiRequest, // ptr to ptr to request buffer
|
|
sizeof(NDIS_TAPI_SELECT_EXT_VERSION) // size of drve req data
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PNDIS_TAPI_SELECT_EXT_VERSION pNdisTapiSelectExtVersion =
|
|
(PNDIS_TAPI_SELECT_EXT_VERSION) pNdisTapiRequest->Data;
|
|
|
|
|
|
pNdisTapiSelectExtVersion->hdLine = (HDRV_LINE) hdLine;
|
|
pNdisTapiSelectExtVersion->ulExtVersion = (ULONG) dwExtVersion;
|
|
|
|
lResult = SyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_SET_INFO,
|
|
pNdisTapiRequest
|
|
);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSendUserUserInfo(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVCALL hdCall,
|
|
LPCSTR lpsUserUserInfo,
|
|
DWORD dwSize
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PASYNC_REQUEST_WRAPPER pAsyncRequestWrapper;
|
|
|
|
|
|
if ((lResult = PrepareAsyncRequest(
|
|
OID_TAPI_SEND_USER_USER_INFO, // opcode
|
|
(LPDWORD) &hdCall, // target handle
|
|
HT_HDCALL, // target handle type
|
|
dwRequestID, // request id
|
|
&pAsyncRequestWrapper, // ptr to ptr to request buffer
|
|
sizeof(NDIS_TAPI_SEND_USER_USER_INFO) + // size of drv request data
|
|
dwSize
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PNDIS_TAPI_SEND_USER_USER_INFO pNdisTapiSendUserUserInfo =
|
|
(PNDIS_TAPI_SEND_USER_USER_INFO)
|
|
pAsyncRequestWrapper->NdisTapiRequest.Data;
|
|
|
|
|
|
pNdisTapiSendUserUserInfo->hdCall = (HDRV_CALL) hdCall;
|
|
|
|
if ((pNdisTapiSendUserUserInfo->ulUserUserInfoSize = (ULONG) dwSize))
|
|
{
|
|
CopyMemory(
|
|
pNdisTapiSendUserUserInfo->UserUserInfo,
|
|
lpsUserUserInfo,
|
|
dwSize
|
|
);
|
|
}
|
|
|
|
lResult = AsyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_SET_INFO,
|
|
pAsyncRequestWrapper
|
|
);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSetAppSpecific(
|
|
HDRVCALL hdCall,
|
|
DWORD dwAppSpecific
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
|
|
|
|
if ((lResult = PrepareSyncRequest(
|
|
OID_TAPI_SET_APP_SPECIFIC, // opcode
|
|
(LPDWORD) &hdCall, // target handle
|
|
HT_HDCALL, // target handle type
|
|
&pNdisTapiRequest, // ptr to ptr to request buffer
|
|
sizeof(NDIS_TAPI_SET_APP_SPECIFIC) // size of driver request data
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PNDIS_TAPI_SET_APP_SPECIFIC pNdisTapiSetAppSpecific =
|
|
(PNDIS_TAPI_SET_APP_SPECIFIC) pNdisTapiRequest->Data;
|
|
|
|
|
|
pNdisTapiSetAppSpecific->hdCall = (HDRV_CALL) hdCall;
|
|
pNdisTapiSetAppSpecific->ulAppSpecific = (ULONG) dwAppSpecific;
|
|
|
|
lResult = SyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_SET_INFO,
|
|
pNdisTapiRequest
|
|
);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSetCallParams(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVCALL hdCall,
|
|
DWORD dwBearerMode,
|
|
DWORD dwMinRate,
|
|
DWORD dwMaxRate,
|
|
LPLINEDIALPARAMS const lpDialParams
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PASYNC_REQUEST_WRAPPER pAsyncRequestWrapper;
|
|
|
|
|
|
if ((lResult = PrepareAsyncRequest(
|
|
OID_TAPI_SET_CALL_PARAMS, // opcode
|
|
(LPDWORD) &hdCall, // target handle
|
|
HT_HDCALL, // target handle type
|
|
dwRequestID, // request id
|
|
&pAsyncRequestWrapper, // ptr to ptr to request buffer
|
|
sizeof(NDIS_TAPI_SET_CALL_PARAMS) // size of drv request data
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PNDIS_TAPI_SET_CALL_PARAMS pNdisTapiSetCallParams =
|
|
(PNDIS_TAPI_SET_CALL_PARAMS)
|
|
pAsyncRequestWrapper->NdisTapiRequest.Data;
|
|
|
|
|
|
pNdisTapiSetCallParams->hdCall = (HDRV_CALL) hdCall;
|
|
pNdisTapiSetCallParams->ulBearerMode = (ULONG) dwBearerMode;
|
|
pNdisTapiSetCallParams->ulMinRate = (ULONG) dwMinRate;
|
|
pNdisTapiSetCallParams->ulMaxRate = (ULONG) dwMaxRate;
|
|
|
|
if (lpDialParams)
|
|
{
|
|
pNdisTapiSetCallParams->bSetLineDialParams = TRUE;
|
|
|
|
CopyMemory(
|
|
&pNdisTapiSetCallParams->LineDialParams,
|
|
lpDialParams,
|
|
sizeof(LINE_DIAL_PARAMS)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
pNdisTapiSetCallParams->bSetLineDialParams = FALSE;
|
|
}
|
|
|
|
lResult = AsyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_SET_INFO,
|
|
pAsyncRequestWrapper
|
|
);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSetDefaultMediaDetection(
|
|
HDRVLINE hdLine,
|
|
DWORD dwMediaModes
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
|
|
|
|
if ((lResult =PrepareSyncRequest(
|
|
OID_TAPI_SET_DEFAULT_MEDIA_DETECTION, // opcode
|
|
(LPDWORD) &hdLine, // target handle
|
|
HT_HDLINE, // target handle type
|
|
&pNdisTapiRequest, // ptr to ptr to req buffer
|
|
sizeof(NDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION) // sizeof req data
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PNDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION
|
|
pNdisTapiSetDefaultMediaDetection =
|
|
(PNDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION)
|
|
pNdisTapiRequest->Data;
|
|
|
|
|
|
pNdisTapiSetDefaultMediaDetection->hdLine = (HDRV_LINE) hdLine;
|
|
pNdisTapiSetDefaultMediaDetection->ulMediaModes = (ULONG) dwMediaModes;
|
|
|
|
lResult = SyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_SET_INFO,
|
|
pNdisTapiRequest
|
|
);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSetDevConfig(
|
|
DWORD dwDeviceID,
|
|
LPVOID const lpDeviceConfig,
|
|
DWORD dwSize,
|
|
LPCWSTR lpszDeviceClass
|
|
)
|
|
{
|
|
LONG lResult;
|
|
DWORD dwLength = lstrlenW (lpszDeviceClass) + 1;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
|
|
|
|
if ((lResult =PrepareSyncRequest(
|
|
OID_TAPI_SET_DEV_CONFIG, // opcode
|
|
&dwDeviceID, // target handle
|
|
HT_DEVICEID, // target handle type
|
|
&pNdisTapiRequest, // ptr to ptr to req buffer
|
|
sizeof(NDIS_TAPI_SET_DEV_CONFIG) + // sizeof req data
|
|
dwLength + dwSize
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PNDIS_TAPI_SET_DEV_CONFIG pNdisTapiSetDevConfig =
|
|
(PNDIS_TAPI_SET_DEV_CONFIG) pNdisTapiRequest->Data;
|
|
|
|
|
|
pNdisTapiSetDevConfig->ulDeviceID = (ULONG) dwDeviceID;
|
|
pNdisTapiSetDevConfig->ulDeviceClassSize = (ULONG) 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
|
|
);
|
|
|
|
lResult = SyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_SET_INFO,
|
|
pNdisTapiRequest
|
|
);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSetMediaMode(
|
|
HDRVCALL hdCall,
|
|
DWORD dwMediaMode
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
|
|
|
|
if ((lResult = PrepareSyncRequest(
|
|
OID_TAPI_SET_MEDIA_MODE, // opcode
|
|
(LPDWORD) &hdCall, // target handle
|
|
HT_HDCALL, // target handle type
|
|
&pNdisTapiRequest, // ptr to ptr to req buffer
|
|
sizeof(NDIS_TAPI_SET_MEDIA_MODE) // size of drv req data
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PNDIS_TAPI_SET_MEDIA_MODE pNdisTapiSetMediaMode =
|
|
(PNDIS_TAPI_SET_MEDIA_MODE) pNdisTapiRequest->Data;
|
|
|
|
|
|
pNdisTapiSetMediaMode->hdCall = (HDRV_CALL) hdCall;
|
|
pNdisTapiSetMediaMode->ulMediaMode = (ULONG) dwMediaMode;
|
|
|
|
lResult = SyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_SET_INFO,
|
|
pNdisTapiRequest
|
|
);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSetStatusMessages(
|
|
HDRVLINE hdLine,
|
|
DWORD dwLineStates,
|
|
DWORD dwAddressStates
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
|
|
|
|
if ((lResult = PrepareSyncRequest(
|
|
OID_TAPI_SET_STATUS_MESSAGES, // opcode
|
|
(LPDWORD) &hdLine, // target handle
|
|
HT_HDLINE, // target handle type
|
|
&pNdisTapiRequest, // ptr to ptr to req buffer
|
|
sizeof(NDIS_TAPI_SET_STATUS_MESSAGES) // size of drv req data
|
|
|
|
)) == TAPI_SUCCESS)
|
|
{
|
|
PNDIS_TAPI_SET_STATUS_MESSAGES pNdisTapiSetStatusMessages =
|
|
(PNDIS_TAPI_SET_STATUS_MESSAGES) pNdisTapiRequest->Data;
|
|
|
|
|
|
pNdisTapiSetStatusMessages->hdLine = (HDRV_LINE) hdLine;
|
|
pNdisTapiSetStatusMessages->ulLineStates = (ULONG) dwLineStates;
|
|
pNdisTapiSetStatusMessages->ulAddressStates = (ULONG) dwAddressStates;
|
|
|
|
lResult = SyncDriverRequest(
|
|
(DWORD) IOCTL_NDISTAPI_SET_INFO,
|
|
pNdisTapiRequest
|
|
);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// TAPI_providerXxx funcs
|
|
//
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_providerEnumDevices(
|
|
DWORD dwPermanentProviderID,
|
|
LPDWORD lpdwNumLines,
|
|
LPDWORD lpdwNumPhones,
|
|
HPROVIDER hProvider,
|
|
LINEEVENT lpfnLineCreateProc,
|
|
PHONEEVENT lpfnPhoneCreateProc
|
|
)
|
|
{
|
|
//
|
|
// Note: We really enum devs in providerInit, see the
|
|
// special case note there
|
|
//
|
|
|
|
*lpdwNumLines = 0;
|
|
*lpdwNumPhones = 0;
|
|
|
|
gpfnLineEvent = lpfnLineCreateProc;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_providerInit(
|
|
DWORD dwTSPIVersion,
|
|
DWORD dwPermanentProviderID,
|
|
DWORD dwLineDeviceIDBase,
|
|
DWORD dwPhoneDeviceIDBase,
|
|
DWORD dwNumLines,
|
|
DWORD dwNumPhones,
|
|
ASYNC_COMPLETION lpfnCompletionProc,
|
|
LPDWORD lpdwTSPIOptions
|
|
)
|
|
{
|
|
LONG lResult= LINEERR_OPERATIONFAILED;
|
|
char szDeviceName[] = "NDISTAPI";
|
|
char szTargetPath[] = "\\Device\\NdisTapi";
|
|
char szCompleteDeviceName[] = "\\\\.\\NDISTAPI";
|
|
DWORD cbReturned, dwThreadID;
|
|
|
|
|
|
DBGOUT((3, "TSPI_providerInit: enter"));
|
|
|
|
|
|
//
|
|
// 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
|
|
//
|
|
|
|
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)
|
|
{
|
|
DBGOUT((
|
|
0,
|
|
"CreateFile (%s, non-overlapped) failed, err=%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)
|
|
{
|
|
DBGOUT((
|
|
0,
|
|
"CreateFile (%s, overlapped) failed, err=%ld",
|
|
szCompleteDeviceName,
|
|
GetLastError()
|
|
));
|
|
|
|
goto providerInit_error1;
|
|
}
|
|
|
|
|
|
//
|
|
// Create io completion port
|
|
//
|
|
|
|
if ((ghCompletionPort = CreateIoCompletionPort(
|
|
ghDriverAsync,
|
|
NULL,
|
|
0,
|
|
0
|
|
|
|
)) == INVALID_HANDLE_VALUE)
|
|
{
|
|
DBGOUT((
|
|
0,
|
|
"CreateIoCompletionPort failed, err=%ld",
|
|
GetLastError()
|
|
));
|
|
|
|
goto providerInit_error2;
|
|
}
|
|
|
|
|
|
//
|
|
// Connect to driver- we send it a device ID base & it returns
|
|
// the number of devices it supports
|
|
//
|
|
|
|
{
|
|
DWORD adwConnectInfo[2] = { 1, 1 };
|
|
|
|
|
|
if (!DeviceIoControl(
|
|
ghDriverSync,
|
|
(DWORD) IOCTL_NDISTAPI_CONNECT,
|
|
adwConnectInfo, // BUGBUG
|
|
2*sizeof(DWORD),
|
|
&dwLineDeviceIDBase, // BUGBUG
|
|
sizeof(DWORD),
|
|
&cbReturned,
|
|
(LPOVERLAPPED) NULL
|
|
) ||
|
|
|
|
(cbReturned < sizeof(DWORD)))
|
|
{
|
|
DBGOUT((0, "CONNECT failed, err=%ld", GetLastError()));
|
|
|
|
goto providerInit_error3;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Alloc the resources needed by the AsyncEventThread, and then
|
|
// create the thread
|
|
//
|
|
|
|
if ((gpAsyncEventsThreadInfo = (PASYNC_EVENTS_THREAD_INFO)
|
|
DrvAlloc (sizeof(ASYNC_EVENTS_THREAD_INFO))) == NULL)
|
|
{
|
|
goto providerInit_error4;
|
|
}
|
|
|
|
gpAsyncEventsThreadInfo->dwBufSize = INITIAL_TLS_BUF_SIZE;
|
|
|
|
if ((gpAsyncEventsThreadInfo->pBuf1 = (PNDISTAPI_EVENT_DATA)
|
|
DrvAlloc (INITIAL_TLS_BUF_SIZE)) == NULL)
|
|
{
|
|
goto providerInit_error5;
|
|
}
|
|
|
|
if ((gpAsyncEventsThreadInfo->pBuf2 = (PNDISTAPI_EVENT_DATA)
|
|
DrvAlloc (INITIAL_TLS_BUF_SIZE)) == NULL)
|
|
{
|
|
goto providerInit_error6;
|
|
}
|
|
|
|
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)
|
|
{
|
|
DBGOUT((1, "CreateThread (GetAsyncEventsThread) failed"));
|
|
|
|
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) = dwLineDeviceIDBase;
|
|
*((LPDWORD)dwNumPhones) = 0; // BUGBUG until we get OIDs for phones
|
|
|
|
|
|
//
|
|
// If here success
|
|
//
|
|
|
|
gpfnCompletionProc = lpfnCompletionProc;
|
|
|
|
lResult = TAPI_SUCCESS;
|
|
|
|
goto providerInit_return;
|
|
|
|
|
|
//
|
|
// Clean up resources if an error occured & then return
|
|
//
|
|
|
|
providerInit_error7:
|
|
|
|
DrvFree (gpAsyncEventsThreadInfo->pBuf2);
|
|
|
|
providerInit_error6:
|
|
|
|
DrvFree (gpAsyncEventsThreadInfo->pBuf1);
|
|
|
|
providerInit_error5:
|
|
|
|
DrvFree (gpAsyncEventsThreadInfo);
|
|
|
|
providerInit_error4:
|
|
providerInit_error3:
|
|
|
|
CloseHandle (ghCompletionPort);
|
|
|
|
providerInit_error2:
|
|
|
|
CloseHandle (ghDriverAsync);
|
|
|
|
providerInit_error1:
|
|
|
|
CloseHandle (ghDriverSync);
|
|
|
|
providerInit_error0:
|
|
|
|
DefineDosDevice (DDD_REMOVE_DEFINITION, szDeviceName, NULL);
|
|
|
|
providerInit_return:
|
|
|
|
DBGOUT((3, "TSPI_providerInit: exit, result=x%x", lResult));
|
|
|
|
return lResult;
|
|
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_providerInstall(
|
|
HWND hwndOwner,
|
|
DWORD dwPermanentProviderID
|
|
)
|
|
{
|
|
return TAPI_SUCCESS;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_providerRemove(
|
|
HWND hwndOwner,
|
|
DWORD dwPermanentProviderID
|
|
)
|
|
{
|
|
return TAPI_SUCCESS;
|
|
}
|
|
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_providerShutdown(
|
|
DWORD dwTSPIVersion,
|
|
DWORD dwPermanentProviderID
|
|
)
|
|
{
|
|
char deviceName[] = "NDISTAPI";
|
|
LONG lResult = TAPI_SUCCESS;
|
|
BOOL bResult;
|
|
ASYNC_REQUEST_WRAPPER asyncRequestWrapper;
|
|
|
|
|
|
DBGOUT((3, "TSPI_providerShutdown: enter"));
|
|
|
|
|
|
// BUGBUG all we ought to have to do here is send a DISCONNECT IOCTL
|
|
|
|
//
|
|
// Post an async request that, once completed, will cause the async
|
|
// request thread to kill itself. Wait until we're sure the thread
|
|
// is gone, then clean it's resources.
|
|
//
|
|
|
|
FillMemory (&asyncRequestWrapper, sizeof (ASYNC_REQUEST_WRAPPER), 0);
|
|
|
|
asyncRequestWrapper.dwKey = ASYNCREQWRAPPER_KEY;
|
|
asyncRequestWrapper.dwRequestID = 0xffffffff;
|
|
|
|
bResult = PostQueuedCompletionStatus(
|
|
ghCompletionPort,
|
|
sizeof (ASYNC_REQUEST_WRAPPER),
|
|
0,
|
|
&asyncRequestWrapper.Overlapped
|
|
);
|
|
|
|
if (bResult== FALSE)
|
|
{
|
|
//
|
|
// Failed to post a completion msg to the async event thread,
|
|
// so we have to manually nuke the thread. This is not the
|
|
// preferred method since resources can be left lying around
|
|
// (i.e. the thread stack isn't freed).
|
|
//
|
|
|
|
DBGOUT((
|
|
1,
|
|
"TSPI_providerShutdown: ERROR- manually terminating " \
|
|
"AsyncEventsThread, err=%d",
|
|
GetLastError()
|
|
));
|
|
|
|
TerminateThread (gpAsyncEventsThreadInfo->hThread, 0);
|
|
}
|
|
else
|
|
{
|
|
WaitForSingleObject (gpAsyncEventsThreadInfo->hThread, INFINITE);
|
|
}
|
|
|
|
CloseHandle (gpAsyncEventsThreadInfo->hThread);
|
|
DrvFree (gpAsyncEventsThreadInfo->pBuf2);
|
|
DrvFree (gpAsyncEventsThreadInfo->pBuf1);
|
|
DrvFree (gpAsyncEventsThreadInfo);
|
|
|
|
|
|
//
|
|
// Close the driver & remove the symbolic link
|
|
//
|
|
|
|
CloseHandle (ghCompletionPort);
|
|
CloseHandle (ghDriverSync);
|
|
CloseHandle (ghDriverAsync);
|
|
|
|
DefineDosDevice (DDD_REMOVE_DEFINITION, deviceName, NULL);
|
|
|
|
DBGOUT((3, "TSPI_providerShutdown: exit, lResult=x%x", lResult));
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
//
|
|
// Private support funcs
|
|
//
|
|
|
|
void
|
|
AsyncEventsThread(
|
|
LPVOID lpParams
|
|
)
|
|
{
|
|
BOOL bReceivedLineEvents;
|
|
OVERLAPPED overlapped;
|
|
PNDISTAPI_EVENT_DATA pNewEventsBuf, pCurrentEventsBuf;
|
|
|
|
|
|
DBGOUT((3, "AsyncEventsThread: enter"));
|
|
|
|
|
|
// BUGBUG bufsize ought be based on reg setting for drivers
|
|
|
|
//
|
|
// There are 2 event data buffers so we can be getting new line events
|
|
// while processing current line events. Mark the current events buf
|
|
// (buf2 in this case) as having 0 events the 1st time thru.
|
|
//
|
|
|
|
pNewEventsBuf = gpAsyncEventsThreadInfo->pBuf1;
|
|
|
|
gpAsyncEventsThreadInfo->pBuf2->ulUsedSize = 0;
|
|
|
|
pCurrentEventsBuf = gpAsyncEventsThreadInfo->pBuf2;
|
|
|
|
bReceivedLineEvents = TRUE;
|
|
|
|
|
|
//
|
|
// Loop waiting for completed requests and retrieving async events
|
|
//
|
|
|
|
while (1)
|
|
{
|
|
DWORD i, cbReturned;
|
|
LPOVERLAPPED lpOverlapped;
|
|
PNDIS_TAPI_EVENT pEvent;
|
|
|
|
|
|
//
|
|
// Start an overlapped request to get new events
|
|
// (while we're processing the current ones)
|
|
//
|
|
|
|
if (bReceivedLineEvents)
|
|
{
|
|
//
|
|
// Don't need events when using completion ports
|
|
//
|
|
|
|
overlapped.hEvent = NULL;
|
|
|
|
pNewEventsBuf->ulTotalSize = gpAsyncEventsThreadInfo->dwBufSize -
|
|
sizeof(NDISTAPI_EVENT_DATA) + 1;
|
|
|
|
pNewEventsBuf->ulUsedSize = 0;
|
|
|
|
DBGOUT((4, "AsyncEventsThread: sending GET_LINE_EVENTS"));
|
|
|
|
if (DeviceIoControl(
|
|
ghDriverAsync,
|
|
(DWORD) IOCTL_NDISTAPI_GET_LINE_EVENTS,
|
|
pNewEventsBuf,
|
|
sizeof(NDISTAPI_EVENT_DATA),
|
|
pNewEventsBuf,
|
|
gpAsyncEventsThreadInfo->dwBufSize,
|
|
&cbReturned,
|
|
&overlapped
|
|
|
|
) == FALSE)
|
|
{
|
|
}
|
|
|
|
|
|
//
|
|
// Handle the current events
|
|
//
|
|
|
|
pEvent = (PNDIS_TAPI_EVENT) pCurrentEventsBuf->Data;
|
|
|
|
for(i = 0;
|
|
i < (pCurrentEventsBuf->ulUsedSize / sizeof(NDIS_TAPI_EVENT));
|
|
i++
|
|
)
|
|
{
|
|
ProcessEvent (pEvent);
|
|
pEvent++;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Wait for a request to complete
|
|
//
|
|
|
|
do
|
|
{
|
|
DWORD dwNumBytesTransferred, dwCompletionKey;
|
|
|
|
|
|
DBGOUT((3, "Calling GetQComplStat"));
|
|
|
|
if (GetQueuedCompletionStatus(
|
|
ghCompletionPort,
|
|
&dwNumBytesTransferred,
|
|
&dwCompletionKey,
|
|
&lpOverlapped,
|
|
(DWORD) -1 // infinite wait
|
|
|
|
) == FALSE && (lpOverlapped == NULL))
|
|
{
|
|
DBGOUT((
|
|
1,
|
|
"AsyncEventsThread: GetQComplStat failed, err=%d",
|
|
GetLastError()
|
|
));
|
|
}
|
|
|
|
} while (lpOverlapped == NULL);
|
|
|
|
|
|
//
|
|
// Check the returned overlapped struct to determine if
|
|
// we have some events to process or a completed request
|
|
//
|
|
|
|
if (lpOverlapped == &overlapped)
|
|
{
|
|
bReceivedLineEvents = TRUE;
|
|
|
|
pNewEventsBuf = pCurrentEventsBuf;
|
|
|
|
pCurrentEventsBuf =
|
|
(pCurrentEventsBuf == gpAsyncEventsThreadInfo->pBuf1 ?
|
|
gpAsyncEventsThreadInfo->pBuf2 :
|
|
gpAsyncEventsThreadInfo->pBuf1);
|
|
}
|
|
else
|
|
{
|
|
LONG lResult;
|
|
DWORD dwRequestID, callStateMsgParams[5];
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper = (PASYNC_REQUEST_WRAPPER)
|
|
lpOverlapped;
|
|
|
|
|
|
bReceivedLineEvents = FALSE;
|
|
|
|
|
|
//
|
|
// Verify that pointer is valid
|
|
//
|
|
|
|
try
|
|
{
|
|
if (pAsyncReqWrapper->dwKey != ASYNCREQWRAPPER_KEY)
|
|
{
|
|
DBGOUT((3,
|
|
"AsyncEventsThread: bogus pReq x%x completed!",
|
|
pAsyncReqWrapper
|
|
));
|
|
|
|
continue;
|
|
}
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
// we expect some AVs and alignment faults
|
|
{
|
|
DBGOUT((3,
|
|
"AsyncEventsThread: bogus pReq x%x completed!",
|
|
pAsyncReqWrapper
|
|
));
|
|
|
|
continue;
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
if ((dwRequestID = pAsyncReqWrapper->dwRequestID) == 0xffffffff)
|
|
{
|
|
DBGOUT((3, "AsyncEventsThread: exit"));
|
|
|
|
ExitThread (0);
|
|
}
|
|
|
|
lResult = TranslateDriverResult(
|
|
pAsyncReqWrapper->NdisTapiRequest.ulReturnValue
|
|
);
|
|
|
|
DBGOUT((3,
|
|
"AsyncEventsThread: pReq=x%x completed, reqID=x%x, lResult=x%x",
|
|
pAsyncReqWrapper,
|
|
dwRequestID,
|
|
lResult
|
|
));
|
|
|
|
|
|
//
|
|
// Call the post processing proc if appropriate
|
|
//
|
|
|
|
callStateMsgParams[0] = 0;
|
|
|
|
if (pAsyncReqWrapper->pfnPostProcess)
|
|
{
|
|
(*pAsyncReqWrapper->pfnPostProcess)(
|
|
pAsyncReqWrapper,
|
|
lResult,
|
|
callStateMsgParams
|
|
);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Free the async request wrapper
|
|
//
|
|
|
|
DrvFree (pAsyncReqWrapper);
|
|
|
|
|
|
//
|
|
// Call completion proc
|
|
//
|
|
|
|
(*gpfnCompletionProc)(dwRequestID, lResult);
|
|
|
|
if (callStateMsgParams[0])
|
|
{
|
|
(*gpfnLineEvent)(
|
|
(HTAPILINE) callStateMsgParams[0],
|
|
(HTAPICALL) callStateMsgParams[1],
|
|
(DWORD) LINE_CALLSTATE,
|
|
(DWORD) callStateMsgParams[2],
|
|
(DWORD) callStateMsgParams[3],
|
|
(DWORD) callStateMsgParams[4]
|
|
);
|
|
}
|
|
}
|
|
|
|
} // while
|
|
}
|
|
|
|
|
|
LONG
|
|
WINAPI
|
|
PrepareSyncRequest(
|
|
ULONG Oid,
|
|
LPDWORD lphWidget,
|
|
DWORD dwWidgetType,
|
|
PNDISTAPI_REQUEST *ppNdisTapiRequest,
|
|
DWORD dwDataSize
|
|
)
|
|
{
|
|
LONG lResult = 0;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PREQUEST_THREAD_INFO pRequestThreadInfo;
|
|
|
|
|
|
//
|
|
// Retrieve the thread local storage (if there is none then create some)
|
|
//
|
|
|
|
if ((pRequestThreadInfo = TlsGetValue (gdwTlsIndex)) == NULL)
|
|
{
|
|
if (!(pRequestThreadInfo = DrvAlloc (sizeof(REQUEST_THREAD_INFO))))
|
|
{
|
|
return LINEERR_NOMEM;
|
|
}
|
|
|
|
pRequestThreadInfo->dwBufSize = INITIAL_TLS_BUF_SIZE;
|
|
|
|
if (!(pRequestThreadInfo->pBuf = DrvAlloc (INITIAL_TLS_BUF_SIZE)))
|
|
{
|
|
return LINEERR_NOMEM;
|
|
}
|
|
|
|
TlsSetValue (gdwTlsIndex, (LPVOID) pRequestThreadInfo);
|
|
}
|
|
|
|
|
|
//
|
|
// Check to make sure our driver request buffer is big enough to
|
|
// hold all the data for this request
|
|
//
|
|
|
|
if (pRequestThreadInfo->dwBufSize < (dwDataSize+sizeof(NDISTAPI_REQUEST)))
|
|
{
|
|
PNDISTAPI_REQUEST pTmpDrvReqBuf;
|
|
|
|
|
|
if (!(pTmpDrvReqBuf = DrvAlloc (dwDataSize+sizeof(NDISTAPI_REQUEST))))
|
|
{
|
|
return LINEERR_NOMEM;
|
|
}
|
|
|
|
DrvFree (pRequestThreadInfo->pBuf);
|
|
|
|
pRequestThreadInfo->pBuf = pTmpDrvReqBuf;
|
|
|
|
pRequestThreadInfo->dwBufSize = dwDataSize;
|
|
}
|
|
|
|
pNdisTapiRequest = pRequestThreadInfo->pBuf;
|
|
|
|
|
|
//
|
|
// Safely initialize thie driver request
|
|
//
|
|
|
|
pNdisTapiRequest->Oid = Oid;
|
|
pNdisTapiRequest->ulDataSize = (DWORD) dwDataSize;
|
|
|
|
try
|
|
{
|
|
switch (dwWidgetType)
|
|
{
|
|
case HT_HDCALL:
|
|
{
|
|
PDRVCALL pCall = (PDRVCALL)(*lphWidget);
|
|
|
|
|
|
pNdisTapiRequest->ulDeviceID = pCall->dwDeviceID;
|
|
*lphWidget = pCall->hd_Call;
|
|
|
|
if (pCall->dwKey != INBOUND_CALL_KEY &&
|
|
pCall->dwKey != OUTBOUND_CALL_KEY)
|
|
{
|
|
lResult = LINEERR_INVALCALLHANDLE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case HT_HDLINE:
|
|
{
|
|
PDRVLINE pLine = (PDRVLINE)(*lphWidget);
|
|
|
|
|
|
pNdisTapiRequest->ulDeviceID = pLine->dwDeviceID;
|
|
*lphWidget = pLine->hd_Line;
|
|
|
|
if (pLine->dwKey != LINE_KEY)
|
|
{
|
|
lResult = LINEERR_INVALLINEHANDLE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case HT_DEVICEID:
|
|
|
|
pNdisTapiRequest->ulDeviceID = *((ULONG *) lphWidget);
|
|
break;
|
|
}
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
// we expect some AVs and alignment faults
|
|
{
|
|
lResult = (dwWidgetType == HT_HDCALL ? LINEERR_INVALCALLHANDLE :
|
|
LINEERR_INVALLINEHANDLE);
|
|
}
|
|
|
|
// Note: since request buf is tls we don't have to free it on error
|
|
|
|
EnterCriticalSection (&gRequestIDCritSec);
|
|
|
|
if (( *((ULONG *)pNdisTapiRequest->Data) = ++gdwRequestID) >= 0x7fffffff)
|
|
{
|
|
gdwRequestID = 1;
|
|
}
|
|
|
|
LeaveCriticalSection (&gRequestIDCritSec);
|
|
|
|
*ppNdisTapiRequest = pNdisTapiRequest;
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
LONG
|
|
WINAPI
|
|
PrepareAsyncRequest(
|
|
ULONG Oid,
|
|
LPDWORD lphWidget,
|
|
DWORD dwWidgetType,
|
|
DWORD dwRequestID,
|
|
PASYNC_REQUEST_WRAPPER *ppAsyncRequestWrapper,
|
|
DWORD dwDataSize
|
|
)
|
|
{
|
|
LONG lResult = 0;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PASYNC_REQUEST_WRAPPER pAsyncRequestWrapper;
|
|
|
|
|
|
//
|
|
// Alloc & init an async request wrapper
|
|
//
|
|
|
|
if (!(pAsyncRequestWrapper = DrvAlloc(
|
|
dwDataSize + sizeof(ASYNC_REQUEST_WRAPPER)
|
|
)))
|
|
{
|
|
return LINEERR_NOMEM;
|
|
}
|
|
|
|
|
|
//
|
|
// Don't need to create an event when using completion ports
|
|
//
|
|
|
|
pAsyncRequestWrapper->Overlapped.hEvent = (HANDLE) NULL;
|
|
|
|
pAsyncRequestWrapper->dwKey = ASYNCREQWRAPPER_KEY;
|
|
pAsyncRequestWrapper->dwRequestID = dwRequestID;
|
|
pAsyncRequestWrapper->pfnPostProcess = (POSTPROCESSPROC) NULL;
|
|
|
|
|
|
//
|
|
// Safely initialize the driver request
|
|
//
|
|
|
|
pNdisTapiRequest = &(pAsyncRequestWrapper->NdisTapiRequest);
|
|
|
|
pNdisTapiRequest->Oid = Oid;
|
|
pNdisTapiRequest->ulDataSize = (ULONG) dwDataSize;
|
|
|
|
try
|
|
{
|
|
if (dwWidgetType == HT_HDCALL)
|
|
{
|
|
pNdisTapiRequest->ulDeviceID =
|
|
((PDRVCALL)(*lphWidget))->dwDeviceID;
|
|
*lphWidget = ((PDRVCALL)(*lphWidget))->hd_Call;
|
|
}
|
|
else // HT_HDLINE
|
|
{
|
|
pNdisTapiRequest->ulDeviceID =
|
|
((PDRVLINE)(*lphWidget))->dwDeviceID;
|
|
*lphWidget = ((PDRVLINE)(*lphWidget))->hd_Line;
|
|
}
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
// we expect some AVs and alignment faults
|
|
{
|
|
lResult = (dwWidgetType == HT_HDCALL ? LINEERR_INVALCALLHANDLE :
|
|
LINEERR_INVALLINEHANDLE);
|
|
}
|
|
|
|
if (lResult == 0)
|
|
{
|
|
EnterCriticalSection (&gRequestIDCritSec);
|
|
|
|
if (( *((ULONG *)pNdisTapiRequest->Data) = ++gdwRequestID)
|
|
>= 0x7fffffff)
|
|
{
|
|
gdwRequestID = 1;
|
|
}
|
|
|
|
LeaveCriticalSection (&gRequestIDCritSec);
|
|
|
|
*ppAsyncRequestWrapper = pAsyncRequestWrapper;
|
|
}
|
|
else
|
|
{
|
|
DrvFree (pAsyncRequestWrapper);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
#if DBG
|
|
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"
|
|
};
|
|
#endif
|
|
|
|
LONG
|
|
WINAPI
|
|
SyncDriverRequest(
|
|
DWORD dwIoControlCode,
|
|
PNDISTAPI_REQUEST pNdisTapiRequest
|
|
)
|
|
{
|
|
//
|
|
// This routine makes a non-overlapped request to NdisTapi.sys (so it
|
|
// doesn't return until the request is completed)
|
|
//
|
|
|
|
BOOL bResult;
|
|
DWORD cbReturned;
|
|
|
|
|
|
DBGOUT((
|
|
3,
|
|
"SyncDrvReq: Oid=%s, devID=%d, dataSize=%d, reqID=x%x, p1=x%x",
|
|
pszOidNames[pNdisTapiRequest->Oid - OID_TAPI_ACCEPT],
|
|
pNdisTapiRequest->ulDeviceID,
|
|
pNdisTapiRequest->ulDataSize,
|
|
*((ULONG *)pNdisTapiRequest->Data),
|
|
*(((ULONG *)pNdisTapiRequest->Data) + 1)
|
|
));
|
|
|
|
if (DeviceIoControl(
|
|
ghDriverSync,
|
|
dwIoControlCode,
|
|
pNdisTapiRequest,
|
|
(DWORD) (sizeof(NDISTAPI_REQUEST) + pNdisTapiRequest->ulDataSize),
|
|
pNdisTapiRequest,
|
|
(DWORD) (sizeof(NDISTAPI_REQUEST) + pNdisTapiRequest->ulDataSize),
|
|
&cbReturned,
|
|
0
|
|
|
|
) == FALSE)
|
|
{
|
|
}
|
|
|
|
//
|
|
// The errors returned by NdisTapi.sys don't match the TAPI LINEERR_'s,
|
|
// so return the translated value (but preserve the original driver
|
|
// return val so it's possible to distinguish between
|
|
// NDISTAPIERR_DEVICEOFFLINE & LINEERR_OPERATIONUNAVAIL, etc.)
|
|
//
|
|
|
|
return (TranslateDriverResult (pNdisTapiRequest->ulReturnValue));
|
|
}
|
|
|
|
|
|
LONG
|
|
WINAPI
|
|
AsyncDriverRequest(
|
|
DWORD dwIoControlCode,
|
|
PASYNC_REQUEST_WRAPPER pAsyncRequestWrapper
|
|
)
|
|
{
|
|
BOOL bResult;
|
|
LONG lResult;
|
|
DWORD dwRequestSize, cbReturned, dwLastError;
|
|
|
|
|
|
DBGOUT((
|
|
3,
|
|
"AsyncDrvReq: pReq=x%x, Oid=%s, devID=%d, dataSize=%d, reqID=x%x, ddReqID=x%x, p1=x%x",
|
|
pAsyncRequestWrapper,
|
|
pszOidNames
|
|
[pAsyncRequestWrapper->NdisTapiRequest.Oid - OID_TAPI_ACCEPT],
|
|
pAsyncRequestWrapper->NdisTapiRequest.ulDeviceID,
|
|
pAsyncRequestWrapper->NdisTapiRequest.ulDataSize,
|
|
pAsyncRequestWrapper->dwRequestID,
|
|
*((ULONG *)pAsyncRequestWrapper->NdisTapiRequest.Data),
|
|
*(((ULONG *)pAsyncRequestWrapper->NdisTapiRequest.Data) + 1)
|
|
));
|
|
|
|
lResult = (LONG) pAsyncRequestWrapper->dwRequestID;
|
|
|
|
dwRequestSize = sizeof(NDISTAPI_REQUEST) +
|
|
(pAsyncRequestWrapper->NdisTapiRequest.ulDataSize - 1);
|
|
|
|
bResult = DeviceIoControl(
|
|
ghDriverAsync,
|
|
dwIoControlCode,
|
|
&pAsyncRequestWrapper->NdisTapiRequest,
|
|
dwRequestSize,
|
|
&pAsyncRequestWrapper->NdisTapiRequest,
|
|
dwRequestSize,
|
|
&cbReturned,
|
|
&pAsyncRequestWrapper->Overlapped
|
|
);
|
|
|
|
dwLastError = GetLastError();
|
|
|
|
if ((bResult == FALSE) && (dwLastError == ERROR_IO_PENDING))
|
|
{
|
|
//
|
|
// Request is pending, just return (async events thread will
|
|
// take care of it when it completes)
|
|
//
|
|
}
|
|
else if (bResult == TRUE)
|
|
{
|
|
//
|
|
// Request completed synchronously, so call the completion proc
|
|
// & clean up
|
|
//
|
|
|
|
(*gpfnCompletionProc)(
|
|
pAsyncRequestWrapper->dwRequestID,
|
|
TranslateDriverResult(
|
|
pAsyncRequestWrapper->NdisTapiRequest.ulReturnValue
|
|
)
|
|
);
|
|
|
|
DrvFree (pAsyncRequestWrapper);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Error
|
|
//
|
|
|
|
DBGOUT((1, "AsyncDrvReq: DevIoCtl failed, err=%d", dwLastError));
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
ConvertLineAndCallHandles(
|
|
HTAPI_LINE *pht_Line,
|
|
HTAPI_CALL *pht_Call
|
|
)
|
|
{
|
|
PDRVCALL pCall;
|
|
PDRVLINE pLine = (PDRVLINE) *pht_Line;
|
|
|
|
|
|
//
|
|
// Check to see that pLine is 64-bit aligned & has a good key
|
|
//
|
|
|
|
{
|
|
BOOL bBadLine;
|
|
|
|
|
|
try
|
|
{
|
|
if (!((DWORD) pLine & 0x7) && pLine->dwKey == LINE_KEY)
|
|
{
|
|
*pht_Line = (HTAPI_LINE) pLine->htLine;
|
|
bBadLine = FALSE;
|
|
}
|
|
else
|
|
{
|
|
bBadLine = TRUE;
|
|
}
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
// we expect some AVs and alignment faults
|
|
{
|
|
bBadLine = TRUE;
|
|
}
|
|
|
|
if (bBadLine)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Incoming calls will have a pCall with the high bit set (a value
|
|
// created by ndistapi), while outgoing calls won't have the high
|
|
// bit set (since they're real ptrs in app space [the low 2 gig])
|
|
//
|
|
|
|
pCall = (PDRVCALL) *pht_Call;
|
|
|
|
if ((DWORD) pCall < 0x80000000)
|
|
{
|
|
BOOL bResult;
|
|
|
|
|
|
try
|
|
{
|
|
//
|
|
// Check that pCall is 64-bit aligned & has a good key
|
|
//
|
|
|
|
if (!((DWORD) pCall & 0x7) &&
|
|
pCall->dwKey == OUTBOUND_CALL_KEY)
|
|
{
|
|
*pht_Call = (HTAPI_CALL) pCall->htCall;
|
|
bResult = TRUE;
|
|
}
|
|
else
|
|
{
|
|
bResult = FALSE;
|
|
}
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
// we expect some AVs and alignment faults
|
|
{
|
|
bResult = FALSE;
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
//
|
|
// If here it's an inbound call, so we need to walk the list
|
|
// of inbound pCalls on this line & find the right one
|
|
//
|
|
|
|
{
|
|
BOOL bInCriticalSection;
|
|
|
|
|
|
try
|
|
{
|
|
HTAPI_CALL ht_Call;
|
|
|
|
|
|
EnterCriticalSection (&gInboundCallsCritSec);
|
|
|
|
bInCriticalSection = TRUE;
|
|
|
|
if ((pCall = pLine->pInboundCalls))
|
|
{
|
|
ht_Call = *pht_Call;
|
|
|
|
while (pCall && (pCall->ht_Call != ht_Call))
|
|
{
|
|
pCall = pCall->pNext;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection (&gInboundCallsCritSec);
|
|
|
|
bInCriticalSection = FALSE;
|
|
|
|
*pht_Call = (pCall ? (HTAPI_CALL)pCall->htCall : (HTAPI_CALL)NULL);
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
// we expect some AVs and alignment faults
|
|
{
|
|
if (bInCriticalSection)
|
|
{
|
|
LeaveCriticalSection (&gInboundCallsCritSec);
|
|
}
|
|
|
|
pCall = NULL;
|
|
}
|
|
}
|
|
|
|
return (pCall ? TRUE : FALSE);
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
ConvertLineHandle(
|
|
HTAPI_LINE *pht_Line
|
|
)
|
|
{
|
|
PDRVLINE pLine = (PDRVLINE) *pht_Line;
|
|
|
|
|
|
//
|
|
// Check to see that pLine is 64-bit aligned & has a good key
|
|
//
|
|
|
|
try
|
|
{
|
|
if (!((DWORD) pLine & 0x7) && pLine->dwKey == LINE_KEY)
|
|
{
|
|
*pht_Line = (HTAPI_LINE) pLine->htLine;
|
|
return TRUE;
|
|
}
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
// we expect some AVs and alignment faults
|
|
{
|
|
// just fall thru
|
|
}
|
|
|
|
DBGOUT((4, "ConvertLineHandle: bad htLine=x%x", *pht_Line));
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
LPVOID
|
|
WINAPI
|
|
DrvAlloc(
|
|
DWORD dwSize
|
|
)
|
|
{
|
|
LPBYTE p;
|
|
LPDWORD pAligned;
|
|
|
|
|
|
//
|
|
// Alloc 16 extra bytes so we can make sure the pointer we pass back
|
|
// is 64-bit aligned & have space to store the original pointer
|
|
//
|
|
|
|
if ((p = (LPBYTE) LocalAlloc (LPTR, dwSize + 16)))
|
|
{
|
|
pAligned = (LPDWORD) (p + 8 - (((DWORD) p) & 0x7));
|
|
*pAligned = (DWORD) p;
|
|
pAligned++;
|
|
pAligned++;
|
|
}
|
|
else
|
|
{
|
|
// send reinit msg?
|
|
|
|
DBGOUT((
|
|
1,
|
|
"ServerAlloc: LocalAlloc (x%lx) failed, err=x%lx",
|
|
dwSize,
|
|
GetLastError())
|
|
);
|
|
|
|
pAligned = NULL;
|
|
}
|
|
|
|
return ((LPVOID) pAligned);
|
|
}
|
|
|
|
|
|
VOID
|
|
WINAPI
|
|
DrvFree(
|
|
LPVOID p
|
|
)
|
|
{
|
|
LPVOID pOrig = (LPVOID) *(((LPDWORD) p) - 2);
|
|
|
|
|
|
LocalFree (pOrig);
|
|
}
|
|
|
|
|
|
VOID
|
|
WINAPI
|
|
ProcessEvent(
|
|
PNDIS_TAPI_EVENT pEvent
|
|
)
|
|
{
|
|
ULONG ulMsg = pEvent->ulMsg;
|
|
HTAPI_LINE ht_Line = (HTAPI_LINE) pEvent->htLine;
|
|
|
|
|
|
DBGOUT((
|
|
4,
|
|
"ProcessEvent: enter, msg=x%x, pLine=x%x, ht_call=x%x",
|
|
ulMsg,
|
|
ht_Line,
|
|
pEvent->htCall
|
|
));
|
|
|
|
DBGOUT((
|
|
4,
|
|
"ProcessEvent: \tp1=x%x, p2=x%x, p3=x%x",
|
|
pEvent->ulParam1,
|
|
pEvent->ulParam2,
|
|
pEvent->ulParam3
|
|
));
|
|
|
|
switch (ulMsg)
|
|
{
|
|
case LINE_ADDRESSSTATE:
|
|
case LINE_CLOSE:
|
|
case LINE_DEVSPECIFIC:
|
|
case LINE_LINEDEVSTATE:
|
|
|
|
if (ConvertLineHandle (&ht_Line))
|
|
{
|
|
(*gpfnLineEvent)(
|
|
(HTAPILINE) ht_Line,
|
|
(HTAPICALL) NULL,
|
|
(DWORD) ulMsg,
|
|
(DWORD) pEvent->ulParam1,
|
|
(DWORD) pEvent->ulParam2,
|
|
(DWORD) pEvent->ulParam3
|
|
);
|
|
}
|
|
|
|
break;
|
|
|
|
case LINE_CALLDEVSPECIFIC:
|
|
case LINE_CALLINFO:
|
|
|
|
if (ConvertLineAndCallHandles (&ht_Line, &pEvent->htCall))
|
|
{
|
|
(*gpfnLineEvent)(
|
|
(HTAPILINE) ht_Line,
|
|
(HTAPICALL) pEvent->htCall,
|
|
(DWORD) ulMsg,
|
|
(DWORD) pEvent->ulParam1,
|
|
(DWORD) pEvent->ulParam2,
|
|
(DWORD) pEvent->ulParam3
|
|
);
|
|
}
|
|
|
|
break;
|
|
|
|
case LINE_CALLSTATE:
|
|
{
|
|
//
|
|
// For outgoing 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 outgoing 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.
|
|
//
|
|
// (Note: incoming calls have high bit turned off)
|
|
//
|
|
|
|
PDRVCALL pCall = (PDRVCALL) pEvent->htCall;
|
|
|
|
|
|
if ((DWORD) pCall < 0x80000000 && !((DWORD) pCall & 0x7))
|
|
{
|
|
try
|
|
{
|
|
if (pCall->dwKey == OUTBOUND_CALL_KEY &&
|
|
pCall->bIncomplete == TRUE)
|
|
{
|
|
pCall->dwPendingCallState = pEvent->ulParam1;
|
|
pCall->dwPendingCallStateMode = pEvent->ulParam2;
|
|
pCall->dwPendingMediaMode = pEvent->ulParam3;
|
|
|
|
break;
|
|
}
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
// we expect some AVs and alignment faults
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ConvertLineAndCallHandles (&ht_Line, &pEvent->htCall))
|
|
{
|
|
(*gpfnLineEvent)(
|
|
(HTAPILINE) ht_Line,
|
|
(HTAPICALL) pEvent->htCall,
|
|
(DWORD) ulMsg,
|
|
(DWORD) pEvent->ulParam1,
|
|
(DWORD) pEvent->ulParam2,
|
|
(DWORD) 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)
|
|
//
|
|
// BUGBUG make sure we don't do this for new style
|
|
// drivers (new style == anything that supports
|
|
// OID_TAPI_NEGOTIATE_API_VERSION)
|
|
//
|
|
|
|
if (pEvent->ulParam1 == LINECALLSTATE_DISCONNECTED)
|
|
{
|
|
(*gpfnLineEvent)(
|
|
(HTAPILINE) ht_Line,
|
|
(HTAPICALL) pEvent->htCall,
|
|
(DWORD) ulMsg,
|
|
(DWORD) LINECALLSTATE_IDLE,
|
|
(DWORD) 0,
|
|
(DWORD) pEvent->ulParam3
|
|
);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
case LINE_NEWCALL:
|
|
{
|
|
BOOL bInCriticalSection = FALSE;
|
|
PDRVCALL pCall;
|
|
PDRVLINE pLine = (PDRVLINE) ht_Line;
|
|
|
|
|
|
if (!(pCall = DrvAlloc (sizeof(DRVCALL))))
|
|
{
|
|
// BUGBUG LINE_NEWCALL: couldn't alloc drvCall, send drop/dealloc call OIDs
|
|
|
|
break;
|
|
}
|
|
|
|
pCall->dwKey = INBOUND_CALL_KEY;
|
|
pCall->ht_Call = (HTAPI_CALL) pEvent->ulParam2;
|
|
pCall->hd_Call = (HDRV_CALL) pEvent->ulParam1;
|
|
pCall->pLine = pLine;
|
|
//pCall->bIncomplete = FALSE; (already 0'd by alloc)
|
|
|
|
try
|
|
{
|
|
pCall->dwDeviceID = pLine->dwDeviceID;
|
|
|
|
EnterCriticalSection (&gInboundCallsCritSec);
|
|
|
|
bInCriticalSection = TRUE;
|
|
|
|
if (pLine->dwKey == LINE_KEY)
|
|
{
|
|
//
|
|
// Insert new call into inbound calls list
|
|
//
|
|
|
|
if ((pCall->pNext = pLine->pInboundCalls))
|
|
{
|
|
pCall->pNext->pPrev = pCall;
|
|
}
|
|
|
|
pLine->pInboundCalls = pCall;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Line was closed after this msg was sent, so clean up
|
|
//
|
|
|
|
DrvFree (pCall);
|
|
pCall = NULL;
|
|
}
|
|
|
|
LeaveCriticalSection (&gInboundCallsCritSec);
|
|
|
|
bInCriticalSection = FALSE;
|
|
|
|
if (pCall)
|
|
{
|
|
(*gpfnLineEvent)(
|
|
(HTAPILINE) pLine->htLine,
|
|
(HTAPICALL) NULL,
|
|
ulMsg,
|
|
(DWORD) pCall,
|
|
(DWORD) &pCall->htCall,
|
|
0
|
|
);
|
|
}
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
// we expect some AVs and alignment faults
|
|
{
|
|
if (bInCriticalSection)
|
|
{
|
|
LeaveCriticalSection (&gInboundCallsCritSec);
|
|
}
|
|
|
|
DrvFree (pCall);
|
|
}
|
|
|
|
// BUGBUG check if pCall->htCall is NULL (tapi couldn't deal w/ newcall)
|
|
|
|
break;
|
|
}
|
|
default:
|
|
|
|
DBGOUT((2, "ProcessEvent: unknown msg, x%x", ulMsg));
|
|
|
|
break;
|
|
|
|
} // switch
|
|
}
|
|
|
|
|
|
LONG
|
|
WINAPI
|
|
TranslateDriverResult(
|
|
ULONG ulResult
|
|
)
|
|
{
|
|
typedef struct _RESULT_LOOKUP
|
|
{
|
|
ULONG NdisTapiResult;
|
|
|
|
LONG TapiResult;
|
|
|
|
} RESULT_LOOKUP, *PRESULT_LOOKUP;
|
|
|
|
#ifdef MYHACK
|
|
|
|
typedef ULONG NDIS_STATUS;
|
|
|
|
#define NDIS_STATUS_SUCCESS 0x00000000L
|
|
#define NDIS_STATUS_RESOURCES 0xC000009AL
|
|
#define NDIS_STATUS_FAILURE 0xC0000001L
|
|
|
|
#endif
|
|
|
|
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 },
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
{ 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 (ulResult == aResults[i].NdisTapiResult)
|
|
{
|
|
return (aResults[i].TapiResult);
|
|
}
|
|
}
|
|
|
|
DBGOUT((1, "TranslateDriverResult: unknown driver result x%x", ulResult));
|
|
|
|
return LINEERR_OPERATIONFAILED;
|
|
}
|
|
|
|
|
|
#if DBG
|
|
VOID
|
|
DbgPrt(
|
|
IN DWORD dwDbgLevel,
|
|
IN PUCHAR lpszFormat,
|
|
IN ...
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Formats the incoming debug message & callsOutputDebugStringA
|
|
|
|
Arguments:
|
|
|
|
DbgLevel - level of message verboseness
|
|
|
|
DbgMessage - printf-style format string, followed by appropriate
|
|
list of arguments
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
if (dwDbgLevel <= gdwDebugLevel)
|
|
{
|
|
int iNumChars;
|
|
char buf[192] = "KMDDSP: ";
|
|
va_list ap;
|
|
|
|
|
|
va_start(ap, lpszFormat);
|
|
|
|
iNumChars = wvsprintfA (&buf[8], lpszFormat, ap);
|
|
|
|
buf[iNumChars] = '\n';
|
|
buf[iNumChars + 1] = 0;
|
|
|
|
OutputDebugStringA (buf);
|
|
|
|
va_end(ap);
|
|
}
|
|
}
|
|
#endif
|