#include #include "tracing.h" #include "utils.h" #include "intflist.h" #include "intfhdl.h" DWORD OpenIntfHandle( LPWSTR wszGuid, PHANDLE pIntfHdl) { DWORD dwErr; PHASH_NODE pNode; PHSH_HANDLE pHshHandle; DbgPrint((TRC_TRACK,"[OpenIntfHandle(%S)", wszGuid)); // the caller is supposed to expect the handle in return // if he doesn't, return with INVALID_PARAMETER. if (pIntfHdl == NULL) { dwErr = ERROR_INVALID_PARAMETER; goto exit; } // lock the hash, to mutual exclude concurrent calls EnterCriticalSection(&g_hshHandles.csMutex); // query the hash for the guid. dwErr = HshQueryObjectRef( g_hshHandles.pRoot, wszGuid, &pNode); // if the guid in the hash, we already have the handle opened.. if (dwErr == ERROR_SUCCESS) { // return it to the caller and bump up the reference counter. // the caller is still supposed to close this handle when it is // no longer needed pHshHandle = (PHSH_HANDLE)pNode->pObject; pHshHandle->nRefCount++; *pIntfHdl = pHshHandle->hdlInterf; DbgPrint((TRC_GENERIC, "OpenIntfHandle -> 0x%x (cached)", *pIntfHdl)); } // if the guid is not in the hash, we need to open a new handle for // this guid. else if (dwErr == ERROR_FILE_NOT_FOUND) { HANDLE IntfHdl = INVALID_HANDLE_VALUE; DWORD dwDummy; dwErr = ERROR_SUCCESS; // first allocate memory for the HSH_HANDLE object. // if this fails no need to go further to ndisuio pHshHandle = MemCAlloc(sizeof(HSH_HANDLE)); if (pHshHandle == NULL) dwErr = GetLastError(); // if everything looks fine so far if (dwErr == ERROR_SUCCESS) { // create the handle IntfHdl = CreateFileA( "\\\\.\\\\Ndisuio", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, INVALID_HANDLE_VALUE); if (IntfHdl == INVALID_HANDLE_VALUE) { dwErr = GetLastError(); DbgPrint((TRC_ERR,"CreateFileA failed with %d", dwErr)); } } // if still fine so far if (dwErr == ERROR_SUCCESS) { // attempt to open the handle if (!DeviceIoControl( IntfHdl, IOCTL_NDISUIO_OPEN_DEVICE, (LPVOID)wszGuid, wcslen(wszGuid)*sizeof(WCHAR), NULL, 0, &dwDummy, NULL)) { dwErr = GetLastError(); DbgPrint((TRC_ERR,"IOCTL_NDISUIO_OPEN_DEVICE failed with %d", dwErr)); } } // if finally we're ok here, if (dwErr == ERROR_SUCCESS) { // set up the HSH_HANDLE structure and insert it in the hash pHshHandle->hdlInterf = IntfHdl; pHshHandle->nRefCount = 1; dwErr = HshInsertObjectRef( g_hshHandles.pRoot, wszGuid, pHshHandle, &g_hshHandles.pRoot); } // if ok at the end, return the handle to the caller if (dwErr == ERROR_SUCCESS) { DbgPrint((TRC_GENERIC, "OpenIntfHandle -> 0x%x (new)", IntfHdl)); *pIntfHdl = IntfHdl; } // otherwise clear up all resources else { if (IntfHdl != INVALID_HANDLE_VALUE) CloseHandle(IntfHdl); MemFree(pHshHandle); } } // out of critical section LeaveCriticalSection(&g_hshHandles.csMutex); exit: DbgPrint((TRC_TRACK,"OpenIntfHandle]=%d", dwErr)); return dwErr; } DWORD CloseIntfHandle( LPWSTR wszGuid) { DWORD dwErr; PHASH_NODE pNode; DbgPrint((TRC_TRACK,"[CloseIntfHandle(%S)", wszGuid)); // lock the hash EnterCriticalSection(&g_hshHandles.csMutex); // query the hash for the guid. dwErr = HshQueryObjectRef( g_hshHandles.pRoot, wszGuid, &pNode); // the object should be found.. but who knows if (dwErr == ERROR_SUCCESS) { PHSH_HANDLE pHshHandle; // the hash refuses to hash in NULL pObjects, so pHshHandle is guaranteed to be not NULL pHshHandle = (PHSH_HANDLE)pNode->pObject; // HshHandles are hashed in with a refCount of 1, and whenever we remove a handle // if the ref count reaches 0 we delete it entirely. // Having here a <=0 ref count is completely wrong. DbgAssert((pHshHandle->nRefCount > 0, "Corrupted nRefCount %d", pHshHandle->nRefCount)); pHshHandle->nRefCount--; // if the ref count reached 0, remove the HSH_HANDLE from the hash.. if (pHshHandle->nRefCount == 0) { dwErr = HshRemoveObjectRef( g_hshHandles.pRoot, pNode, &pHshHandle, &g_hshHandles.pRoot); if (dwErr == ERROR_SUCCESS) { // .. and clear all associated resources DbgPrint((TRC_GENERIC,"CloseIntfHandle -> 0x%x (closed)", pHshHandle->hdlInterf)); CloseHandle(pHshHandle->hdlInterf); MemFree(pHshHandle); } } else { DbgPrint((TRC_GENERIC,"CloseIntfHandle -> 0x%x (deref)", pHshHandle->hdlInterf)); } } LeaveCriticalSection(&g_hshHandles.csMutex); DbgPrint((TRC_TRACK,"CloseIntfHandle]=%d", dwErr)); return dwErr; }