7441 lines
212 KiB
C
7441 lines
212 KiB
C
//============================================================================
|
|
// Copyright (c) 2000, Microsoft Corporation
|
|
//
|
|
// File: ndptsp.c
|
|
//
|
|
// History:
|
|
// Dan Knudson (DanKn) 11-Apr-1995 Created
|
|
// Richard Machin (RMachin) 05-05-97 NDIS 5.0 changes
|
|
// Radu Simionescu (RaduS) 10-Feb-1999 UI config
|
|
// Yi Sun (YiSun) June-29-2000 Rewriten
|
|
//
|
|
// Abstract:
|
|
//============================================================================
|
|
|
|
#define NDIS_TAPI_CURRENT_VERSION 0x00030000
|
|
#define TAPI_CURRENT_VERSION NDIS_TAPI_CURRENT_VERSION
|
|
|
|
#include "nt.h"
|
|
#include "ntrtl.h"
|
|
#include "nturtl.h"
|
|
#include "windows.h"
|
|
#include "rtutils.h"
|
|
#include "winioctl.h"
|
|
#include "ntddndis.h"
|
|
#include "ndistapi.h"
|
|
#include "ndpif.h"
|
|
|
|
//
|
|
// NOTE: the following are defined in both ndistapi.h & tapi.h (or tspi.h)
|
|
// and cause (more or less non-interesting) build warnings, so we
|
|
// undefine them after the first #include to do away with this
|
|
//
|
|
|
|
#undef LAST_LINEMEDIAMODE
|
|
#undef TSPI_MESSAGE_BASE
|
|
#undef LINE_NEWCALL
|
|
#undef LINE_CALLDEVSPECIFIC
|
|
#undef LINE_CREATE
|
|
|
|
#include "tapi.h"
|
|
#include "tspi.h"
|
|
#include "ndptsp.h"
|
|
#include "resource.h"
|
|
|
|
#define OUTBOUND_CALL_KEY ((DWORD) 'OCAL')
|
|
#define INBOUND_CALL_KEY ((DWORD) 'ICAL')
|
|
#define LINE_KEY ((DWORD) 'KLIN')
|
|
#define ASYNCREQWRAPPER_KEY ((DWORD) 'ARWK')
|
|
#define MSP_KEY ((DWORD) 'MSPK')
|
|
#define INVALID_KEY ((DWORD) 'XXXX')
|
|
|
|
#define EVENT_BUFFER_SIZE 1024
|
|
|
|
#define RCA_SAP_STRING L"WAN/RCA"
|
|
#define NDPTSP_UIDLL L"NDPTSP.TSP"
|
|
|
|
#define WINDOWS_REGKEY_ROOT L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion"
|
|
#define NDPTSP_SUBKEY L"NdpTsp"
|
|
#define NDPTSP_NOTIFY_SUBKEY L"ForceRefresh"
|
|
|
|
#define NDPTSP_REGKEY_ROOT \
|
|
WINDOWS_REGKEY_ROOT L"\\" NDPTSP_SUBKEY
|
|
|
|
#define NDPTSP_NOTIFY_REGKEY_ROOT \
|
|
NDPTSP_REGKEY_ROOT L"\\" NDPTSP_NOTIFY_SUBKEY
|
|
|
|
typedef struct _NDP_MEDIA_TYPE
|
|
{
|
|
DWORD dwResourceID; // Resource ID for the localized string
|
|
PWSTR pwszString;
|
|
DWORD dwMediaMode;
|
|
PWSTR pwszRegString; // Name of the registry value
|
|
} NDP_MEDIA_TYPE;
|
|
|
|
|
|
NDP_MEDIA_TYPE NdpModeArray[] = {
|
|
IDS_TYPE_DIGITALDATA, NULL,
|
|
LINEMEDIAMODE_DIGITALDATA, L"Digita lData",
|
|
|
|
IDS_TYPE_INTERACTIVEVOICE, NULL,
|
|
LINEMEDIAMODE_INTERACTIVEVOICE, L"Intera ctiveVoice",
|
|
|
|
IDS_TYPE_G3FAX, NULL,
|
|
LINEMEDIAMODE_G3FAX, L"G3Fax" ,
|
|
|
|
IDS_TYPE_G4FAX, NULL,
|
|
LINEMEDIAMODE_G4FAX, L"G4Fax"
|
|
};
|
|
|
|
#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
|
|
#define NUM_NDP_MODES ARRAYSIZE(NdpModeArray)
|
|
|
|
typedef struct _ADDRESS_MAP
|
|
{
|
|
PWSTR pwszAddress;
|
|
DWORD dwAddressLength;
|
|
struct _ADDRESS_MAP *pNext;
|
|
struct _ADDRESS_MAP *pPrev;
|
|
} ADDRESS_MAP, *PADDRESS_MAP;
|
|
|
|
typedef struct _CONFIG_UI_CTX
|
|
{
|
|
PADDRESS_MAP pAddressMapListArray[NUM_NDP_MODES];
|
|
HWND hwndListBox;
|
|
DWORD dwCrtTypeIndex;
|
|
} CONFIG_UI_CTX;
|
|
|
|
//
|
|
// help support
|
|
//
|
|
#define NDPTSP_HELP_FILE L"tapi.hlp"
|
|
|
|
#ifndef IDH_DISABLEHELP
|
|
#define IDH_DISABLEHELP ((DWORD)-1)
|
|
#endif
|
|
|
|
#define IDH_MEDIA_MAP_MEDIA_TYPE 10011
|
|
#define IDH_MEDIA_MAP_ADDRESS_GROUP 10012
|
|
#define IDH_MEDIA_MAP_ADDRESS_LIST 10013
|
|
#define IDH_MEDIA_MAP_ADD_ADDRESS 10014
|
|
#define IDH_MEDIA_MAP_DELETE_ADDRESS 10015
|
|
#define IDH_MEDIA_ADD_ADD_ADDRESS 10016
|
|
|
|
static const DWORD g_aHelpIDs_IDD_MEDIA_MAP[]=
|
|
{
|
|
IDC_MEDIA_TYPE, IDH_MEDIA_MAP_MEDIA_TYPE, // Drop-down list
|
|
IDC_ADDRESS_GROUP, IDH_MEDIA_MAP_ADDRESS_GROUP, // Group box
|
|
IDC_ADDRESS_LIST, IDH_MEDIA_MAP_ADDRESS_LIST, // List box
|
|
IDC_ADD_ADDRESS, IDH_MEDIA_MAP_ADD_ADDRESS, // Add button
|
|
IDC_DELETE_ADDRESS, IDH_MEDIA_MAP_DELETE_ADDRESS, // Delete button
|
|
0, 0
|
|
};
|
|
|
|
const DWORD g_aHelpIDs_IDD_MEDIA_ADD[]=
|
|
{
|
|
IDC_ADD_ADDRESS, IDH_MEDIA_ADD_ADD_ADDRESS, // edit box
|
|
0, 0
|
|
};
|
|
|
|
typedef LONG (*POSTPROCESSPROC)(PASYNC_REQUEST_WRAPPER, LONG, PDWORD_PTR);
|
|
|
|
typedef struct _ASYNC_REQUEST_WRAPPER
|
|
{
|
|
// NOTE: overlapped must remain 1st field in this struct
|
|
OVERLAPPED Overlapped;
|
|
DWORD dwKey;
|
|
DWORD dwRequestID;
|
|
POSTPROCESSPROC pfnPostProcess;
|
|
CRITICAL_SECTION CritSec;
|
|
ULONG RefCount;
|
|
DWORD_PTR dwRequestSpecific;
|
|
// NOTE: NdisTapiRequest must follow a ptr to avoid alignment problem
|
|
NDISTAPI_REQUEST NdisTapiRequest;
|
|
|
|
} ASYNC_REQUEST_WRAPPER, *PASYNC_REQUEST_WRAPPER;
|
|
|
|
#define REF_ASYNC_REQUEST_WRAPPER(_pAsyncReqWrapper) \
|
|
{ \
|
|
EnterCriticalSection(&_pAsyncReqWrapper->CritSec); \
|
|
_pAsyncReqWrapper->RefCount++; \
|
|
LeaveCriticalSection(&_pAsyncReqWrapper->CritSec); \
|
|
}
|
|
|
|
#define DEREF_ASYNC_REQUEST_WRAPPER(_pAsyncReqWrapper) \
|
|
{ \
|
|
EnterCriticalSection(&_pAsyncReqWrapper->CritSec); \
|
|
if (--(_pAsyncReqWrapper->RefCount) == 0) { \
|
|
LeaveCriticalSection(&_pAsyncReqWrapper->CritSec); \
|
|
DeleteCriticalSection(&_pAsyncReqWrapper->CritSec); \
|
|
FreeRequest(_pAsyncReqWrapper); \
|
|
_pAsyncReqWrapper = NULL; \
|
|
} else { \
|
|
LeaveCriticalSection(&_pAsyncReqWrapper->CritSec); \
|
|
} \
|
|
}
|
|
|
|
typedef struct _ASYNC_EVENTS_THREAD_INFO
|
|
{
|
|
HANDLE hThread; // thread handle
|
|
PNDISTAPI_EVENT_DATA pBuf; // ptr to a buf for async events
|
|
DWORD dwBufSize; // size of the previous buffer
|
|
|
|
} ASYNC_EVENTS_THREAD_INFO, *PASYNC_EVENTS_THREAD_INFO;
|
|
|
|
|
|
typedef struct _DRVCALL
|
|
{
|
|
DWORD dwKey;
|
|
DWORD dwDeviceID;
|
|
HTAPICALL htCall; // TAPI's handle to the call
|
|
HDRVCALL hdCall; // TSP's handle to the call
|
|
HDRV_CALL hd_Call; // NDPROXY's call handle
|
|
HDRVLINE hdLine; // TSP's handle to the line
|
|
union
|
|
{
|
|
struct _DRVCALL *pPrev; // for inbound calls only
|
|
DWORD dwPendingCallState; // for outbound calls only
|
|
};
|
|
union
|
|
{
|
|
struct _DRVCALL *pNext; // for inbound calls only
|
|
DWORD dwPendingCallStateMode; // for outbound calls only
|
|
};
|
|
union
|
|
{
|
|
HTAPI_CALL ht_Call; // for inbound calls only
|
|
DWORD dwPendingMediaMode; // for outbound calls only
|
|
};
|
|
BOOL bIncomplete;
|
|
BOOL bDropped;
|
|
|
|
} DRVCALL, *PDRVCALL;
|
|
|
|
typedef struct _DRVMSPLINE
|
|
{
|
|
DWORD dwKey;
|
|
DWORD dwAddressID;
|
|
HDRVLINE hdLine;
|
|
HTAPIMSPLINE htMSPLine;
|
|
BOOL bStreamingStarted;
|
|
|
|
} DRVMSPLINE, *PDRVMSPLINE;
|
|
|
|
typedef struct _DRVLINE
|
|
{
|
|
DWORD dwKey;
|
|
DWORD dwDeviceID;
|
|
HTAPILINE htLine; // TAPI's line handle
|
|
HDRV_LINE hd_Line; // NDPROXY's line handle
|
|
PDRVCALL pInboundCalls; // inbound call list
|
|
|
|
HANDLE hMSPMutex;
|
|
PDRVMSPLINE pMSPLine;
|
|
|
|
// the following two related to PNP/POWER
|
|
GUID Guid;
|
|
NDIS_WAN_MEDIUM_SUBTYPE MediaType;
|
|
|
|
} DRVLINE, *PDRVLINE;
|
|
|
|
// globals
|
|
HANDLE ghDriverSync, ghDriverAsync, ghCompletionPort;
|
|
PASYNC_EVENTS_THREAD_INFO gpAsyncEventsThreadInfo;
|
|
PADDRESS_MAP gpAddressMapListArray[NUM_NDP_MODES];
|
|
BOOL gbAddressMapListLoaded;
|
|
CRITICAL_SECTION gAddressMapCritSec;
|
|
DWORD gdwRequestID;
|
|
ASYNC_COMPLETION gpfnCompletionProc;
|
|
CRITICAL_SECTION gRequestIDCritSec;
|
|
DWORD gInitResult;
|
|
LINEEVENT gpfnLineEvent;
|
|
HPROVIDER ghProvider;
|
|
HINSTANCE ghInstance;
|
|
|
|
|
|
//
|
|
// CLSID for the RCA MSP.
|
|
// @@@ we should grab this from an include directory in the MSP
|
|
// sources, but that can only be done when the MSP/TSP source is
|
|
// moved to the right place.
|
|
//
|
|
const CLSID CLSID_RCAMSP = {
|
|
0x11D59011, 0xCF23, 0x11d1,
|
|
{0xA0, 0x2D, 0x00, 0xC0, 0x4F, 0xB6, 0x80, 0x9F}
|
|
};
|
|
|
|
//
|
|
// debug globals
|
|
//
|
|
#if DBG
|
|
DWORD gdwDebugLevel;
|
|
#endif // DBG
|
|
|
|
DWORD gdwTraceID = INVALID_TRACEID;
|
|
|
|
//
|
|
// creates a log using the RAS tracing utility
|
|
// also prints it onto the attached debugger
|
|
// if a debug build is running
|
|
//
|
|
VOID
|
|
TspLog(
|
|
IN DWORD dwDebugLevel,
|
|
IN PCHAR pchFormat,
|
|
...
|
|
)
|
|
{
|
|
va_list arglist;
|
|
CHAR chNewFmt[256];
|
|
|
|
va_start(arglist, pchFormat);
|
|
|
|
switch (dwDebugLevel)
|
|
{
|
|
case DL_ERROR:
|
|
strcpy(chNewFmt, "!!! ");
|
|
break;
|
|
|
|
case DL_WARNING:
|
|
strcpy(chNewFmt, "!! ");
|
|
break;
|
|
|
|
case DL_INFO:
|
|
strcpy(chNewFmt, "! ");
|
|
break;
|
|
|
|
case DL_TRACE:
|
|
strcpy(chNewFmt, " ");
|
|
break;
|
|
}
|
|
strcat(chNewFmt, pchFormat);
|
|
|
|
#if DBG
|
|
if (dwDebugLevel <= gdwDebugLevel)
|
|
{
|
|
#if 0
|
|
DbgPrint("++NDPTSP++ ");
|
|
DbgPrint(chNewFmt, arglist);
|
|
DbgPrint("\n");
|
|
#else
|
|
char szBuffer[256];
|
|
OutputDebugString("++NDPTSP++ ");
|
|
wvsprintf(szBuffer, chNewFmt, arglist);
|
|
OutputDebugString(szBuffer);
|
|
OutputDebugString("\n");
|
|
#endif
|
|
}
|
|
#endif // DBG
|
|
|
|
if (gdwTraceID != INVALID_TRACEID)
|
|
{
|
|
TraceVprintfEx(gdwTraceID,
|
|
(dwDebugLevel << 16) | TRACE_USE_MASK | TRACE_USE_MSEC,
|
|
chNewFmt,
|
|
arglist);
|
|
}
|
|
|
|
va_end(arglist);
|
|
|
|
#if DBG
|
|
if (DL_ERROR == dwDebugLevel)
|
|
{
|
|
//DebugBreak();
|
|
}
|
|
#endif // DBG
|
|
}
|
|
|
|
#if DBG
|
|
|
|
#define INSERTVARDATASTRING(a,b,c,d,e,f) InsertVarDataString(a,b,c,d,e,f)
|
|
|
|
void
|
|
PASCAL
|
|
InsertVarDataString(
|
|
LPVOID pStruct,
|
|
LPDWORD pdwXxxSize,
|
|
LPVOID pNewStruct,
|
|
LPDWORD pdwNewXxxSize,
|
|
DWORD dwFixedStructSize,
|
|
char *pszFieldName
|
|
)
|
|
|
|
#else
|
|
|
|
#define INSERTVARDATASTRING(a,b,c,d,e,f) InsertVarDataString(a,b,c,d,e)
|
|
|
|
void
|
|
PASCAL
|
|
InsertVarDataString(
|
|
LPVOID pStruct,
|
|
LPDWORD pdwXxxSize,
|
|
LPVOID pNewStruct,
|
|
LPDWORD pdwNewXxxSize,
|
|
DWORD dwFixedStructSize
|
|
)
|
|
|
|
#endif
|
|
{
|
|
DWORD dwXxxSize, dwTotalSize, dwXxxOffset;
|
|
|
|
|
|
//
|
|
// If the dwXxxSize field of the old struct is non-zero, then
|
|
// we need to do a ascii->unicode conversion on it. Check to
|
|
// make sure that the size/offset are valid (if not set the
|
|
// data size/offset in the new struct to 0) and then convert.
|
|
//
|
|
|
|
if ((dwXxxSize = *pdwXxxSize))
|
|
{
|
|
dwXxxOffset = *(pdwXxxSize + 1);
|
|
|
|
#if DBG
|
|
dwTotalSize = ((LPVARSTRING) pStruct)->dwTotalSize;
|
|
|
|
if (dwXxxSize > (dwTotalSize - dwFixedStructSize) ||
|
|
dwXxxOffset < dwFixedStructSize ||
|
|
dwXxxOffset >= dwTotalSize ||
|
|
(dwXxxSize + dwXxxOffset) > dwTotalSize)
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"INSERTVARDATASTRING: bad %s values - size(x%x), "\
|
|
"offset(x%x)",
|
|
pszFieldName, dwXxxSize, dwXxxOffset);
|
|
|
|
*pdwNewXxxSize = *(pdwNewXxxSize + 1) = 0;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
// make sure the string is NULL terminated
|
|
*(((LPBYTE)pStruct) + (dwXxxOffset + dwXxxSize - 1)) = '\0';
|
|
|
|
MultiByteToWideChar(
|
|
CP_ACP,
|
|
MB_PRECOMPOSED,
|
|
((LPBYTE) pStruct) + dwXxxOffset,
|
|
dwXxxSize,
|
|
(LPWSTR) (((LPBYTE) pNewStruct) +
|
|
((LPVARSTRING) pNewStruct)->dwUsedSize),
|
|
dwXxxSize * 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)
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"INSERTVARDATA: bad %s values - size(x%x), offset(x%x)",
|
|
pszFieldName, dwXxxSize, dwXxxOffset);
|
|
|
|
*pdwNewXxxSize = *(pdwNewXxxSize + 1) = 0;
|
|
return;
|
|
}
|
|
#endif
|
|
CopyMemory(
|
|
((LPBYTE) pNewStruct) + ((LPVARSTRING) pNewStruct)->dwUsedSize,
|
|
((LPBYTE) pStruct) + dwXxxOffset,
|
|
dwXxxSize
|
|
);
|
|
|
|
*pdwNewXxxSize = dwXxxSize;
|
|
*(pdwNewXxxSize + 1) = ((LPVARSTRING) pNewStruct)->dwUsedSize; // offset
|
|
((LPVARSTRING) pNewStruct)->dwUsedSize += dwXxxSize;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
IsValidAddressChar(
|
|
WCHAR wch
|
|
)
|
|
{
|
|
// 0..9, A..F, * # .
|
|
if (iswdigit(wch) || (wch >= L'A' && wch <= L'F') ||
|
|
(wch >= L'a' && wch <= L'f') || wch == L'*' ||
|
|
wch == L'#' || wch == L'.')
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
int
|
|
CompareAddressChars(
|
|
WCHAR wch1,
|
|
WCHAR wch2
|
|
)
|
|
{
|
|
// convert lowercase to uppercase
|
|
wch1 = (WCHAR)towupper(wch1);
|
|
wch2 = (WCHAR)towupper(wch2);
|
|
|
|
return (int)(wch1-wch2);
|
|
}
|
|
|
|
int
|
|
CompareAddresses(
|
|
PCWSTR pwszAddress1,
|
|
PCWSTR pwszAddress2
|
|
)
|
|
{
|
|
WCHAR const * pCrt1,* pCrt2;
|
|
int iResult;
|
|
|
|
pCrt1 = pwszAddress1;
|
|
pCrt2 = pwszAddress2;
|
|
while (1)
|
|
{
|
|
// skip invalid chars from the first string
|
|
while (*pCrt1 && !IsValidAddressChar(*pCrt1))
|
|
{
|
|
pCrt1++;
|
|
}
|
|
|
|
// skip invalid chars from the second string
|
|
while (*pCrt2 && !IsValidAddressChar(*pCrt2))
|
|
{
|
|
pCrt2++;
|
|
}
|
|
|
|
if (!*pCrt1 && !*pCrt2)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (!*pCrt1)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
if (!*pCrt2)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
iResult = CompareAddressChars(*pCrt1, *pCrt2);
|
|
if (iResult!=0)
|
|
{
|
|
return iResult;
|
|
}
|
|
|
|
pCrt1++;
|
|
pCrt2++;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
FindAddressInOneList(
|
|
PADDRESS_MAP pAddress,
|
|
PCWSTR pwszAddress,
|
|
PADDRESS_MAP *pAddressEntry
|
|
)
|
|
{
|
|
while (pAddress!=NULL)
|
|
{
|
|
if (0 == CompareAddresses(pAddress->pwszAddress, pwszAddress))
|
|
{
|
|
// found !
|
|
*pAddressEntry = pAddress;
|
|
return TRUE;
|
|
}
|
|
pAddress = pAddress->pNext;
|
|
}
|
|
|
|
// not found
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
FindAddressInLists(
|
|
PADDRESS_MAP *pAddressListArray,
|
|
PCWSTR pwszAddress,
|
|
DWORD *pdwModeIndex,
|
|
PADDRESS_MAP *pAddressEntry
|
|
)
|
|
{
|
|
DWORD dwModeCnt;
|
|
|
|
for (dwModeCnt=0; dwModeCnt<NUM_NDP_MODES; dwModeCnt++)
|
|
{
|
|
if (FindAddressInOneList(pAddressListArray[dwModeCnt],
|
|
pwszAddress,
|
|
pAddressEntry))
|
|
{
|
|
*pdwModeIndex = dwModeCnt;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// not found
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
FreeAddressList(
|
|
PADDRESS_MAP pAddressList
|
|
)
|
|
{
|
|
PADDRESS_MAP pCrtCell;
|
|
PADDRESS_MAP pPrevCell;
|
|
|
|
pCrtCell = pAddressList;
|
|
|
|
while (pCrtCell!=NULL)
|
|
{
|
|
if (pCrtCell->pwszAddress)
|
|
{
|
|
FREE(pCrtCell->pwszAddress);
|
|
}
|
|
pPrevCell = pCrtCell;
|
|
pCrtCell = pCrtCell->pNext;
|
|
FREE(pPrevCell);
|
|
}
|
|
}
|
|
|
|
void
|
|
FreeAllAddressLists(
|
|
PADDRESS_MAP *pAddressListArray
|
|
)
|
|
{
|
|
DWORD dwModeCnt;
|
|
|
|
for (dwModeCnt=0; dwModeCnt<NUM_NDP_MODES; dwModeCnt++)
|
|
{
|
|
FreeAddressList(pAddressListArray[dwModeCnt]);
|
|
}
|
|
}
|
|
|
|
INT_PTR
|
|
CALLBACK
|
|
ProviderConfigDetailDlgProc(
|
|
HWND hDlg,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
LONG lStatus;
|
|
CONFIG_UI_CTX *UIContext;
|
|
|
|
PADDRESS_MAP pAddressList;
|
|
PADDRESS_MAP pAddress;
|
|
PADDRESS_MAP pLastCell;
|
|
DWORD dwStart;
|
|
DWORD dwEnd;
|
|
DWORD dwStrLength;
|
|
DWORD dwTmp;
|
|
PADDRESS_MAP pAddressEntry;
|
|
PWSTR pwszAddress = NULL;
|
|
PWSTR pwszCrt;
|
|
WCHAR wszTmp[0x40];
|
|
DWORD dwLengthW;
|
|
DWORD dwErrorID;
|
|
|
|
// decode
|
|
switch (uMsg) {
|
|
|
|
case WM_HELP:
|
|
|
|
// F1 key or the "?" button is pressed
|
|
(void) WinHelpW(((LPHELPINFO) lParam)->hItemHandle,
|
|
NDPTSP_HELP_FILE,
|
|
HELP_WM_HELP,
|
|
(DWORD_PTR) (LPVOID) g_aHelpIDs_IDD_MEDIA_ADD);
|
|
break;
|
|
|
|
case WM_CONTEXTMENU:
|
|
|
|
// Right-mouse click on a dialog control
|
|
(void) WinHelpW((HWND) wParam,
|
|
NDPTSP_HELP_FILE,
|
|
HELP_CONTEXTMENU,
|
|
(DWORD_PTR) (LPVOID) g_aHelpIDs_IDD_MEDIA_ADD);
|
|
break;
|
|
|
|
case WM_INITDIALOG:
|
|
|
|
SetWindowLongPtr(hDlg,
|
|
DWLP_USER,
|
|
lParam);
|
|
|
|
SetFocus(GetDlgItem(hDlg, IDC_ADD_ADDRESS));
|
|
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
|
|
UIContext = (CONFIG_UI_CTX *)GetWindowLongPtr(hDlg, DWLP_USER);
|
|
|
|
// decode command
|
|
switch (LOWORD(wParam)) {
|
|
|
|
case IDOK:
|
|
|
|
pAddressList = NULL;
|
|
pLastCell = NULL;
|
|
dwErrorID = 0;
|
|
|
|
// Get the text
|
|
SendDlgItemMessageW(hDlg, IDC_ADD_ADDRESS, EM_SETSEL, 0, -1);
|
|
SendDlgItemMessageW(hDlg, IDC_ADD_ADDRESS,
|
|
EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwEnd);
|
|
|
|
dwEnd++; // add room for a NULL terminator
|
|
dwStrLength = dwEnd*sizeof(WCHAR); // We have unicode chars
|
|
pwszAddress = (dwEnd <= ARRAYSIZE(wszTmp)) ? wszTmp :
|
|
MALLOC(dwStrLength);
|
|
if (pwszAddress==NULL)
|
|
{
|
|
TspLog(DL_ERROR, "ProviderConfigDetailDlgProc: out of mem");
|
|
break;
|
|
}
|
|
|
|
GetWindowTextW(GetDlgItem(hDlg, IDC_ADD_ADDRESS),
|
|
pwszAddress, dwEnd);
|
|
|
|
// Parse the string and create a local list
|
|
pwszCrt = pwszAddress;
|
|
while (*pwszCrt)
|
|
{
|
|
PWSTR pwszNext;
|
|
WCHAR wch;
|
|
|
|
// trim leading spaces
|
|
while ((*pwszCrt == L' ') || (*pwszCrt == L','))
|
|
{
|
|
pwszCrt++;
|
|
}
|
|
|
|
// check if trimming the spaces toke us to the end of the string
|
|
if (*pwszCrt)
|
|
{
|
|
// find next space and make it a temporary null
|
|
// in the same time verify the address chars
|
|
pwszNext = pwszCrt;
|
|
while (*pwszNext &&
|
|
(*pwszNext != L' ') &&
|
|
(*pwszNext != L',') )
|
|
{
|
|
// All characters allowed
|
|
|
|
//if (*pszNext>='0' && *pszNext<='9')
|
|
pwszNext++;
|
|
//else
|
|
//{
|
|
// dwErrorID = IDS_ERR_BAD_ADDRESS;
|
|
// break;
|
|
//}
|
|
}
|
|
if (dwErrorID)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// save the char and replace with a temporary NULL
|
|
wch = *pwszNext;
|
|
*pwszNext = L'\0';
|
|
|
|
// Test 1 - the address must not be already assigned
|
|
if (FindAddressInLists(UIContext->pAddressMapListArray,
|
|
pwszCrt,
|
|
&dwTmp,
|
|
&pAddressEntry))
|
|
{
|
|
dwErrorID = IDS_ERR_ALREADY_ASSIGNED;
|
|
break;
|
|
}
|
|
|
|
// Test 2 - the address must be unique in the edit field
|
|
if (FindAddressInOneList(pAddressList,
|
|
pwszCrt,
|
|
&pAddressEntry))
|
|
{
|
|
dwErrorID = IDS_ERR_DUPLICATE_ADDRESS;
|
|
break;
|
|
}
|
|
|
|
// Create cell
|
|
pAddress = (PADDRESS_MAP)MALLOC(sizeof(ADDRESS_MAP));
|
|
if (pAddress == NULL)
|
|
{
|
|
dwErrorID = IDS_ERR_OOM;
|
|
break;
|
|
}
|
|
|
|
dwLengthW = lstrlenW(pwszCrt);
|
|
pAddress -> pwszAddress = MALLOC((dwLengthW + 1)*sizeof(WCHAR));
|
|
if (pAddress->pwszAddress == NULL)
|
|
{
|
|
dwErrorID = IDS_ERR_OOM;
|
|
FREE(pAddress);
|
|
break;
|
|
}
|
|
|
|
lstrcpynW(pAddress->pwszAddress, pwszCrt, dwLengthW+1);
|
|
pAddress->dwAddressLength = dwLengthW;
|
|
|
|
// insert the entry in the local list
|
|
pAddress->pNext = NULL;
|
|
pAddress->pPrev = pLastCell;
|
|
if (pLastCell)
|
|
{
|
|
pLastCell->pNext = pAddress;
|
|
}
|
|
else
|
|
{
|
|
pAddressList = pAddress;
|
|
}
|
|
pLastCell = pAddress;
|
|
|
|
// replace our temporary null with it's previous value
|
|
*pwszNext = wch;
|
|
|
|
// advance the pszCrt point
|
|
pwszCrt = pwszNext;
|
|
}
|
|
}
|
|
|
|
if (pwszAddress!=wszTmp)
|
|
{
|
|
FREE(pwszAddress);
|
|
}
|
|
|
|
if (dwErrorID == 0)
|
|
{
|
|
// no error
|
|
PADDRESS_MAP *ppInsertPoint;
|
|
|
|
if (pAddressList)
|
|
{
|
|
// add the addresses to the list box
|
|
for (pAddress=pAddressList;
|
|
pAddress!=NULL;
|
|
pAddress = pAddress->pNext)
|
|
{
|
|
SendMessageW(UIContext->hwndListBox,
|
|
LB_ADDSTRING,
|
|
0,
|
|
(LPARAM)pAddress->pwszAddress);
|
|
}
|
|
|
|
// glue the local list to the global one
|
|
ppInsertPoint = &UIContext->pAddressMapListArray[
|
|
UIContext->dwCrtTypeIndex];
|
|
pLastCell->pNext = *ppInsertPoint;
|
|
if (pLastCell->pNext)
|
|
{
|
|
pLastCell->pNext->pPrev = pLastCell;
|
|
}
|
|
*ppInsertPoint = pAddressList;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WCHAR wszErrorMsg[0x100];
|
|
|
|
// load error string
|
|
LoadStringW(ghInstance,
|
|
dwErrorID,
|
|
wszErrorMsg,
|
|
ARRAYSIZE(wszErrorMsg));
|
|
|
|
// pop up error dialog
|
|
MessageBoxW(hDlg,wszErrorMsg,NULL,MB_OK | MB_ICONEXCLAMATION);
|
|
|
|
break;
|
|
}
|
|
|
|
// close dialog
|
|
EndDialog(hDlg, 0);
|
|
break;
|
|
|
|
case IDCANCEL:
|
|
|
|
// close dialog
|
|
EndDialog(hDlg, 0);
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// success
|
|
return FALSE;
|
|
}
|
|
|
|
LONG
|
|
RegistrySaveConfig(
|
|
PADDRESS_MAP *pAddressListArray
|
|
)
|
|
{
|
|
HKEY hKey;
|
|
HKEY hNotifyKey;
|
|
LONG lRes;
|
|
DWORD dwDisp;
|
|
DWORD dwModeCnt;
|
|
PADDRESS_MAP pAddress;
|
|
DWORD dwLengthW;
|
|
DWORD dwTotalLengthW;
|
|
DWORD dwBufferLengthW;
|
|
WCHAR wszBuffer[0x100];
|
|
PWSTR pwszBuffer;
|
|
PWSTR pwszCrt;
|
|
|
|
// Open/create the key
|
|
lRes = RegCreateKeyExW (HKEY_LOCAL_MACHINE,
|
|
NDPTSP_REGKEY_ROOT,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_READ | KEY_WRITE,
|
|
NULL,
|
|
&hKey,
|
|
&dwDisp
|
|
);
|
|
|
|
if (lRes != ERROR_SUCCESS)
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"RegistrySaveConfig: open/create config key failed(%ld)",
|
|
lRes);
|
|
|
|
return lRes;
|
|
}
|
|
|
|
// for speed we use a local buffer. If it is too small, alloc one
|
|
pwszBuffer = wszBuffer;
|
|
dwBufferLengthW = ARRAYSIZE(wszBuffer);
|
|
|
|
// for each type
|
|
for (dwModeCnt=0; dwModeCnt<NUM_NDP_MODES; dwModeCnt++)
|
|
{
|
|
pAddress = pAddressListArray[dwModeCnt];
|
|
|
|
// calculate the length needed for multistring
|
|
dwTotalLengthW = 1;
|
|
while (pAddress!=NULL)
|
|
{
|
|
dwTotalLengthW += pAddress->dwAddressLength + 1;
|
|
pAddress = pAddress->pNext;
|
|
}
|
|
|
|
if (dwTotalLengthW > dwBufferLengthW)
|
|
{
|
|
// need a bigger buffer..
|
|
if (pwszBuffer!=wszBuffer)
|
|
{
|
|
FREE(pwszBuffer);
|
|
}
|
|
|
|
pwszBuffer = MALLOC(dwTotalLengthW*sizeof(WCHAR));
|
|
if (pwszBuffer == NULL)
|
|
{
|
|
TspLog(DL_ERROR, "RegistrySaveConfig: out of mem");
|
|
RegCloseKey(hKey);
|
|
return ERROR_OUTOFMEMORY;
|
|
}
|
|
dwBufferLengthW = dwTotalLengthW;
|
|
}
|
|
|
|
pAddress = pAddressListArray[dwModeCnt];
|
|
pwszCrt = pwszBuffer;
|
|
|
|
// linear search, hope not too many values...
|
|
while (pAddress != NULL)
|
|
{
|
|
// Add the value to the multi string
|
|
lstrcpyW(pwszCrt, pAddress->pwszAddress);
|
|
// prepare for next string
|
|
pwszCrt += pAddress->dwAddressLength + 1 ;
|
|
|
|
pAddress = pAddress->pNext;
|
|
}
|
|
// final NULL
|
|
*pwszCrt++ = L'\0';
|
|
|
|
dwLengthW = (DWORD)(pwszCrt - pwszBuffer);
|
|
lRes = RegSetValueExW(hKey,
|
|
NdpModeArray[dwModeCnt].pwszRegString,
|
|
0,
|
|
REG_MULTI_SZ,
|
|
(PVOID)pwszBuffer,
|
|
dwLengthW*sizeof(WCHAR));
|
|
if (lRes != ERROR_SUCCESS)
|
|
{
|
|
TspLog(DL_ERROR, "RegistrySaveConfig: failed(%ld) to save value",
|
|
lRes);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// notify the server with a volatile key
|
|
if (lRes==ERROR_SUCCESS)
|
|
{
|
|
lRes = RegCreateKeyExW(hKey,
|
|
NDPTSP_NOTIFY_SUBKEY,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_VOLATILE,
|
|
KEY_READ,
|
|
NULL,
|
|
&hNotifyKey,
|
|
&dwDisp);
|
|
|
|
if (lRes == ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey(hNotifyKey);
|
|
}
|
|
else
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"RegistrySaveConfig: failed(%ld) to create notify key",
|
|
lRes);
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
if (pwszBuffer != wszBuffer)
|
|
{
|
|
FREE(pwszBuffer);
|
|
}
|
|
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
RegistryLoadConfig(
|
|
PADDRESS_MAP *pAddressListArray
|
|
)
|
|
{
|
|
HKEY hKey;
|
|
LONG lRes;
|
|
DWORD dwDisp;
|
|
DWORD dwModeCnt;
|
|
PADDRESS_MAP pAddress;
|
|
PADDRESS_MAP pPrevCell;
|
|
DWORD dwLength;
|
|
DWORD dwLengthW;
|
|
DWORD dwBufferLength;
|
|
DWORD dwType;
|
|
WCHAR wszBuffer[0x100];
|
|
PWSTR pwszBuffer;
|
|
PWSTR pwszCrt;
|
|
|
|
FreeAllAddressLists(pAddressListArray);
|
|
|
|
// Open/create the key
|
|
lRes = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
|
|
NDPTSP_REGKEY_ROOT,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_READ ,
|
|
NULL,
|
|
&hKey,
|
|
&dwDisp);
|
|
|
|
if (lRes != ERROR_SUCCESS)
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"RegistryLoadConfig: open/create config key failed(%ld)",
|
|
lRes);
|
|
|
|
return lRes;
|
|
}
|
|
|
|
// for speed we use a local buffer. If it is too small, alloc one
|
|
pwszBuffer = wszBuffer;
|
|
dwBufferLength = sizeof(wszBuffer); // In bytes !!
|
|
|
|
// for each type
|
|
for (dwModeCnt=0; dwModeCnt<NUM_NDP_MODES; dwModeCnt++)
|
|
{
|
|
pPrevCell = NULL;
|
|
|
|
// try to load the value. If the space is a problem, grow the buffer
|
|
while (TRUE)
|
|
{
|
|
dwLength = dwBufferLength;
|
|
lRes = RegQueryValueExW(hKey,
|
|
NdpModeArray[dwModeCnt].pwszRegString,
|
|
NULL,
|
|
&dwType,
|
|
(PVOID)pwszBuffer,
|
|
&dwLength
|
|
);
|
|
|
|
if (lRes == ERROR_MORE_DATA)
|
|
{
|
|
// need a bigger buffer..
|
|
if (pwszBuffer!=wszBuffer)
|
|
{
|
|
FREE(pwszBuffer);
|
|
}
|
|
|
|
pwszBuffer = MALLOC(dwLength);
|
|
if (pwszBuffer == NULL)
|
|
{
|
|
TspLog(DL_ERROR, "RegistryLoadConfig: out of mem");
|
|
RegCloseKey(hKey);
|
|
return ERROR_OUTOFMEMORY;
|
|
}
|
|
|
|
dwBufferLength = dwLength;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (lRes != ERROR_SUCCESS || dwType != REG_MULTI_SZ)
|
|
{
|
|
// no values
|
|
pwszBuffer[0] = L'\0';
|
|
lRes = ERROR_SUCCESS;
|
|
}
|
|
|
|
// parse the multistring and create the list
|
|
pwszCrt = pwszBuffer;
|
|
|
|
while (*pwszCrt != L'\0')
|
|
{
|
|
// Alloc a cell
|
|
pAddress = (PADDRESS_MAP)MALLOC(sizeof(ADDRESS_MAP));
|
|
if (pAddress!= NULL)
|
|
{
|
|
dwLengthW = lstrlenW(pwszCrt);
|
|
pAddress->pwszAddress = MALLOC((dwLengthW + 1)*sizeof(WCHAR));
|
|
if (pAddress->pwszAddress != NULL)
|
|
{
|
|
lstrcpynW(pAddress->pwszAddress, pwszCrt, dwLengthW+1);
|
|
pAddress->dwAddressLength = dwLengthW;
|
|
|
|
// Insert in the list. Don't matter where, the lists are not sorted...
|
|
pAddress->pNext = NULL;
|
|
pAddress->pPrev = pPrevCell;
|
|
if (pPrevCell)
|
|
pPrevCell->pNext = pAddress;
|
|
else
|
|
pAddressListArray[dwModeCnt] = pAddress;
|
|
|
|
pPrevCell = pAddress;
|
|
}
|
|
else
|
|
{
|
|
TspLog(DL_ERROR, "RegistryLoadConfig: out of mem");
|
|
lRes = ERROR_OUTOFMEMORY;
|
|
FREE(pAddress);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TspLog(DL_ERROR, "RegistryLoadConfig: out of mem");
|
|
lRes = ERROR_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
// Next string
|
|
pwszCrt += dwLengthW + 1;
|
|
}
|
|
}
|
|
|
|
if (lRes!=ERROR_SUCCESS)
|
|
{
|
|
FreeAllAddressLists(pAddressListArray);
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
if (pwszBuffer != wszBuffer)
|
|
{
|
|
FREE(pwszBuffer);
|
|
}
|
|
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
GetMediaModeForAddress(
|
|
PCWSTR pwszAddress,
|
|
DWORD * pdwMediaMode
|
|
)
|
|
{
|
|
|
|
LONG lRes;
|
|
DWORD dwModeIndex;
|
|
PADDRESS_MAP pAddressEntry;
|
|
|
|
EnterCriticalSection(&gAddressMapCritSec);
|
|
|
|
// force a reload:
|
|
// 1. at first call
|
|
// 2. after a change notification
|
|
if (gbAddressMapListLoaded)
|
|
{
|
|
lRes = RegDeleteKeyW(HKEY_LOCAL_MACHINE,
|
|
NDPTSP_NOTIFY_REGKEY_ROOT);
|
|
|
|
gbAddressMapListLoaded = (lRes != ERROR_SUCCESS);
|
|
}
|
|
|
|
lRes = ERROR_SUCCESS;
|
|
if (!gbAddressMapListLoaded)
|
|
{
|
|
TspLog(DL_TRACE, "GetMediaModeForAddress: reload the reg settings");
|
|
|
|
lRes = RegistryLoadConfig(gpAddressMapListArray);
|
|
}
|
|
|
|
if (lRes == ERROR_SUCCESS)
|
|
{
|
|
if (FindAddressInLists(gpAddressMapListArray,
|
|
pwszAddress,
|
|
&dwModeIndex,
|
|
&pAddressEntry))
|
|
{
|
|
*pdwMediaMode = NdpModeArray[dwModeIndex].dwMediaMode;
|
|
}
|
|
else
|
|
{
|
|
*pdwMediaMode = LINEMEDIAMODE_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&gAddressMapCritSec);
|
|
|
|
return lRes;
|
|
}
|
|
|
|
void
|
|
UpdateAddressListBox(
|
|
PADDRESS_MAP pAddress,
|
|
HWND hwndListBox
|
|
)
|
|
{
|
|
|
|
SendMessageW(hwndListBox, LB_RESETCONTENT, 0, 0);
|
|
|
|
for (; pAddress!=NULL; pAddress = pAddress->pNext)
|
|
{
|
|
SendMessageW(hwndListBox,
|
|
LB_ADDSTRING,
|
|
0,
|
|
(LPARAM)(pAddress->pwszAddress));
|
|
}
|
|
}
|
|
|
|
INT_PTR
|
|
CALLBACK
|
|
ProviderConfigDlgProc(
|
|
HWND hDlg,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
LONG lStatus;
|
|
CONFIG_UI_CTX *UIContext;
|
|
DWORD dwModeIndex;
|
|
LONG lIndex;
|
|
LONG lRes;
|
|
WCHAR wszTmp[0x40];
|
|
|
|
// decode
|
|
switch (uMsg) {
|
|
|
|
case WM_HELP:
|
|
|
|
// F1 key or the "?" button is pressed
|
|
(void) WinHelpW(((LPHELPINFO)lParam)->hItemHandle,
|
|
NDPTSP_HELP_FILE,
|
|
HELP_WM_HELP,
|
|
(DWORD_PTR)(LPVOID)g_aHelpIDs_IDD_MEDIA_MAP);
|
|
|
|
break;
|
|
|
|
case WM_CONTEXTMENU:
|
|
|
|
// Right-mouse click on a dialog control
|
|
(void) WinHelpW((HWND)wParam,
|
|
NDPTSP_HELP_FILE,
|
|
HELP_CONTEXTMENU,
|
|
(DWORD_PTR)(LPVOID)g_aHelpIDs_IDD_MEDIA_MAP);
|
|
|
|
break;
|
|
|
|
case WM_INITDIALOG:
|
|
|
|
SetWindowLongPtr(
|
|
hDlg,
|
|
DWLP_USER,
|
|
lParam);
|
|
|
|
UIContext = (CONFIG_UI_CTX *)lParam;
|
|
|
|
// Get the registry values
|
|
lRes = RegistryLoadConfig(UIContext->pAddressMapListArray);
|
|
if (lRes != ERROR_SUCCESS)
|
|
{
|
|
WCHAR wszErrorMsg[0x100];
|
|
|
|
TspLog(DL_ERROR,
|
|
"ProviderConfigDlgProc: loading reg key failed(0x%08lx)",
|
|
lRes);
|
|
|
|
// load error string
|
|
LoadStringW(ghInstance,
|
|
IDS_ERR_REGLOAD,
|
|
wszErrorMsg,
|
|
ARRAYSIZE(wszErrorMsg));
|
|
|
|
// pop up error dialog
|
|
MessageBoxW(hDlg, wszErrorMsg, NULL, MB_OK | MB_ICONSTOP);
|
|
|
|
// stop dialog
|
|
EndDialog(hDlg, 0);
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
// populate the combo box
|
|
for (dwModeIndex = 0; dwModeIndex < NUM_NDP_MODES; dwModeIndex++)
|
|
{
|
|
LoadStringW(ghInstance,
|
|
NdpModeArray[dwModeIndex].dwResourceID,
|
|
wszTmp,
|
|
ARRAYSIZE(wszTmp));
|
|
|
|
|
|
lIndex = (LONG)SendDlgItemMessageW(hDlg,
|
|
IDC_MEDIA_TYPE,
|
|
CB_ADDSTRING,
|
|
0,
|
|
(LPARAM)wszTmp);
|
|
if (lIndex >= 0)
|
|
{
|
|
SendDlgItemMessage(hDlg,
|
|
IDC_MEDIA_TYPE,
|
|
CB_SETITEMDATA,
|
|
(WPARAM)lIndex,
|
|
(LPARAM)dwModeIndex);
|
|
}
|
|
else {
|
|
TspLog(DL_ERROR,
|
|
"ProviderConfigDlgProc: CB_ADDSTRING failed(%ld)",
|
|
lIndex);
|
|
}
|
|
|
|
}
|
|
|
|
// select the first
|
|
SendDlgItemMessage(hDlg, IDC_MEDIA_TYPE, CB_SETCURSEL, (WPARAM)0, 0);
|
|
dwModeIndex = (DWORD)SendDlgItemMessageW(hDlg,
|
|
IDC_MEDIA_TYPE,
|
|
CB_GETITEMDATA,
|
|
(WPARAM)0,
|
|
0);
|
|
|
|
UIContext->hwndListBox = GetDlgItem(hDlg, IDC_ADDRESS_LIST);
|
|
UIContext->dwCrtTypeIndex = dwModeIndex;
|
|
|
|
// update the listbox
|
|
UpdateAddressListBox(UIContext->pAddressMapListArray[dwModeIndex],
|
|
UIContext->hwndListBox);
|
|
|
|
// Disable the Delete button
|
|
EnableWindow(GetDlgItem(hDlg, IDC_DELETE_ADDRESS), FALSE);
|
|
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
|
|
UIContext = (CONFIG_UI_CTX *)GetWindowLongPtr(hDlg, DWLP_USER);
|
|
|
|
// decode command
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case IDC_ADD_ADDRESS:
|
|
|
|
if (HIWORD(wParam)==BN_CLICKED)
|
|
{
|
|
DialogBoxParamW(ghInstance,
|
|
(LPWSTR)MAKEINTRESOURCE(IDD_MEDIA_ADD),
|
|
hDlg,
|
|
ProviderConfigDetailDlgProc,
|
|
(LPARAM)UIContext);
|
|
}
|
|
break;
|
|
|
|
case IDC_DELETE_ADDRESS:
|
|
|
|
if (HIWORD(wParam)==BN_CLICKED)
|
|
{
|
|
lIndex = (LONG)SendDlgItemMessageW(hDlg,
|
|
IDC_ADDRESS_LIST,
|
|
LB_GETCURSEL,
|
|
0,
|
|
0);
|
|
if (lIndex>=0)
|
|
{
|
|
PWSTR pwszAddress = NULL;
|
|
DWORD dwLengthW;
|
|
DWORD dwMode;
|
|
PADDRESS_MAP pAddress;
|
|
|
|
dwLengthW =1 + (DWORD)SendDlgItemMessageW(hDlg,
|
|
IDC_ADDRESS_LIST,
|
|
LB_GETTEXTLEN,
|
|
(WPARAM)lIndex,
|
|
0);
|
|
|
|
pwszAddress = (dwLengthW <= ARRAYSIZE(wszTmp)) ? wszTmp :
|
|
MALLOC(dwLengthW * sizeof(WCHAR));
|
|
|
|
if (pwszAddress)
|
|
{
|
|
SendDlgItemMessageW(hDlg,
|
|
IDC_ADDRESS_LIST,
|
|
LB_GETTEXT,
|
|
(WPARAM)lIndex,
|
|
(LPARAM)pwszAddress);
|
|
|
|
// Find the address in the lists
|
|
if (FindAddressInLists(UIContext->pAddressMapListArray,
|
|
pwszAddress,
|
|
&dwMode,
|
|
&pAddress))
|
|
{
|
|
// delete from list
|
|
if (pAddress->pNext)
|
|
{
|
|
pAddress->pNext->pPrev = pAddress->pPrev;
|
|
}
|
|
if (pAddress->pPrev)
|
|
{
|
|
pAddress->pPrev->pNext = pAddress->pNext;
|
|
}
|
|
else
|
|
{
|
|
UIContext->pAddressMapListArray[dwMode] =
|
|
pAddress->pNext;
|
|
}
|
|
|
|
FREE(pAddress->pwszAddress);
|
|
FREE(pAddress);
|
|
}
|
|
else
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"ProviderConfigDlgProc: "\
|
|
"IDC_DELETE_ADDRESS - cannot find address");
|
|
}
|
|
|
|
// delete from list box
|
|
SendDlgItemMessageW(hDlg,
|
|
IDC_ADDRESS_LIST,
|
|
LB_DELETESTRING,
|
|
(WPARAM)lIndex,
|
|
0);
|
|
|
|
// Try to select the previous one
|
|
if (lIndex > 0)
|
|
{
|
|
lIndex--;
|
|
}
|
|
|
|
if (LB_ERR == SendDlgItemMessageW(hDlg,
|
|
IDC_ADDRESS_LIST,
|
|
LB_SETCURSEL,
|
|
(WPARAM)lIndex,
|
|
0))
|
|
{
|
|
// Disable the Delete button
|
|
EnableWindow(GetDlgItem(hDlg, IDC_DELETE_ADDRESS),
|
|
FALSE);
|
|
}
|
|
|
|
|
|
if (pwszAddress != wszTmp)
|
|
{
|
|
FREE(pwszAddress);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"ProviderConfigDlgProc: "\
|
|
"IDC_DELETE_ADDRESS - out of memory");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TspLog(DL_ERROR, "ProviderConfigDlgProc: "\
|
|
"IDC_DELETE_ADDRESS - no item selected");
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case IDOK:
|
|
RegistrySaveConfig(UIContext->pAddressMapListArray);
|
|
|
|
FreeAllAddressLists(UIContext->pAddressMapListArray);
|
|
|
|
// close dialog
|
|
EndDialog(hDlg, 0);
|
|
break;
|
|
|
|
case IDCANCEL:
|
|
|
|
FreeAllAddressLists(UIContext->pAddressMapListArray);
|
|
|
|
// close dialog
|
|
EndDialog(hDlg, 0);
|
|
break;
|
|
|
|
case IDC_MEDIA_TYPE:
|
|
|
|
if (HIWORD(wParam)==CBN_SELCHANGE)
|
|
{
|
|
// Disable the Delete button
|
|
EnableWindow(GetDlgItem(hDlg, IDC_DELETE_ADDRESS), FALSE);
|
|
|
|
// refresh the list box
|
|
lIndex = (LONG)SendDlgItemMessageW(hDlg,
|
|
IDC_MEDIA_TYPE,
|
|
CB_GETCURSEL,
|
|
0,
|
|
0);
|
|
|
|
dwModeIndex = (DWORD)SendDlgItemMessageW(hDlg,
|
|
IDC_MEDIA_TYPE,
|
|
CB_GETITEMDATA,
|
|
(WPARAM)lIndex,
|
|
0);
|
|
|
|
// Update the context structure
|
|
UIContext->dwCrtTypeIndex = dwModeIndex;
|
|
|
|
// update the listbox
|
|
UpdateAddressListBox(
|
|
UIContext->pAddressMapListArray[dwModeIndex],
|
|
GetDlgItem(hDlg, IDC_ADDRESS_LIST));
|
|
}
|
|
|
|
break;
|
|
|
|
case IDC_ADDRESS_LIST:
|
|
if (HIWORD(wParam) == LBN_SELCHANGE)
|
|
{
|
|
// Enable the Delete button
|
|
EnableWindow(GetDlgItem(hDlg, IDC_DELETE_ADDRESS), TRUE);
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// success
|
|
return FALSE;
|
|
}
|
|
|
|
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"
|
|
};
|
|
|
|
//
|
|
// translates NDIS TAPI status codes into LINEERR_XXX
|
|
//
|
|
LONG
|
|
WINAPI
|
|
TranslateDriverResult(
|
|
ULONG ulRes
|
|
)
|
|
{
|
|
typedef struct _RESULT_LOOKUP
|
|
{
|
|
ULONG NdisTapiResult;
|
|
LONG TapiResult;
|
|
|
|
} RESULT_LOOKUP, *PRESULT_LOOKUP;
|
|
|
|
typedef ULONG NDIS_STATUS;
|
|
#define NDIS_STATUS_SUCCESS 0x00000000L
|
|
#define NDIS_STATUS_RESOURCES 0xC000009AL
|
|
#define NDIS_STATUS_FAILURE 0xC0000001L
|
|
#define NDIS_STATUS_INVALID_OID 0xC0010017L
|
|
|
|
static RESULT_LOOKUP aResults[] =
|
|
{
|
|
|
|
//
|
|
// Defined in NDIS.H
|
|
//
|
|
|
|
{ NDIS_STATUS_SUCCESS ,0 },
|
|
|
|
//
|
|
// These errors are defined in NDISTAPI.H
|
|
//
|
|
|
|
{ NDIS_STATUS_TAPI_ADDRESSBLOCKED ,LINEERR_ADDRESSBLOCKED },
|
|
{ NDIS_STATUS_TAPI_BEARERMODEUNAVAIL ,LINEERR_BEARERMODEUNAVAIL },
|
|
{ NDIS_STATUS_TAPI_CALLUNAVAIL ,LINEERR_CALLUNAVAIL },
|
|
{ NDIS_STATUS_TAPI_DIALBILLING ,LINEERR_DIALBILLING },
|
|
{ NDIS_STATUS_TAPI_DIALDIALTONE ,LINEERR_DIALDIALTONE },
|
|
{ NDIS_STATUS_TAPI_DIALPROMPT ,LINEERR_DIALPROMPT },
|
|
{ NDIS_STATUS_TAPI_DIALQUIET ,LINEERR_DIALQUIET },
|
|
{ NDIS_STATUS_TAPI_INCOMPATIBLEEXTVERSION,LINEERR_INCOMPATIBLEEXTVERSION},
|
|
{ NDIS_STATUS_TAPI_INUSE ,LINEERR_INUSE },
|
|
{ NDIS_STATUS_TAPI_INVALADDRESS ,LINEERR_INVALADDRESS },
|
|
{ NDIS_STATUS_TAPI_INVALADDRESSID ,LINEERR_INVALADDRESSID },
|
|
{ NDIS_STATUS_TAPI_INVALADDRESSMODE ,LINEERR_INVALADDRESSMODE },
|
|
{ NDIS_STATUS_TAPI_INVALBEARERMODE ,LINEERR_INVALBEARERMODE },
|
|
{ NDIS_STATUS_TAPI_INVALCALLHANDLE ,LINEERR_INVALCALLHANDLE },
|
|
{ NDIS_STATUS_TAPI_INVALCALLPARAMS ,LINEERR_INVALCALLPARAMS },
|
|
{ NDIS_STATUS_TAPI_INVALCALLSTATE ,LINEERR_INVALCALLSTATE },
|
|
{ NDIS_STATUS_TAPI_INVALDEVICECLASS ,LINEERR_INVALDEVICECLASS },
|
|
{ NDIS_STATUS_TAPI_INVALLINEHANDLE ,LINEERR_INVALLINEHANDLE },
|
|
{ NDIS_STATUS_TAPI_INVALLINESTATE ,LINEERR_INVALLINESTATE },
|
|
{ NDIS_STATUS_TAPI_INVALMEDIAMODE ,LINEERR_INVALMEDIAMODE },
|
|
{ NDIS_STATUS_TAPI_INVALRATE ,LINEERR_INVALRATE },
|
|
{ NDIS_STATUS_TAPI_NODRIVER ,LINEERR_NODRIVER },
|
|
{ NDIS_STATUS_TAPI_OPERATIONUNAVAIL ,LINEERR_OPERATIONUNAVAIL },
|
|
{ NDIS_STATUS_TAPI_RATEUNAVAIL ,LINEERR_RATEUNAVAIL },
|
|
{ NDIS_STATUS_TAPI_RESOURCEUNAVAIL ,LINEERR_RESOURCEUNAVAIL },
|
|
{ NDIS_STATUS_TAPI_STRUCTURETOOSMALL ,LINEERR_STRUCTURETOOSMALL },
|
|
{ NDIS_STATUS_TAPI_USERUSERINFOTOOBIG ,LINEERR_USERUSERINFOTOOBIG },
|
|
{ NDIS_STATUS_TAPI_ALLOCATED ,LINEERR_ALLOCATED },
|
|
{ NDIS_STATUS_TAPI_INVALADDRESSSTATE ,LINEERR_INVALADDRESSSTATE },
|
|
{ NDIS_STATUS_TAPI_INVALPARAM ,LINEERR_INVALPARAM },
|
|
{ NDIS_STATUS_TAPI_NODEVICE ,LINEERR_NODEVICE },
|
|
|
|
//
|
|
// These errors are defined in NDIS.H
|
|
//
|
|
|
|
{ NDIS_STATUS_RESOURCES ,LINEERR_NOMEM },
|
|
{ NDIS_STATUS_FAILURE ,LINEERR_OPERATIONFAILED },
|
|
{ NDIS_STATUS_INVALID_OID ,LINEERR_OPERATIONFAILED },
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
{ NDISTAPIERR_UNINITIALIZED ,LINEERR_OPERATIONFAILED },
|
|
{ NDISTAPIERR_BADDEVICEID ,LINEERR_OPERATIONFAILED },
|
|
{ NDISTAPIERR_DEVICEOFFLINE ,LINEERR_OPERATIONFAILED },
|
|
|
|
//
|
|
// The terminating fields
|
|
//
|
|
|
|
{ 0xffffffff, 0xffffffff }
|
|
|
|
};
|
|
|
|
int i;
|
|
|
|
for (i = 0; aResults[i].NdisTapiResult != 0xffffffff; i++)
|
|
{
|
|
if (ulRes == aResults[i].NdisTapiResult)
|
|
{
|
|
return (aResults[i].TapiResult);
|
|
}
|
|
}
|
|
|
|
TspLog(DL_WARNING, "TranslateDriverResult: unknown driver result(%x)",
|
|
ulRes);
|
|
|
|
return LINEERR_OPERATIONFAILED;
|
|
}
|
|
|
|
//
|
|
// NOTE: for functions that need to acquire (read, write) locks for both
|
|
// a line and a call, we enforce the order to be line first, call
|
|
// second to avoid potential DEADLOCK.
|
|
//
|
|
|
|
LONG
|
|
GetLineObjWithReadLock(
|
|
IN HDRVLINE hdLine,
|
|
OUT PDRVLINE *ppLine
|
|
)
|
|
{
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
|
|
lRes = GetObjWithReadLock((HANDLE)hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return LINEERR_INVALLINEHANDLE;
|
|
}
|
|
|
|
ASSERT(pLine != NULL);
|
|
if (pLine->dwKey != LINE_KEY)
|
|
{
|
|
TspLog(DL_WARNING, "GetLineObjWithReadLock: obj(%p) has bad key(%x)",
|
|
hdLine, pLine->dwKey);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return LINEERR_INVALLINEHANDLE;
|
|
}
|
|
|
|
*ppLine = pLine;
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
GetLineObjWithWriteLock(
|
|
IN HDRVLINE hdLine,
|
|
OUT PDRVLINE *ppLine
|
|
)
|
|
{
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
|
|
lRes = GetObjWithWriteLock((HANDLE)hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return LINEERR_INVALLINEHANDLE;
|
|
}
|
|
|
|
ASSERT(pLine != NULL);
|
|
if (pLine->dwKey != LINE_KEY)
|
|
{
|
|
TspLog(DL_WARNING, "GetLineObjWithWriteLock: obj(%p) has bad key(%x)",
|
|
hdLine, pLine->dwKey);
|
|
|
|
ReleaseObjWriteLock((HANDLE)hdLine);
|
|
return LINEERR_INVALLINEHANDLE;
|
|
}
|
|
|
|
*ppLine = pLine;
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
GetMSPLineObjWithReadLock(
|
|
IN HDRVMSPLINE hdMSPLine,
|
|
OUT PDRVMSPLINE *ppMSPLine
|
|
)
|
|
{
|
|
LONG lRes;
|
|
PDRVMSPLINE pMSPLine;
|
|
|
|
lRes = GetObjWithReadLock((HANDLE)hdMSPLine, &pMSPLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return LINEERR_INVALLINEHANDLE;
|
|
}
|
|
|
|
ASSERT(pMSPLine != NULL);
|
|
if (pMSPLine->dwKey != MSP_KEY)
|
|
{
|
|
TspLog(DL_WARNING, "GetMSPLineObjWithReadLock: obj(%p) has bad key(%x)",
|
|
hdMSPLine, pMSPLine->dwKey);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdMSPLine);
|
|
return LINEERR_INVALLINEHANDLE;
|
|
}
|
|
|
|
*ppMSPLine = pMSPLine;
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
GetMSPLineObjWithWriteLock(
|
|
IN HDRVMSPLINE hdMSPLine,
|
|
OUT PDRVMSPLINE *ppMSPLine
|
|
)
|
|
{
|
|
LONG lRes;
|
|
PDRVMSPLINE pMSPLine;
|
|
|
|
lRes = GetObjWithWriteLock((HANDLE)hdMSPLine, &pMSPLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return LINEERR_INVALLINEHANDLE;
|
|
}
|
|
|
|
ASSERT(pMSPLine != NULL);
|
|
if (pMSPLine->dwKey != MSP_KEY)
|
|
{
|
|
TspLog(DL_WARNING,
|
|
"GetMSPLineObjWithWriteLock: obj(%p) has bad key(%x)",
|
|
hdMSPLine, pMSPLine->dwKey);
|
|
|
|
ReleaseObjWriteLock((HANDLE)hdMSPLine);
|
|
return LINEERR_INVALLINEHANDLE;
|
|
}
|
|
|
|
*ppMSPLine = pMSPLine;
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
GetLineHandleFromMSPLineHandle(
|
|
IN HDRVMSPLINE hdMSPLine,
|
|
OUT HDRVLINE *phdLine
|
|
)
|
|
{
|
|
LONG lRes;
|
|
PDRVMSPLINE pMSPLine;
|
|
|
|
lRes = GetObjWithReadLock((HANDLE)hdMSPLine, &pMSPLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return LINEERR_INVALLINEHANDLE;
|
|
}
|
|
|
|
ASSERT(pMSPLine != NULL);
|
|
if (pMSPLine->dwKey != MSP_KEY)
|
|
{
|
|
TspLog(DL_WARNING,
|
|
"GetLineHandleFromMSPLineHandle: obj(%p) has bad key(%x)",
|
|
hdMSPLine, pMSPLine->dwKey);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdMSPLine);
|
|
return LINEERR_INVALLINEHANDLE;
|
|
}
|
|
|
|
*phdLine = pMSPLine->hdLine;
|
|
|
|
ReleaseObjReadLock((HANDLE)hdMSPLine);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
GetCallObjWithReadLock(
|
|
IN HDRVCALL hdCall,
|
|
OUT PDRVCALL *ppCall
|
|
)
|
|
{
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
|
|
lRes = GetObjWithReadLock((HANDLE)hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return LINEERR_INVALCALLHANDLE;
|
|
}
|
|
|
|
ASSERT(pCall != NULL);
|
|
if (pCall->dwKey != INBOUND_CALL_KEY &&
|
|
pCall->dwKey != OUTBOUND_CALL_KEY)
|
|
{
|
|
TspLog(DL_WARNING, "GetCallObjWithReadLock: obj(%p) has bad key(%x)",
|
|
hdCall, pCall->dwKey);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return LINEERR_INVALCALLHANDLE;
|
|
}
|
|
|
|
*ppCall = pCall;
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
GetCallObjWithWriteLock(
|
|
IN HDRVCALL hdCall,
|
|
OUT PDRVCALL *ppCall
|
|
)
|
|
{
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
|
|
lRes = GetObjWithWriteLock((HANDLE)hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return LINEERR_INVALCALLHANDLE;
|
|
}
|
|
|
|
ASSERT(pCall != NULL);
|
|
if (pCall->dwKey != INBOUND_CALL_KEY &&
|
|
pCall->dwKey != OUTBOUND_CALL_KEY)
|
|
{
|
|
TspLog(DL_WARNING, "GetCallObjWithWriteLock: obj(%p) has bad key(%x)",
|
|
hdCall, pCall->dwKey);
|
|
|
|
ReleaseObjWriteLock((HANDLE)hdCall);
|
|
return LINEERR_INVALCALLHANDLE;
|
|
}
|
|
|
|
*ppCall = pCall;
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
GetLineHandleFromCallHandle(
|
|
IN HDRVCALL hdCall,
|
|
OUT HDRVLINE *phdLine
|
|
)
|
|
{
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
|
|
lRes = GetObjWithReadLock((HANDLE)hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return LINEERR_INVALCALLHANDLE;
|
|
}
|
|
|
|
ASSERT(pCall != NULL);
|
|
if (pCall->dwKey != INBOUND_CALL_KEY &&
|
|
pCall->dwKey != OUTBOUND_CALL_KEY)
|
|
{
|
|
TspLog(DL_WARNING,
|
|
"GetLineHandleFromCallHandle: obj(%p) has bad key(%x)",
|
|
hdCall, pCall->dwKey);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return LINEERR_INVALCALLHANDLE;
|
|
}
|
|
|
|
*phdLine = pCall->hdLine;
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
GetLineAndCallObjWithReadLock(
|
|
HTAPI_LINE ht_Line,
|
|
HTAPI_CALL ht_Call,
|
|
PDRVLINE *ppLine,
|
|
PDRVCALL *ppCall
|
|
)
|
|
{
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
PDRVLINE pLine;
|
|
|
|
lRes = GetLineObjWithReadLock((HDRVLINE)ht_Line, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
*ppLine = pLine;
|
|
|
|
//
|
|
// figure out whether this is an inbound call or
|
|
// outbound call: for inbound calls, ht_Call is
|
|
// generated by NDPROXY and bit 0 is 1;
|
|
// for outbound calls, ht_Call is a TSP handle
|
|
// and we make sure that bit 0 is 0
|
|
//
|
|
if (ht_Call & 0x1)
|
|
{
|
|
// inbound call: we need to walk the list
|
|
// of inbound calls on this line and
|
|
// find the right one
|
|
if ((pCall = pLine->pInboundCalls) != NULL)
|
|
{
|
|
while (pCall && (pCall->ht_Call != ht_Call))
|
|
{
|
|
pCall = pCall->pNext;
|
|
}
|
|
}
|
|
|
|
if (NULL == pCall || pCall->dwKey != INBOUND_CALL_KEY)
|
|
{
|
|
TspLog(DL_WARNING,
|
|
"GetLineAndCallObjWithReadLock: "\
|
|
"inbound ht_call(%p) closed already",
|
|
ht_Call);
|
|
|
|
ReleaseObjReadLock((HANDLE)ht_Line);
|
|
return LINEERR_INVALCALLHANDLE;
|
|
}
|
|
|
|
// call the following to increase the ref count
|
|
lRes = AcquireObjReadLock((HANDLE)pCall->hdCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)ht_Line);
|
|
return lRes;
|
|
}
|
|
|
|
*ppCall = pCall;
|
|
|
|
return TAPI_SUCCESS;
|
|
}
|
|
|
|
// ht_Call is a TSP handle and the call is OUTBOUND
|
|
lRes = GetObjWithReadLock((HANDLE)ht_Call, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)ht_Line);
|
|
return lRes;
|
|
}
|
|
|
|
ASSERT(pCall != NULL);
|
|
if (pCall->dwKey != OUTBOUND_CALL_KEY)
|
|
{
|
|
TspLog(DL_WARNING,
|
|
"GetLineAndCallObjWithReadLock: bad call handle(%p, %x)",
|
|
ht_Call, pCall->dwKey);
|
|
|
|
ReleaseObjReadLock((HANDLE)ht_Call);
|
|
ReleaseObjReadLock((HANDLE)ht_Line);
|
|
return LINEERR_INVALCALLHANDLE;
|
|
}
|
|
|
|
*ppCall = pCall;
|
|
|
|
return TAPI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// allocates mem for a NDISTAPI_REQUEST plus some initialization
|
|
//
|
|
LONG
|
|
WINAPI
|
|
PrepareSyncRequest(
|
|
ULONG Oid,
|
|
ULONG ulDeviceID,
|
|
DWORD dwDataSize,
|
|
PNDISTAPI_REQUEST *ppNdisTapiRequest
|
|
)
|
|
{
|
|
PNDISTAPI_REQUEST pNdisTapiRequest =
|
|
(PNDISTAPI_REQUEST)AllocRequest(dwDataSize + sizeof(NDISTAPI_REQUEST));
|
|
if (NULL == pNdisTapiRequest)
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"PrepareSyncRequest: failed to alloc sync req for oid(%x)",
|
|
Oid);
|
|
return LINEERR_NOMEM;
|
|
}
|
|
|
|
pNdisTapiRequest->Oid = Oid;
|
|
pNdisTapiRequest->ulDeviceID = ulDeviceID;
|
|
pNdisTapiRequest->ulDataSize = dwDataSize;
|
|
|
|
EnterCriticalSection(&gRequestIDCritSec);
|
|
|
|
// setting ulRequestId of NDIS_TAPI_xxxx
|
|
if ((*((ULONG *)pNdisTapiRequest->Data) = ++gdwRequestID) >= 0x7fffffff)
|
|
{
|
|
gdwRequestID = 1;
|
|
}
|
|
|
|
LeaveCriticalSection(&gRequestIDCritSec);
|
|
|
|
*ppNdisTapiRequest = pNdisTapiRequest;
|
|
|
|
return TAPI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// allocates mem for a ASYNC_REQUEST_WRAPPER plus some initialization
|
|
//
|
|
LONG
|
|
WINAPI
|
|
PrepareAsyncRequest(
|
|
ULONG Oid,
|
|
ULONG ulDeviceID,
|
|
DWORD dwRequestID,
|
|
DWORD dwDataSize,
|
|
PASYNC_REQUEST_WRAPPER *ppAsyncReqWrapper
|
|
)
|
|
{
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper;
|
|
|
|
// alloc & init an async request wrapper
|
|
pAsyncReqWrapper = (PASYNC_REQUEST_WRAPPER)
|
|
AllocRequest(dwDataSize + sizeof(ASYNC_REQUEST_WRAPPER));
|
|
if (NULL == pAsyncReqWrapper)
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"PrepareAsyncRequest: failed to alloc async req for oid(%x)",
|
|
Oid);
|
|
return LINEERR_NOMEM;
|
|
}
|
|
|
|
// don't need to create an event when using completion ports
|
|
pAsyncReqWrapper->Overlapped.hEvent = (HANDLE)NULL;
|
|
|
|
pAsyncReqWrapper->dwKey = ASYNCREQWRAPPER_KEY;
|
|
pAsyncReqWrapper->dwRequestID = dwRequestID;
|
|
pAsyncReqWrapper->pfnPostProcess = (POSTPROCESSPROC)NULL;
|
|
|
|
// initialize the critical section, ref the request wrapper.
|
|
// NOTE: this crit sec will be deleted by the last deref.
|
|
InitializeCriticalSection(&pAsyncReqWrapper->CritSec);
|
|
pAsyncReqWrapper->RefCount = 1;
|
|
|
|
// safely initialize the driver request
|
|
pNdisTapiRequest = &(pAsyncReqWrapper->NdisTapiRequest);
|
|
|
|
pNdisTapiRequest->Oid = Oid;
|
|
pNdisTapiRequest->ulDeviceID = ulDeviceID;
|
|
pNdisTapiRequest->ulDataSize = dwDataSize;
|
|
|
|
EnterCriticalSection(&gRequestIDCritSec);
|
|
|
|
if ((*((ULONG *)pNdisTapiRequest->Data) = ++gdwRequestID) >= 0x7fffffff)
|
|
{
|
|
gdwRequestID = 1;
|
|
}
|
|
|
|
LeaveCriticalSection(&gRequestIDCritSec);
|
|
|
|
*ppAsyncReqWrapper = pAsyncReqWrapper;
|
|
|
|
return TAPI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// makes a non-overlapped request to ndproxy.sys
|
|
// so it doesn't return until the req is completed
|
|
//
|
|
LONG
|
|
WINAPI
|
|
SyncDriverRequest(
|
|
DWORD dwIoControlCode,
|
|
PNDISTAPI_REQUEST pNdisTapiRequest
|
|
)
|
|
{
|
|
BOOL bRes;
|
|
DWORD cbReturned;
|
|
|
|
TspLog(DL_INFO,
|
|
"SyncDriverRequest: oid(%s), devID(%x), reqID(%x), hdCall(%x)",
|
|
pszOidNames[pNdisTapiRequest->Oid - OID_TAPI_ACCEPT],
|
|
pNdisTapiRequest->ulDeviceID,
|
|
*((ULONG *)pNdisTapiRequest->Data),
|
|
*(((ULONG *)pNdisTapiRequest->Data) + 1));
|
|
|
|
// mark the request as being processed by the driver
|
|
MarkRequest(pNdisTapiRequest);
|
|
|
|
bRes = DeviceIoControl(ghDriverSync,
|
|
dwIoControlCode,
|
|
pNdisTapiRequest,
|
|
(DWORD)(sizeof(NDISTAPI_REQUEST) +
|
|
pNdisTapiRequest->ulDataSize),
|
|
pNdisTapiRequest,
|
|
(DWORD)(sizeof(NDISTAPI_REQUEST) +
|
|
pNdisTapiRequest->ulDataSize),
|
|
&cbReturned,
|
|
0);
|
|
|
|
// unmark the request now that the ioctl is completed
|
|
UnmarkRequest(pNdisTapiRequest);
|
|
|
|
if (bRes != TRUE)
|
|
{
|
|
TspLog(DL_ERROR, "SyncDriverRequest: IoCtl(Oid %x) failed(%d)",
|
|
pNdisTapiRequest->Oid, GetLastError());
|
|
|
|
return (LINEERR_OPERATIONFAILED);
|
|
}
|
|
else
|
|
{
|
|
// the errors returned by ndproxy.sys don't match the TAPI
|
|
// LINEERR_'s, so return the translated values (but preserve
|
|
// the original driver return val so it's possible to distinguish
|
|
// between NDISTAPIERR_DEVICEOFFLINE & LINEERR_OPERATIONUNAVAIL,
|
|
// etc.)
|
|
return (TranslateDriverResult(pNdisTapiRequest->ulReturnValue));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// Sends a message to the MSP telling it the VC handle for a call and
|
|
// instructing it to begin streaming on that call.
|
|
//
|
|
// Arguments:
|
|
// hdLine - Handle to line device
|
|
// hdCall - Handle for call
|
|
//
|
|
// NOTES - must be called while holding the MSP mutex
|
|
//
|
|
VOID
|
|
StartMSPStream(
|
|
HDRVLINE hdLine,
|
|
HDRVCALL hdCall
|
|
)
|
|
{
|
|
LONG lRes;
|
|
DWORD adwMSPMessage[2];
|
|
PDRVLINE pLine;
|
|
PDRVCALL pCall;
|
|
PDRVMSPLINE pMSPLine;
|
|
LPVARSTRING lpDeviceID;
|
|
|
|
TspLog(DL_TRACE, "StartMSPStream: enter");
|
|
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return;
|
|
}
|
|
|
|
pMSPLine = pLine->pMSPLine;
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// allocate a VARSTRING structure with enough space for the DWORD line id.
|
|
// @@@ shouldn't always assume that this will be the right size.
|
|
//
|
|
lpDeviceID = (LPVARSTRING)MALLOC(sizeof(VARSTRING) + sizeof(DWORD));
|
|
if (NULL == lpDeviceID)
|
|
{
|
|
TspLog(DL_ERROR, "StartMSPStream: failed to alloc deviceID");
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return;
|
|
}
|
|
lpDeviceID->dwTotalSize = sizeof(VARSTRING) + sizeof(DWORD);
|
|
|
|
if ((lRes = TSPI_lineGetID(
|
|
hdLine,
|
|
0, // @@@ the proxy always makes this 0, so we use 0.
|
|
// Change this if the proxy changes.
|
|
hdCall,
|
|
LINECALLSELECT_CALL,
|
|
lpDeviceID,
|
|
RCA_SAP_STRING,
|
|
0 // @@@ we don't use this parameter, so I set it 0.
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
TspLog(DL_ERROR, "StartMSPStream: failed to get the VC handle");
|
|
|
|
FREE(lpDeviceID);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// pass the VC Handle to the MSP.
|
|
//
|
|
adwMSPMessage[0] = 0; // command code for "Here's the VC Handle"
|
|
adwMSPMessage[1] = *((DWORD *)(((PBYTE)lpDeviceID) +
|
|
lpDeviceID->dwStringOffset));
|
|
|
|
TspLog(DL_INFO,
|
|
"StartMSPStream: sending VC handle(%x) to htline(%p), htcall(%p)",
|
|
adwMSPMessage[1], pLine->htLine, pCall->htCall);
|
|
|
|
(*gpfnLineEvent)(pLine->htLine,
|
|
pCall->htCall,
|
|
LINE_SENDMSPDATA,
|
|
(DWORD_PTR)0,
|
|
(DWORD_PTR)adwMSPMessage,
|
|
(DWORD_PTR)sizeof(DWORD) * 2);
|
|
|
|
//
|
|
// tell the MSP to start streaming.
|
|
//
|
|
adwMSPMessage[0] = 1; // command code for "Start Streaming"
|
|
|
|
(*gpfnLineEvent)(pLine->htLine,
|
|
pCall->htCall,
|
|
LINE_SENDMSPDATA,
|
|
(DWORD_PTR)0,
|
|
(DWORD_PTR)adwMSPMessage,
|
|
(DWORD_PTR)sizeof(DWORD));
|
|
|
|
pMSPLine->bStreamingStarted = TRUE;
|
|
|
|
FREE(lpDeviceID);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
}
|
|
|
|
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// Sends a message to the MSP telling it to stop streaming on a
|
|
// particular call.
|
|
//
|
|
// Arguments:
|
|
// hdLine - Handle to line device
|
|
// hdCall - Handle for call
|
|
//
|
|
// NOTES - must be called while holding the MSP mutex
|
|
//
|
|
VOID
|
|
StopMSPStream(
|
|
HDRVLINE hdLine,
|
|
HDRVCALL hdCall
|
|
)
|
|
{
|
|
LONG lRes;
|
|
DWORD adwMSPMessage;
|
|
PDRVLINE pLine;
|
|
PDRVCALL pCall;
|
|
PDRVMSPLINE pMSPLine;
|
|
|
|
TspLog(DL_TRACE, "StopMSPStream: enter");
|
|
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return;
|
|
}
|
|
|
|
pMSPLine = pLine->pMSPLine;
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// tell the MSP to stop streaming.
|
|
//
|
|
adwMSPMessage = 2; // command code for "Stop Streaming"
|
|
|
|
TspLog(DL_INFO,
|
|
"StopMSPStream: sending MSP stop cmd to htline(%p), htcall(%p)",
|
|
pLine->htLine, pCall->htCall);
|
|
|
|
(*gpfnLineEvent)(pLine->htLine,
|
|
pCall->htCall,
|
|
LINE_SENDMSPDATA,
|
|
(DWORD_PTR)0,
|
|
(DWORD_PTR)&adwMSPMessage,
|
|
(DWORD_PTR)sizeof(DWORD));
|
|
|
|
pMSPLine->bStreamingStarted = FALSE;
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
}
|
|
|
|
//
|
|
// make an overlapped call
|
|
//
|
|
LONG
|
|
WINAPI
|
|
AsyncDriverRequest(
|
|
DWORD dwIoControlCode,
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper
|
|
)
|
|
{
|
|
BOOL bRes;
|
|
LONG lRes;
|
|
DWORD dwRequestSize, cbReturned, dwLastError;
|
|
|
|
TspLog(DL_INFO,
|
|
"AsyncDriverRequest: oid(%s), devID(%x), ReqID(%x), "
|
|
"reqID(%x), hdCall(%x)",
|
|
pszOidNames[pAsyncReqWrapper->NdisTapiRequest.Oid -
|
|
OID_TAPI_ACCEPT],
|
|
pAsyncReqWrapper->NdisTapiRequest.ulDeviceID,
|
|
pAsyncReqWrapper->dwRequestID,
|
|
*((ULONG *)pAsyncReqWrapper->NdisTapiRequest.Data),
|
|
*(((ULONG *)pAsyncReqWrapper->NdisTapiRequest.Data) + 1));
|
|
|
|
lRes = (LONG)pAsyncReqWrapper->dwRequestID;
|
|
|
|
dwRequestSize = sizeof(NDISTAPI_REQUEST) +
|
|
(pAsyncReqWrapper->NdisTapiRequest.ulDataSize - 1);
|
|
|
|
REF_ASYNC_REQUEST_WRAPPER(pAsyncReqWrapper);
|
|
|
|
// mark the request as being processed by the driver
|
|
MarkRequest(pAsyncReqWrapper);
|
|
|
|
bRes = DeviceIoControl(
|
|
ghDriverAsync,
|
|
dwIoControlCode,
|
|
&pAsyncReqWrapper->NdisTapiRequest,
|
|
dwRequestSize,
|
|
&pAsyncReqWrapper->NdisTapiRequest,
|
|
dwRequestSize,
|
|
&cbReturned,
|
|
&pAsyncReqWrapper->Overlapped
|
|
);
|
|
|
|
DEREF_ASYNC_REQUEST_WRAPPER(pAsyncReqWrapper);
|
|
|
|
if (bRes != TRUE) {
|
|
|
|
dwLastError = GetLastError();
|
|
|
|
if (dwLastError != ERROR_IO_PENDING) {
|
|
|
|
TspLog(DL_ERROR, "AsyncDriverRequest: IoCtl(oid %x) failed(%d)",
|
|
pAsyncReqWrapper->NdisTapiRequest.Oid, dwLastError);
|
|
|
|
// the ioctl failed and was not pended
|
|
// this does not trigger the completion port
|
|
// so we have to cleanup here.
|
|
(*gpfnCompletionProc)(pAsyncReqWrapper->dwRequestID,
|
|
LINEERR_OPERATIONFAILED);
|
|
|
|
DEREF_ASYNC_REQUEST_WRAPPER(pAsyncReqWrapper);
|
|
}
|
|
}
|
|
|
|
return lRes;
|
|
}
|
|
|
|
//
|
|
// reports to TAPI events that occur on the line or on calls on the line
|
|
//
|
|
VOID
|
|
WINAPI
|
|
ProcessEvent(
|
|
PNDIS_TAPI_EVENT pEvent
|
|
)
|
|
{
|
|
LONG lRes;
|
|
ULONG ulMsg = pEvent->ulMsg;
|
|
HTAPI_LINE ht_Line = (HTAPI_LINE)pEvent->htLine;
|
|
HTAPI_CALL ht_Call = (HTAPI_CALL)pEvent->htCall;
|
|
|
|
TspLog(DL_INFO,
|
|
"ProcessEvent: event(%p), msg(%x), ht_line(%p), ht_call(%p), "\
|
|
"p1(%p), p2(%p), p3(%p)",
|
|
pEvent, ulMsg, ht_Line, ht_Call,
|
|
pEvent->ulParam1, pEvent->ulParam2, pEvent->ulParam3);
|
|
|
|
switch (ulMsg)
|
|
{
|
|
case LINE_ADDRESSSTATE:
|
|
case LINE_CLOSE:
|
|
case LINE_DEVSPECIFIC:
|
|
case LINE_LINEDEVSTATE:
|
|
{
|
|
PDRVLINE pLine;
|
|
|
|
lRes = GetLineObjWithReadLock((HDRVLINE)ht_Line, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
TspLog(DL_INFO,
|
|
"PE::fnLineEvent: msg(%x), htline(%p), p1(%p), p2(%p), p3(%p)",
|
|
ulMsg, pLine->htLine,
|
|
pEvent->ulParam1, pEvent->ulParam2, pEvent->ulParam3);
|
|
|
|
(*gpfnLineEvent)(pLine->htLine,
|
|
(HTAPICALL)NULL,
|
|
ulMsg,
|
|
(DWORD_PTR)pEvent->ulParam1,
|
|
(DWORD_PTR)pEvent->ulParam2,
|
|
(DWORD_PTR)pEvent->ulParam3);
|
|
|
|
ReleaseObjReadLock((HANDLE)ht_Line);
|
|
|
|
break;
|
|
}
|
|
case LINE_CALLDEVSPECIFIC:
|
|
case LINE_CALLINFO:
|
|
{
|
|
PDRVLINE pLine;
|
|
PDRVCALL pCall;
|
|
HDRVLINE hdLine;
|
|
|
|
lRes = GetLineAndCallObjWithReadLock(ht_Line, ht_Call, &pLine, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
hdLine = pCall->hdLine;
|
|
|
|
TspLog(DL_INFO,
|
|
"PE::fnLineEvent: msg(%x), htline(%p), htcall(%p), "\
|
|
"p1(%p), p2(%p), p3(%p)",
|
|
ulMsg, pLine->htLine, pCall->htCall,
|
|
pEvent->ulParam1, pEvent->ulParam2, pEvent->ulParam3);
|
|
|
|
(*gpfnLineEvent)(pLine->htLine,
|
|
pCall->htCall,
|
|
ulMsg,
|
|
(DWORD_PTR)pEvent->ulParam1,
|
|
(DWORD_PTR)pEvent->ulParam2,
|
|
(DWORD_PTR)pEvent->ulParam3);
|
|
|
|
ReleaseObjReadLock((HANDLE)pCall->hdCall);
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
|
|
break;
|
|
}
|
|
case LINE_CALLSTATE:
|
|
{
|
|
DWORD dwWaitStatus;
|
|
PDRVLINE pLine;
|
|
PDRVCALL pCall;
|
|
HDRVLINE hdLine;
|
|
|
|
lRes = GetLineAndCallObjWithReadLock(ht_Line, ht_Call, &pLine, &pCall);
|
|
// we may still receive a few events
|
|
// for calls that have been closed/dropped
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
hdLine = pCall->hdLine;
|
|
|
|
//
|
|
// for outbound calls there exists a race condition between
|
|
// receiving the first call state msg(s) and receiving the
|
|
// make call completion notification (if we pass a call state
|
|
// msg on to tapi for a call that hasn't been completed yet
|
|
// tapi will just discard the msg since the htCall really
|
|
// isn't valid at that point). So if htCall references a
|
|
// valid outbound call which hasn't completed yet, we'll save
|
|
// the call state params, and pass them on to tapi after we
|
|
// get & indicate a (successful) completion notification.
|
|
//
|
|
|
|
if ((OUTBOUND_CALL_KEY == pCall->dwKey) &&
|
|
(TRUE == pCall->bIncomplete))
|
|
{
|
|
TspLog(DL_INFO,
|
|
"ProcessEvent: incomplete outbound call, saving state");
|
|
|
|
pCall->dwPendingCallState = (DWORD)pEvent->ulParam1;
|
|
pCall->dwPendingCallStateMode = (DWORD)pEvent->ulParam2;
|
|
pCall->dwPendingMediaMode = (DWORD)pEvent->ulParam3;
|
|
|
|
ReleaseObjReadLock((HANDLE)pCall->hdCall);
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Start or stop the MSP streaming as appropriate. The only states in
|
|
// which this might happen are CONNECTED, DISCONNECTED, or IDLE.
|
|
//
|
|
if ((LINECALLSTATE_CONNECTED == pEvent->ulParam1) ||
|
|
(LINECALLSTATE_DISCONNECTED == pEvent->ulParam1) ||
|
|
(LINECALLSTATE_IDLE == pEvent->ulParam1)) {
|
|
|
|
TspLog(DL_TRACE, "ProcessEvent: using MSP");
|
|
|
|
if ((dwWaitStatus = WaitForSingleObject(pLine->hMSPMutex, INFINITE))
|
|
== WAIT_OBJECT_0)
|
|
{
|
|
TspLog(DL_TRACE, "ProcessEvent: acquired MSP Mutex");
|
|
|
|
if (pLine->pMSPLine)
|
|
{
|
|
TspLog(DL_TRACE, "ProcessEvent: we have an MSP");
|
|
|
|
if ((LINECALLSTATE_CONNECTED == pEvent->ulParam1) &&
|
|
(FALSE == pLine->pMSPLine->bStreamingStarted))
|
|
{
|
|
DWORD dwMessage = 3; // Command code for
|
|
// "Are you there?"
|
|
(*gpfnLineEvent)(pLine->htLine,
|
|
pCall->htCall,
|
|
LINE_SENDMSPDATA,
|
|
(DWORD_PTR)0, // Send to all MSPs
|
|
(DWORD_PTR)&dwMessage,
|
|
(DWORD_PTR)sizeof(DWORD));
|
|
|
|
TspLog(DL_TRACE,
|
|
"ProcessEvent: sent 'are you there ?' "\
|
|
"message to MSP");
|
|
|
|
}
|
|
else if(((LINECALLSTATE_DISCONNECTED == pEvent->ulParam1) ||
|
|
(LINECALLSTATE_IDLE == pEvent->ulParam1)) &&
|
|
(pLine->pMSPLine->bStreamingStarted))
|
|
{
|
|
TspLog(DL_TRACE,
|
|
"ProcessEvent: about to call StopMSPStream");
|
|
StopMSPStream(pCall->hdLine, pCall->hdCall);
|
|
}
|
|
}
|
|
|
|
ReleaseMutex(pLine->hMSPMutex);
|
|
TspLog(DL_TRACE, "ProcessEvent: released MSP Mutex");
|
|
}
|
|
else
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"ProcessEvent: wait for MSP Mutex failed(%x)",
|
|
dwWaitStatus);
|
|
}
|
|
}
|
|
|
|
if (LINECALLSTATE_OFFERING == pEvent->ulParam1)
|
|
{
|
|
LPLINECALLINFO lpLineCallInfo;
|
|
//
|
|
// We're about to indicate up an offering call. We need
|
|
// to make sure the media mode we're indicating up is
|
|
// correct (we can't rely on what the proxy gave us).
|
|
// So, we call lineGetCallInfo, which will look up the
|
|
// proper value in a table based on the called address.
|
|
//
|
|
lpLineCallInfo = (LPLINECALLINFO)MALLOC(sizeof(LINECALLINFO));
|
|
|
|
if (lpLineCallInfo)
|
|
{
|
|
lpLineCallInfo->dwTotalSize = sizeof(LINECALLINFO);
|
|
|
|
if (TSPI_lineGetCallInfo(pCall->hdCall, lpLineCallInfo)
|
|
== TAPI_SUCCESS)
|
|
{
|
|
if (lpLineCallInfo->dwNeededSize >
|
|
lpLineCallInfo->dwTotalSize)
|
|
{
|
|
DWORD dwNeededSize = lpLineCallInfo->dwNeededSize;
|
|
|
|
FREE(lpLineCallInfo);
|
|
lpLineCallInfo = (LPLINECALLINFO)MALLOC(dwNeededSize);
|
|
|
|
if (lpLineCallInfo)
|
|
{
|
|
lpLineCallInfo->dwTotalSize = dwNeededSize;
|
|
|
|
if (TSPI_lineGetCallInfo(pCall->hdCall,
|
|
lpLineCallInfo)
|
|
!= TAPI_SUCCESS)
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"ProcessEvent: second call to "\
|
|
"TSPI_lineGetCallInfo failed");
|
|
|
|
FREE(lpLineCallInfo);
|
|
lpLineCallInfo = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"ProcessEvent: failed to allocate line "\
|
|
"call info structure 2nd time");
|
|
}
|
|
}
|
|
|
|
if (lpLineCallInfo) {
|
|
pEvent->ulParam3 = lpLineCallInfo->dwMediaMode;
|
|
|
|
TspLog(DL_TRACE,
|
|
"ProcessEvent: just set media mode(%x)",
|
|
pEvent->ulParam3);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"ProcessEvent: first call to "\
|
|
"TSPI_lineGetCallInfo failed");
|
|
}
|
|
|
|
if (lpLineCallInfo)
|
|
{
|
|
FREE(lpLineCallInfo);
|
|
lpLineCallInfo = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"ProcessEvent: couldn't allocate mem "\
|
|
"for line call info");
|
|
}
|
|
}
|
|
|
|
TspLog(DL_INFO,
|
|
"PE::fnLineEvent(CALLSTATE): htline(%p), htcall(%p), "\
|
|
"p1(%p), p2(%p), p3(%p)",
|
|
pLine->htLine, pCall->htCall,
|
|
pEvent->ulParam1, pEvent->ulParam2, pEvent->ulParam3);
|
|
|
|
(*gpfnLineEvent)(pLine->htLine,
|
|
pCall->htCall,
|
|
ulMsg,
|
|
(DWORD_PTR)pEvent->ulParam1,
|
|
(DWORD_PTR)pEvent->ulParam2,
|
|
(DWORD_PTR)pEvent->ulParam3);
|
|
|
|
//
|
|
// As a perf tweak we want to indicate an IDLE
|
|
// immediately following the disconnected. The proxy
|
|
// will never indicate a callstate_idle.
|
|
//
|
|
if(LINECALLSTATE_DISCONNECTED == pEvent->ulParam1)
|
|
{
|
|
TspLog(DL_INFO,
|
|
"PE::fnLineEvent(CALLSTATE_IDLE): htline(%p), htcall(%p), p3(%p)",
|
|
pLine->htLine, pCall->htCall, pEvent->ulParam3);
|
|
|
|
(*gpfnLineEvent)(pLine->htLine,
|
|
pCall->htCall,
|
|
ulMsg,
|
|
(DWORD_PTR)LINECALLSTATE_IDLE,
|
|
(DWORD_PTR)0,
|
|
(DWORD_PTR)pEvent->ulParam3);
|
|
}
|
|
|
|
ReleaseObjReadLock((HANDLE)pCall->hdCall);
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
|
|
break;
|
|
}
|
|
case LINE_NEWCALL:
|
|
{
|
|
HDRVCALL hdCall;
|
|
PDRVCALL pCall;
|
|
PDRVLINE pLine;
|
|
|
|
lRes = GetLineObjWithWriteLock((HDRVLINE)ht_Line, &pLine);
|
|
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// alloc & initialize a new DRVCALL object
|
|
if (pCall = AllocCallObj(sizeof(DRVCALL)))
|
|
{
|
|
pCall->dwKey = INBOUND_CALL_KEY;
|
|
pCall->hd_Call = (HDRV_CALL)pEvent->ulParam1;
|
|
pCall->ht_Call = (HTAPI_CALL)pEvent->ulParam2;
|
|
pCall->hdLine = (HDRVLINE)ht_Line;
|
|
pCall->bIncomplete = FALSE;
|
|
}
|
|
|
|
//
|
|
// if the new call object allocation failed above then we
|
|
// want to tell the driver to drop & close the call,
|
|
// then just break
|
|
//
|
|
|
|
if (NULL == pCall)
|
|
{
|
|
PNDISTAPI_REQUEST pNdisTapiRequestDrop;
|
|
PNDISTAPI_REQUEST pNdisTapiRequestCloseCall;
|
|
PNDIS_TAPI_DROP pNdisTapiDrop;
|
|
PNDIS_TAPI_CLOSE_CALL pNdisTapiCloseCall;
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_DROP, // opcode
|
|
pLine->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_DROP), // size of drve req data
|
|
&pNdisTapiRequestDrop // ptr to ptr to request buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjWriteLock((HANDLE)ht_Line);
|
|
break;
|
|
}
|
|
|
|
pNdisTapiDrop = (PNDIS_TAPI_DROP)pNdisTapiRequestDrop->Data;
|
|
|
|
pNdisTapiDrop->hdCall = (HDRV_CALL) pEvent->ulParam1;
|
|
pNdisTapiDrop->ulUserUserInfoSize = 0;
|
|
|
|
SyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pNdisTapiRequestDrop);
|
|
FreeRequest(pNdisTapiRequestDrop);
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_CLOSE_CALL, // opcode
|
|
pLine->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_CLOSE_CALL), // size of drve req data
|
|
&pNdisTapiRequestCloseCall // ptr to ptr to request buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjWriteLock((HANDLE)ht_Line);
|
|
break;
|
|
}
|
|
|
|
pNdisTapiCloseCall =
|
|
(PNDIS_TAPI_CLOSE_CALL)pNdisTapiRequestCloseCall->Data;
|
|
|
|
pNdisTapiCloseCall->hdCall = (HDRV_CALL) pEvent->ulParam1;
|
|
|
|
SyncDriverRequest(IOCTL_NDISTAPI_SET_INFO,
|
|
pNdisTapiRequestCloseCall);
|
|
|
|
FreeRequest(pNdisTapiRequestCloseCall);
|
|
|
|
ReleaseObjWriteLock((HANDLE)ht_Line);
|
|
break;
|
|
}
|
|
|
|
ASSERT(pCall != NULL);
|
|
|
|
pCall->dwDeviceID = pLine->dwDeviceID;
|
|
|
|
// make sure releasing write lock before calling OpenObjHandle()
|
|
// to avoid deadlock on acquiring write lock for the global mapper
|
|
ReleaseObjWriteLock((HANDLE)ht_Line);
|
|
|
|
lRes = OpenObjHandle(pCall, FreeCallObj, (HANDLE *)&hdCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"ProcessEvent: failed to map obj(%p) to handle",
|
|
pCall);
|
|
|
|
FreeCallObj(pCall);
|
|
break;
|
|
}
|
|
|
|
// reacquire the write lock
|
|
lRes = AcquireObjWriteLock((HANDLE)ht_Line);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"ProcessEvent: failed to reacquire write lock for obj(%p)",
|
|
ht_Line);
|
|
|
|
CloseObjHandle((HANDLE)hdCall);
|
|
break;
|
|
}
|
|
|
|
// save the TSP handle
|
|
pCall->hdCall = hdCall;
|
|
|
|
// send the LINE_NEWCALL to TAPI, getting back the TAPI call handle
|
|
TspLog(DL_INFO,
|
|
"PE::fnLineEvent(NEWCALL): htline(%p), call(%p)",
|
|
pLine->htLine, hdCall);
|
|
|
|
(*gpfnLineEvent)(pLine->htLine,
|
|
(HTAPICALL)NULL,
|
|
LINE_NEWCALL,
|
|
(DWORD_PTR)hdCall,
|
|
(DWORD_PTR)&pCall->htCall,
|
|
0);
|
|
|
|
//
|
|
// insert the new call into the line's inbound calls list
|
|
// regardless of the result of the LINE_NEWCALL
|
|
// if it failed, we'll destroy the call next, and
|
|
// TSPI_lineCloseCall will expect the call to be
|
|
// in the line's inbound call list
|
|
//
|
|
if ((pCall->pNext = pLine->pInboundCalls) != NULL)
|
|
{
|
|
pCall->pNext->pPrev = pCall;
|
|
}
|
|
pLine->pInboundCalls = pCall;
|
|
|
|
ReleaseObjWriteLock((HANDLE)ht_Line);
|
|
|
|
//
|
|
// if TAPI didn't create it's own representation of this
|
|
// cal (if pCall->htCall == NULL), then either:
|
|
//
|
|
// 1) the line is in the process of being closed, or
|
|
// 2) TAPI was unable to allocate the necessary resources
|
|
//
|
|
// ...so we'll close the call
|
|
//
|
|
if (NULL == pCall->htCall)
|
|
{
|
|
TspLog(DL_WARNING, "ProcessEvent: TAPI failed to create "
|
|
"its own handle for the new call, so we close the call");
|
|
TSPI_lineCloseCall(hdCall);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case LINE_CREATE:
|
|
|
|
TspLog(DL_INFO,
|
|
"PE::fnLineEvent(CREATE): ghProvider(%p), p2(%p), p3(%p)",
|
|
ghProvider, pEvent->ulParam2, pEvent->ulParam3);
|
|
|
|
(*gpfnLineEvent)((HTAPILINE)NULL,
|
|
(HTAPICALL)NULL,
|
|
ulMsg,
|
|
(DWORD_PTR)ghProvider,
|
|
(DWORD_PTR)pEvent->ulParam2,
|
|
(DWORD_PTR)pEvent->ulParam3);
|
|
|
|
break;
|
|
|
|
case LINE_MONITORDIGITS:
|
|
{
|
|
PDRVLINE pLine;
|
|
PDRVCALL pCall;
|
|
HDRVLINE hdLine;
|
|
|
|
lRes = GetLineAndCallObjWithReadLock(ht_Line, ht_Call, &pLine, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
hdLine = pCall->hdLine;
|
|
|
|
TspLog(DL_INFO,
|
|
"PE::fnLineEvent(MONITORDIGITS): htline(%p), htcall(%p), "\
|
|
"p1(%p), p2(%p), p3(%p)",
|
|
pLine->htLine, pCall->htCall,
|
|
pEvent->ulParam1, pEvent->ulParam2, pEvent->ulParam3);
|
|
|
|
(*gpfnLineEvent)(pLine->htLine,
|
|
pCall->htCall,
|
|
ulMsg,
|
|
(DWORD_PTR)pEvent->ulParam1,
|
|
(DWORD_PTR)pEvent->ulParam2,
|
|
(DWORD_PTR)pEvent->ulParam3);
|
|
|
|
ReleaseObjReadLock((HANDLE)pCall->hdCall);
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
|
|
break;
|
|
}
|
|
default:
|
|
|
|
TspLog(DL_ERROR, "ProcessEvent: unknown msg(%x)", ulMsg);
|
|
|
|
break;
|
|
|
|
} // switch
|
|
}
|
|
|
|
//
|
|
// thread proc that retrieves and processes completed requests
|
|
// and async events
|
|
//
|
|
VOID
|
|
AsyncEventsThread(
|
|
LPVOID lpParams
|
|
)
|
|
{
|
|
OVERLAPPED overlapped;
|
|
DWORD cbReturned;
|
|
|
|
//
|
|
// send an IOCTL to retrieve async events
|
|
//
|
|
overlapped.hEvent = NULL; // don't need event when using completion ports
|
|
|
|
gpAsyncEventsThreadInfo->pBuf->ulTotalSize =
|
|
gpAsyncEventsThreadInfo->dwBufSize - sizeof(NDISTAPI_EVENT_DATA);
|
|
|
|
gpAsyncEventsThreadInfo->pBuf->ulUsedSize = 0;
|
|
|
|
if (DeviceIoControl(
|
|
ghDriverAsync,
|
|
IOCTL_NDISTAPI_GET_LINE_EVENTS,
|
|
gpAsyncEventsThreadInfo->pBuf,
|
|
sizeof(NDISTAPI_EVENT_DATA),
|
|
gpAsyncEventsThreadInfo->pBuf,
|
|
gpAsyncEventsThreadInfo->dwBufSize,
|
|
&cbReturned,
|
|
&overlapped
|
|
) != TRUE)
|
|
{
|
|
DWORD dwLastError = GetLastError();
|
|
if (dwLastError != ERROR_IO_PENDING)
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"AsyncEventsThread: IoCtl(GetEvent) failed(%d)",
|
|
dwLastError);
|
|
}
|
|
ASSERT(ERROR_IO_PENDING == dwLastError);
|
|
}
|
|
|
|
// loop waiting for completed requests and retrieving async events
|
|
while (1)
|
|
{
|
|
BOOL bRes;
|
|
LPOVERLAPPED lpOverlapped;
|
|
PNDIS_TAPI_EVENT pEvent;
|
|
|
|
// wait for a request to complete
|
|
while (1) {
|
|
DWORD dwNumBytesTransferred;
|
|
DWORD_PTR dwCompletionKey;
|
|
|
|
bRes = GetQueuedCompletionStatus(
|
|
ghCompletionPort,
|
|
&dwNumBytesTransferred,
|
|
&dwCompletionKey,
|
|
&lpOverlapped,
|
|
(DWORD)-1); // infinite wait
|
|
|
|
if (bRes) {
|
|
//
|
|
// GetQueuedCompletion returned success so if our
|
|
// overlapped field is non-NULL then process the
|
|
// event. If the overlapped field is NULL try
|
|
// to get another event.
|
|
//
|
|
if (lpOverlapped != NULL) {
|
|
break;
|
|
}
|
|
|
|
TspLog(DL_WARNING,
|
|
"AsyncEventsThread: GetQueuedCompletionStatus "\
|
|
"lpOverlapped == NULL!");
|
|
|
|
} else {
|
|
//
|
|
// Error returned from GetQueuedCompletionStatus so
|
|
// shutdown the thread.
|
|
//
|
|
TspLog(DL_ERROR,
|
|
"AsyncEventsThread: GetQueuedCompletionStatus "\
|
|
"failed(%d)", GetLastError());
|
|
|
|
TspLog(DL_WARNING, "AsyncEventsThread: exiting thread");
|
|
|
|
ExitThread (0);
|
|
}
|
|
}
|
|
|
|
ASSERT(lpOverlapped != NULL);
|
|
|
|
//
|
|
// check the returned overlapped struct to determine if
|
|
// we have some events to process or a completed request
|
|
//
|
|
if (lpOverlapped == &overlapped)
|
|
{
|
|
DWORD i;
|
|
|
|
TspLog(DL_INFO, "AsyncEventsThread: got a line event");
|
|
|
|
// handle the events
|
|
pEvent = (PNDIS_TAPI_EVENT)gpAsyncEventsThreadInfo->pBuf->Data;
|
|
|
|
for (i = 0;
|
|
i < (gpAsyncEventsThreadInfo->pBuf->ulUsedSize /
|
|
sizeof(NDIS_TAPI_EVENT));
|
|
i++
|
|
)
|
|
{
|
|
ProcessEvent(pEvent);
|
|
pEvent++;
|
|
}
|
|
|
|
//
|
|
// send another IOCTL to retrieve new async events
|
|
//
|
|
overlapped.hEvent = NULL;
|
|
|
|
gpAsyncEventsThreadInfo->pBuf->ulTotalSize =
|
|
gpAsyncEventsThreadInfo->dwBufSize -
|
|
sizeof(NDISTAPI_EVENT_DATA) + 1;
|
|
|
|
gpAsyncEventsThreadInfo->pBuf->ulUsedSize = 0;
|
|
|
|
if (DeviceIoControl(
|
|
ghDriverAsync,
|
|
IOCTL_NDISTAPI_GET_LINE_EVENTS,
|
|
gpAsyncEventsThreadInfo->pBuf,
|
|
sizeof(NDISTAPI_EVENT_DATA),
|
|
gpAsyncEventsThreadInfo->pBuf,
|
|
gpAsyncEventsThreadInfo->dwBufSize,
|
|
&cbReturned,
|
|
&overlapped
|
|
) != TRUE)
|
|
{
|
|
DWORD dwLastError = GetLastError();
|
|
if (dwLastError != ERROR_IO_PENDING) {
|
|
TspLog(DL_ERROR,
|
|
"AsyncEventsThread: IoCtl(GetEvent) failed(%d)",
|
|
dwLastError);
|
|
|
|
TspLog(DL_INFO, "AsyncEventsThread: exiting thread");
|
|
|
|
ExitThread (0);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LONG lRes;
|
|
DWORD dwRequestID, callStateMsgParams[5];
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper =
|
|
(PASYNC_REQUEST_WRAPPER)lpOverlapped;
|
|
|
|
TspLog(DL_INFO, "AsyncEventsThread: got a completed req");
|
|
|
|
// verify that pointer is valid
|
|
if (pAsyncReqWrapper->dwKey != ASYNCREQWRAPPER_KEY)
|
|
{
|
|
TspLog(DL_WARNING, "AsyncEventsThread: got a bogus req");
|
|
continue;
|
|
}
|
|
|
|
dwRequestID = pAsyncReqWrapper->dwRequestID;
|
|
|
|
// unmark the request now that the ioctl is completed
|
|
UnmarkRequest(pAsyncReqWrapper);
|
|
|
|
lRes = TranslateDriverResult(
|
|
pAsyncReqWrapper->NdisTapiRequest.ulReturnValue
|
|
);
|
|
|
|
TspLog(DL_INFO,
|
|
"AsyncEventsThread: req(%p) with reqID(%x) returned lRes(%x)",
|
|
pAsyncReqWrapper, dwRequestID, lRes);
|
|
|
|
// call the post processing proc if appropriate
|
|
callStateMsgParams[0] = 0;
|
|
if (pAsyncReqWrapper->pfnPostProcess)
|
|
{
|
|
(*pAsyncReqWrapper->pfnPostProcess)(
|
|
pAsyncReqWrapper,
|
|
lRes,
|
|
callStateMsgParams
|
|
);
|
|
}
|
|
|
|
// call completion proc
|
|
TspLog(DL_TRACE,
|
|
"AsyncEventsThread: call compproc with ReqID(%x), lRes(%x)",
|
|
dwRequestID, lRes);
|
|
|
|
// this is a bit ugly. LineGatherDigits is not actually
|
|
// an asynchronous call though conceptually it seems as though it
|
|
// is. The upshot of this is that we're not supposed to call the
|
|
// completion proc for it. If there are more calls like this that
|
|
// we have to support, we should come up with a better mechanism
|
|
// than this "if" statement.
|
|
if (pAsyncReqWrapper->NdisTapiRequest.Oid !=
|
|
OID_TAPI_GATHER_DIGITS)
|
|
{
|
|
(*gpfnCompletionProc)(dwRequestID, lRes);
|
|
}
|
|
|
|
// free the async request wrapper
|
|
DEREF_ASYNC_REQUEST_WRAPPER(pAsyncReqWrapper);
|
|
|
|
// when outbounding call completes, we need to
|
|
// report back the saved call state
|
|
if (callStateMsgParams[0])
|
|
{
|
|
TspLog(DL_INFO,
|
|
"AsyncEventsThread: report back the saved call state");
|
|
|
|
TspLog(DL_INFO,
|
|
"AET::fnLineEvent(CALLSTATE): htline(%p), htcall(%p), "\
|
|
"p1(%p), p2(%p), p3(%p)",
|
|
callStateMsgParams[0], callStateMsgParams[1],
|
|
callStateMsgParams[2], callStateMsgParams[3],
|
|
callStateMsgParams[4]);
|
|
|
|
(*gpfnLineEvent)((HTAPILINE)ULongToPtr(callStateMsgParams[0]),
|
|
(HTAPICALL)ULongToPtr(callStateMsgParams[1]),
|
|
LINE_CALLSTATE,
|
|
(DWORD_PTR)callStateMsgParams[2],
|
|
(DWORD_PTR)callStateMsgParams[3],
|
|
(DWORD_PTR)callStateMsgParams[4]);
|
|
}
|
|
}
|
|
} // while
|
|
}
|
|
|
|
HDRV_CALL
|
|
GetNdisTapiHandle(
|
|
PDRVCALL pCall,
|
|
LONG *plRes
|
|
)
|
|
{
|
|
HDRVCALL hdCall;
|
|
PDRVCALL pCallLocal = pCall;
|
|
LONG lRes;
|
|
|
|
ASSERT(pCall != NULL);
|
|
|
|
hdCall = pCall->hdCall;
|
|
|
|
if(plRes != NULL)
|
|
{
|
|
*plRes = TAPI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// if the call is outbound, wait until the make call request
|
|
// has completed so we don't send a bad NDPROXY handle down
|
|
// to the driver
|
|
//
|
|
if (OUTBOUND_CALL_KEY == pCall->dwKey)
|
|
{
|
|
if (pCall->bIncomplete)
|
|
{
|
|
TspLog(DL_INFO,
|
|
"GetNdisTapiHandle: wait for the outbound call to complete...");
|
|
|
|
do
|
|
{
|
|
ASSERT(plRes != NULL);
|
|
|
|
//
|
|
// Release lock before going to sleep, ow we
|
|
// have a deadlock.
|
|
//
|
|
ReleaseObjReadLock((HANDLE) hdCall);
|
|
Sleep(250);
|
|
|
|
//
|
|
// ReAcquire Read Lock. Break if we can't
|
|
//
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCallLocal);
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
*plRes = lRes;
|
|
break;
|
|
}
|
|
} while (pCall->bIncomplete);
|
|
}
|
|
}
|
|
|
|
return pCall->hd_Call;
|
|
}
|
|
|
|
//
|
|
// TSPI_lineXXX functions
|
|
//
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineAccept(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVCALL hdCall,
|
|
LPCSTR lpsUserUserInfo,
|
|
DWORD dwSize
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper;
|
|
PNDIS_TAPI_ACCEPT pNdisTapiAccept;
|
|
|
|
TspLog(DL_TRACE, "lineAccept(%d): reqID(%x), call(%p)",
|
|
++dwSum, dwRequestID, hdCall);
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareAsyncRequest(
|
|
OID_TAPI_ACCEPT, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
dwRequestID, // request id
|
|
sizeof(NDIS_TAPI_ACCEPT) + dwSize, // size of drv request data
|
|
&pAsyncReqWrapper // ptr to ptr to request buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiAccept =
|
|
(PNDIS_TAPI_ACCEPT)pAsyncReqWrapper->NdisTapiRequest.Data;
|
|
|
|
pNdisTapiAccept->hdCall = GetNdisTapiHandle(pCall, NULL);
|
|
|
|
if ((pNdisTapiAccept->ulUserUserInfoSize = dwSize) != 0)
|
|
{
|
|
CopyMemory(pNdisTapiAccept->UserUserInfo, lpsUserUserInfo, dwSize);
|
|
}
|
|
|
|
lRes = AsyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pAsyncReqWrapper);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineAnswer(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVCALL hdCall,
|
|
LPCSTR lpsUserUserInfo,
|
|
DWORD dwSize
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper;
|
|
PNDIS_TAPI_ANSWER pNdisTapiAnswer;
|
|
|
|
TspLog(DL_TRACE, "lineAnswer(%d): reqID(%x), call(%p)",
|
|
++dwSum, dwRequestID, hdCall);
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareAsyncRequest(
|
|
OID_TAPI_ANSWER, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
dwRequestID, // request id
|
|
sizeof(NDIS_TAPI_ANSWER) + dwSize, // size of drv request data
|
|
&pAsyncReqWrapper // ptr to ptr to request buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiAnswer =
|
|
(PNDIS_TAPI_ANSWER)pAsyncReqWrapper->NdisTapiRequest.Data;
|
|
|
|
pNdisTapiAnswer->hdCall = GetNdisTapiHandle(pCall, NULL);
|
|
|
|
if ((pNdisTapiAnswer->ulUserUserInfoSize = dwSize) != 0)
|
|
{
|
|
CopyMemory(pNdisTapiAnswer->UserUserInfo, lpsUserUserInfo, dwSize);
|
|
}
|
|
|
|
lRes = AsyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pAsyncReqWrapper);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineClose(
|
|
HDRVLINE hdLine
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_CLOSE pNdisTapiClose;
|
|
|
|
TspLog(DL_TRACE, "lineClose(%d): line(%p)", ++dwSum, hdLine);
|
|
|
|
lRes = GetLineObjWithWriteLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_CLOSE, // opcode
|
|
pLine->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_CLOSE), // size of drve req data
|
|
&pNdisTapiRequest // ptr to ptr to request buffer
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjWriteLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiClose = (PNDIS_TAPI_CLOSE)pNdisTapiRequest->Data;
|
|
|
|
// mark line as invalid so any related events that show up
|
|
// will be discarded.
|
|
pLine->dwKey = INVALID_KEY;
|
|
|
|
pNdisTapiClose->hdLine = pLine->hd_Line;
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pNdisTapiRequest);
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
CloseHandle(pLine->hMSPMutex);
|
|
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
lRes = DecommitNegotiatedTSPIVersion(pLine->dwDeviceID);
|
|
}
|
|
|
|
ReleaseObjWriteLock((HANDLE)hdLine);
|
|
|
|
// release line resources
|
|
CloseObjHandle((HANDLE)hdLine);
|
|
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineCloseCall(
|
|
HDRVCALL hdCall
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
HDRVLINE hdLine;
|
|
PDRVLINE pLine;
|
|
PDRVCALL pCall;
|
|
PNDISTAPI_REQUEST pNdisTapiRequestCloseCall;
|
|
PNDIS_TAPI_CLOSE_CALL pNdisTapiCloseCall;
|
|
BOOL bInboundCall;
|
|
HDRV_CALL NdisTapiHandle;
|
|
|
|
TspLog(DL_TRACE, "lineCloseCall(%d): call(%p)", ++dwSum, hdCall);
|
|
|
|
lRes = GetLineHandleFromCallHandle(hdCall, &hdLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
//
|
|
// Initially we need to acquire the read lock for the objects.
|
|
// We can't acquire the write lock immediately because we might
|
|
// have to spin-wait in the GetNdisTapiHandle call.
|
|
//
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
bInboundCall = (INBOUND_CALL_KEY == pCall->dwKey);
|
|
|
|
NdisTapiHandle = GetNdisTapiHandle(pCall, &lRes);
|
|
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
|
|
//
|
|
// Now acquire the write locks
|
|
//
|
|
lRes = AcquireObjWriteLock((HANDLE)hdLine);
|
|
if (lRes != TAPI_SUCCESS) {
|
|
return lRes;
|
|
}
|
|
|
|
lRes = AcquireObjWriteLock((HANDLE)hdCall);
|
|
if (lRes != TAPI_SUCCESS) {
|
|
ReleaseObjWriteLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_CLOSE_CALL, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_CLOSE_CALL), // size of drve req data
|
|
&pNdisTapiRequestCloseCall // ptr to ptr to request buffer
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjWriteLock((HANDLE)hdCall);
|
|
ReleaseObjWriteLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
|
|
// mark the call as bad so any events get discarded
|
|
pCall->dwKey = INVALID_KEY;
|
|
|
|
// set up the params & call the driver
|
|
pNdisTapiCloseCall = (PNDIS_TAPI_CLOSE_CALL)pNdisTapiRequestCloseCall->Data;
|
|
pNdisTapiCloseCall->hdCall = NdisTapiHandle;
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_SET_INFO,
|
|
pNdisTapiRequestCloseCall);
|
|
FreeRequest(pNdisTapiRequestCloseCall);
|
|
|
|
// if inbound call, remove it from the list
|
|
if (bInboundCall)
|
|
{
|
|
if (pCall->pNext)
|
|
{
|
|
pCall->pNext->pPrev = pCall->pPrev;
|
|
}
|
|
if (pCall->pPrev)
|
|
{
|
|
pCall->pPrev->pNext = pCall->pNext;
|
|
}
|
|
else
|
|
{
|
|
pLine->pInboundCalls = pCall->pNext;
|
|
}
|
|
}
|
|
|
|
ReleaseObjWriteLock((HANDLE)hdCall);
|
|
ReleaseObjWriteLock((HANDLE)hdLine);
|
|
|
|
// free the call struct now that the call is closed
|
|
CloseObjHandle((HANDLE)hdCall);
|
|
|
|
return lRes;
|
|
}
|
|
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// Called when an instance of our MSP is closed. In this routine we
|
|
// just clean up our structures.
|
|
//
|
|
// Arguments:
|
|
// hdMSPLine - Our MSP handle: we returned this in
|
|
// TSPI_lineCreateMSPInstance()
|
|
//
|
|
// Return value:
|
|
// If the MSP handle is invalid, we return LINEERR_OPERATIONFAILED,
|
|
// otherwise we return NOERROR.
|
|
//
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineCloseMSPInstance(
|
|
HDRVMSPLINE hdMSPLine
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVMSPLINE pMSPLine;
|
|
HDRVLINE hdLine;
|
|
PDRVLINE pLine;
|
|
DWORD dwStatus;
|
|
|
|
TspLog(DL_TRACE, "lineCloseMSPInstance(%d): MSPline(%p)",
|
|
++dwSum, hdMSPLine);
|
|
|
|
lRes = GetLineHandleFromMSPLineHandle(hdMSPLine, &hdLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
lRes = GetLineObjWithWriteLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
lRes = GetMSPLineObjWithWriteLock(hdMSPLine, &pMSPLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjWriteLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
pMSPLine->dwKey = INVALID_KEY;
|
|
|
|
if ((dwStatus = WaitForSingleObject(pLine->hMSPMutex, INFINITE))
|
|
!= WAIT_OBJECT_0)
|
|
{
|
|
TspLog(DL_ERROR, "lineCloseMSPInstance: MSP mutex wait failed(%x)",
|
|
dwStatus);
|
|
|
|
ReleaseObjWriteLock((HANDLE)hdMSPLine);
|
|
ReleaseObjWriteLock((HANDLE)hdLine);
|
|
return LINEERR_OPERATIONFAILED;
|
|
}
|
|
|
|
pLine->pMSPLine = NULL;
|
|
|
|
if (!ReleaseMutex(pLine->hMSPMutex))
|
|
{
|
|
TspLog(DL_ERROR, "lineCloseMSPInstance: MSP mutex release failed");
|
|
|
|
ReleaseObjWriteLock((HANDLE)hdMSPLine);
|
|
ReleaseObjWriteLock((HANDLE)hdLine);
|
|
return LINEERR_OPERATIONFAILED;
|
|
}
|
|
|
|
ReleaseObjWriteLock((HANDLE)hdMSPLine);
|
|
ReleaseObjWriteLock((HANDLE)hdLine);
|
|
|
|
CloseObjHandle((HANDLE)hdMSPLine);
|
|
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineConditionalMediaDetection(
|
|
HDRVLINE hdLine,
|
|
DWORD dwMediaModes,
|
|
LPLINECALLPARAMS const lpCallParams
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_CONDITIONAL_MEDIA_DETECTION pNdisTapiConditionalMediaDetection;
|
|
|
|
TspLog(DL_TRACE, "lineConditionalMediaDetection(%d): line(%p), mode(%x)",
|
|
++dwSum, hdLine, dwMediaModes);
|
|
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_CONDITIONAL_MEDIA_DETECTION, // opcode
|
|
pLine->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_CONDITIONAL_MEDIA_DETECTION) +
|
|
(lpCallParams->dwTotalSize - sizeof(LINE_CALL_PARAMS)),
|
|
&pNdisTapiRequest // ptr to ptr to
|
|
// req buffer
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiConditionalMediaDetection =
|
|
(PNDIS_TAPI_CONDITIONAL_MEDIA_DETECTION) pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiConditionalMediaDetection->hdLine = pLine->hd_Line;
|
|
pNdisTapiConditionalMediaDetection->ulMediaModes = dwMediaModes;
|
|
|
|
CopyMemory(
|
|
&pNdisTapiConditionalMediaDetection->LineCallParams,
|
|
lpCallParams,
|
|
lpCallParams->dwTotalSize
|
|
);
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pNdisTapiRequest);
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// Called when an instance of our MSP is created. In this routine we
|
|
// just set up our structures and save away the TAPI handle to this
|
|
// MSP instance.
|
|
//
|
|
// Arguments:
|
|
// hdLine - Handle to the line on which the MSP is being created
|
|
// dwAddressID - An address on the given open line device
|
|
// htMSPLine - The TAPI handle to the MSP call
|
|
// lphdMSPLine - Pointer to location in which to return our handle
|
|
// to the MSP instance.
|
|
//
|
|
// Return value:
|
|
// If things go well, NOERROR, otherwise LINEERR_NOMEM if we fail to
|
|
// allocate a DRVMSPLINE structure.
|
|
//
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineCreateMSPInstance(
|
|
HDRVLINE hdLine,
|
|
DWORD dwAddressID,
|
|
HTAPIMSPLINE htMSPLine,
|
|
LPHDRVMSPLINE lphdMSPLine
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
PDRVMSPLINE pMSPLine;
|
|
DWORD dwStatus;
|
|
|
|
TspLog(DL_TRACE, "lineCreateMSPInstance(%d): line(%p), addressID(%x)",
|
|
++dwSum, hdLine, dwAddressID);
|
|
|
|
lRes = GetLineObjWithWriteLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
// allocate and init a DRVMSPLINE struct
|
|
if (!(pMSPLine = AllocMSPLineObj(sizeof(DRVMSPLINE))))
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"lineCreateMSPInstance: failed to create MSP line obj");
|
|
|
|
ReleaseObjWriteLock((HANDLE)hdLine);
|
|
return LINEERR_NOMEM;
|
|
}
|
|
pMSPLine->dwKey = MSP_KEY;
|
|
pMSPLine->hdLine = hdLine;
|
|
pMSPLine->dwAddressID = dwAddressID;
|
|
pMSPLine->htMSPLine = htMSPLine;
|
|
|
|
if ((dwStatus = WaitForSingleObject(pLine->hMSPMutex, INFINITE))
|
|
!= WAIT_OBJECT_0)
|
|
{
|
|
TspLog(DL_ERROR, "lineCreateMSPInstance: MSP mutex wait failed(%x)",
|
|
dwStatus);
|
|
|
|
FreeMSPLineObj(pMSPLine);
|
|
ReleaseObjWriteLock((HANDLE)hdLine);
|
|
return LINEERR_OPERATIONFAILED;
|
|
}
|
|
|
|
pLine->pMSPLine = pMSPLine;
|
|
|
|
if (!ReleaseMutex(pLine->hMSPMutex))
|
|
{
|
|
TspLog(DL_ERROR, "lineCreateMSPInstance: MSP mutex release failed");
|
|
|
|
FreeMSPLineObj(pMSPLine);
|
|
ReleaseObjWriteLock((HANDLE)hdLine);
|
|
return LINEERR_OPERATIONFAILED;
|
|
}
|
|
|
|
// make sure release read lock before calling OpenObjHandle()
|
|
// to avoid deadlock on acquiring write lock for the global mapper
|
|
ReleaseObjWriteLock((HANDLE)hdLine);
|
|
|
|
lRes = OpenObjHandle(pMSPLine, FreeMSPLineObj, (HANDLE *)lphdMSPLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"lineCreateMSPInstance: failed to map obj(%p) to handle",
|
|
pMSPLine);
|
|
|
|
FreeMSPLineObj(pMSPLine);
|
|
}
|
|
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
PASCAL
|
|
TSPI_lineDevSpecific_postProcess(
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper,
|
|
LONG lRes,
|
|
PDWORD_PTR callStateMsgParams
|
|
)
|
|
{
|
|
TspLog(DL_TRACE, "lineDevSpecific_post: lRes(%x)", lRes);
|
|
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
PNDIS_TAPI_DEV_SPECIFIC pNdisTapiDevSpecific =
|
|
(PNDIS_TAPI_DEV_SPECIFIC)pAsyncReqWrapper->NdisTapiRequest.Data;
|
|
|
|
CopyMemory(
|
|
(LPVOID) pAsyncReqWrapper->dwRequestSpecific,
|
|
pNdisTapiDevSpecific->Params,
|
|
pNdisTapiDevSpecific->ulParamsSize
|
|
);
|
|
}
|
|
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineDevSpecific(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVLINE hdLine,
|
|
DWORD dwAddressID,
|
|
HDRVCALL hdCall,
|
|
LPVOID lpParams,
|
|
DWORD dwSize
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
PDRVCALL pCall = NULL;
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper;
|
|
PNDIS_TAPI_DEV_SPECIFIC pNdisTapiDevSpecific;
|
|
|
|
TspLog(DL_TRACE,
|
|
"lineDevSpecific(%d): reqID(%x), line(%p), addressID(%x), call(%p)",
|
|
++dwSum, dwRequestID, hdLine, dwAddressID, hdCall);
|
|
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareAsyncRequest(
|
|
OID_TAPI_DEV_SPECIFIC, // opcode
|
|
pLine->dwDeviceID, // device id
|
|
dwRequestID, // request id
|
|
sizeof(NDIS_TAPI_DEV_SPECIFIC) + // size of drv request data
|
|
(dwSize - 1),
|
|
&pAsyncReqWrapper // ptr to ptr to request buffer
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiDevSpecific =
|
|
(PNDIS_TAPI_DEV_SPECIFIC)pAsyncReqWrapper->NdisTapiRequest.Data;
|
|
|
|
pNdisTapiDevSpecific->hdLine = pLine->hd_Line;
|
|
pNdisTapiDevSpecific->ulAddressID = dwAddressID;
|
|
|
|
if (hdCall)
|
|
{
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pAsyncReqWrapper);
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
pNdisTapiDevSpecific->hdCall = GetNdisTapiHandle(pCall, &lRes);
|
|
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pAsyncReqWrapper);
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pNdisTapiDevSpecific->hdCall = (HDRV_CALL)NULL;
|
|
}
|
|
|
|
pNdisTapiDevSpecific->ulParamsSize = dwSize;
|
|
CopyMemory(pNdisTapiDevSpecific->Params, lpParams, dwSize);
|
|
|
|
pAsyncReqWrapper->dwRequestSpecific = (DWORD_PTR)lpParams;
|
|
pAsyncReqWrapper->pfnPostProcess = TSPI_lineDevSpecific_postProcess;
|
|
|
|
lRes = AsyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pAsyncReqWrapper);
|
|
|
|
if (pCall != NULL)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
}
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineDial(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVCALL hdCall,
|
|
LPCWSTR lpszDestAddress,
|
|
DWORD dwCountryCode
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
DWORD dwLength = lstrlenW (lpszDestAddress) + 1;
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper;
|
|
PNDIS_TAPI_DIAL pNdisTapiDial;
|
|
|
|
TspLog(DL_TRACE, "lineDial(%d): reqID(%x), call(%p)",
|
|
++dwSum, dwRequestID, hdCall);
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareAsyncRequest(
|
|
OID_TAPI_DIAL, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
dwRequestID, // request id
|
|
sizeof(NDIS_TAPI_DIAL) + dwLength, // size of driver req buffer
|
|
&pAsyncReqWrapper // ptr to ptr to req buffer
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiDial =
|
|
(PNDIS_TAPI_DIAL)pAsyncReqWrapper->NdisTapiRequest.Data;
|
|
|
|
pNdisTapiDial->hdCall = GetNdisTapiHandle(pCall, &lRes);
|
|
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pAsyncReqWrapper);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiDial->ulDestAddressSize = dwLength;
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, lpszDestAddress,
|
|
-1, (LPSTR)pNdisTapiDial->szDestAddress,
|
|
dwLength, NULL, NULL);
|
|
|
|
lRes = AsyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pAsyncReqWrapper);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineDrop(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVCALL hdCall,
|
|
LPCSTR lpsUserUserInfo,
|
|
DWORD dwSize
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper;
|
|
PNDIS_TAPI_DROP pNdisTapiDrop;
|
|
HDRV_CALL NdisTapiHandle;
|
|
|
|
TspLog(DL_TRACE, "lineDrop(%d): reqID(%x), call(%p)",
|
|
++dwSum, dwRequestID, hdCall);
|
|
|
|
//
|
|
// Initially we need to acquire the read lock for the object.
|
|
// We can't acquire the write lock immediately because we
|
|
// might have to spin-wait in the GetNdisTapiHandle call.
|
|
//
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
NdisTapiHandle = GetNdisTapiHandle(pCall, &lRes);
|
|
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
|
|
//
|
|
// Now acquire the write lock
|
|
//
|
|
lRes = AcquireObjWriteLock((HANDLE)hdCall);
|
|
if (lRes) {
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareAsyncRequest(
|
|
OID_TAPI_DROP, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
dwRequestID, // request id
|
|
sizeof(NDIS_TAPI_DROP) + dwSize, // size of driver req buffer
|
|
&pAsyncReqWrapper // ptr to ptr to req buffer
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjWriteLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiDrop =
|
|
(PNDIS_TAPI_DROP)pAsyncReqWrapper->NdisTapiRequest.Data;
|
|
|
|
pNdisTapiDrop->hdCall = NdisTapiHandle;
|
|
|
|
//
|
|
// @@@: the following is for legacy NDISWAN ISDN miniports
|
|
//
|
|
// Safely mark the call as dropped so the CloseCall code
|
|
// won't follow up with another "automatic" drop
|
|
//
|
|
pCall->bDropped = TRUE;
|
|
|
|
if ((pNdisTapiDrop->ulUserUserInfoSize = dwSize) != 0)
|
|
{
|
|
CopyMemory(pNdisTapiDrop->UserUserInfo, lpsUserUserInfo, dwSize);
|
|
}
|
|
|
|
ReleaseObjWriteLock((HANDLE)hdCall);
|
|
|
|
lRes = AsyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pAsyncReqWrapper);
|
|
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
PASCAL
|
|
TSPI_lineGatherDigits_postProcess(
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper,
|
|
LONG lRes,
|
|
LPDWORD callStateMsgParams
|
|
)
|
|
{
|
|
PNDIS_TAPI_GATHER_DIGITS pNdisTapiGatherDigits;
|
|
LPWSTR lpsDigitsBuffer;
|
|
LONG lSuc;
|
|
HDRVLINE hdLine;
|
|
PDRVLINE pLine;
|
|
HDRVCALL hdCall;
|
|
PDRVCALL pCall;
|
|
|
|
TspLog(DL_TRACE, "lineGatherDigits_post: lRes(%x)", lRes);
|
|
|
|
hdCall = (HDRVCALL)(pAsyncReqWrapper->dwRequestSpecific);
|
|
|
|
lSuc = GetLineHandleFromCallHandle(hdCall, &hdLine);
|
|
if (lSuc != TAPI_SUCCESS)
|
|
{
|
|
return lSuc;
|
|
}
|
|
|
|
lSuc = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lSuc != TAPI_SUCCESS)
|
|
{
|
|
return lSuc;
|
|
}
|
|
|
|
lSuc = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lSuc != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lSuc;
|
|
}
|
|
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
pNdisTapiGatherDigits =
|
|
(PNDIS_TAPI_GATHER_DIGITS)pAsyncReqWrapper->NdisTapiRequest.Data;
|
|
|
|
lpsDigitsBuffer = (LPWSTR)(((LPBYTE)pNdisTapiGatherDigits) +
|
|
pNdisTapiGatherDigits->ulDigitsBufferOffset);
|
|
|
|
wcscpy(pNdisTapiGatherDigits->lpsOrigDigitsBuffer, lpsDigitsBuffer);
|
|
|
|
// send the LINE_GATHERDIGITS message to TAPI.
|
|
(*gpfnLineEvent)(pLine->htLine,
|
|
pCall->htCall,
|
|
LINE_GATHERDIGITS,
|
|
(DWORD_PTR)pNdisTapiGatherDigits->ulTerminationReason,
|
|
(DWORD_PTR)pNdisTapiGatherDigits->ulEndToEndID,
|
|
(DWORD_PTR)pNdisTapiGatherDigits->ulTickCount);
|
|
}
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
// ++ DTMFDigitToOrdinal
|
|
//
|
|
// Turn a DTMF digit into a number between 0 and 15. The digits are assigned
|
|
// numbers in the following order: '0' - '9', 'A' - 'D', '*', '#'.
|
|
//
|
|
// Arguments:
|
|
// wcDigit - The digit, expressed as a UNICODE character.
|
|
//
|
|
// Return value:
|
|
// A number between 0 and 15, or 16 if the digit passed in was not a valid
|
|
// DTMF digit.
|
|
//
|
|
ULONG
|
|
DTMFDigitToOrdinal(
|
|
WCHAR wcDigit
|
|
)
|
|
{
|
|
if ((wcDigit >= L'0') && (wcDigit <= L'9'))
|
|
{
|
|
return (wcDigit - L'0');
|
|
}
|
|
if ((wcDigit >= L'A') && (wcDigit <= L'D'))
|
|
{
|
|
return (10 + (wcDigit - L'A'));
|
|
}
|
|
if (L'*' == wcDigit)
|
|
{
|
|
return 14;
|
|
}
|
|
if (L'#' == wcDigit)
|
|
{
|
|
return 15;
|
|
}
|
|
|
|
return 16;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGatherDigits(
|
|
HDRVCALL hdCall,
|
|
DWORD dwEndToEndID,
|
|
DWORD dwDigitModes,
|
|
LPWSTR lpsDigits,
|
|
DWORD dwNumDigits,
|
|
LPCWSTR lpszTerminationDigits,
|
|
DWORD dwFirstDigitTimeout,
|
|
DWORD dwInterDigitTimeout
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
DWORD dwDigitsLength, dwTermDigitsLength;
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper;
|
|
PDRVCALL pCall;
|
|
WCHAR *pwszTerminationDigit;
|
|
PNDIS_TAPI_GATHER_DIGITS pNdisTapiGatherDigits;
|
|
|
|
TspLog(DL_TRACE, "lineGatherDigits(%d): call(%p), EndToEndID(%x)",
|
|
hdCall, dwEndToEndID);
|
|
|
|
if (0 == dwNumDigits)
|
|
{
|
|
TspLog(DL_ERROR, "lineGatherDigits: dwNumDigits is 0");
|
|
return LINEERR_INVALPARAM;
|
|
}
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
// calculate the length required to store the digits.
|
|
if (lpsDigits)
|
|
{
|
|
dwDigitsLength = dwNumDigits + 1;
|
|
}
|
|
else
|
|
{
|
|
dwDigitsLength = 0;
|
|
}
|
|
|
|
if ((lRes = PrepareAsyncRequest(
|
|
OID_TAPI_GATHER_DIGITS,
|
|
pCall->dwDeviceID,
|
|
dwEndToEndID, // @@@: don't know what to pass in
|
|
sizeof(NDIS_TAPI_GATHER_DIGITS) + (dwDigitsLength * 2),
|
|
&pAsyncReqWrapper
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiGatherDigits =
|
|
(PNDIS_TAPI_GATHER_DIGITS) pAsyncReqWrapper->NdisTapiRequest.Data;
|
|
|
|
// store the pointer to the pCall because we'll need it
|
|
// in our postprocess function.
|
|
pAsyncReqWrapper->dwRequestSpecific = (DWORD_PTR)hdCall;
|
|
|
|
//
|
|
// Set up the parameters in our structure.
|
|
//
|
|
pNdisTapiGatherDigits->hdCall = GetNdisTapiHandle(pCall, &lRes);
|
|
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pAsyncReqWrapper);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiGatherDigits->ulEndToEndID = dwEndToEndID;
|
|
pNdisTapiGatherDigits->ulDigitModes = dwDigitModes;
|
|
pNdisTapiGatherDigits->lpsOrigDigitsBuffer = lpsDigits;
|
|
pNdisTapiGatherDigits->ulDigitsBufferOffset =
|
|
(lpsDigits ? sizeof(NDIS_TAPI_GATHER_DIGITS) : 0);
|
|
pNdisTapiGatherDigits->ulNumDigitsNeeded = dwNumDigits;
|
|
pNdisTapiGatherDigits->ulNumDigitsRead = 0;
|
|
pNdisTapiGatherDigits->ulFirstDigitTimeout = dwFirstDigitTimeout;
|
|
pNdisTapiGatherDigits->ulInterDigitTimeout = dwInterDigitTimeout;
|
|
|
|
//
|
|
// Turn the termination digits into a bit mask. There are 16 DTMF digits
|
|
// and I assign each one a bit in a word. If the digit is present in the
|
|
// termination digit string we were passed, we set the bit to 1 in the
|
|
// mask, otherwise it's set to zero. This makes it easier for the proxy
|
|
// to determine if it's read a termination digit: just turn the read digit
|
|
// into it's assigned bit number between 0 and 15 (I use the order '0' -
|
|
// '9', 'A' - 'D', '*', '#') and bitwise AND the mask with a word
|
|
// containing a 1 in the bit belonging to the digit. This makes it an O(1)
|
|
// operation.
|
|
//
|
|
pNdisTapiGatherDigits->ulTerminationDigitsMask = 0;
|
|
|
|
pwszTerminationDigit = (LPWSTR)lpszTerminationDigits;
|
|
while (*pwszTerminationDigit != UNICODE_NULL)
|
|
{
|
|
ULONG ulBitNum = DTMFDigitToOrdinal(*pwszTerminationDigit);
|
|
|
|
if (ulBitNum < 16) {
|
|
pNdisTapiGatherDigits->ulTerminationDigitsMask |= (1 << ulBitNum);
|
|
}
|
|
|
|
pwszTerminationDigit++;
|
|
}
|
|
|
|
pAsyncReqWrapper->pfnPostProcess = TSPI_lineGatherDigits_postProcess;
|
|
|
|
//
|
|
// I'm not setting lRes to the return value from here. This is because
|
|
// TAPI requires this function to return zero in the success case. This
|
|
// is a bit of a hokey situation - will need further discussion.
|
|
//
|
|
AsyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pAsyncReqWrapper);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetAddressCaps(
|
|
DWORD dwDeviceID,
|
|
DWORD dwAddressID,
|
|
DWORD dwTSPIVersion,
|
|
DWORD dwExtVersion,
|
|
LPLINEADDRESSCAPS lpAddressCaps
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PLINE_ADDRESS_CAPS pCaps;
|
|
PNDIS_TAPI_GET_ADDRESS_CAPS pNdisTapiGetAddressCaps;
|
|
|
|
TspLog(DL_TRACE,
|
|
"lineGetAddressCaps(%d): deviceID(%x), addressID(%x), "\
|
|
"TSPIV(%x), ExtV(%x)",
|
|
++dwSum, dwDeviceID, dwAddressID);
|
|
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_GET_ADDRESS_CAPS, // opcode
|
|
dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_GET_ADDRESS_CAPS) + // size of req data
|
|
(lpAddressCaps->dwTotalSize - sizeof(LINE_ADDRESS_CAPS)),
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiGetAddressCaps =
|
|
(PNDIS_TAPI_GET_ADDRESS_CAPS)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiGetAddressCaps->ulDeviceID = dwDeviceID;
|
|
pNdisTapiGetAddressCaps->ulAddressID = dwAddressID;
|
|
pNdisTapiGetAddressCaps->ulExtVersion = dwExtVersion;
|
|
|
|
pCaps = &pNdisTapiGetAddressCaps->LineAddressCaps;
|
|
pCaps->ulTotalSize = lpAddressCaps->dwTotalSize;
|
|
pCaps->ulNeededSize = pCaps->ulUsedSize = sizeof(LINE_ADDRESS_CAPS);
|
|
|
|
ZeroMemory(
|
|
&pCaps->ulLineDeviceID,
|
|
sizeof(LINE_ADDRESS_CAPS) - 3 * sizeof(ULONG)
|
|
);
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
//
|
|
// Do some post processing to the returned data structure
|
|
// before passing it back to tapi:
|
|
// 1. Pad the area between the fixed 1.0 structure and the
|
|
// var data that the miniports pass back with 0's so a
|
|
// bad app that disregards the 1.0 version negotiation &
|
|
// references new 1.4 or 2.0 structure fields won't blow up
|
|
// 2. Convert ascii strings to unicode, & rebase all var data
|
|
//
|
|
|
|
//
|
|
// The real needed size is the sum of that requested by the
|
|
// underlying driver, plus padding for the new TAPI 1.4/2.0
|
|
// structure fields, plus the size of the var data returned
|
|
// by the driver to account for the ascii->unicode conversion.
|
|
// @@@ Granted, we are very liberal in computing the value for
|
|
// this last part, but at least this way it's fast & we'll
|
|
// never have too little buffer space.
|
|
//
|
|
|
|
lpAddressCaps->dwNeededSize =
|
|
pCaps->ulNeededSize +
|
|
(sizeof(LINEADDRESSCAPS) - // v2.0 struct
|
|
sizeof(LINE_ADDRESS_CAPS)) + // v1.0 struct
|
|
(pCaps->ulNeededSize - sizeof(LINE_ADDRESS_CAPS));
|
|
|
|
|
|
//
|
|
// Copy over the fixed fields that don't need changing, i.e.
|
|
// everything from dwAddressSharing to dwCallCompletionModes
|
|
//
|
|
|
|
lpAddressCaps->dwLineDeviceID = dwDeviceID;
|
|
|
|
CopyMemory(
|
|
&lpAddressCaps->dwAddressSharing,
|
|
&pCaps->ulAddressSharing,
|
|
sizeof(LINE_ADDRESS_CAPS) - (12 * sizeof(DWORD))
|
|
);
|
|
|
|
if (lpAddressCaps->dwNeededSize > lpAddressCaps->dwTotalSize)
|
|
{
|
|
lpAddressCaps->dwUsedSize =
|
|
(lpAddressCaps->dwTotalSize < sizeof(LINEADDRESSCAPS) ?
|
|
lpAddressCaps->dwTotalSize : sizeof(LINEADDRESSCAPS));
|
|
}
|
|
else
|
|
{
|
|
lpAddressCaps->dwUsedSize = sizeof(LINEADDRESSCAPS); // v2.0 struct
|
|
|
|
//
|
|
// Supported device classes
|
|
//
|
|
INSERTVARDATA(
|
|
pCaps,
|
|
&pCaps->ulDeviceClassesSize,
|
|
lpAddressCaps,
|
|
&lpAddressCaps->dwDeviceClassesSize,
|
|
sizeof(LINE_ADDRESS_CAPS),
|
|
"LINE_ADDRESS_CAPS.DeviceClasses"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pCaps,
|
|
&pCaps->ulAddressSize,
|
|
lpAddressCaps,
|
|
&lpAddressCaps->dwAddressSize,
|
|
sizeof(LINE_ADDRESS_CAPS),
|
|
"LINE_ADDRESS_CAPS.Address"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pCaps,
|
|
&pCaps->ulDevSpecificSize,
|
|
lpAddressCaps,
|
|
&lpAddressCaps->dwDevSpecificSize,
|
|
sizeof(LINE_ADDRESS_CAPS),
|
|
"LINE_ADDRESS_CAPS.DevSpecific"
|
|
);
|
|
|
|
if (pCaps->ulCompletionMsgTextSize != 0)
|
|
{
|
|
// @@@ convert ComplMsgText to unicode???
|
|
INSERTVARDATA(
|
|
pCaps,
|
|
&pCaps->ulCompletionMsgTextSize,
|
|
lpAddressCaps,
|
|
&lpAddressCaps->dwCompletionMsgTextSize,
|
|
sizeof(LINE_ADDRESS_CAPS),
|
|
"LINE_ADDRESS_CAPS.CompletionMsgText"
|
|
);
|
|
|
|
lpAddressCaps->dwNumCompletionMessages =
|
|
pCaps->ulNumCompletionMessages;
|
|
lpAddressCaps->dwCompletionMsgTextEntrySize =
|
|
pCaps->ulCompletionMsgTextEntrySize;
|
|
}
|
|
|
|
// make sure dwNeededSize == dwUsedSize
|
|
lpAddressCaps->dwNeededSize = lpAddressCaps->dwUsedSize;
|
|
}
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetAddressID(
|
|
HDRVLINE hdLine,
|
|
LPDWORD lpdwAddressID,
|
|
DWORD dwAddressMode,
|
|
LPCWSTR lpsAddress,
|
|
DWORD dwSize
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_GET_ADDRESS_ID pNdisTapiGetAddressID;
|
|
|
|
TspLog(DL_TRACE, "lineGetAddressID(%d): line(%p), addressMode(%x)",
|
|
++dwSum, hdLine, dwAddressMode);
|
|
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_GET_ADDRESS_ID, // opcode
|
|
pLine->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_GET_ADDRESS_ID) + // size of req data
|
|
dwSize / 2 - 1,
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiGetAddressID = (PNDIS_TAPI_GET_ADDRESS_ID)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiGetAddressID->hdLine = pLine->hd_Line;
|
|
pNdisTapiGetAddressID->ulAddressMode = dwAddressMode;
|
|
pNdisTapiGetAddressID->ulAddressSize = dwSize / 2;
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, lpsAddress, dwSize,
|
|
(LPSTR)pNdisTapiGetAddressID->szAddress, dwSize / 2, NULL, NULL);
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
*lpdwAddressID = pNdisTapiGetAddressID->ulAddressID;
|
|
|
|
TspLog(DL_INFO, "lineGetAddressID: addressID(%x)", *lpdwAddressID);
|
|
}
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetAddressStatus(
|
|
HDRVLINE hdLine,
|
|
DWORD dwAddressID,
|
|
LPLINEADDRESSSTATUS lpAddressStatus
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PLINE_ADDRESS_STATUS pStatus;
|
|
PNDIS_TAPI_GET_ADDRESS_STATUS pNdisTapiGetAddressStatus;
|
|
|
|
TspLog(DL_TRACE, "lineGetAddressStatus(%d): line(%p), addressID(%x)",
|
|
++dwSum, hdLine, dwAddressID);
|
|
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_GET_ADDRESS_STATUS, // opcode
|
|
pLine->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_GET_ADDRESS_STATUS) + // size of req data
|
|
(lpAddressStatus->dwTotalSize - sizeof(LINE_ADDRESS_STATUS)),
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiGetAddressStatus =
|
|
(PNDIS_TAPI_GET_ADDRESS_STATUS)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiGetAddressStatus->hdLine = pLine->hd_Line;
|
|
pNdisTapiGetAddressStatus->ulAddressID = dwAddressID;
|
|
|
|
pStatus = &pNdisTapiGetAddressStatus->LineAddressStatus;
|
|
|
|
pStatus->ulTotalSize = lpAddressStatus->dwTotalSize;
|
|
pStatus->ulNeededSize = pStatus->ulUsedSize = sizeof(LINE_ADDRESS_STATUS);
|
|
|
|
ZeroMemory(&pStatus->ulNumInUse,
|
|
sizeof(LINE_ADDRESS_STATUS) - 3 * sizeof(ULONG));
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
CopyMemory(
|
|
lpAddressStatus,
|
|
&pNdisTapiGetAddressStatus->LineAddressStatus,
|
|
pNdisTapiGetAddressStatus->LineAddressStatus.ulUsedSize
|
|
);
|
|
}
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetCallAddressID(
|
|
HDRVCALL hdCall,
|
|
LPDWORD lpdwAddressID
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_GET_CALL_ADDRESS_ID pNdisTapiGetCallAddressID;
|
|
|
|
TspLog(DL_TRACE, "lineGetCallAddressID(%d): call(%p)", ++dwSum, hdCall);
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_GET_CALL_ADDRESS_ID, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_GET_CALL_ADDRESS_ID), // size of req data
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiGetCallAddressID =
|
|
(PNDIS_TAPI_GET_CALL_ADDRESS_ID)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiGetCallAddressID->hdCall = GetNdisTapiHandle(pCall, &lRes);
|
|
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
*lpdwAddressID = pNdisTapiGetCallAddressID->ulAddressID;
|
|
TspLog(DL_INFO, "lineGetCallAddressID: addressID(%x)", *lpdwAddressID);
|
|
}
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetCallInfo(
|
|
HDRVCALL hdCall,
|
|
LPLINECALLINFO lpCallInfo
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PLINE_CALL_INFO pInfo;
|
|
PNDIS_TAPI_GET_CALL_INFO pNdisTapiGetCallInfo;
|
|
|
|
TspLog(DL_TRACE, "lineGetCallInfo(%d): call(%p)", ++dwSum, hdCall);
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_GET_CALL_INFO, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_GET_CALL_INFO) + // size of req data
|
|
(lpCallInfo->dwTotalSize - sizeof(LINE_CALL_INFO)),
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiGetCallInfo = (PNDIS_TAPI_GET_CALL_INFO)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiGetCallInfo->hdCall = GetNdisTapiHandle(pCall, &lRes);
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
pInfo = &pNdisTapiGetCallInfo->LineCallInfo;
|
|
|
|
pInfo->ulTotalSize = lpCallInfo->dwTotalSize;
|
|
pInfo->ulNeededSize = pInfo->ulUsedSize = sizeof(LINE_CALL_INFO);
|
|
|
|
ZeroMemory(&pInfo->hLine, sizeof(LINE_CALL_INFO) - 3 * sizeof(ULONG));
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
//
|
|
// Do some post processing to the returned data structure
|
|
// before passing it back to tapi:
|
|
// 1. Pad the area between the fixed 1.0 structure and the
|
|
// var data that the miniports pass back with 0's so a
|
|
// bad app that disregards the 1.0 version negotiation &
|
|
// references new 1.4 or 2.0 structure fields won't blow up
|
|
// 2. Convert ascii strings to unicode, & rebase all var data
|
|
//
|
|
|
|
//
|
|
// The real needed size is the sum of that requested by the
|
|
// underlying driver, plus padding for the new TAPI 1.4/2.0
|
|
// structure fields, plus the size of the var data returned
|
|
// by the driver to account for the ascii->unicode conversion.
|
|
// @@@ Granted, we are very liberal in computing the value for
|
|
// this last part, but at least this way it's fast & we'll
|
|
// never have too little buffer space.
|
|
//
|
|
|
|
lpCallInfo->dwNeededSize =
|
|
pInfo->ulNeededSize +
|
|
(sizeof(LINECALLINFO) - // v2.0 struct
|
|
sizeof(LINE_CALL_INFO)) + // v1.0 struct
|
|
(pInfo->ulNeededSize - sizeof(LINE_CALL_INFO));
|
|
|
|
//
|
|
// Copy over the fixed fields that don't need changing,
|
|
// i.e. everything from dwLineDeviceID to dwTrunk
|
|
//
|
|
|
|
CopyMemory(
|
|
&lpCallInfo->dwLineDeviceID,
|
|
&pInfo->ulLineDeviceID,
|
|
23 * sizeof(DWORD)
|
|
);
|
|
|
|
if (lpCallInfo->dwNeededSize > lpCallInfo->dwTotalSize)
|
|
{
|
|
lpCallInfo->dwUsedSize =
|
|
(lpCallInfo->dwTotalSize < sizeof(LINECALLINFO) ?
|
|
lpCallInfo->dwTotalSize : sizeof(LINECALLINFO));
|
|
}
|
|
else
|
|
{
|
|
PWSTR pwszCalledAddress;
|
|
DWORD dwAlteredMediaModes;
|
|
|
|
lpCallInfo->dwUsedSize = sizeof(LINECALLINFO); // v2.0 struct
|
|
|
|
lpCallInfo->dwCallerIDFlags = pInfo->ulCallerIDFlags;
|
|
|
|
INSERTVARDATA(
|
|
pInfo,
|
|
&pInfo->ulCallerIDSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwCallerIDSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.CallerID"
|
|
);
|
|
|
|
lpCallInfo->dwCallerIDAddressType = pInfo->ulCallerIDAddressType;
|
|
|
|
INSERTVARDATA(
|
|
pInfo,
|
|
&pInfo->ulCallerIDNameSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwCallerIDNameSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.CallerIDName"
|
|
);
|
|
|
|
lpCallInfo->dwCalledIDFlags = pInfo->ulCalledIDFlags;
|
|
|
|
INSERTVARDATA(
|
|
pInfo,
|
|
&pInfo->ulCalledIDSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwCalledIDSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.CalledID"
|
|
);
|
|
|
|
lpCallInfo->dwCalledIDAddressType = pInfo->ulCalledIDAddressType;
|
|
|
|
INSERTVARDATA(
|
|
pInfo,
|
|
&pInfo->ulCalledIDNameSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwCalledIDNameSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.CalledIDName"
|
|
);
|
|
|
|
lpCallInfo->dwConnectedIDFlags = pInfo->ulConnectedIDFlags;
|
|
|
|
INSERTVARDATA(
|
|
pInfo,
|
|
&pInfo->ulConnectedIDSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwConnectedIDSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.ConnectID"
|
|
);
|
|
|
|
lpCallInfo->dwConnectedIDAddressType = pInfo->ulConnectedIDAddressType;
|
|
|
|
INSERTVARDATA(
|
|
pInfo,
|
|
&pInfo->ulConnectedIDNameSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwConnectedIDNameSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.ConnectIDName"
|
|
);
|
|
|
|
lpCallInfo->dwRedirectionIDFlags = pInfo->ulRedirectionIDFlags;
|
|
|
|
INSERTVARDATA(
|
|
pInfo,
|
|
&pInfo->ulRedirectionIDSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwRedirectionIDSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.RedirectionID"
|
|
);
|
|
|
|
lpCallInfo->dwRedirectionIDAddressType =
|
|
pInfo->ulRedirectionIDAddressType;
|
|
|
|
INSERTVARDATA(
|
|
pInfo,
|
|
&pInfo->ulRedirectionIDNameSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwRedirectionIDNameSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.RedirectionIDName"
|
|
);
|
|
|
|
lpCallInfo->dwRedirectingIDFlags = pInfo->ulRedirectingIDFlags;
|
|
|
|
INSERTVARDATA(
|
|
pInfo,
|
|
&pInfo->ulRedirectingIDSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwRedirectingIDSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.RedirectingID"
|
|
);
|
|
|
|
lpCallInfo->dwRedirectingIDAddressType =
|
|
pInfo->ulRedirectingIDAddressType;
|
|
|
|
INSERTVARDATA(
|
|
pInfo,
|
|
&pInfo->ulRedirectingIDNameSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwRedirectingIDNameSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.RedirectingIDName"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pInfo,
|
|
&pInfo->ulDisplaySize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwDisplaySize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.Display"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pInfo,
|
|
&pInfo->ulUserUserInfoSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwUserUserInfoSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.UserUserInfo"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pInfo,
|
|
&pInfo->ulHighLevelCompSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwHighLevelCompSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.HighLevelComp"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pInfo,
|
|
&pInfo->ulLowLevelCompSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwLowLevelCompSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.LowLevelComp"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pInfo,
|
|
&pInfo->ulChargingInfoSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwChargingInfoSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.ChargingInfo"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pInfo,
|
|
&pInfo->ulTerminalModesSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwTerminalModesSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.TerminalModes"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pInfo,
|
|
&pInfo->ulDevSpecificSize,
|
|
lpCallInfo,
|
|
&lpCallInfo->dwDevSpecificSize,
|
|
sizeof(LINE_CALL_INFO),
|
|
"LINE_CALL_INFO.DevSpecific"
|
|
);
|
|
|
|
// make sure that dwNeededSize == dwUsedSize
|
|
lpCallInfo->dwNeededSize = lpCallInfo->dwUsedSize;
|
|
|
|
//
|
|
// we now have the called address, look up the
|
|
// proper associated media mode in TAPI's table
|
|
//
|
|
if (lpCallInfo->dwCalledIDFlags & LINECALLPARTYID_UNAVAIL)
|
|
{
|
|
TspLog(DL_INFO,
|
|
"lineGetCallInfo: dwCalledIDFlags contained "\
|
|
"LINECALLPARTYID_UNAVAIL");
|
|
|
|
goto get_call_info_end;
|
|
}
|
|
if (lpCallInfo->dwCalledIDSize == 0)
|
|
{
|
|
TspLog(DL_INFO, "lineGetCallInfo: dwCalledIDSize was 0");
|
|
|
|
goto get_call_info_end;
|
|
}
|
|
|
|
// we've got a called address that we need to look up.
|
|
// we have to copy it and make it null-terminated.
|
|
pwszCalledAddress = (PWSTR)MALLOC(lpCallInfo->dwCalledIDSize +
|
|
sizeof(UNICODE_NULL));
|
|
if (NULL == pwszCalledAddress)
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"lineGetCallInfo: failed to alloc mem for called address");
|
|
|
|
lRes = LINEERR_NOMEM;
|
|
goto get_call_info_end;
|
|
}
|
|
|
|
CopyMemory((PUCHAR)pwszCalledAddress,
|
|
(((PUCHAR)lpCallInfo) + lpCallInfo->dwCalledIDOffset),
|
|
lpCallInfo->dwCalledIDSize);
|
|
|
|
*((PWSTR)(((PUCHAR)pwszCalledAddress) + lpCallInfo->dwCalledIDSize))
|
|
= UNICODE_NULL;
|
|
|
|
lRes = GetMediaModeForAddress(pwszCalledAddress,
|
|
&dwAlteredMediaModes);
|
|
|
|
FREE(pwszCalledAddress);
|
|
pwszCalledAddress = NULL;
|
|
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
goto get_call_info_end;
|
|
}
|
|
|
|
if (dwAlteredMediaModes == LINEMEDIAMODE_UNKNOWN)
|
|
{
|
|
TspLog(DL_INFO, "lineGetCallInfo: got unknown media mode");
|
|
|
|
goto get_call_info_end;
|
|
}
|
|
|
|
TspLog(DL_INFO, "lineGetCallInfo: got media mode(%x)",
|
|
dwAlteredMediaModes);
|
|
|
|
lpCallInfo->dwMediaMode = dwAlteredMediaModes;
|
|
}
|
|
|
|
get_call_info_end:
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetCallStatus(
|
|
HDRVCALL hdCall,
|
|
LPLINECALLSTATUS lpCallStatus
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PLINE_CALL_STATUS pStatus;
|
|
PNDIS_TAPI_GET_CALL_STATUS pNdisTapiGetCallStatus;
|
|
|
|
TspLog(DL_TRACE, "lineGetCallStatus(%d): call(%p)", ++dwSum, hdCall);
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_GET_CALL_STATUS, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_GET_CALL_STATUS) + // size of req data
|
|
(lpCallStatus->dwTotalSize - sizeof(LINE_CALL_STATUS)),
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiGetCallStatus = (PNDIS_TAPI_GET_CALL_STATUS)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiGetCallStatus->hdCall = GetNdisTapiHandle(pCall, &lRes);
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
pStatus = &pNdisTapiGetCallStatus->LineCallStatus;
|
|
|
|
pStatus->ulTotalSize = lpCallStatus->dwTotalSize;
|
|
pStatus->ulNeededSize = pStatus->ulUsedSize = sizeof(LINE_CALL_STATUS);
|
|
|
|
ZeroMemory(&pStatus->ulCallState,
|
|
sizeof(LINE_CALL_STATUS) - 3 * sizeof(ULONG));
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
//
|
|
// Do some post processing to the returned data structure
|
|
// before passing it back to tapi:
|
|
// 1. Pad the area between the fixed 1.0 structure and the
|
|
// var data that the miniports pass back with 0's so a
|
|
// bad app that disregards the 1.0 version negotiation &
|
|
// references new 1.4 or 2.0 structure fields won't blow up
|
|
// (no embedded ascii strings to convert to unicode)
|
|
//
|
|
|
|
//
|
|
// The real needed size is the sum of that requested by the
|
|
// underlying driver, plus padding for the new TAPI 1.4/2.0
|
|
// structure fields. (There are no embedded ascii strings to
|
|
// convert to unicode, so no extra space needed for that.)
|
|
//
|
|
|
|
lpCallStatus->dwNeededSize =
|
|
pStatus->ulNeededSize +
|
|
(sizeof(LINECALLSTATUS) - // v2.0 struct
|
|
sizeof(LINE_CALL_STATUS)); // v1.0 struct
|
|
|
|
//
|
|
// Copy over the fixed fields that don't need changing,
|
|
// i.e. everything from dwLineDeviceID to dwCallCompletionModes
|
|
//
|
|
|
|
CopyMemory(
|
|
&lpCallStatus->dwCallState,
|
|
&pStatus->ulCallState,
|
|
4 * sizeof(DWORD)
|
|
);
|
|
|
|
if (lpCallStatus->dwNeededSize > lpCallStatus->dwTotalSize)
|
|
{
|
|
lpCallStatus->dwUsedSize =
|
|
(lpCallStatus->dwTotalSize < sizeof(LINECALLSTATUS) ?
|
|
lpCallStatus->dwTotalSize : sizeof(LINECALLSTATUS));
|
|
}
|
|
else
|
|
{
|
|
lpCallStatus->dwUsedSize = sizeof(LINECALLSTATUS);
|
|
// v2.0 struct
|
|
INSERTVARDATA(
|
|
pStatus,
|
|
&pStatus->ulDevSpecificSize,
|
|
lpCallStatus,
|
|
&lpCallStatus->dwDevSpecificSize,
|
|
sizeof(LINE_CALL_STATUS),
|
|
"LINE_CALL_STATUS.DevSpecific"
|
|
);
|
|
}
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
LINEDEVCAPS *
|
|
GetLineDevCaps(
|
|
IN DWORD dwDeviceID,
|
|
IN DWORD dwExtVersion
|
|
)
|
|
{
|
|
LONG lRes;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PLINE_DEV_CAPS pCaps;
|
|
PNDIS_TAPI_GET_DEV_CAPS pNdisTapiGetDevCaps;
|
|
DWORD dwNeededSize;
|
|
LINEDEVCAPS *pLineDevCaps;
|
|
DWORD dwTotalSize = sizeof(LINEDEVCAPS) + 0x80;
|
|
|
|
get_caps:
|
|
pLineDevCaps = (LINEDEVCAPS *)MALLOC(dwTotalSize);
|
|
if (NULL == pLineDevCaps)
|
|
{
|
|
TspLog(DL_ERROR, "GetLineDevCaps: failed to alloc mem of size(%x)",
|
|
dwTotalSize);
|
|
return NULL;
|
|
}
|
|
|
|
pLineDevCaps->dwTotalSize = dwTotalSize;
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_GET_DEV_CAPS, // opcode
|
|
dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_GET_DEV_CAPS) + // size of req data
|
|
(dwTotalSize - sizeof(LINE_DEV_CAPS)),
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
pNdisTapiGetDevCaps = (PNDIS_TAPI_GET_DEV_CAPS)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiGetDevCaps->ulDeviceID = dwDeviceID;
|
|
pNdisTapiGetDevCaps->ulExtVersion = dwExtVersion;
|
|
|
|
pCaps = &pNdisTapiGetDevCaps->LineDevCaps;
|
|
|
|
pCaps->ulTotalSize = dwTotalSize;
|
|
pCaps->ulNeededSize = pCaps->ulUsedSize = sizeof(LINE_DEV_CAPS);
|
|
|
|
ZeroMemory(&pCaps->ulProviderInfoSize,
|
|
sizeof(LINE_DEV_CAPS) - 3 * sizeof(ULONG));
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pNdisTapiRequest);
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// The real needed size is the sum of that requested by the
|
|
// underlying driver, plus padding for the new TAPI 1.4/2.0
|
|
// structure fields, plus the size of the var data returned
|
|
// by the driver to account for the ascii->unicode conversion.
|
|
// @@@ Granted, we are very liberal in computing the value for
|
|
// this last part, but at least this way it's fast & we'll
|
|
// never have too little buffer space.
|
|
//
|
|
TspLog(DL_TRACE,
|
|
"GetLineDevCaps: ulNeeded(%x), LINEDEVCAPS(%x), LINE_DEV_CAPS(%x)",
|
|
pCaps->ulNeededSize, sizeof(LINEDEVCAPS), sizeof(LINE_DEV_CAPS));
|
|
|
|
dwNeededSize =
|
|
pCaps->ulNeededSize +
|
|
(sizeof(LINEDEVCAPS) - // v2.0 struct
|
|
sizeof(LINE_DEV_CAPS)) + // v1.0 struct
|
|
(pCaps->ulNeededSize - sizeof(LINE_DEV_CAPS));
|
|
|
|
TspLog(DL_TRACE, "GetLineDevCaps: dwNeededSize(%x), dwTotalSize(%x)",
|
|
dwNeededSize, dwTotalSize);
|
|
|
|
if (dwNeededSize > dwTotalSize)
|
|
{
|
|
// free up the old req
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
// free the old buffer
|
|
FREE(pLineDevCaps);
|
|
|
|
// try again with a larger buffer
|
|
dwTotalSize = dwNeededSize;
|
|
goto get_caps;
|
|
}
|
|
|
|
ASSERT(dwNeededSize <= dwTotalSize);
|
|
|
|
//
|
|
// Copy over the fixed fields that don't need changing,
|
|
// i.e. everything from dwPermanentLineID to dwNumTerminals
|
|
//
|
|
CopyMemory(
|
|
&pLineDevCaps->dwPermanentLineID,
|
|
&pCaps->ulPermanentLineID,
|
|
sizeof(LINE_DEV_CAPS) - (7 * sizeof(DWORD))
|
|
);
|
|
|
|
// @@@ not sure if this is the right place to do this
|
|
pLineDevCaps->dwDevCapFlags |= LINEDEVCAPFLAGS_MSP;
|
|
|
|
// set the local flag to indicate that
|
|
// the line can't be used from remote machine
|
|
pLineDevCaps->dwDevCapFlags |= LINEDEVCAPFLAGS_LOCAL;
|
|
|
|
//
|
|
// Do some post processing to the returned data structure
|
|
// before passing it back to tapi:
|
|
// 1. Pad the area between the fixed 1.0 structure and the
|
|
// var data that the miniports pass back with 0's so a
|
|
// bad app that disregards the 1.0 version negotiation &
|
|
// references new 1.4 or 2.0 structure fields won't blow up
|
|
// 2. Convert ascii strings to unicode, & rebase all var data
|
|
//
|
|
|
|
pLineDevCaps->dwUsedSize = sizeof(LINEDEVCAPS); // v2.0 struct
|
|
|
|
INSERTVARDATA(
|
|
pCaps,
|
|
&pCaps->ulDeviceClassesSize,
|
|
pLineDevCaps,
|
|
&pLineDevCaps->dwDeviceClassesSize,
|
|
sizeof (LINE_DEV_CAPS),
|
|
"LINE_DEV_CAPS.DeviceClasses"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pCaps,
|
|
&pCaps->ulProviderInfoSize,
|
|
pLineDevCaps,
|
|
&pLineDevCaps->dwProviderInfoSize,
|
|
sizeof(LINE_DEV_CAPS),
|
|
"LINE_DEV_CAPS.ProviderInfo"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pCaps,
|
|
&pCaps->ulSwitchInfoSize,
|
|
pLineDevCaps,
|
|
&pLineDevCaps->dwSwitchInfoSize,
|
|
sizeof(LINE_DEV_CAPS),
|
|
"LINE_DEV_CAPS.SwitchInfo"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pCaps,
|
|
&pCaps->ulLineNameSize,
|
|
pLineDevCaps,
|
|
&pLineDevCaps->dwLineNameSize,
|
|
sizeof(LINE_DEV_CAPS),
|
|
"LINE_DEV_CAPS.LineName"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pCaps,
|
|
&pCaps->ulTerminalCapsSize,
|
|
pLineDevCaps,
|
|
&pLineDevCaps->dwTerminalCapsSize,
|
|
sizeof(LINE_DEV_CAPS),
|
|
"LINE_DEV_CAPS.TerminalCaps"
|
|
);
|
|
|
|
// @@@ convert DevCaps.TermText to unicode???
|
|
|
|
pLineDevCaps->dwTerminalTextEntrySize =
|
|
pCaps->ulTerminalTextEntrySize;
|
|
|
|
INSERTVARDATA(
|
|
pCaps,
|
|
&pCaps->ulTerminalTextSize,
|
|
pLineDevCaps,
|
|
&pLineDevCaps->dwTerminalTextSize,
|
|
sizeof(LINE_DEV_CAPS),
|
|
"LINE_DEV_CAPS.TerminalText"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pCaps,
|
|
&pCaps->ulDevSpecificSize,
|
|
pLineDevCaps,
|
|
&pLineDevCaps->dwDevSpecificSize,
|
|
sizeof(LINE_DEV_CAPS),
|
|
"LINE_DEV_CAPS.DevSpecific"
|
|
);
|
|
|
|
// make sure dwNeededSize == dwUsedSize
|
|
pLineDevCaps->dwNeededSize = pLineDevCaps->dwUsedSize;
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
return pLineDevCaps;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetDevCaps(
|
|
DWORD dwDeviceID,
|
|
DWORD dwTSPIVersion,
|
|
DWORD dwExtVersion,
|
|
LPLINEDEVCAPS lpLineDevCaps
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
|
|
TspLog(DL_TRACE, "lineGetDevCaps(%d): deviceID(%x), TSPIV(%x), ExtV(%x)",
|
|
++dwSum, dwDeviceID, dwTSPIVersion, dwExtVersion);
|
|
|
|
lRes = GetDevCaps(dwDeviceID, dwTSPIVersion, dwExtVersion, lpLineDevCaps);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetDevConfig(
|
|
DWORD dwDeviceID,
|
|
LPVARSTRING lpDeviceConfig,
|
|
LPCWSTR lpszDeviceClass
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
DWORD dwLength = lstrlenW (lpszDeviceClass) + 1;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PVAR_STRING pConfig;
|
|
PNDIS_TAPI_GET_DEV_CONFIG pNdisTapiGetDevConfig;
|
|
|
|
TspLog(DL_TRACE, "lineGetDevConfig(%d): deviceID(%x)", ++dwSum, dwDeviceID);
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_GET_DEV_CONFIG, // opcode
|
|
dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_GET_DEV_CONFIG) + // size of req data
|
|
(lpDeviceConfig->dwTotalSize - sizeof(VAR_STRING)) + dwLength,
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiGetDevConfig = (PNDIS_TAPI_GET_DEV_CONFIG)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiGetDevConfig->ulDeviceID = dwDeviceID;
|
|
pNdisTapiGetDevConfig->ulDeviceClassSize = dwLength;
|
|
pNdisTapiGetDevConfig->ulDeviceClassOffset =
|
|
sizeof(NDIS_TAPI_GET_DEV_CONFIG) +
|
|
(lpDeviceConfig->dwTotalSize - sizeof(VAR_STRING));
|
|
|
|
pConfig = &pNdisTapiGetDevConfig->DeviceConfig;
|
|
pConfig->ulTotalSize = lpDeviceConfig->dwTotalSize;
|
|
pConfig->ulNeededSize = pConfig->ulUsedSize = sizeof(VAR_STRING);
|
|
|
|
pConfig->ulStringFormat =
|
|
pConfig->ulStringSize =
|
|
pConfig->ulStringOffset = 0;
|
|
|
|
// NOTE: old miniports expect strings to be ascii
|
|
WideCharToMultiByte(CP_ACP, 0, lpszDeviceClass, -1,
|
|
(LPSTR) (((LPBYTE) pNdisTapiGetDevConfig) +
|
|
pNdisTapiGetDevConfig->ulDeviceClassOffset),
|
|
dwLength, NULL, NULL);
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
CopyMemory(
|
|
lpDeviceConfig,
|
|
&pNdisTapiGetDevConfig->DeviceConfig,
|
|
pNdisTapiGetDevConfig->DeviceConfig.ulUsedSize
|
|
);
|
|
}
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetExtensionID(
|
|
DWORD dwDeviceID,
|
|
DWORD dwTSPIVersion,
|
|
LPLINEEXTENSIONID lpExtensionID
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_GET_EXTENSION_ID pNdisTapiGetExtensionID;
|
|
|
|
TspLog(DL_TRACE, "lineGetExtensionID(%d): deviceID(%x), TSPIV(%x)",
|
|
++dwSum, dwDeviceID, dwTSPIVersion);
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_GET_EXTENSION_ID, // opcode
|
|
dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_GET_EXTENSION_ID), // size of req data
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiGetExtensionID =
|
|
(PNDIS_TAPI_GET_EXTENSION_ID)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiGetExtensionID->ulDeviceID = dwDeviceID;
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
CopyMemory(
|
|
lpExtensionID,
|
|
&pNdisTapiGetExtensionID->LineExtensionID,
|
|
sizeof(LINE_EXTENSION_ID)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Rather than indicating a failure, we'll just zero out the
|
|
// ext id (implying driver doesn't support extensions) and
|
|
// return success to tapisrv so it'll complete the open ok
|
|
//
|
|
ZeroMemory(lpExtensionID, sizeof(LINE_EXTENSION_ID));
|
|
|
|
lRes = TAPI_SUCCESS;
|
|
}
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetID(
|
|
HDRVLINE hdLine,
|
|
DWORD dwAddressID,
|
|
HDRVCALL hdCall,
|
|
DWORD dwSelect,
|
|
LPVARSTRING lpDeviceID,
|
|
LPCWSTR lpszDeviceClass,
|
|
HANDLE hTargetProcess
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine = NULL;
|
|
PDRVCALL pCall = NULL;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
DWORD dwLength = lstrlenW(lpszDeviceClass) + 1;
|
|
DWORD dwDeviceID;
|
|
PUCHAR pchDest;
|
|
PVAR_STRING pID;
|
|
PNDIS_TAPI_GET_ID pNdisTapiGetID;
|
|
|
|
TspLog(DL_TRACE,
|
|
"lineGetID(%d): line(%p), call(%p), addressID(%x), select(%x)",
|
|
++dwSum, hdLine, hdCall, dwAddressID, dwSelect);
|
|
|
|
ASSERT(LINECALLSELECT_LINE == dwSelect ||
|
|
LINECALLSELECT_ADDRESS == dwSelect ||
|
|
LINECALLSELECT_CALL == dwSelect);
|
|
|
|
if (LINECALLSELECT_LINE == dwSelect ||
|
|
LINECALLSELECT_ADDRESS == dwSelect)
|
|
{
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
}
|
|
|
|
if (LINECALLSELECT_CALL == dwSelect)
|
|
{
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Ndptsp will field this specific call on behalf of the
|
|
// wan miniports. It returns the guid and media string
|
|
// of the adapter that this line lives on
|
|
//
|
|
if (LINECALLSELECT_LINE == dwSelect &&
|
|
!wcscmp(lpszDeviceClass, L"LineGuid"))
|
|
{
|
|
lpDeviceID->dwNeededSize =
|
|
sizeof(VARSTRING) + sizeof(GUID) +
|
|
sizeof(pLine->MediaType) + sizeof('\0');
|
|
|
|
if (lpDeviceID->dwTotalSize < lpDeviceID->dwNeededSize)
|
|
{
|
|
if (pCall != NULL)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
}
|
|
if (pLine != NULL)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
}
|
|
return LINEERR_STRUCTURETOOSMALL;
|
|
}
|
|
|
|
lpDeviceID->dwUsedSize = lpDeviceID->dwNeededSize;
|
|
lpDeviceID->dwStringFormat = STRINGFORMAT_ASCII;
|
|
pchDest = (PUCHAR)lpDeviceID + sizeof(*lpDeviceID);
|
|
lpDeviceID->dwStringOffset = (DWORD)(pchDest - (PUCHAR)lpDeviceID);
|
|
lpDeviceID->dwStringSize =
|
|
sizeof(GUID) + sizeof(pLine->MediaType) +sizeof('\0');
|
|
|
|
MoveMemory(
|
|
pchDest,
|
|
(PUCHAR)&pLine->Guid,
|
|
sizeof(pLine->Guid)
|
|
);
|
|
|
|
pchDest += sizeof(pLine->Guid);
|
|
|
|
MoveMemory(
|
|
pchDest,
|
|
&pLine->MediaType,
|
|
sizeof(pLine->MediaType)
|
|
);
|
|
|
|
pchDest += sizeof(pLine->MediaType);
|
|
*pchDest = '\0';
|
|
|
|
TspLog(DL_INFO, "lineGetID: obj(%p)", hdLine);
|
|
|
|
TspLog(
|
|
DL_INFO,
|
|
"Guid %4.4x-%2.2x-%2.2x-%1.1x%1.1x-%1.1x%1.1x%1.1x%1.1x%1.1x%1.1x",
|
|
pLine->Guid.Data1, pLine->Guid.Data2,
|
|
pLine->Guid.Data3, pLine->Guid.Data4[0],
|
|
pLine->Guid.Data4[1], pLine->Guid.Data4[2],
|
|
pLine->Guid.Data4[3], pLine->Guid.Data4[4],
|
|
pLine->Guid.Data4[5], pLine->Guid.Data4[6],
|
|
pLine->Guid.Data4[7]
|
|
);
|
|
|
|
TspLog(DL_INFO, "MediaType: %d", pLine->MediaType);
|
|
|
|
if (pCall != NULL)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
}
|
|
if (pLine != NULL)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
}
|
|
|
|
return TAPI_SUCCESS;
|
|
}
|
|
else if (LINECALLSELECT_CALL == dwSelect)
|
|
{
|
|
lpDeviceID->dwNeededSize = sizeof(VARSTRING) + sizeof(DWORD);
|
|
if (lpDeviceID->dwTotalSize < lpDeviceID->dwNeededSize)
|
|
{
|
|
if (pCall != NULL)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
}
|
|
if (pLine != NULL)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
}
|
|
|
|
return LINEERR_STRUCTURETOOSMALL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pCall != NULL)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
}
|
|
if (pLine != NULL)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
}
|
|
|
|
return LINEERR_OPERATIONUNAVAIL;
|
|
}
|
|
|
|
dwDeviceID = (LINECALLSELECT_CALL == dwSelect) ?
|
|
pCall->dwDeviceID : pLine->dwDeviceID;
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_GET_ID, // opcode
|
|
dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_GET_ID) + // size of req data
|
|
(lpDeviceID->dwTotalSize - sizeof(VAR_STRING)) + 2 * dwLength + 4,
|
|
// 4 for returned ID
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
if (pCall != NULL)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
}
|
|
if (pLine != NULL)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
}
|
|
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiGetID = (PNDIS_TAPI_GET_ID)pNdisTapiRequest->Data;
|
|
|
|
if (LINECALLSELECT_LINE == dwSelect ||
|
|
LINECALLSELECT_ADDRESS == dwSelect)
|
|
{
|
|
pNdisTapiGetID->hdLine = pLine->hd_Line;
|
|
}
|
|
|
|
pNdisTapiGetID->ulAddressID = dwAddressID;
|
|
|
|
if (LINECALLSELECT_CALL == dwSelect)
|
|
{
|
|
pNdisTapiGetID->hdCall = GetNdisTapiHandle(pCall, &lRes);
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
if(pLine != NULL)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
}
|
|
|
|
return lRes;
|
|
}
|
|
}
|
|
|
|
pNdisTapiGetID->ulSelect = dwSelect;
|
|
pNdisTapiGetID->ulDeviceClassSize = dwLength;
|
|
pNdisTapiGetID->ulDeviceClassOffset = sizeof(NDIS_TAPI_GET_ID) +
|
|
(lpDeviceID->dwTotalSize - sizeof(VAR_STRING));
|
|
|
|
pID = &pNdisTapiGetID->DeviceID;
|
|
|
|
pID->ulTotalSize = lpDeviceID->dwTotalSize;
|
|
pID->ulNeededSize = pID->ulUsedSize = sizeof(VAR_STRING);
|
|
pID->ulStringFormat = pID->ulStringSize = pID->ulStringOffset = 0;
|
|
|
|
// we use wide strings in the proxy
|
|
wcsncpy ((LPWSTR)(((LPBYTE)pNdisTapiGetID) +
|
|
pNdisTapiGetID->ulDeviceClassOffset),
|
|
lpszDeviceClass,
|
|
dwLength);
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
CopyMemory(
|
|
lpDeviceID,
|
|
&pNdisTapiGetID->DeviceID,
|
|
pNdisTapiGetID->DeviceID.ulUsedSize
|
|
);
|
|
}
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
if (pCall != NULL)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
}
|
|
if (pLine != NULL)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
}
|
|
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetLineDevStatus(
|
|
HDRVLINE hdLine,
|
|
LPLINEDEVSTATUS lpLineDevStatus
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PLINE_DEV_STATUS pStatus;
|
|
PNDIS_TAPI_GET_LINE_DEV_STATUS pNdisTapiGetLineDevStatus;
|
|
|
|
TspLog(DL_TRACE, "lineGetLineDevStatus(%d): line(%p)", ++dwSum, hdLine);
|
|
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_GET_LINE_DEV_STATUS, // opcode
|
|
pLine->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_GET_LINE_DEV_STATUS) + // size of req data
|
|
(lpLineDevStatus->dwTotalSize - sizeof(LINE_DEV_STATUS)),
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiGetLineDevStatus =
|
|
(PNDIS_TAPI_GET_LINE_DEV_STATUS)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiGetLineDevStatus->hdLine = pLine->hd_Line;
|
|
|
|
pStatus = &pNdisTapiGetLineDevStatus->LineDevStatus;
|
|
|
|
pStatus->ulTotalSize = lpLineDevStatus->dwTotalSize;
|
|
pStatus->ulNeededSize = pStatus->ulUsedSize = sizeof(LINE_DEV_STATUS);
|
|
|
|
ZeroMemory(&pStatus->ulNumOpens,
|
|
sizeof(LINE_DEV_STATUS) - 3 * sizeof(ULONG));
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pNdisTapiRequest);
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
//
|
|
// Do some post processing to the returned data structure
|
|
// before passing it back to tapi:
|
|
// 1. Pad the area between the fixed 1.0 structure and the
|
|
// var data that the miniports pass back with 0's so a
|
|
// bad app that disregards the 1.0 version negotiation &
|
|
// references new 1.4 or 2.0 structure fields won't blow up
|
|
// (no embedded ascii strings to convert to unicode)
|
|
//
|
|
|
|
//
|
|
// The real needed size is the sum of that requested by the
|
|
// underlying driver, plus padding for the new TAPI 1.4/2.0
|
|
// structure fields. (There are no embedded ascii strings to
|
|
// convert to unicode, so no extra space needed for that.)
|
|
//
|
|
|
|
lpLineDevStatus->dwNeededSize =
|
|
pStatus->ulNeededSize +
|
|
(sizeof(LINEDEVSTATUS) - // v2.0 struct
|
|
sizeof(LINE_DEV_STATUS)); // v1.0 struct
|
|
|
|
//
|
|
// Copy over the fixed fields that don't need changing,
|
|
// i.e. everything from dwNumActiveCalls to dwDevStatusFlags
|
|
//
|
|
|
|
CopyMemory(
|
|
&lpLineDevStatus->dwNumActiveCalls,
|
|
&pStatus->ulNumActiveCalls,
|
|
sizeof(LINE_DEV_STATUS) - (9 * sizeof(DWORD))
|
|
);
|
|
|
|
if (lpLineDevStatus->dwNeededSize > lpLineDevStatus->dwTotalSize)
|
|
{
|
|
lpLineDevStatus->dwUsedSize =
|
|
(lpLineDevStatus->dwTotalSize < sizeof(LINEDEVSTATUS) ?
|
|
lpLineDevStatus->dwTotalSize : sizeof(LINEDEVSTATUS));
|
|
}
|
|
else
|
|
{
|
|
lpLineDevStatus->dwUsedSize = sizeof(LINEDEVSTATUS);
|
|
// v2.0 struct
|
|
INSERTVARDATA(
|
|
pStatus,
|
|
&pStatus->ulTerminalModesSize,
|
|
lpLineDevStatus,
|
|
&lpLineDevStatus->dwTerminalModesSize,
|
|
sizeof(LINE_DEV_STATUS),
|
|
"LINE_DEV_STATUS.TerminalModes"
|
|
);
|
|
|
|
INSERTVARDATA(
|
|
pStatus,
|
|
&pStatus->ulDevSpecificSize,
|
|
lpLineDevStatus,
|
|
&lpLineDevStatus->dwDevSpecificSize,
|
|
sizeof(LINE_DEV_STATUS),
|
|
"LINE_DEV_STATUS.DevSpecific"
|
|
);
|
|
}
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineGetNumAddressIDs(
|
|
HDRVLINE hdLine,
|
|
LPDWORD lpdwNumAddressIDs
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
|
|
TspLog(DL_TRACE, "lineGetNumAddressIDs(%d): line(%p)", ++dwSum, hdLine);
|
|
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
lRes = GetNumAddressIDs(pLine->dwDeviceID, lpdwNumAddressIDs);
|
|
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
TspLog(DL_INFO, "lineGetNumAddressIDs: numAddressIDs(%x)",
|
|
*lpdwNumAddressIDs);
|
|
}
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
PASCAL
|
|
TSPI_lineMakeCall_postProcess(
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper,
|
|
LONG lRes,
|
|
PDWORD_PTR callStateMsgParams
|
|
)
|
|
{
|
|
LONG lSuc;
|
|
HDRVLINE hdLine;
|
|
PDRVLINE pLine;
|
|
HDRVCALL hdCall;
|
|
PDRVCALL pCall;
|
|
|
|
TspLog(DL_TRACE, "lineMakeCall_post: lRes(%x)", lRes);
|
|
|
|
hdCall = (HDRVCALL)(pAsyncReqWrapper->dwRequestSpecific);
|
|
|
|
lSuc = GetLineHandleFromCallHandle(hdCall, &hdLine);
|
|
if (lSuc != TAPI_SUCCESS)
|
|
{
|
|
return lSuc;
|
|
}
|
|
|
|
lSuc = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lSuc != TAPI_SUCCESS)
|
|
{
|
|
return lSuc;
|
|
}
|
|
|
|
lSuc = GetCallObjWithWriteLock(hdCall, &pCall);
|
|
if (lSuc != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lSuc;
|
|
}
|
|
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
PNDIS_TAPI_MAKE_CALL pNdisTapiMakeCall = (PNDIS_TAPI_MAKE_CALL)
|
|
pAsyncReqWrapper->NdisTapiRequest.Data;
|
|
|
|
// check to see if a call state msg was received before we had
|
|
// the chance to process the completion notification, & if so
|
|
// fill in the msg params
|
|
if (pCall->dwPendingCallState)
|
|
{
|
|
callStateMsgParams[0] = (DWORD_PTR)pLine->htLine;
|
|
callStateMsgParams[1] = (DWORD_PTR)pCall->htCall;
|
|
callStateMsgParams[2] = pCall->dwPendingCallState;
|
|
callStateMsgParams[3] = pCall->dwPendingCallStateMode;
|
|
callStateMsgParams[4] = pCall->dwPendingMediaMode;
|
|
}
|
|
pCall->hd_Call = pNdisTapiMakeCall->hdCall;
|
|
pCall->bIncomplete = FALSE;
|
|
|
|
ReleaseObjWriteLock((HANDLE)hdCall);
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
}
|
|
else
|
|
{
|
|
pCall->dwKey = INVALID_KEY;
|
|
|
|
ReleaseObjWriteLock((HANDLE)hdCall);
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
|
|
CloseObjHandle((HANDLE)hdCall);
|
|
}
|
|
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineMakeCall(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVLINE hdLine,
|
|
HTAPICALL htCall,
|
|
LPHDRVCALL lphdCall,
|
|
LPCWSTR lpszDestAddress,
|
|
DWORD dwCountryCode,
|
|
LPLINECALLPARAMS const lpCallParams
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
PDRVCALL pCall;
|
|
HDRVCALL hdCall;
|
|
DWORD dwDALength, dwCPLength;
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper;
|
|
PNDIS_TAPI_MAKE_CALL pNdisTapiMakeCall;
|
|
|
|
TspLog(DL_TRACE, "lineMakeCall(%d): reqID(%x), line(%p)",
|
|
++dwSum, dwRequestID, hdLine);
|
|
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
// alloc & init a DRVCALL
|
|
if (!(pCall = AllocCallObj(sizeof(DRVCALL))))
|
|
{
|
|
TspLog(DL_ERROR, "lineMakeCall: failed to create call obj");
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return LINEERR_NOMEM;
|
|
}
|
|
pCall->dwKey = OUTBOUND_CALL_KEY;
|
|
pCall->dwDeviceID = pLine->dwDeviceID;
|
|
pCall->htCall = htCall;
|
|
pCall->hdLine = hdLine;
|
|
pCall->bIncomplete = TRUE;
|
|
|
|
// init the request
|
|
dwDALength = (lpszDestAddress ? (lstrlenW (lpszDestAddress) + 1) : 0);
|
|
dwCPLength = (lpCallParams ?
|
|
(lpCallParams->dwTotalSize - sizeof(LINE_CALL_PARAMS)) : 0);
|
|
|
|
if ((lRes = PrepareAsyncRequest(
|
|
OID_TAPI_MAKE_CALL, // opcode
|
|
pLine->dwDeviceID, // device id
|
|
dwRequestID, // request id
|
|
sizeof(NDIS_TAPI_MAKE_CALL) +
|
|
2 * dwDALength + dwCPLength +
|
|
sizeof(PVOID), // size
|
|
&pAsyncReqWrapper // ptr to ptr to request buffer
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
FreeCallObj(pCall);
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiMakeCall = (PNDIS_TAPI_MAKE_CALL)
|
|
pAsyncReqWrapper->NdisTapiRequest.Data;
|
|
|
|
// make sure releasing read lock before calling OpenObjHandle()
|
|
// to avoid deadlock on acquiring write lock for the global mapper
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
|
|
lRes = OpenObjHandle(pCall, FreeCallObj, (HANDLE *)&hdCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"lineMakeCall: failed to map obj(%p) to handle",
|
|
pCall);
|
|
|
|
FreeRequest(pAsyncReqWrapper);
|
|
FreeCallObj(pCall);
|
|
return lRes;
|
|
}
|
|
|
|
// reacquire the read lock
|
|
lRes = AcquireObjReadLock((HANDLE)hdLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"lineMakeCall: failed to reacquire read lock for obj(%p)",
|
|
hdLine);
|
|
|
|
FreeRequest(pAsyncReqWrapper);
|
|
CloseObjHandle((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
// save the TSP handle
|
|
pCall->hdCall = hdCall;
|
|
|
|
pNdisTapiMakeCall->hdLine = pLine->hd_Line;
|
|
pNdisTapiMakeCall->htCall = (HTAPI_CALL)hdCall;
|
|
pNdisTapiMakeCall->ulDestAddressSize = dwDALength;
|
|
|
|
if (lpszDestAddress)
|
|
{
|
|
UCHAR *pDest;
|
|
|
|
// end of pNdisTapiMakeCall
|
|
pDest = (UCHAR *)(pNdisTapiMakeCall + 1);
|
|
|
|
// add room for lpCallParams
|
|
(ULONG_PTR)pDest += dwCPLength;
|
|
|
|
// align
|
|
(ULONG_PTR)pDest += sizeof(PVOID);
|
|
(ULONG_PTR)pDest &= ~((ULONG_PTR)sizeof(PVOID) - 1);
|
|
|
|
pNdisTapiMakeCall->ulDestAddressOffset =
|
|
(ULONG)(pDest - (UCHAR*)pNdisTapiMakeCall);
|
|
|
|
// use wide strings in NDPROXY
|
|
wcsncpy ((LPWSTR)pDest, lpszDestAddress, dwDALength);
|
|
}
|
|
else
|
|
{
|
|
pNdisTapiMakeCall->ulDestAddressOffset = 0;
|
|
}
|
|
|
|
if (lpCallParams)
|
|
{
|
|
pNdisTapiMakeCall->bUseDefaultLineCallParams = FALSE;
|
|
|
|
CopyMemory(
|
|
&pNdisTapiMakeCall->LineCallParams,
|
|
lpCallParams,
|
|
lpCallParams->dwTotalSize
|
|
);
|
|
|
|
if (lpCallParams->dwOrigAddressSize != 0)
|
|
{
|
|
WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
(LPCWSTR) (((LPBYTE) lpCallParams) +
|
|
lpCallParams->dwOrigAddressOffset),
|
|
lpCallParams->dwOrigAddressSize / sizeof(WCHAR),
|
|
(LPSTR) (((LPBYTE) &pNdisTapiMakeCall->LineCallParams) +
|
|
lpCallParams->dwOrigAddressOffset),
|
|
lpCallParams->dwOrigAddressSize,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
pNdisTapiMakeCall->LineCallParams.ulOrigAddressSize /= 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pNdisTapiMakeCall->bUseDefaultLineCallParams = TRUE;
|
|
}
|
|
|
|
pAsyncReqWrapper->dwRequestSpecific = (DWORD_PTR)hdCall;
|
|
pAsyncReqWrapper->pfnPostProcess = TSPI_lineMakeCall_postProcess;
|
|
|
|
*lphdCall = hdCall;
|
|
|
|
lRes = AsyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pAsyncReqWrapper);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineMonitorDigits(
|
|
HDRVCALL hdCall,
|
|
DWORD dwDigitModes
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_MONITOR_DIGITS pNdisTapiMonitorDigits;
|
|
|
|
TspLog(DL_TRACE, "lineMonitorDigits(%d): call(%p), DigitModes(%x)",
|
|
++dwSum, hdCall, dwDigitModes);
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_MONITOR_DIGITS, // opcode
|
|
pCall->dwDeviceID, // device ID
|
|
sizeof(NDIS_TAPI_MONITOR_DIGITS), // size of req data
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiMonitorDigits = (PNDIS_TAPI_MONITOR_DIGITS)pNdisTapiRequest->Data;
|
|
|
|
// set up the parameters in our structure.
|
|
pNdisTapiMonitorDigits->hdCall = GetNdisTapiHandle(pCall, &lRes);
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
|
|
pNdisTapiMonitorDigits->ulDigitModes = dwDigitModes;
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// Identifies the MSP to use for a particular line device. In our case,
|
|
// this is always the RCA MSP for all devices that support audio.
|
|
//
|
|
// Arguments:
|
|
// dwDeviceID - The line device whose MSP identifier is being requested
|
|
// pCLSID - Pointer to location at which to store the MSP CLSID
|
|
//
|
|
// Return value:
|
|
// For devices that support TAPIMEDIAMODE_AUDIO, returns NOERROR, otherwise
|
|
// LINEERR_OPERATIONUNAVAIL.
|
|
//
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineMSPIdentify(
|
|
DWORD dwDeviceID,
|
|
GUID *pCLSID
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
LINEDEVCAPS DevCaps;
|
|
|
|
TspLog(DL_TRACE, "lineMSPIdentify(%d): deviceID(%x)", ++dwSum, dwDeviceID);
|
|
|
|
//
|
|
// ugly, but we have to do it. We need to get the dev caps so we can see
|
|
// if the line supports audio. If it does, then we return the CLSID of
|
|
// the RCA MSP, otherwise return a null GUID
|
|
// (@@@ check if a null guid is the right thing to return)
|
|
//
|
|
|
|
ZeroMemory(&DevCaps, sizeof(LINEDEVCAPS));
|
|
|
|
DevCaps.dwTotalSize = sizeof(LINEDEVCAPS);
|
|
|
|
if ((lRes = TSPI_lineGetDevCaps(dwDeviceID, 0, 0, &DevCaps))
|
|
== TAPI_SUCCESS) {
|
|
//
|
|
// NOTE: LINEMEDIAMODE_AUTOMATEDVOICE == TAPIMEDIAMODE_AUDIO
|
|
//
|
|
if (DevCaps.dwMediaModes & LINEMEDIAMODE_AUTOMATEDVOICE) {
|
|
//
|
|
// The RCA MSP handles all lines that support AUDIO,
|
|
// so send this there.
|
|
//
|
|
*pCLSID = CLSID_RCAMSP;
|
|
}
|
|
}
|
|
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineNegotiateExtVersion(
|
|
DWORD dwDeviceID,
|
|
DWORD dwTSPIVersion,
|
|
DWORD dwLowVersion,
|
|
DWORD dwHighVersion,
|
|
LPDWORD lpdwExtVersion
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_NEGOTIATE_EXT_VERSION pNdisTapiNegotiateExtVersion;
|
|
|
|
TspLog(DL_TRACE,
|
|
"lineNegotiateExtVersion(%d): deviceID(%x), TSPIV(%x), "\
|
|
"LowV(%x), HighV(%x)",
|
|
++dwSum, dwDeviceID, dwTSPIVersion, dwLowVersion, dwHighVersion);
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_NEGOTIATE_EXT_VERSION, // opcode
|
|
dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_NEGOTIATE_EXT_VERSION), // size of req data
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiNegotiateExtVersion =
|
|
(PNDIS_TAPI_NEGOTIATE_EXT_VERSION)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiNegotiateExtVersion->ulDeviceID = dwDeviceID;
|
|
pNdisTapiNegotiateExtVersion->ulLowVersion = dwLowVersion;
|
|
pNdisTapiNegotiateExtVersion->ulHighVersion = dwHighVersion;
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
*lpdwExtVersion = pNdisTapiNegotiateExtVersion->ulExtVersion;
|
|
|
|
// save version for future verification
|
|
lRes = SetNegotiatedExtVersion(dwDeviceID, *lpdwExtVersion);
|
|
}
|
|
else
|
|
{
|
|
TspLog(DL_WARNING, "lineNegotiateExtVersion: syncRequest returned(%x)",
|
|
lRes);
|
|
}
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineNegotiateTSPIVersion(
|
|
DWORD dwDeviceID,
|
|
DWORD dwLowVersion,
|
|
DWORD dwHighVersion,
|
|
LPDWORD lpdwTSPIVersion
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
|
|
TspLog(DL_TRACE, "lineNegotiateTSPIVersion(%d): deviceID(%x)",
|
|
++dwSum, dwDeviceID);
|
|
|
|
*lpdwTSPIVersion = 0x00030000;
|
|
|
|
// save version for future verification
|
|
lRes = SetNegotiatedTSPIVersion(dwDeviceID, 0x00030000);
|
|
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
TspLog(DL_INFO, "lineNegotiateTSPIVersion: TSPIVersion(%x)",
|
|
*lpdwTSPIVersion);
|
|
}
|
|
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineOpen(
|
|
DWORD dwDeviceID,
|
|
HTAPILINE htLine,
|
|
LPHDRVLINE lphdLine,
|
|
DWORD dwTSPIVersion,
|
|
LINEEVENT lpfnEventProc
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
HDRVLINE hdLine;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_OPEN pNdisTapiOpen;
|
|
GUID Guid;
|
|
NDIS_WAN_MEDIUM_SUBTYPE MediaType;
|
|
PNDISTAPI_OPENDATA OpenData;
|
|
|
|
|
|
TspLog(DL_TRACE, "lineOpen(%d): deviceID(%x), htLine(%p)",
|
|
++dwSum, dwDeviceID, htLine);
|
|
|
|
// alloc & init a DRVLINE
|
|
if (!(pLine = AllocLineObj(sizeof(DRVLINE))))
|
|
{
|
|
TspLog(DL_ERROR, "lineOpen: failed to create line obj");
|
|
return LINEERR_NOMEM;
|
|
}
|
|
pLine->dwKey = LINE_KEY;
|
|
pLine->dwDeviceID = dwDeviceID;
|
|
pLine->htLine = htLine;
|
|
|
|
pLine->hMSPMutex = CreateMutex(NULL, FALSE, "MSPMutex");
|
|
if (NULL == pLine->hMSPMutex)
|
|
{
|
|
TspLog(DL_ERROR, "lineOpen: failed to create mutex");
|
|
FreeLineObj(pLine);
|
|
return LINEERR_NOMEM;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_OPEN, // opcode
|
|
dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_OPEN) +
|
|
sizeof(NDISTAPI_OPENDATA), // size
|
|
&pNdisTapiRequest // ptr to ptr to request buffer
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
CloseHandle(pLine->hMSPMutex);
|
|
FreeLineObj(pLine);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiOpen = (PNDIS_TAPI_OPEN)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiOpen->ulDeviceID = dwDeviceID;
|
|
|
|
lRes = OpenObjHandle(pLine, FreeLineObj, (HANDLE *)&hdLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
TspLog(DL_ERROR, "lineOpen: failed to map obj(%p) to handle", pLine);
|
|
CloseHandle(pLine->hMSPMutex);
|
|
FreeLineObj(pLine);
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
pNdisTapiOpen->htLine = (HTAPI_LINE)hdLine;
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_QUERY_INFO, pNdisTapiRequest);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
CloseHandle(pLine->hMSPMutex);
|
|
CloseObjHandle((HANDLE)hdLine);
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
OpenData = (PNDISTAPI_OPENDATA)
|
|
((PUCHAR)pNdisTapiOpen + sizeof(NDIS_TAPI_OPEN));
|
|
|
|
MoveMemory(&pLine->Guid,&OpenData->Guid, sizeof(pLine->Guid));
|
|
pLine->MediaType = OpenData->MediaType;
|
|
|
|
TspLog(DL_INFO, "lineOpen: obj(%p)", hdLine);
|
|
TspLog(
|
|
DL_INFO,
|
|
"Guid: %4.4x-%4.4x-%2.2x%2.2x-%1.1x%1.1x%1.1x%1.1x%1.1x%1.1x%1.1x",
|
|
pLine->Guid.Data1, pLine->Guid.Data2,
|
|
pLine->Guid.Data3, pLine->Guid.Data4[0],
|
|
pLine->Guid.Data4[1], pLine->Guid.Data4[2],
|
|
pLine->Guid.Data4[3], pLine->Guid.Data4[4],
|
|
pLine->Guid.Data4[5], pLine->Guid.Data4[6],
|
|
pLine->Guid.Data4[7]
|
|
);
|
|
|
|
TspLog(DL_INFO, "MediaType(%ld)", pLine->MediaType);
|
|
|
|
pLine->hd_Line = pNdisTapiOpen->hdLine;
|
|
*lphdLine = hdLine;
|
|
|
|
lRes = CommitNegotiatedTSPIVersion(dwDeviceID);
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// Called when an MSP wants to send us data. Right now we have not
|
|
// defined any TSP / MSP communication, so this function does nothing.
|
|
//
|
|
// Arguments:
|
|
// hdLine - Handle to line device
|
|
// hdCall - Handle for call
|
|
// hdMSPLine - MSP handle for the call
|
|
// pBuffer - Pointer to buffer containing MSP data
|
|
// dwSize - Size of MSP data buffer
|
|
//
|
|
// Return value:
|
|
// LINEERR_OPERATIONFAILED - if data size is too small
|
|
// LINEERR_OPERATIONUNAVAIL - if the message contains an unrecognized command
|
|
// NOERROR - if everything went OK
|
|
//
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineReceiveMSPData(
|
|
HDRVLINE hdLine,
|
|
HDRVCALL hdCall,
|
|
HDRVMSPLINE hdMSPLine,
|
|
LPVOID pBuffer,
|
|
DWORD dwSize
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
DWORD dwMsg;
|
|
DWORD dwStatus;
|
|
|
|
TspLog(DL_TRACE, "lineReceiveMSPData(%d): line(%p), call(%p), MSPline(%p)",
|
|
++dwSum, hdLine, hdCall, hdMSPLine);
|
|
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if (dwSize < sizeof(DWORD))
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"lineReceiveMSPData: data buf smaller than dword size");
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return LINEERR_OPERATIONFAILED;
|
|
}
|
|
|
|
dwMsg = *((DWORD *)pBuffer);
|
|
|
|
if (dwMsg != 0)
|
|
{
|
|
TspLog(DL_ERROR, "lineReceiveMSPData: unrecognized msg(%x)", dwMsg);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return LINEERR_OPERATIONUNAVAIL;
|
|
}
|
|
|
|
//
|
|
// have to call StartMSPStream with the MSP mutex held
|
|
//
|
|
if ((dwStatus = WaitForSingleObject(pLine->hMSPMutex, INFINITE))
|
|
!= WAIT_OBJECT_0)
|
|
{
|
|
TspLog(DL_ERROR, "lineReceiveMSPData: MSP mutex wait failed(%x)",
|
|
dwStatus);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return LINEERR_OPERATIONFAILED;
|
|
}
|
|
|
|
StartMSPStream(hdLine, hdCall);
|
|
|
|
if (!ReleaseMutex(pLine->hMSPMutex))
|
|
{
|
|
TspLog(DL_ERROR, "lineReceiveMSPData: MSP mutex release failed");
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return LINEERR_OPERATIONFAILED;
|
|
}
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSecureCall(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVCALL hdCall
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper;
|
|
PNDIS_TAPI_SECURE_CALL pNdisTapiSecureCall;
|
|
|
|
TspLog(DL_TRACE, "lineSecureCall(%d): reqID(%x), call(%p)",
|
|
++dwSum, dwRequestID, hdCall);
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareAsyncRequest(
|
|
OID_TAPI_SECURE_CALL, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
dwRequestID, // req id
|
|
sizeof(NDIS_TAPI_SECURE_CALL), // size
|
|
&pAsyncReqWrapper // ptr to ptr to request buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiSecureCall =
|
|
(PNDIS_TAPI_SECURE_CALL)pAsyncReqWrapper->NdisTapiRequest.Data;
|
|
|
|
pNdisTapiSecureCall->hdCall = GetNdisTapiHandle(pCall, &lRes);
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pAsyncReqWrapper);
|
|
return lRes;
|
|
}
|
|
|
|
lRes = AsyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pAsyncReqWrapper);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSelectExtVersion(
|
|
HDRVLINE hdLine,
|
|
DWORD dwExtVersion
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_SELECT_EXT_VERSION pNdisTapiSelectExtVersion;
|
|
|
|
TspLog(DL_TRACE, "lineSelectExtVersion(%d): line(%p), ExtV(%x)",
|
|
++dwSum, hdLine, dwExtVersion);
|
|
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_SELECT_EXT_VERSION, // opcode
|
|
pLine->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_SELECT_EXT_VERSION), // size
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiSelectExtVersion =
|
|
(PNDIS_TAPI_SELECT_EXT_VERSION)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiSelectExtVersion->hdLine = pLine->hd_Line;
|
|
pNdisTapiSelectExtVersion->ulExtVersion = dwExtVersion;
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pNdisTapiRequest);
|
|
|
|
if (TAPI_SUCCESS == lRes)
|
|
{
|
|
lRes = SetSelectedExtVersion(pLine->dwDeviceID, dwExtVersion);
|
|
}
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSendUserUserInfo(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVCALL hdCall,
|
|
LPCSTR lpsUserUserInfo,
|
|
DWORD dwSize
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper;
|
|
PNDIS_TAPI_SEND_USER_USER_INFO pNdisTapiSendUserUserInfo;
|
|
|
|
TspLog(DL_TRACE, "lineSendUserUserInfo(%d): reqID(%x), call(%p)",
|
|
++dwSum, dwRequestID, hdCall);
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareAsyncRequest(
|
|
OID_TAPI_SEND_USER_USER_INFO, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
dwRequestID, // request id
|
|
sizeof(NDIS_TAPI_SEND_USER_USER_INFO) + dwSize,
|
|
&pAsyncReqWrapper // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiSendUserUserInfo = (PNDIS_TAPI_SEND_USER_USER_INFO)
|
|
pAsyncReqWrapper->NdisTapiRequest.Data;
|
|
|
|
pNdisTapiSendUserUserInfo->hdCall = GetNdisTapiHandle(pCall, &lRes);
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pAsyncReqWrapper);
|
|
return lRes;
|
|
}
|
|
|
|
if (pNdisTapiSendUserUserInfo->ulUserUserInfoSize = dwSize)
|
|
{
|
|
CopyMemory(
|
|
pNdisTapiSendUserUserInfo->UserUserInfo,
|
|
lpsUserUserInfo,
|
|
dwSize
|
|
);
|
|
}
|
|
|
|
lRes = AsyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pAsyncReqWrapper);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSetAppSpecific(
|
|
HDRVCALL hdCall,
|
|
DWORD dwAppSpecific
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_SET_APP_SPECIFIC pNdisTapiSetAppSpecific;
|
|
|
|
TspLog(DL_TRACE, "lineSetAppSpecific(%d): call(%p)", ++dwSum, hdCall);
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_SET_APP_SPECIFIC, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_SET_APP_SPECIFIC), // size
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiSetAppSpecific =
|
|
(PNDIS_TAPI_SET_APP_SPECIFIC)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiSetAppSpecific->hdCall = GetNdisTapiHandle(pCall, &lRes);
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiSetAppSpecific->ulAppSpecific = dwAppSpecific;
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pNdisTapiRequest);
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSetCallParams(
|
|
DRV_REQUESTID dwRequestID,
|
|
HDRVCALL hdCall,
|
|
DWORD dwBearerMode,
|
|
DWORD dwMinRate,
|
|
DWORD dwMaxRate,
|
|
LPLINEDIALPARAMS const lpDialParams
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
PASYNC_REQUEST_WRAPPER pAsyncReqWrapper;
|
|
PNDIS_TAPI_SET_CALL_PARAMS pNdisTapiSetCallParams;
|
|
|
|
TspLog(DL_TRACE, "lineSetCallParams(%d): reqID(%x), call(%p)",
|
|
++dwSum, dwRequestID, hdCall);
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareAsyncRequest(
|
|
OID_TAPI_SET_CALL_PARAMS, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
dwRequestID, // request id
|
|
sizeof(NDIS_TAPI_SET_CALL_PARAMS), // size
|
|
&pAsyncReqWrapper // ptr to ptr to request buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiSetCallParams =
|
|
(PNDIS_TAPI_SET_CALL_PARAMS)pAsyncReqWrapper->NdisTapiRequest.Data;
|
|
|
|
pNdisTapiSetCallParams->hdCall = GetNdisTapiHandle(pCall, &lRes);
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pAsyncReqWrapper);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiSetCallParams->ulBearerMode = dwBearerMode;
|
|
pNdisTapiSetCallParams->ulMinRate = dwMinRate;
|
|
pNdisTapiSetCallParams->ulMaxRate = dwMaxRate;
|
|
|
|
if (lpDialParams)
|
|
{
|
|
pNdisTapiSetCallParams->bSetLineDialParams = TRUE;
|
|
CopyMemory(
|
|
&pNdisTapiSetCallParams->LineDialParams,
|
|
lpDialParams,
|
|
sizeof(LINE_DIAL_PARAMS)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
pNdisTapiSetCallParams->bSetLineDialParams = FALSE;
|
|
}
|
|
|
|
lRes = AsyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pAsyncReqWrapper);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSetDefaultMediaDetection(
|
|
HDRVLINE hdLine,
|
|
DWORD dwMediaModes
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION pNdisTapiSetDefaultMediaDetection;
|
|
|
|
TspLog(DL_TRACE, "lineSetDefaultMediaDetection(%d): line(%p), mode(%x)",
|
|
++dwSum, hdLine, dwMediaModes);
|
|
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_SET_DEFAULT_MEDIA_DETECTION, // opcode
|
|
pLine->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION), // size
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiSetDefaultMediaDetection =
|
|
(PNDIS_TAPI_SET_DEFAULT_MEDIA_DETECTION) pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiSetDefaultMediaDetection->hdLine = pLine->hd_Line;
|
|
pNdisTapiSetDefaultMediaDetection->ulMediaModes = dwMediaModes;
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pNdisTapiRequest);
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSetDevConfig(
|
|
DWORD dwDeviceID,
|
|
LPVOID const lpDeviceConfig,
|
|
DWORD dwSize,
|
|
LPCWSTR lpszDeviceClass
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
DWORD dwLength = lstrlenW(lpszDeviceClass) + 1;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_SET_DEV_CONFIG pNdisTapiSetDevConfig;
|
|
|
|
TspLog(DL_TRACE, "lineSetDevConfig(%d): deviceID(%x)", ++dwSum, dwDeviceID);
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_SET_DEV_CONFIG, // opcode
|
|
dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_SET_DEV_CONFIG) + dwLength + dwSize,
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiSetDevConfig = (PNDIS_TAPI_SET_DEV_CONFIG)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiSetDevConfig->ulDeviceID = dwDeviceID;
|
|
pNdisTapiSetDevConfig->ulDeviceClassSize = dwLength;
|
|
pNdisTapiSetDevConfig->ulDeviceClassOffset =
|
|
sizeof(NDIS_TAPI_SET_DEV_CONFIG) + dwSize - 1;
|
|
pNdisTapiSetDevConfig->ulDeviceConfigSize = dwSize;
|
|
|
|
CopyMemory(
|
|
pNdisTapiSetDevConfig->DeviceConfig,
|
|
lpDeviceConfig,
|
|
dwSize
|
|
);
|
|
|
|
// NOTE: old miniports expect strings to be ascii
|
|
WideCharToMultiByte(CP_ACP, 0, lpszDeviceClass, -1,
|
|
(LPSTR) (((LPBYTE) pNdisTapiSetDevConfig) +
|
|
pNdisTapiSetDevConfig->ulDeviceClassOffset),
|
|
dwLength, NULL, NULL);
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pNdisTapiRequest);
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSetMediaMode(
|
|
HDRVCALL hdCall,
|
|
DWORD dwMediaMode
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVCALL pCall;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_SET_MEDIA_MODE pNdisTapiSetMediaMode;
|
|
|
|
TspLog(DL_TRACE, "lineSetMediaMode(%d): call(%p), mode(%x)",
|
|
++dwSum, hdCall, dwMediaMode);
|
|
|
|
lRes = GetCallObjWithReadLock(hdCall, &pCall);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_SET_MEDIA_MODE, // opcode
|
|
pCall->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_SET_MEDIA_MODE), // size
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiSetMediaMode = (PNDIS_TAPI_SET_MEDIA_MODE)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiSetMediaMode->hdCall = GetNdisTapiHandle(pCall, &lRes);
|
|
if(lRes != TAPI_SUCCESS)
|
|
{
|
|
FreeRequest(pNdisTapiRequest);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiSetMediaMode->ulMediaMode = dwMediaMode;
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pNdisTapiRequest);
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdCall);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_lineSetStatusMessages(
|
|
HDRVLINE hdLine,
|
|
DWORD dwLineStates,
|
|
DWORD dwAddressStates
|
|
)
|
|
{
|
|
static DWORD dwSum = 0;
|
|
LONG lRes;
|
|
PDRVLINE pLine;
|
|
PNDISTAPI_REQUEST pNdisTapiRequest;
|
|
PNDIS_TAPI_SET_STATUS_MESSAGES pNdisTapiSetStatusMessages;
|
|
|
|
TspLog(DL_TRACE, "lineSetStatusMessages(%d): line(%p)", ++dwSum, hdLine);
|
|
|
|
lRes = GetLineObjWithReadLock(hdLine, &pLine);
|
|
if (lRes != TAPI_SUCCESS)
|
|
{
|
|
return lRes;
|
|
}
|
|
|
|
if ((lRes = PrepareSyncRequest(
|
|
OID_TAPI_SET_STATUS_MESSAGES, // opcode
|
|
pLine->dwDeviceID, // device id
|
|
sizeof(NDIS_TAPI_SET_STATUS_MESSAGES), // size
|
|
&pNdisTapiRequest // ptr to ptr to req buf
|
|
)) != TAPI_SUCCESS)
|
|
{
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
pNdisTapiSetStatusMessages =
|
|
(PNDIS_TAPI_SET_STATUS_MESSAGES)pNdisTapiRequest->Data;
|
|
|
|
pNdisTapiSetStatusMessages->hdLine = pLine->hd_Line;
|
|
pNdisTapiSetStatusMessages->ulLineStates = dwLineStates;
|
|
pNdisTapiSetStatusMessages->ulAddressStates = dwAddressStates;
|
|
|
|
lRes = SyncDriverRequest(IOCTL_NDISTAPI_SET_INFO, pNdisTapiRequest);
|
|
|
|
FreeRequest(pNdisTapiRequest);
|
|
|
|
ReleaseObjReadLock((HANDLE)hdLine);
|
|
return lRes;
|
|
}
|
|
|
|
//
|
|
// TAPI_providerXxx funcs
|
|
//
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_providerEnumDevices(
|
|
DWORD dwPermanentProviderID,
|
|
LPDWORD lpdwNumLines,
|
|
LPDWORD lpdwNumPhones,
|
|
HPROVIDER hProvider,
|
|
LINEEVENT lpfnLineCreateProc,
|
|
PHONEEVENT lpfnPhoneCreateProc
|
|
)
|
|
{
|
|
char szDeviceName[] = "NDProxy";
|
|
char szTargetPath[] = "\\Device\\NDProxy";
|
|
char szCompleteDeviceName[] = "\\\\.\\NDProxy";
|
|
DWORD cbReturned, dwNumLines;
|
|
DWORD adwConnectInfo[2] = {1, 1};
|
|
|
|
TspLog(DL_TRACE, "providerEnumDevices: permProvID(%x)",
|
|
dwPermanentProviderID);
|
|
|
|
gpfnLineEvent = lpfnLineCreateProc;
|
|
ghProvider = hProvider;
|
|
|
|
gInitResult= LINEERR_OPERATIONFAILED;
|
|
|
|
// create symbolic link to the kernel-mode driver
|
|
DefineDosDevice (DDD_RAW_TARGET_PATH, szDeviceName, szTargetPath);
|
|
|
|
//
|
|
// open driver handles
|
|
//
|
|
if ((ghDriverSync = CreateFileA(
|
|
szCompleteDeviceName,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL, // no security attrs
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL // no template file
|
|
)) == INVALID_HANDLE_VALUE)
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"providerEnumDevices: CreateFile(%s, sync) failed(%ld)",
|
|
szCompleteDeviceName, GetLastError());
|
|
|
|
goto enumdevs_error0;
|
|
}
|
|
|
|
if ((ghDriverAsync = CreateFileA(
|
|
szCompleteDeviceName,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL, // no security attrs
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
|
|
NULL // no template file
|
|
)) == INVALID_HANDLE_VALUE)
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"providerEnumDevices: CreateFile(%s, async) failed(%ld)",
|
|
szCompleteDeviceName, GetLastError());
|
|
|
|
goto enumdevs_error1;
|
|
}
|
|
|
|
// create io completion port
|
|
if ((ghCompletionPort = CreateIoCompletionPort(ghDriverAsync, NULL, 0, 0))
|
|
== INVALID_HANDLE_VALUE)
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"providerEnumDevices: CreateIoCompletionPort failed(%ld)",
|
|
GetLastError());
|
|
|
|
goto enumdevs_error2;
|
|
}
|
|
|
|
// connect to driver: sending a device ID base
|
|
// and it will return the number of devices it supports
|
|
if (!DeviceIoControl(ghDriverSync,
|
|
(DWORD) IOCTL_NDISTAPI_CONNECT,
|
|
adwConnectInfo,
|
|
2*sizeof(DWORD),
|
|
&dwNumLines,
|
|
sizeof(DWORD),
|
|
&cbReturned,
|
|
(LPOVERLAPPED) NULL
|
|
) || (cbReturned < sizeof(DWORD)))
|
|
{
|
|
TspLog(DL_ERROR,
|
|
"providerEnumDevices: CONNECT failed(%ld)",
|
|
GetLastError());
|
|
|
|
goto enumdevs_error3;
|
|
}
|
|
|
|
// init the req id
|
|
gdwRequestID = 1;
|
|
|
|
// set the number of devices
|
|
*((LPDWORD)lpdwNumLines) = dwNumLines;
|
|
|
|
// if here, success
|
|
gInitResult = TAPI_SUCCESS;
|
|
goto enumdevs_return;
|
|
|
|
// clean up resources if an error occurred
|
|
enumdevs_error3:
|
|
CloseHandle (ghCompletionPort);
|
|
|
|
enumdevs_error2:
|
|
CloseHandle (ghDriverAsync);
|
|
|
|
enumdevs_error1:
|
|
CloseHandle (ghDriverSync);
|
|
|
|
enumdevs_error0:
|
|
DefineDosDevice (DDD_REMOVE_DEFINITION, szDeviceName, NULL);
|
|
|
|
enumdevs_return:
|
|
TspLog(DL_INFO, "providerEnumDevices: gInitResult(%x)", gInitResult);
|
|
return gInitResult;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_providerConfig(
|
|
HWND hwndOwner,
|
|
DWORD dwPermanentProviderID
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(hwndOwner); // no dialog here
|
|
UNREFERENCED_PARAMETER(dwPermanentProviderID); // not needed anymore
|
|
|
|
// success
|
|
return TAPI_SUCCESS;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_providerInit(
|
|
DWORD dwTSPIVersion,
|
|
DWORD dwPermanentProviderID,
|
|
DWORD dwLineDeviceIDBase,
|
|
DWORD dwPhoneDeviceIDBase,
|
|
DWORD_PTR dwNumLines,
|
|
DWORD_PTR dwNumPhones,
|
|
ASYNC_COMPLETION lpfnCompletionProc,
|
|
LPDWORD lpdwTSPIOptions
|
|
)
|
|
{
|
|
LONG lRes = LINEERR_OPERATIONFAILED;
|
|
DWORD cbReturned, dwThreadID;
|
|
|
|
TspLog(DL_TRACE, "providerInit: perfProvID(%x), lineDevIDBase(%x)",
|
|
dwPermanentProviderID, dwLineDeviceIDBase);
|
|
|
|
gpfnCompletionProc = lpfnCompletionProc;
|
|
|
|
// inform tapisrv that we support multiple simultaneous requests
|
|
// (the WAN wrapper handles request serialization for miniports)
|
|
*lpdwTSPIOptions = 0;
|
|
|
|
// check for successful init in EnumDevs
|
|
if (gInitResult != TAPI_SUCCESS)
|
|
{
|
|
goto providerInit_return;
|
|
}
|
|
|
|
// send the base ID to the proxy
|
|
if (!DeviceIoControl(ghDriverSync,
|
|
(DWORD) IOCTL_NDISTAPI_SET_DEVICEID_BASE,
|
|
&dwLineDeviceIDBase,
|
|
sizeof(DWORD),
|
|
NULL,
|
|
0,
|
|
&cbReturned,
|
|
(LPOVERLAPPED)NULL))
|
|
{
|
|
TspLog(DL_ERROR, "providerInit: SET_DEVICEID_BASE failed(%ld)",
|
|
GetLastError());
|
|
|
|
goto providerInit_return;
|
|
}
|
|
|
|
//
|
|
// init mapper and allocator
|
|
//
|
|
if (InitializeMapper() != TAPI_SUCCESS)
|
|
{
|
|
goto providerInit_return;
|
|
}
|
|
|
|
InitAllocator();
|
|
|
|
//
|
|
// alloc the resources needed by the AsyncEventThread,
|
|
// and then create the thread
|
|
//
|
|
if ((gpAsyncEventsThreadInfo = (PASYNC_EVENTS_THREAD_INFO)
|
|
MALLOC(sizeof(ASYNC_EVENTS_THREAD_INFO))) == NULL)
|
|
{
|
|
TspLog(DL_ERROR, "providerInit: failed to alloc thread info");
|
|
goto providerInit_error4;
|
|
}
|
|
|
|
gpAsyncEventsThreadInfo->dwBufSize = EVENT_BUFFER_SIZE;
|
|
|
|
if ((gpAsyncEventsThreadInfo->pBuf = (PNDISTAPI_EVENT_DATA)
|
|
MALLOC(EVENT_BUFFER_SIZE)) == NULL)
|
|
{
|
|
TspLog(DL_ERROR, "providerInit: failed to alloc event buf");
|
|
goto providerInit_error5;
|
|
}
|
|
|
|
if ((gpAsyncEventsThreadInfo->hThread = CreateThread(
|
|
(LPSECURITY_ATTRIBUTES)NULL, // no security attrs
|
|
0, // default stack size
|
|
(LPTHREAD_START_ROUTINE) // func addr
|
|
AsyncEventsThread,
|
|
(LPVOID)NULL, // thread param
|
|
0, // create flags
|
|
&dwThreadID // thread id
|
|
)) == NULL)
|
|
{
|
|
TspLog(DL_ERROR, "providerInit: CreateThread failed(%ld)",
|
|
GetLastError());
|
|
|
|
goto providerInit_error7;
|
|
}
|
|
|
|
//
|
|
// If here success
|
|
//
|
|
lRes = TAPI_SUCCESS;
|
|
goto providerInit_return;
|
|
|
|
//
|
|
// clean up resources if an error occured & then return
|
|
//
|
|
providerInit_error7:
|
|
|
|
FREE(gpAsyncEventsThreadInfo->pBuf);
|
|
|
|
providerInit_error5:
|
|
|
|
FREE(gpAsyncEventsThreadInfo);
|
|
|
|
providerInit_error4:
|
|
UninitAllocator();
|
|
UninitializeMapper();
|
|
|
|
providerInit_return:
|
|
|
|
TspLog(DL_INFO, "providerInit: lRes(%x)", lRes);
|
|
return lRes;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_providerCreateLineDevice(
|
|
DWORD_PTR dwTempID,
|
|
DWORD dwDeviceID
|
|
)
|
|
{
|
|
DWORD cbReturned;
|
|
NDISTAPI_CREATE_INFO CreateInfo;
|
|
|
|
CreateInfo.TempID = (DWORD)dwTempID;
|
|
CreateInfo.DeviceID = dwDeviceID;
|
|
|
|
TspLog(DL_TRACE, "providerCreateLineDevice: tempID(%x), deviceID(%x)",
|
|
dwTempID, dwDeviceID);
|
|
|
|
if (!DeviceIoControl(
|
|
ghDriverSync,
|
|
IOCTL_NDISTAPI_CREATE,
|
|
&CreateInfo,
|
|
sizeof(CreateInfo),
|
|
&CreateInfo,
|
|
sizeof(CreateInfo),
|
|
&cbReturned,
|
|
(LPOVERLAPPED)NULL
|
|
))
|
|
{
|
|
TspLog(DL_ERROR, "providerCreateLineDevice: failed(%ld) to create",
|
|
GetLastError());
|
|
return LINEERR_OPERATIONFAILED;
|
|
}
|
|
|
|
return TAPI_SUCCESS;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_providerShutdown(
|
|
DWORD dwTSPIVersion,
|
|
DWORD dwPermanentProviderID
|
|
)
|
|
{
|
|
char deviceName[] = "NDPROXY";
|
|
ASYNC_REQUEST_WRAPPER asyncRequestWrapper;
|
|
DWORD cbReturned;
|
|
|
|
TspLog(DL_TRACE, "providerShutdown: perfProvID(%x)", dwPermanentProviderID);
|
|
|
|
// disconnect with the driver
|
|
if (!DeviceIoControl(ghDriverSync,
|
|
(DWORD) IOCTL_NDISTAPI_DISCONNECT,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&cbReturned,
|
|
(LPOVERLAPPED) NULL
|
|
))
|
|
{
|
|
TspLog(DL_ERROR, "providerShutdown: DISCONNECT failed(%ld)",
|
|
GetLastError());
|
|
}
|
|
|
|
//
|
|
// Close the driver & remove the symbolic link
|
|
//
|
|
CancelIo(ghDriverSync);
|
|
CancelIo(ghDriverAsync);
|
|
CloseHandle (ghDriverSync);
|
|
CloseHandle (ghDriverAsync);
|
|
CloseHandle (ghCompletionPort);
|
|
DefineDosDevice (DDD_REMOVE_DEFINITION, deviceName, NULL);
|
|
|
|
WaitForSingleObject(gpAsyncEventsThreadInfo->hThread, INFINITE);
|
|
|
|
CloseHandle(gpAsyncEventsThreadInfo->hThread);
|
|
FREE(gpAsyncEventsThreadInfo->pBuf);
|
|
FREE(gpAsyncEventsThreadInfo);
|
|
|
|
UninitAllocator();
|
|
UninitializeMapper();
|
|
|
|
return TAPI_SUCCESS;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_providerUIIdentify(
|
|
LPWSTR pwszUIDLLName
|
|
)
|
|
{
|
|
// copy name of our dll as ui dll
|
|
lstrcpyW(pwszUIDLLName, NDPTSP_UIDLL);
|
|
|
|
// success
|
|
return TAPI_SUCCESS;
|
|
}
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TUISPI_providerConfig(
|
|
TUISPIDLLCALLBACK pfnUIDLLCallback,
|
|
HWND hwndOwner,
|
|
DWORD dwPermanentProviderID
|
|
)
|
|
{
|
|
INT_PTR nResult;
|
|
CONFIG_UI_CTX Ctx;
|
|
|
|
UNREFERENCED_PARAMETER(pfnUIDLLCallback);
|
|
UNREFERENCED_PARAMETER(dwPermanentProviderID);
|
|
|
|
ZeroMemory(&Ctx, sizeof(Ctx));
|
|
|
|
// invoke dialog box
|
|
nResult = DialogBoxParamW(
|
|
ghInstance,
|
|
(LPWSTR)MAKEINTRESOURCE(IDD_MEDIA_MAP),
|
|
hwndOwner,
|
|
ProviderConfigDlgProc,
|
|
(LPARAM)&Ctx
|
|
);
|
|
|
|
// status based on whether dialog executed properly
|
|
return ((DWORD)nResult == 0) ? TAPI_SUCCESS : LINEERR_OPERATIONFAILED;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
DllMain(
|
|
HANDLE hDLL,
|
|
DWORD dwReason,
|
|
LPVOID lpReserved
|
|
)
|
|
{
|
|
switch (dwReason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
{
|
|
#if DBG
|
|
{
|
|
HKEY hKey;
|
|
DWORD dwDataSize, dwDataType;
|
|
TCHAR szTelephonyKey[] =
|
|
"Software\\Microsoft\\Windows\\CurrentVersion\\Telephony";
|
|
TCHAR szNdptspDebugLevel[] = "NdptspDebugLevel";
|
|
|
|
RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
szTelephonyKey,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hKey
|
|
);
|
|
|
|
dwDataSize = sizeof(DWORD);
|
|
gdwDebugLevel = DL_WARNING;
|
|
|
|
RegQueryValueEx(
|
|
hKey,
|
|
szNdptspDebugLevel,
|
|
0,
|
|
&dwDataType,
|
|
(LPBYTE)&gdwDebugLevel,
|
|
&dwDataSize
|
|
);
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
#endif
|
|
gdwTraceID = TraceRegisterA("NDPTSP");
|
|
ASSERT(gdwTraceID != INVALID_TRACEID);
|
|
|
|
TspLog(DL_TRACE, "DLL_PROCESS_ATTACH");
|
|
|
|
// save the handle for the UI
|
|
ghInstance = hDLL;
|
|
|
|
ZeroMemory(&gpAddressMapListArray, sizeof(gpAddressMapListArray));
|
|
gbAddressMapListLoaded = FALSE;
|
|
|
|
//
|
|
// Init global sync objects
|
|
//
|
|
InitializeCriticalSection(&gRequestIDCritSec);
|
|
InitializeCriticalSection(&gAddressMapCritSec);
|
|
|
|
InitLineDevList();
|
|
|
|
break;
|
|
}
|
|
case DLL_PROCESS_DETACH:
|
|
{
|
|
TspLog(DL_TRACE, "DLL_PROCESS_DETACH");
|
|
|
|
UninitLineDevList();
|
|
|
|
// free address list
|
|
FreeAllAddressLists(gpAddressMapListArray);
|
|
|
|
DeleteCriticalSection(&gRequestIDCritSec);
|
|
DeleteCriticalSection(&gAddressMapCritSec);
|
|
|
|
TraceDeregisterA(gdwTraceID);
|
|
|
|
break;
|
|
}
|
|
} // switch
|
|
|
|
return TRUE;
|
|
}
|