windows-nt/Source/XPSP1/NT/net/layer2svc/zeroconf/server/deviceio.c
2020-09-26 16:20:57 +08:00

1114 lines
35 KiB
C

#include <precomp.h>
#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;
}