#include #include "tracing.h" #include "utils.h" #include "intflist.h" #include "deviceio.h" #include "intfhdl.h" //------------------------------------------------------ // Open a handle to Ndisuio and returns it to the caller DWORD DevioGetNdisuioHandle ( PHANDLE pHandle) // OUT opened handle to Ndisuio { DWORD dwErr = ERROR_SUCCESS; HANDLE hHandle; DWORD dwOutSize; DbgAssert((pHandle != NULL, "NULL pointer to output handle?")); hHandle = CreateFileA( "\\\\.\\\\Ndisuio", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (hHandle == INVALID_HANDLE_VALUE) { dwErr = GetLastError(); DbgPrint((TRC_ERR,"Err: Open Ndisuio->%d", dwErr)); goto exit; } // make sure NDISUIO binds to all relevant interfaces if (!DeviceIoControl( hHandle, IOCTL_NDISUIO_BIND_WAIT, NULL, 0, NULL, 0, &dwOutSize, NULL)) { dwErr = GetLastError(); DbgPrint((TRC_ERR,"Err: IOCTL_NDISUIO_BIND_WAIT->%d", dwErr)); goto exit; } *pHandle = hHandle; exit: return dwErr; } //------------------------------------------------------ // Checks the NDISUIO_QUERY_BINDING object for consistency // against the length for this binding as returned by NDISUIO. DWORD DevioCheckNdisBinding( PNDISUIO_QUERY_BINDING pndBinding, ULONG nBindingLen) { DWORD dwErr = ERROR_SUCCESS; // check for the data to contain at least the NDISUIO_QUERY_BINDING // header (that is offsets & lengths fields should be there) if (nBindingLen < sizeof(NDISUIO_QUERY_BINDING)) dwErr = ERROR_INVALID_DATA; // check the offsets are correctly set over the NDISUIO_QUERY_BINDING header // and within the length indicated by nBindingLen if (dwErr == ERROR_SUCCESS && ((pndBinding->DeviceNameOffset < sizeof(NDISUIO_QUERY_BINDING)) || (pndBinding->DeviceNameOffset > nBindingLen) || (pndBinding->DeviceDescrOffset < sizeof(NDISUIO_QUERY_BINDING)) || (pndBinding->DeviceDescrOffset > nBindingLen) ) ) dwErr = ERROR_INVALID_DATA; // check whether the lengths are correctly set within the limits if (dwErr == ERROR_SUCCESS && ((pndBinding->DeviceNameLength > nBindingLen - pndBinding->DeviceNameOffset) || (pndBinding->DeviceDescrLength > nBindingLen - pndBinding->DeviceDescrOffset) ) ) dwErr = ERROR_INVALID_DATA; return dwErr; } //------------------------------------------------------ // Get the NDISUIO_QUERY_BINDING for the interface index nIntfIndex. // If hNdisuio is valid, this handle is used, otherwise a local handle // is opened, used and closed before returning. DWORD DevioGetIntfBindingByIndex( HANDLE hNdisuio, // IN opened handle to NDISUIO. If INVALID_HANDLE_VALUE, open one locally UINT nIntfIndex, // IN interface index to look for PRAW_DATA prdOutput) // OUT result of the IOCTL { DWORD dwErr = ERROR_SUCCESS; BOOL bLocalHandle = FALSE; DbgPrint((TRC_TRACK,"[DevioGetIntfBindingByIndex(%d..)", nIntfIndex)); // assert what are the expected valid parameters DbgAssert((prdOutput != NULL && prdOutput->dwDataLen > sizeof(NDISUIO_QUERY_BINDING), "Invalid input parameters")); // see if Ndisuio should be opened locally if (hNdisuio == INVALID_HANDLE_VALUE) { dwErr = DevioGetNdisuioHandle(&hNdisuio); bLocalHandle = (dwErr == ERROR_SUCCESS); } // if everything went well, go query the driver for the Binding structure if (dwErr == ERROR_SUCCESS) { PNDISUIO_QUERY_BINDING pndBinding; DWORD dwOutSize; ZeroMemory(prdOutput->pData, prdOutput->dwDataLen); pndBinding = (PNDISUIO_QUERY_BINDING)prdOutput->pData; pndBinding->BindingIndex = nIntfIndex; if (!DeviceIoControl( hNdisuio, IOCTL_NDISUIO_QUERY_BINDING, prdOutput->pData, prdOutput->dwDataLen, prdOutput->pData, prdOutput->dwDataLen, &dwOutSize, NULL)) { // if the index is over the number of interfaces // we'll have here ERROR_NO_MORE_ITEMS which will be carried out // to the caller dwErr = GetLastError(); DbgPrint((TRC_ERR,"Err: IOCTL_NDISUIO_QUERY_BINDING->%d", dwErr)); } else { dwErr = DevioCheckNdisBinding(pndBinding, dwOutSize); } } // close the handle if it was opened locally if (bLocalHandle) CloseHandle(hNdisuio); DbgPrint((TRC_TRACK,"DevioGetIntfBindingByIndex]=%d", dwErr)); return dwErr; } //------------------------------------------------------ // Get the NDISUIO_QUERY_BINDING for the interface having // the GUID wszGuid. If hNdisuio is INVALID_HANDLE_VALUE // a local handle is opened, used and closed at the end DWORD DevioGetInterfaceBindingByGuid( HANDLE hNdisuio, // IN opened handle to NDISUIO LPWSTR wszGuid, // IN interface GUID as "{guid}" PRAW_DATA prdOutput) // OUT result of the IOCTL { DWORD dwErr = ERROR_SUCCESS; BOOL bLocalHandle = FALSE; INT i; // assert what are the expected valid parameters DbgAssert((wszGuid != NULL && prdOutput != NULL && prdOutput->dwDataLen > sizeof(NDISUIO_QUERY_BINDING), "Invalid input parameter")); DbgPrint((TRC_TRACK,"[DevioGetInterfaceBindingByGuid(%S..)", wszGuid)); // see if Ndisuio should be opened locally if (hNdisuio == INVALID_HANDLE_VALUE) { dwErr = DevioGetNdisuioHandle(&hNdisuio); bLocalHandle = (dwErr == ERROR_SUCCESS); } // iterate through all the interfaces, one by one!! No other better way to do this for (i = 0; dwErr == ERROR_SUCCESS; i++) { PNDISUIO_QUERY_BINDING pndBinding; DWORD dwOutSize; LPWSTR wsName; ZeroMemory(prdOutput->pData, prdOutput->dwDataLen); pndBinding = (PNDISUIO_QUERY_BINDING)prdOutput->pData; pndBinding->BindingIndex = i; if (!DeviceIoControl( hNdisuio, IOCTL_NDISUIO_QUERY_BINDING, prdOutput->pData, prdOutput->dwDataLen, prdOutput->pData, prdOutput->dwDataLen, &dwOutSize, NULL)) { // if the IOCTL failed, get the error code dwErr = GetLastError(); // translate the NO_MORE_ITEMS error in FILE_NOT_FOUND // since the caller is not iterating, is searching for a specific adapter if (dwErr == ERROR_NO_MORE_ITEMS) dwErr = ERROR_FILE_NOT_FOUND; } else { dwErr = DevioCheckNdisBinding(pndBinding, dwOutSize); } if (dwErr == ERROR_SUCCESS) { // Device name is "\DEVICE\{guid}" and is L'\0' terminated // wszGuid is "{guid}" wsName = (LPWSTR)((LPBYTE)pndBinding + pndBinding->DeviceNameOffset); // if the GUID matches, this is the adapter we were looking for if (wcsstr(wsName, wszGuid) != NULL) { // the adapter's BINDING record is already filled in // prdOutput - so just get out of here. dwErr = ERROR_SUCCESS; break; } } } // if handle was opened locally, close it here if (bLocalHandle) CloseHandle(hNdisuio); DbgPrint((TRC_TRACK,"DevioGetInterfaceBindingByGuid]=%d", dwErr)); return dwErr; } DWORD DevioGetIntfStats(PINTF_CONTEXT pIntf) { DWORD dwErr = ERROR_SUCCESS; WCHAR ndisDeviceString[128]; NIC_STATISTICS ndisStats; UNICODE_STRING uniIntfGuid; DbgPrint((TRC_TRACK,"[DevioGetIntfStats(0x%p)", pIntf)); wcscpy(ndisDeviceString, L"\\DEVICE\\"); wcscat(ndisDeviceString, pIntf->wszGuid); RtlInitUnicodeString(&uniIntfGuid, ndisDeviceString); ZeroMemory(&ndisStats, sizeof(NIC_STATISTICS)); ndisStats.Size = sizeof(NIC_STATISTICS); if (!NdisQueryStatistics(&uniIntfGuid, &ndisStats)) { dwErr = GetLastError(); } else { pIntf->ulMediaState = ndisStats.MediaState; pIntf->ulMediaType = ndisStats.MediaType; pIntf->ulPhysicalMediaType = ndisStats.PhysicalMediaType; } DbgPrint((TRC_TRACK,"DevioGetIntfStats]=%d", dwErr)); return dwErr; } DWORD DevioGetIntfMac(PINTF_CONTEXT pIntf) { DWORD dwErr = ERROR_SUCCESS; RAW_DATA rdBuffer = {0, NULL}; DbgPrint((TRC_TRACK,"[DevioGetIntfMac(0x%p)", pIntf)); dwErr = DevioRefreshIntfOIDs( pIntf, INTF_HANDLE, NULL); if (dwErr == ERROR_SUCCESS) { dwErr = DevioQueryBinaryOID( pIntf->hIntf, OID_802_3_CURRENT_ADDRESS, &rdBuffer, sizeof(NDIS_802_11_MAC_ADDRESS)); } if (dwErr == ERROR_SUCCESS) { if (rdBuffer.dwDataLen == sizeof(NDIS_802_11_MAC_ADDRESS)) { memcpy(&(pIntf->ndLocalMac), rdBuffer.pData, sizeof(NDIS_802_11_MAC_ADDRESS)); } else { dwErr = ERROR_INVALID_DATA; } MemFree(rdBuffer.pData); } DbgPrint((TRC_TRACK,"DevioGetIntfMac]=%d", dwErr)); return dwErr; } //------------------------------------------------------ // Notify dependent components the wireless configuration has failed. // Specifically this notification goes to TCP allowing TCP to generate // the NetReady notification asap (instead of waiting for an IP address // to be plumbed down, which might never happen anyhow). DWORD DevioNotifyFailure( LPWSTR wszIntfGuid) { DWORD dwErr = ERROR_SUCCESS; WCHAR ndisDeviceString[128]; UNICODE_STRING UpperComponent; UNICODE_STRING LowerComponent; UNICODE_STRING BindList; struct { IP_PNP_RECONFIG_REQUEST Reconfig; IP_PNP_INIT_COMPLETE InitComplete; } Request; DbgPrint((TRC_TRACK,"[DevioNotifyFailure(%S)", wszIntfGuid)); wcscpy(ndisDeviceString, L"\\DEVICE\\"); wcscat(ndisDeviceString, wszIntfGuid); RtlInitUnicodeString(&UpperComponent, L"Tcpip"); RtlInitUnicodeString(&LowerComponent, ndisDeviceString); RtlInitUnicodeString(&BindList, NULL); ZeroMemory(&Request, sizeof(Request)); Request.Reconfig.version = IP_PNP_RECONFIG_VERSION; Request.Reconfig.NextEntryOffset = (USHORT)((PUCHAR)&Request.InitComplete - (PUCHAR)&Request.Reconfig); Request.InitComplete.Header.EntryType = IPPnPInitCompleteEntryType; dwErr = NdisHandlePnPEvent( NDIS, RECONFIGURE, &LowerComponent, &UpperComponent, &BindList, &Request, sizeof(Request)); DbgPrint((TRC_TRACK,"DevioNotifyFailure]=%d", dwErr)); return dwErr; } DWORD DevioOpenIntfHandle(LPWSTR wszIntfGuid, PHANDLE phIntf) { DWORD dwErr = ERROR_SUCCESS; WCHAR ndisDeviceString[128]; DbgPrint((TRC_TRACK,"[DevioOpenIntfHandle(%S)", wszIntfGuid)); DbgAssert((phIntf!=NULL, "Invalid out param in DevioOpenIntfHandle")); wcscpy(ndisDeviceString, L"\\DEVICE\\"); wcscat(ndisDeviceString, wszIntfGuid); dwErr = OpenIntfHandle(ndisDeviceString, phIntf); DbgPrint((TRC_TRACK,"DevioOpenIntfHandle]=%d", dwErr)); return dwErr; } DWORD DevioCloseIntfHandle(PINTF_CONTEXT pIntf) { DWORD dwErr = ERROR_SUCCESS; DbgPrint((TRC_TRACK,"[DevioCloseIntfHandle(0x%p)", pIntf)); // destroy the handle only if we did have one in the first instance. Otherwise // based only on the GUID we might mess the ref counter on a handle opened by // some other app (i.e. 802.1x) if (pIntf != NULL && pIntf->hIntf != INVALID_HANDLE_VALUE) { WCHAR ndisDeviceString[128]; wcscpy(ndisDeviceString, L"\\DEVICE\\"); wcscat(ndisDeviceString, pIntf->wszGuid); dwErr = CloseIntfHandle(ndisDeviceString); pIntf->hIntf = INVALID_HANDLE_VALUE; } DbgPrint((TRC_TRACK,"DevioCloseIntfHandle]=%d", dwErr)); return dwErr; } DWORD DevioSetIntfOIDs( PINTF_CONTEXT pIntfContext, PINTF_ENTRY pIntfEntry, DWORD dwInFlags, PDWORD pdwOutFlags) { DWORD dwErr = ERROR_SUCCESS; DWORD dwLErr = ERROR_SUCCESS; DWORD dwOutFlags = 0; DbgPrint((TRC_TRACK,"[DevioSetIntfOIDs(0x%p, 0x%p)", pIntfContext, pIntfEntry)); if (pIntfContext == NULL || pIntfEntry == NULL) { dwErr = ERROR_INVALID_PARAMETER; goto exit; } // Set the Infrastructure Mode, if requested if (dwInFlags & INTF_INFRAMODE) { dwLErr = DevioSetEnumOID( pIntfContext->hIntf, OID_802_11_INFRASTRUCTURE_MODE, pIntfEntry->nInfraMode); if (dwLErr != ERROR_SUCCESS) { // set the mode in the client's structure to what it // is currently set in the driver pIntfEntry->nInfraMode = pIntfContext->wzcCurrent.InfrastructureMode; } else { pIntfContext->wzcCurrent.InfrastructureMode = pIntfEntry->nInfraMode; dwOutFlags |= INTF_INFRAMODE; } if (dwErr == ERROR_SUCCESS) dwErr = dwLErr; } // Set the Authentication mode if requested if (dwInFlags & INTF_AUTHMODE) { dwLErr = DevioSetEnumOID( pIntfContext->hIntf, OID_802_11_AUTHENTICATION_MODE, pIntfEntry->nAuthMode); if (dwLErr != ERROR_SUCCESS) { // set the mode in the client's structure to what it // is currently set in the driver pIntfEntry->nAuthMode = pIntfContext->wzcCurrent.AuthenticationMode; } else { pIntfContext->wzcCurrent.AuthenticationMode = pIntfEntry->nAuthMode; dwOutFlags |= INTF_AUTHMODE; } if (dwErr == ERROR_SUCCESS) dwErr = dwLErr; } // Ask the driver to reload the default WEP key if requested if (dwInFlags & INTF_LDDEFWKEY) { dwLErr = DevioSetEnumOID( pIntfContext->hIntf, OID_802_11_RELOAD_DEFAULTS, (DWORD)Ndis802_11ReloadWEPKeys); if (dwLErr == ERROR_SUCCESS) dwOutFlags |= INTF_LDDEFWKEY; if (dwErr == ERROR_SUCCESS) dwErr = dwLErr; } // Add the WEP key if requested if (dwInFlags & INTF_ADDWEPKEY) { // the call below takes care of the case rdCtrlData is bogus dwLErr = DevioSetBinaryOID( pIntfContext->hIntf, OID_802_11_ADD_WEP, &pIntfEntry->rdCtrlData); if (dwLErr == ERROR_SUCCESS) dwOutFlags |= INTF_ADDWEPKEY; if (dwErr == ERROR_SUCCESS) dwErr = dwLErr; } // Remove the WEP key if requested if (dwInFlags & INTF_REMWEPKEY) { if (pIntfEntry->rdCtrlData.dwDataLen >= sizeof(NDIS_802_11_WEP) && pIntfEntry->rdCtrlData.pData != NULL) { PNDIS_802_11_WEP pndWepKey = (PNDIS_802_11_WEP)pIntfEntry->rdCtrlData.pData; dwLErr = DevioSetEnumOID( pIntfContext->hIntf, OID_802_11_REMOVE_WEP, pndWepKey->KeyIndex); if (dwLErr == ERROR_SUCCESS) dwOutFlags |= INTF_REMWEPKEY; } else { dwLErr = ERROR_INVALID_PARAMETER; } if (dwErr == ERROR_SUCCESS) dwErr = dwLErr; } // Set the WEP Status if requested if (dwInFlags & INTF_WEPSTATUS) { dwLErr = DevioSetEnumOID( pIntfContext->hIntf, OID_802_11_WEP_STATUS, pIntfEntry->nWepStatus); if (dwLErr != ERROR_SUCCESS) { // set the mode in the client's structure to what it // is currently set in the driver pIntfEntry->nWepStatus = pIntfContext->wzcCurrent.Privacy; } else { pIntfContext->wzcCurrent.Privacy = pIntfEntry->nWepStatus; dwOutFlags |= INTF_WEPSTATUS; } if (dwErr == ERROR_SUCCESS) dwErr = dwLErr; } // Plumb the new SSID down to the driver. If success, copy this new // SSID into the interface's context if (dwInFlags & INTF_SSID) { // ntddndis.h defines NDIS_802_11_SSID with a maximum of // 32 UCHARs for the SSID name if (pIntfEntry->rdSSID.dwDataLen > 32) { dwLErr = ERROR_INVALID_PARAMETER; } else { NDIS_802_11_SSID ndSSID = {0}; RAW_DATA rdBuffer; ndSSID.SsidLength = pIntfEntry->rdSSID.dwDataLen; memcpy(&ndSSID.Ssid, pIntfEntry->rdSSID.pData, ndSSID.SsidLength); rdBuffer.dwDataLen = sizeof(NDIS_802_11_SSID); rdBuffer.pData = (LPBYTE)&ndSSID; dwLErr = DevioSetBinaryOID( pIntfContext->hIntf, OID_802_11_SSID, &rdBuffer); if (dwLErr == ERROR_SUCCESS) { // copy over the new SSID into the interface's context CopyMemory(&pIntfContext->wzcCurrent.Ssid, &ndSSID, sizeof(NDIS_802_11_SSID)); dwOutFlags |= INTF_SSID; // on the same time, if a new SSID has been set, it means we broke whatever association // we had before, hence the BSSID field can no longer be correct: ZeroMemory(&pIntfContext->wzcCurrent.MacAddress, sizeof(NDIS_802_11_MAC_ADDRESS)); } } if (dwErr == ERROR_SUCCESS) dwErr = dwLErr; } // set the new BSSID to the driver. If this succeeds, copy // the data that was passed down to the interface's context (allocate // space for it if not already allocated). if (dwInFlags & INTF_BSSID) { dwLErr = DevioSetBinaryOID( pIntfContext->hIntf, OID_802_11_BSSID, &pIntfEntry->rdBSSID); // if the BSSID is not a MAC address, the call above should fail! if (dwLErr == ERROR_SUCCESS) { DbgAssert((pIntfEntry->rdBSSID.dwDataLen == sizeof(NDIS_802_11_MAC_ADDRESS), "Data to be set is %d bytes, which is not a MAC address!", pIntfEntry->rdBSSID.dwDataLen)); memcpy(&pIntfContext->wzcCurrent.MacAddress, pIntfEntry->rdBSSID.pData, sizeof(NDIS_802_11_MAC_ADDRESS)); dwOutFlags |= INTF_BSSID; } if (dwErr == ERROR_SUCCESS) dwErr = dwLErr; } exit: if (pdwOutFlags != NULL) *pdwOutFlags = dwOutFlags; DbgPrint((TRC_TRACK,"DevioSetIntfOIDs]=%d", dwErr)); return dwErr; } DWORD DevioRefreshIntfOIDs( PINTF_CONTEXT pIntf, DWORD dwInFlags, PDWORD pdwOutFlags) { DWORD dwErr = ERROR_SUCCESS; DWORD dwLErr = ERROR_SUCCESS; DWORD dwOutFlags = 0; RAW_DATA rdBuffer; DbgPrint((TRC_TRACK,"[DevioRefreshIntfOIDs(0x%p)", pIntf)); if (pIntf == NULL) { dwErr = ERROR_INVALID_PARAMETER; goto exit; } // if the interface handle is invalid or there is an explicit requested // to reopen the interface's handle do it as the first thing if (pIntf->hIntf == INVALID_HANDLE_VALUE || dwInFlags & INTF_HANDLE) { if (pIntf->hIntf != INVALID_HANDLE_VALUE) { dwErr = DevioCloseIntfHandle(pIntf); DbgAssert((dwErr == ERROR_SUCCESS, "Couldn't close handle for Intf %S", pIntf->wszGuid)); } dwErr = DevioOpenIntfHandle(pIntf->wszGuid, &pIntf->hIntf); DbgAssert((dwErr == ERROR_SUCCESS, "DevioOpenIntfHandle failed for Intf context 0x%p", pIntf)); if (dwErr == ERROR_SUCCESS && (dwInFlags & INTF_HANDLE)) dwOutFlags |= INTF_HANDLE; } // if failed to refresh the interface's handle (this is the only way // dwErr could not be success) then we already have a closed handle // so there's no point in going further if (dwErr != ERROR_SUCCESS) goto exit; // if requested to scan the interface's BSSID list, do it as // the next thing. Note however that rescanning is asynchronous. // Querying for the BSSID_LIST in the same shot with forcing a rescan // might not result in getting the most up to date list. if (dwInFlags & INTF_LIST_SCAN) { // indicate to the driver to rescan the BSSID_LIST for this adapter dwLErr = DevioSetEnumOID( pIntf->hIntf, OID_802_11_BSSID_LIST_SCAN, 0); DbgAssert((dwLErr == ERROR_SUCCESS, "DevioSetEnumOID(BSSID_LIST_SCAN) failed for Intf hdl 0x%x", pIntf->hIntf)); if (dwLErr == ERROR_SUCCESS) dwOutFlags |= INTF_LIST_SCAN; else if (dwErr == ERROR_SUCCESS) dwErr = dwLErr; } if (dwInFlags & INTF_AUTHMODE) { // query the authentication mode for the interface dwLErr = DevioQueryEnumOID( pIntf->hIntf, OID_802_11_AUTHENTICATION_MODE, (LPDWORD)&pIntf->wzcCurrent.AuthenticationMode); DbgAssert((dwLErr == ERROR_SUCCESS, "DevioQueryEnumOID(AUTH_MODE) failed for Intf hdl 0x%x", pIntf->hIntf)); if (dwLErr == ERROR_SUCCESS) dwOutFlags |= INTF_AUTHMODE; else if (dwErr == ERROR_SUCCESS) dwErr = dwLErr; } if (dwInFlags & INTF_INFRAMODE) { // query the infrastructure mode for the interface dwLErr = DevioQueryEnumOID( pIntf->hIntf, OID_802_11_INFRASTRUCTURE_MODE, (LPDWORD)&pIntf->wzcCurrent.InfrastructureMode); DbgAssert((dwLErr == ERROR_SUCCESS, "DevioQueryEnumOID(INFRA_MODE) failed for Intf hdl 0x%x", pIntf->hIntf)); if (dwLErr == ERROR_SUCCESS) dwOutFlags |= INTF_INFRAMODE; else if (dwErr == ERROR_SUCCESS) dwErr = dwLErr; } if (dwInFlags & INTF_WEPSTATUS) { // query the WEP_STATUS for the interface dwLErr = DevioQueryEnumOID( pIntf->hIntf, OID_802_11_WEP_STATUS, (LPDWORD)&pIntf->wzcCurrent.Privacy); DbgAssert((dwLErr == ERROR_SUCCESS, "DevioQueryEnumOID(WEP_STATUS) failed for Intf hdl 0x%x", pIntf->hIntf)); if (dwLErr == ERROR_SUCCESS) dwOutFlags |= INTF_WEPSTATUS; else if (dwErr == ERROR_SUCCESS) dwErr = dwLErr; } if (dwInFlags & INTF_BSSID) { // query the BSSID (MAC address) for the interface rdBuffer.dwDataLen = 0; rdBuffer.pData = NULL; dwLErr = DevioQueryBinaryOID( pIntf->hIntf, OID_802_11_BSSID, &rdBuffer, 6); DbgAssert((dwLErr == ERROR_SUCCESS, "DevioQueryBinaryOID(BSSID) failed for Intf hdl 0x%x", pIntf->hIntf)); // if the call above succeeded... if (dwLErr == ERROR_SUCCESS) { DbgAssert((rdBuffer.dwDataLen == 6, "BSSID len %d is not a MAC address len??", rdBuffer.dwDataLen)); // ...and returned correctly a MAC address if (rdBuffer.dwDataLen == sizeof(NDIS_802_11_MAC_ADDRESS)) { // copy it in the interface's context memcpy(&pIntf->wzcCurrent.MacAddress, rdBuffer.pData, rdBuffer.dwDataLen); } else { ZeroMemory(&pIntf->wzcCurrent.MacAddress, sizeof(NDIS_802_11_MAC_ADDRESS)); dwLErr = ERROR_INVALID_DATA; } } // free whatever might have had been allocated in DevioQueryBinaryOID MemFree(rdBuffer.pData); if (dwLErr == ERROR_SUCCESS) dwOutFlags |= INTF_BSSID; else if (dwErr == ERROR_SUCCESS) dwErr = dwLErr; } if (dwInFlags & INTF_SSID) { PNDIS_802_11_SSID pndSSID; // query the SSID for the interface rdBuffer.dwDataLen = 0; rdBuffer.pData = NULL; dwLErr = DevioQueryBinaryOID( pIntf->hIntf, OID_802_11_SSID, &rdBuffer, sizeof(NDIS_802_11_SSID)); DbgAssert((dwLErr == ERROR_SUCCESS, "DevioQueryBinaryOID(SSID) failed for Intf hdl 0x%x", pIntf->hIntf)); // if we succeeded up to here then we can't fail further for this OID if (dwLErr == ERROR_SUCCESS) dwOutFlags |= INTF_SSID; else if (dwErr == ERROR_SUCCESS) dwErr = dwLErr; // copy the pointer to the buffer that was allocated in Query call pndSSID = (PNDIS_802_11_SSID)rdBuffer.pData; if (pndSSID != NULL) { // HACK - if the driver doesn't return the NDIS_802_11_SSID structure but just // the SSID itself, correct this! if (pndSSID->SsidLength > 32) { DbgAssert((FALSE,"Driver returns SSID instead of NDIS_802_11_SSID structure")); // we have enough space in the buffer to slide the data up (it was shifted down // in DevioQueryBinaryOID. MoveMemory(pndSSID->Ssid, pndSSID, rdBuffer.dwDataLen); pndSSID->SsidLength = rdBuffer.dwDataLen; } // copy over the current SSID into the interface's context if there was no error CopyMemory(&pIntf->wzcCurrent.Ssid, pndSSID, sizeof(NDIS_802_11_SSID)); } // free whatever might have been allocated in DevioQueryBinaryOID MemFree(pndSSID); } if (dwInFlags & INTF_BSSIDLIST) { rdBuffer.dwDataLen = 0; rdBuffer.pData = NULL; // estimate a buffer large enough for 20 SSIDs. dwLErr = DevioQueryBinaryOID( pIntf->hIntf, OID_802_11_BSSID_LIST, &rdBuffer, sizeof(NDIS_802_11_BSSID_LIST) + 19*sizeof(NDIS_WLAN_BSSID)); DbgAssert((dwLErr == ERROR_SUCCESS, "DevioQueryBinaryOID(BSSID_LIST) failed for Intf hdl 0x%x", pIntf->hIntf)); // if we succeeded getting the visible list we should have a valid // rdBuffer.pData, even if it shows '0 entries' if (dwLErr == ERROR_SUCCESS) { PWZC_802_11_CONFIG_LIST pNewVList; pNewVList = WzcNdisToWzc((PNDIS_802_11_BSSID_LIST)rdBuffer.pData); if (rdBuffer.pData == NULL || pNewVList != NULL) { // cleanup whatever we might have had before MemFree(pIntf->pwzcVList); // copy the new visible list we got pIntf->pwzcVList = pNewVList; dwOutFlags |= INTF_BSSIDLIST; } else dwLErr = GetLastError(); // whatever the outcome is, free the buffer returned from the driver MemFree(rdBuffer.pData); } // if any error happened here, save it unless some other error has already // been saved if (dwErr == ERROR_SUCCESS) dwErr = dwLErr; } exit: if (pdwOutFlags != NULL) *pdwOutFlags = dwOutFlags; DbgPrint((TRC_TRACK,"DevioRefreshIntfOIDs]=%d", dwErr)); return dwErr; } DWORD DevioQueryEnumOID( HANDLE hIntf, NDIS_OID Oid, DWORD *pdwEnumValue) { DWORD dwErr = ERROR_SUCCESS; NDISUIO_QUERY_OID QueryOid; DWORD dwBytesReturned = 0; DbgPrint((TRC_TRACK,"[DevioQueryEnumOID(0x%x, 0x%x)", hIntf, Oid)); DbgAssert((pdwEnumValue != NULL, "Invalid out param in DevioQueryEnumOID")); if (hIntf == INVALID_HANDLE_VALUE || pdwEnumValue == NULL) { dwErr = ERROR_INVALID_PARAMETER; goto exit; } // the NDISUIO_QUERY_OID includes data for 1 dword, sufficient for getting // an enumerative value from the driver. This spares us of an additional // allocation. ZeroMemory(&QueryOid, sizeof(NDISUIO_QUERY_OID)); QueryOid.Oid = Oid; if (!DeviceIoControl ( hIntf, IOCTL_NDISUIO_QUERY_OID_VALUE, (LPVOID)&QueryOid, sizeof(NDISUIO_QUERY_OID), (LPVOID)&QueryOid, sizeof(NDISUIO_QUERY_OID), &dwBytesReturned, NULL)) // no overlapping routine { dwErr = GetLastError(); DbgPrint((TRC_ERR, "Err: IOCTL_NDISUIO_QUERY_OID_VALUE->%d", dwErr)); goto exit; } //dwErr = GetLastError(); //DbgAssert((dwErr == ERROR_SUCCESS, "DeviceIoControl suceeded, but GetLastError() is =0x%x", dwErr)); dwErr = ERROR_SUCCESS; *pdwEnumValue = *(LPDWORD)QueryOid.Data; exit: DbgPrint((TRC_TRACK,"DevioQueryEnumOID]=%d", dwErr)); return dwErr; } DWORD DevioSetEnumOID( HANDLE hIntf, NDIS_OID Oid, DWORD dwEnumValue) { DWORD dwErr = ERROR_SUCCESS; NDISUIO_SET_OID SetOid; DWORD dwBytesReturned = 0; DbgPrint((TRC_TRACK,"[DevioSetEnumOID(0x%x, 0x%x, %d)", hIntf, Oid, dwEnumValue)); if (hIntf == INVALID_HANDLE_VALUE) { dwErr = ERROR_INVALID_PARAMETER; goto exit; } // the NDISUIO_SET_OID includes data for 1 dword, sufficient for setting // an enumerative value from the driver. This spares us of an additional // allocation. SetOid.Oid = Oid; *(LPDWORD)SetOid.Data = dwEnumValue; if (!DeviceIoControl ( hIntf, IOCTL_NDISUIO_SET_OID_VALUE, (LPVOID)&SetOid, sizeof(NDISUIO_SET_OID), NULL, 0, &dwBytesReturned, NULL)) // no overlapping routine { dwErr = GetLastError(); DbgPrint((TRC_ERR, "Err: IOCTL_NDISUIO_SET_OID_VALUE->%d", dwErr)); goto exit; } //dwErr = GetLastError(); //DbgAssert((dwErr == ERROR_SUCCESS, "DeviceIoControl suceeded, but GetLastError() is =0x%x", dwErr)); dwErr = ERROR_SUCCESS; exit: DbgPrint((TRC_TRACK,"DevioSetEnumOID]=%d", dwErr)); return dwErr; } #define DATA_MEM_MIN 32 // the minimum mem block to be sent out to the ioctl #define DATA_MEM_MAX 65536 // the maximum mem block that will be sent out to the ioctl (64K) #define DATA_MEM_INC 512 // increment the existent block in 512 bytes increment DWORD DevioQueryBinaryOID( HANDLE hIntf, NDIS_OID Oid, PRAW_DATA pRawData, // buffer is internally allocated DWORD dwMemEstimate) // how much memory is estimated the result needs { DWORD dwErr = ERROR_SUCCESS; PNDISUIO_QUERY_OID pQueryOid=NULL; DbgPrint((TRC_TRACK, "[DevioQueryBinaryOID(0x%x, 0x%x)", hIntf, Oid)); if (hIntf == INVALID_HANDLE_VALUE || pRawData == NULL) { dwErr = ERROR_INVALID_PARAMETER; goto exit; } if (dwMemEstimate < DATA_MEM_MIN) dwMemEstimate = DATA_MEM_MIN; do { DWORD dwBuffSize; DWORD dwBytesReturned; MemFree(pQueryOid); if (dwMemEstimate > DATA_MEM_MAX) dwMemEstimate = DATA_MEM_MAX; dwBuffSize = FIELD_OFFSET(NDISUIO_QUERY_OID, Data) + dwMemEstimate; pQueryOid = (PNDISUIO_QUERY_OID) MemCAlloc(dwBuffSize); if (pQueryOid == NULL) { dwErr = GetLastError(); break; } pQueryOid->Oid = Oid; if (DeviceIoControl ( hIntf, IOCTL_NDISUIO_QUERY_OID_VALUE, (LPVOID)pQueryOid, dwBuffSize, (LPVOID)pQueryOid, dwBuffSize, &dwBytesReturned, NULL)) { DbgAssert(( dwBytesReturned <= dwBuffSize, "DeviceIoControl returned %d > %d that was passed down!", dwBytesReturned, dwBuffSize)); pRawData->pData = (LPBYTE)pQueryOid; pRawData->dwDataLen = dwBytesReturned - FIELD_OFFSET(NDISUIO_QUERY_OID, Data); if (pRawData->dwDataLen != 0) { MoveMemory(pQueryOid, pQueryOid->Data, pRawData->dwDataLen); } else { pRawData->pData = NULL; MemFree(pQueryOid); pQueryOid = NULL; } dwErr = ERROR_SUCCESS; break; } dwErr = GetLastError(); if (((dwErr == ERROR_INSUFFICIENT_BUFFER) || (dwErr == ERROR_INVALID_USER_BUFFER)) && (dwMemEstimate < DATA_MEM_MAX)) { dwMemEstimate += DATA_MEM_INC; dwErr = ERROR_SUCCESS; } } while (dwErr == ERROR_SUCCESS); exit: if (dwErr != ERROR_SUCCESS) { MemFree(pQueryOid); pRawData->pData= NULL; pRawData->dwDataLen = 0; } DbgPrint((TRC_TRACK, "DevioQueryBinaryOID]=%d", dwErr)); return dwErr; } DWORD DevioSetBinaryOID( HANDLE hIntf, NDIS_OID Oid, PRAW_DATA pRawData) { DWORD dwErr = ERROR_SUCCESS; PNDISUIO_SET_OID pSetOid = NULL; DWORD dwBytesReturned = 0; DWORD dwBufferSize; DbgPrint((TRC_TRACK,"[DevioSetBinaryOID(0x%x,0x%x,...)", hIntf, Oid)); if (hIntf == INVALID_HANDLE_VALUE || pRawData == NULL || pRawData->dwDataLen == 0 || pRawData->pData == NULL) { dwErr = ERROR_INVALID_PARAMETER; goto exit; } dwBufferSize = FIELD_OFFSET(NDISUIO_QUERY_OID, Data) + pRawData->dwDataLen; pSetOid = (PNDISUIO_SET_OID) MemCAlloc(dwBufferSize); if (pSetOid == NULL) { dwErr = GetLastError(); goto exit; } pSetOid->Oid = Oid; CopyMemory(pSetOid->Data, pRawData->pData, pRawData->dwDataLen); if (!DeviceIoControl ( hIntf, IOCTL_NDISUIO_SET_OID_VALUE, (LPVOID)pSetOid, dwBufferSize, NULL, 0, &dwBytesReturned, NULL)) // no overlapping routine { dwErr = GetLastError(); DbgPrint((TRC_ERR, "Err: IOCTL_NDISUIO_SET_OID_VALUE->%d", dwErr)); goto exit; } //dwErr = GetLastError(); //DbgAssert((dwErr == ERROR_SUCCESS, "DeviceIoControl suceeded, but GetLastError() is 0x%x", dwErr)); dwErr = ERROR_SUCCESS; exit: MemFree(pSetOid); DbgPrint((TRC_TRACK,"DevioSetBinaryOID]=%d", dwErr)); return dwErr; }