//============================================================================ // 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; dwModeCntpwszAddress) { FREE(pCrtCell->pwszAddress); } pPrevCell = pCrtCell; pCrtCell = pCrtCell->pNext; FREE(pPrevCell); } } void FreeAllAddressLists( PADDRESS_MAP *pAddressListArray ) { DWORD dwModeCnt; for (dwModeCnt=0; dwModeCnthItemHandle, 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; dwModeCntdwAddressLength + 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; dwModeCntpwszAddress = 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; }