You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2951 lines
116 KiB
2951 lines
116 KiB
#include <precomp.h>
|
|
#include "wzcsvc.h"
|
|
#include "notify.h"
|
|
#include "intflist.h"
|
|
#include "tracing.h"
|
|
#include "utils.h"
|
|
#include "deviceio.h"
|
|
#include "storage.h"
|
|
#include "zcdblog.h"
|
|
|
|
// global interfaces list. It has to be initialized to {NULL, NULL} just
|
|
// to differentiate the case when the list head was never initialized.
|
|
HASH g_hshHandles = {0}; // HASH handing GUID<->Handle mapping; Key = "\DEVICE\{guid}"
|
|
INTF_HASHES g_lstIntfHashes = {0}; // set of hashes for all INTF_CONTEXTs
|
|
HANDLE g_htmQueue = NULL; // global timer queue
|
|
|
|
//-----------------------------------------------------------
|
|
// Synchronization routines
|
|
DWORD
|
|
LstRccsReference(PINTF_CONTEXT pIntfContext)
|
|
{
|
|
DWORD dwErr = ERROR_INVALID_PARAMETER;
|
|
DbgPrint((TRC_TRACK,"[LstRccsReference(0x%p)", pIntfContext));
|
|
if (pIntfContext)
|
|
{
|
|
DbgPrint((TRC_SYNC," LstRccsReference 0x%p.refCount=%d", pIntfContext, pIntfContext->rccs.nRefCount));
|
|
InterlockedIncrement(&(pIntfContext->rccs.nRefCount));
|
|
dwErr = ERROR_SUCCESS;
|
|
}
|
|
DbgPrint((TRC_TRACK,"LstRccsReference]=%d", dwErr));
|
|
return dwErr;
|
|
}
|
|
|
|
DWORD
|
|
LstRccsLock(PINTF_CONTEXT pIntfContext)
|
|
{
|
|
DWORD dwErr = ERROR_INVALID_PARAMETER;
|
|
DbgPrint((TRC_TRACK,"[LstRccsLock(0x%p)", pIntfContext));
|
|
if (pIntfContext)
|
|
{
|
|
EnterCriticalSection(&(pIntfContext->rccs.csMutex));
|
|
dwErr = ERROR_SUCCESS;
|
|
}
|
|
DbgPrint((TRC_TRACK,"LstRccsLock]=%d", dwErr));
|
|
return dwErr;
|
|
}
|
|
|
|
DWORD
|
|
LstRccsUnlockUnref(PINTF_CONTEXT pIntfContext)
|
|
{
|
|
DWORD dwErr = ERROR_INVALID_PARAMETER;
|
|
DbgPrint((TRC_TRACK,"[LstRccsUnlockUnref(0x%p)", pIntfContext));
|
|
if (pIntfContext)
|
|
{
|
|
UINT nLastCount;
|
|
|
|
// before doing anything, while we're still in the critical section,
|
|
// decrement the ref counter and store the result in a local variable
|
|
nLastCount = InterlockedDecrement(&(pIntfContext->rccs.nRefCount));
|
|
LeaveCriticalSection(&(pIntfContext->rccs.csMutex));
|
|
|
|
// if we were the last to use this context, efectively destroy it.
|
|
DbgPrint((TRC_SYNC," LstRccsUnlockUnref 0x%p.refCount=%d", pIntfContext, nLastCount));
|
|
|
|
if (nLastCount == 0)
|
|
LstDestroyIntfContext(pIntfContext);
|
|
|
|
dwErr = ERROR_SUCCESS;
|
|
}
|
|
DbgPrint((TRC_TRACK,"LstRccsUnlockUnref]=%d", dwErr));
|
|
return dwErr;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Intializes all the internal interfaces hashes
|
|
DWORD
|
|
LstInitIntfHashes()
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
__try
|
|
{
|
|
InitializeCriticalSection(&g_lstIntfHashes.csMutex);
|
|
g_lstIntfHashes.bValid = TRUE;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
dwErr = GetExceptionCode();
|
|
}
|
|
|
|
g_lstIntfHashes.pHnGUID = NULL;
|
|
InitializeListHead(&g_lstIntfHashes.lstIntfs);
|
|
g_lstIntfHashes.nNumIntfs = 0;
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Destructs all the internal data structures - hash & lists
|
|
// This call is done after all the threads confirmed they're done.
|
|
DWORD
|
|
LstDestroyIntfHashes()
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
DbgPrint((TRC_TRACK,"[LstDestroyIntfHashes"));
|
|
|
|
// destruct whatever hashes we have
|
|
HshDestructor(g_lstIntfHashes.pHnGUID);
|
|
|
|
while (!IsListEmpty(&g_lstIntfHashes.lstIntfs))
|
|
{
|
|
PLIST_ENTRY pEntry;
|
|
PINTF_CONTEXT pIntfContext;
|
|
|
|
pEntry = RemoveHeadList(&g_lstIntfHashes.lstIntfs);
|
|
pIntfContext = CONTAINING_RECORD(pEntry, INTF_CONTEXT, Link);
|
|
// DevioCloseIntfHandle closes the handle only if it is valid.
|
|
// Otherwise noop. pIntfContext is created in LstAddIntfToList
|
|
// and there, the handle is initialized to HANDLE_INVALID_VALUE.
|
|
// So .. attempting to close the handle here is safe.
|
|
// also, this call is done after all the threads are terminated
|
|
// meaning that all the ref counts should be already balanced (set
|
|
// to 1)
|
|
LstDestroyIntfContext(pIntfContext);
|
|
}
|
|
if (g_lstIntfHashes.bValid)
|
|
{
|
|
g_lstIntfHashes.bValid = FALSE;
|
|
DeleteCriticalSection(&g_lstIntfHashes.csMutex);
|
|
}
|
|
|
|
DbgPrint((TRC_TRACK,"LstDestroyIntfHashes]=%d", dwErr));
|
|
return dwErr;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Intializes the global timer queue
|
|
DWORD
|
|
LstInitTimerQueue()
|
|
{
|
|
g_htmQueue = CreateTimerQueue();
|
|
return (g_htmQueue == NULL) ? GetLastError() : ERROR_SUCCESS;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Destructs the global timer queue
|
|
DWORD
|
|
LstDestroyTimerQueue()
|
|
{
|
|
|
|
DbgPrint((TRC_TRACK|TRC_SYNC,"[LstDestroyTimerQueue"));
|
|
if (g_htmQueue != NULL)
|
|
{
|
|
DeleteTimerQueueEx(g_htmQueue, INVALID_HANDLE_VALUE);
|
|
g_htmQueue = NULL;
|
|
}
|
|
DbgPrint((TRC_TRACK|TRC_SYNC,"LstDestroyTimerQueue]"));
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Intializes all the internal data structures. Reads the list of interfaces from
|
|
// Ndisuio and gets all the parameters & OIDS.
|
|
DWORD
|
|
LstLoadInterfaces()
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
HANDLE hNdisuio = INVALID_HANDLE_VALUE;
|
|
INT i;
|
|
RAW_DATA rdBuffer;
|
|
UINT nRequired = QUERY_BUFFER_SIZE;
|
|
|
|
rdBuffer.dwDataLen = 0;
|
|
rdBuffer.pData = NULL;
|
|
|
|
DbgPrint((TRC_TRACK,"[LstLoadInterfaces"));
|
|
|
|
// open the handle to Ndisuio. It should be used throughout
|
|
// the adapters iteration
|
|
dwErr = DevioGetNdisuioHandle(&hNdisuio);
|
|
|
|
// since we're going to add a bunch of interface contexts,
|
|
// lock the hashes first thing to do
|
|
EnterCriticalSection(&g_lstIntfHashes.csMutex);
|
|
|
|
for (i = 0; dwErr == ERROR_SUCCESS; i++)
|
|
{
|
|
PNDISUIO_QUERY_BINDING pQueryBinding;
|
|
PINTF_CONTEXT pIntfContext = NULL;
|
|
|
|
// allocate as much buffer as needed by DevioGetIntfBindingByIndex
|
|
if (rdBuffer.dwDataLen < nRequired)
|
|
{
|
|
MemFree(rdBuffer.pData);
|
|
rdBuffer.pData = MemCAlloc(nRequired);
|
|
if (rdBuffer.pData == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
rdBuffer.dwDataLen = nRequired;
|
|
}
|
|
|
|
pQueryBinding = (PNDISUIO_QUERY_BINDING)rdBuffer.pData;
|
|
|
|
// go get the binding structure for this adapter's index
|
|
dwErr = DevioGetIntfBindingByIndex(
|
|
hNdisuio,
|
|
i,
|
|
&rdBuffer);
|
|
// if Ndisuio says the buffer is not large enough, increase it with 1K
|
|
if (dwErr == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
// increase the buffer only if it is not obscenely large already
|
|
// otherwise just skip this index and move to the next.
|
|
if (nRequired < QUERY_BUFFER_MAX)
|
|
{
|
|
nRequired += QUERY_BUFFER_SIZE;
|
|
i--;
|
|
}
|
|
dwErr = ERROR_SUCCESS;
|
|
continue;
|
|
}
|
|
|
|
// if we got back NO_MORE_ITEMS then we did our job successfully
|
|
if (dwErr == ERROR_NO_MORE_ITEMS)
|
|
{
|
|
// translate this error to success and break out
|
|
dwErr = ERROR_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
// in case any other failure was returned from NDISUIO, just break out
|
|
// this SHOULDN'T HAPPEN
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
DbgAssert((FALSE,
|
|
"DevioGetIntfBindingByIndex failed for interface %d with err=%d", i, dwErr));
|
|
break;
|
|
}
|
|
|
|
// go build the INTF_CONTEXT structure, based on
|
|
// the binding information (key info for the adapter)
|
|
dwErr = LstConstructIntfContext(
|
|
pQueryBinding,
|
|
&pIntfContext);
|
|
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
// reference and lock this brand new context
|
|
LstRccsReference(pIntfContext);
|
|
LstRccsLock(pIntfContext);
|
|
|
|
// add it to the hashes
|
|
dwErr = LstAddIntfToHashes(pIntfContext);
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
// and dispatch the eEventAdd
|
|
dwErr = StateDispatchEvent(
|
|
eEventAdd,
|
|
pIntfContext,
|
|
NULL);
|
|
|
|
// clear up the INTFCTL_INTERNAL_BLK_MEDIACONN bit since this is not a media sense handler
|
|
pIntfContext->dwCtlFlags &= ~INTFCTL_INTERNAL_BLK_MEDIACONN;
|
|
}
|
|
// if for any reason hashing or dispatching failed, cleanup the context here
|
|
if (dwErr != ERROR_SUCCESS)
|
|
LstRemoveIntfContext(pIntfContext);
|
|
|
|
// we're done with this context, unlock & unref it here.
|
|
LstRccsUnlockUnref(pIntfContext);
|
|
}
|
|
|
|
// error happened at this point, recover and go to the next interface
|
|
dwErr = ERROR_SUCCESS;
|
|
}
|
|
|
|
// unlock the hashes here
|
|
LeaveCriticalSection(&g_lstIntfHashes.csMutex);
|
|
|
|
// close the handle to Ndisuio - if it was opened successfully.
|
|
if (hNdisuio != INVALID_HANDLE_VALUE)
|
|
CloseHandle(hNdisuio);
|
|
|
|
// free memory (it handles the case when the pointer is NULL)
|
|
MemFree(rdBuffer.pData);
|
|
|
|
DbgPrint((TRC_TRACK,"LstLoadInterfaces]=%d", dwErr));
|
|
return dwErr;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Constructor for the INTF_CONTEXT. Takes as parameter the binding information.
|
|
// Interface's GUID constitutes the context's key info.
|
|
// This call doesn't insert the new context in any hash or list
|
|
DWORD
|
|
LstConstructIntfContext(
|
|
PNDISUIO_QUERY_BINDING pBinding,
|
|
PINTF_CONTEXT *ppIntfContext)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
PINTF_CONTEXT pIntfContext;
|
|
LPWSTR wszName;
|
|
DWORD dwNameLen;
|
|
|
|
DbgPrint((TRC_TRACK,"[LstConstructIntfContext(0x%p)", pBinding));
|
|
DbgAssert((ppIntfContext != NULL, "Invalid in/out parameter"));
|
|
|
|
// zero the output param
|
|
*ppIntfContext = NULL;
|
|
|
|
// pIntfContext is allocated with zero_init meaning
|
|
// all internal pointers are set to null
|
|
pIntfContext = MemCAlloc(sizeof(INTF_CONTEXT));
|
|
if (pIntfContext == NULL)
|
|
{
|
|
dwErr = GetLastError();
|
|
goto exit;
|
|
}
|
|
|
|
// initialize context's fields, in their definition order..
|
|
// Initialize the context specific fields (links, sync, control flags, state)
|
|
InitializeListHead(&pIntfContext->Link);
|
|
dwErr = RccsInit(&(pIntfContext->rccs)); // reference counter is initially set to 1
|
|
if (dwErr != ERROR_SUCCESS)
|
|
goto exit;
|
|
pIntfContext->dwCtlFlags = (INTFCTL_ENABLED | Ndis802_11AutoUnknown);
|
|
// initially, the ncstatus is "DISCONNECTED" (until wzc plumbs it down)
|
|
pIntfContext->ncStatus = NCS_MEDIA_DISCONNECTED;
|
|
// the state handler is initially set to NULL - it will be set to the
|
|
// appropriate state when the context will be added to the state machine through
|
|
// dispatching an eEventAdd event.
|
|
pIntfContext->pfnStateHandler = NULL;
|
|
// init the timer
|
|
pIntfContext->hTimer = INVALID_HANDLE_VALUE;
|
|
|
|
// if we do have a valid NDIS binding for this interface
|
|
// otherwise, the following fields gets initialized as below:
|
|
// hTimer <- INVALID_HANDLE_VALUE
|
|
// dwIndex <- 0
|
|
// wszGuid <- NULL
|
|
// wszDescr <- NULL
|
|
if (pBinding != NULL)
|
|
{
|
|
// create an inactive timer for this interface.
|
|
if (!CreateTimerQueueTimer(
|
|
&(pIntfContext->hTimer),
|
|
g_htmQueue,
|
|
(WAITORTIMERCALLBACK)WZCTimeoutCallback,
|
|
pIntfContext,
|
|
TMMS_INFINITE,
|
|
TMMS_INFINITE,
|
|
WT_EXECUTEDEFAULT))
|
|
{
|
|
dwErr = GetLastError();
|
|
goto exit;
|
|
}
|
|
|
|
// initialize the ndis specific fields
|
|
pIntfContext->dwIndex = pBinding->BindingIndex;
|
|
// Copy the interface's device name.
|
|
// Device name is "\DEVICE\{guid}". We keep only the guid
|
|
wszName = (LPWSTR)((LPBYTE)pBinding + pBinding->DeviceNameOffset);
|
|
// the DeviceNameLength is in bytes and includes the null terminator
|
|
dwNameLen = pBinding->DeviceNameLength / sizeof(WCHAR);
|
|
if (dwNameLen >= 8 && !_wcsnicmp(wszName, L"\\DEVICE\\", 8)) // 8 is the # of chars in "\\DEVICE\\"
|
|
{
|
|
wszName += 8;
|
|
dwNameLen -= 8;
|
|
}
|
|
if (dwNameLen > 0)
|
|
{
|
|
pIntfContext->wszGuid = MemCAlloc(sizeof(WCHAR)*dwNameLen);
|
|
if (pIntfContext->wszGuid == NULL)
|
|
{
|
|
dwErr = GetLastError();
|
|
goto exit;
|
|
}
|
|
wcscpy(pIntfContext->wszGuid, wszName);
|
|
}
|
|
// Copy the interface's description.name
|
|
wszName = (LPWSTR)((LPBYTE)pBinding + pBinding->DeviceDescrOffset);
|
|
// the DeviceDescrLength is in bytes and includes the null terminator
|
|
dwNameLen = pBinding->DeviceDescrLength;
|
|
if (dwNameLen > 0)
|
|
{
|
|
pIntfContext->wszDescr = MemCAlloc(dwNameLen);
|
|
if (pIntfContext->wszDescr == NULL)
|
|
{
|
|
dwErr = GetLastError();
|
|
goto exit;
|
|
}
|
|
wcscpy(pIntfContext->wszDescr, wszName);
|
|
}
|
|
}
|
|
|
|
// ulMediaState, ulMediaType, ulPhysicalMediaType defaults to 0
|
|
pIntfContext->hIntf = INVALID_HANDLE_VALUE;
|
|
|
|
// initialize the 802.11 specific fields
|
|
pIntfContext->wzcCurrent.Length = sizeof(WZC_WLAN_CONFIG);
|
|
pIntfContext->wzcCurrent.InfrastructureMode = -1;
|
|
pIntfContext->wzcCurrent.AuthenticationMode = -1;
|
|
pIntfContext->wzcCurrent.Privacy = -1;
|
|
// wzcCurrent is all zero-ed out because of how the allocation was done
|
|
// pwzcVList, pwzcPList, pwzcSList, pwzcBList all default to NULL
|
|
|
|
DbgPrint((TRC_GENERIC,
|
|
"Intf [%d] %S - %S",
|
|
pIntfContext->dwIndex,
|
|
pIntfContext->wszGuid,
|
|
pIntfContext->wszDescr));
|
|
exit:
|
|
// if there was any error hit, clear up all resources allocated so far
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
if (pIntfContext != NULL)
|
|
{
|
|
// this was a brand new context so there should be no timer queued for it
|
|
if (pIntfContext->hTimer != NULL)
|
|
DeleteTimerQueueTimer(g_htmQueue, pIntfContext->hTimer, INVALID_HANDLE_VALUE);
|
|
|
|
MemFree(pIntfContext->wszDescr);
|
|
MemFree(pIntfContext->wszGuid);
|
|
}
|
|
MemFree(pIntfContext);
|
|
}
|
|
else
|
|
{
|
|
// if success, copy out the new context
|
|
*ppIntfContext = pIntfContext;
|
|
}
|
|
|
|
DbgPrint((TRC_TRACK,"LstConstructIntfContext(->0x%p)]=%d", *ppIntfContext, dwErr));
|
|
return dwErr;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Prepares a context for the destruction:
|
|
// - Deletes any attached timer, making sure no other timer routines will be fired.
|
|
// - Removes the context from any hash, making sure no one else will find the context
|
|
// - Decrements the reference counter such that the context will be destroyed when unrefed.
|
|
// This function is called while holding the critical section on the interface.
|
|
DWORD
|
|
LstRemoveIntfContext(
|
|
PINTF_CONTEXT pIntfContext)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
PINTF_CONTEXT pRemovedIntfContext = NULL;
|
|
|
|
DbgPrint((TRC_TRACK,"[LstRemoveIntfContext(0x%p)", pIntfContext));
|
|
|
|
// synchronously delete any timer associated with the context.
|
|
// Since the timer routine is lightweight there is no risk of deadlock
|
|
pIntfContext->dwCtlFlags &= ~INTFCTL_INTERNAL_TM_ON;
|
|
if (pIntfContext->hTimer != INVALID_HANDLE_VALUE)
|
|
{
|
|
HANDLE hTimer = pIntfContext->hTimer;
|
|
pIntfContext->hTimer = INVALID_HANDLE_VALUE;
|
|
DeleteTimerQueueTimer(g_htmQueue, hTimer, INVALID_HANDLE_VALUE);
|
|
}
|
|
|
|
// do the removal by passing down the guid formatted as "{guid}"
|
|
// and expecting back the interface context in pIntfContext
|
|
dwErr = LstRemIntfFromHashes(pIntfContext->wszGuid, &pRemovedIntfContext);
|
|
DbgAssert((pIntfContext == pRemovedIntfContext, "The context removed from hashes doesn't match!"));
|
|
|
|
// decrement the reference counter of the interface. This is what will make the context to be
|
|
// effectively destroyed when the last thread unreference it.
|
|
if (pIntfContext->rccs.nRefCount != 0)
|
|
InterlockedDecrement(&(pIntfContext->rccs.nRefCount));
|
|
|
|
DbgPrint((TRC_TRACK,"LstRemoveIntfContext]=%d", dwErr));
|
|
return dwErr;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Destructs the INTF_CONTEXT clearing all the resources allocated for it
|
|
// This call doesn't remove this context from any hash or list
|
|
DWORD
|
|
LstDestroyIntfContext(PINTF_CONTEXT pIntfContext)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;;
|
|
DbgPrint((TRC_TRACK,"[LstDestroyIntfContext(0x%p)", pIntfContext));
|
|
|
|
if (pIntfContext == NULL)
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
goto exit;
|
|
}
|
|
|
|
// the destroy call is made when it is sure thing the context needs to be
|
|
// deleted (either something wrong happened while loading the context or its
|
|
// ref counter reached 0). There is no point in testing the ref counter again.
|
|
if (pIntfContext->hTimer != INVALID_HANDLE_VALUE)
|
|
DeleteTimerQueueTimer(g_htmQueue, pIntfContext->hTimer, NULL);
|
|
|
|
dwErr = DevioCloseIntfHandle(pIntfContext);
|
|
|
|
MemFree(pIntfContext->wszGuid);
|
|
MemFree(pIntfContext->wszDescr);
|
|
MemFree(pIntfContext->pwzcVList);
|
|
MemFree(pIntfContext->pwzcPList);
|
|
WzcCleanupWzcList(pIntfContext->pwzcSList);
|
|
WzcSSKFree(pIntfContext->pSecSessionKeys);
|
|
WzcCleanupWzcList(pIntfContext->pwzcBList);
|
|
|
|
// since rccs.nRefCount reached 0, this means there is absolutely
|
|
// no other thread referencing this object and that no one will
|
|
// ever be able to reference it again. Getting to 0 means at least
|
|
// one thread explicitly called LstDestroyIntfContext after removed
|
|
// the object from the internal hashes.
|
|
RccsDestroy(&pIntfContext->rccs);
|
|
|
|
// at the end clear the interface context entirely
|
|
MemFree(pIntfContext);
|
|
|
|
exit:
|
|
DbgPrint((TRC_TRACK,"LstDestroyIntfContext]=%d", dwErr));
|
|
return dwErr;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Returns the number of contexts enlisted in the service
|
|
DWORD
|
|
LstNumInterfaces()
|
|
{
|
|
return g_lstIntfHashes.nNumIntfs;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Inserts the given context in all the internal hashes
|
|
// This call assumes the hashes are locked by the caller
|
|
DWORD
|
|
LstAddIntfToHashes(PINTF_CONTEXT pIntf)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
DbgPrint((TRC_TRACK,"[LstAddIntfToHashes(0x%p)", pIntf));
|
|
DbgAssert((pIntf != NULL, "Cannot insert NULL context into hashes!"))
|
|
|
|
// Insert this interface in the GUID hash
|
|
dwErr = HshInsertObjectRef(
|
|
g_lstIntfHashes.pHnGUID,
|
|
pIntf->wszGuid,
|
|
pIntf,
|
|
&g_lstIntfHashes.pHnGUID);
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
// inserting to tail insures an ascending ordered list on dwIndex
|
|
// not that it matters :o)
|
|
InsertTailList(&g_lstIntfHashes.lstIntfs, &(pIntf->Link));
|
|
|
|
// everything went out successfully, so increment the global number
|
|
// of interfaces.
|
|
g_lstIntfHashes.nNumIntfs++;
|
|
}
|
|
|
|
DbgPrint((TRC_TRACK,"LstAddIntfToHashes]=%d", dwErr));
|
|
return dwErr;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Removes the context referenced by GUID from all the internal hashes.
|
|
// The GUID is expected to be in the format "{guid}"
|
|
// Returns in ppIntfContext the object that was removed from all hashes.
|
|
// This call assumes the hashes are locked already
|
|
DWORD
|
|
LstRemIntfFromHashes(LPWSTR wszGuid, PINTF_CONTEXT *ppIntfContext)
|
|
{
|
|
DWORD dwErr;
|
|
PHASH_NODE pNode;
|
|
PINTF_CONTEXT pIntfContext = NULL;
|
|
|
|
DbgPrint((TRC_TRACK,"[LstRemIntfFromHashes(%S)", wszGuid == NULL? L"(null)" : wszGuid));
|
|
DbgAssert((wszGuid != NULL, "Cannot clear NULL GUID from hashes!"));
|
|
DbgAssert((ppIntfContext != NULL, "Invalid in/out parameter"));
|
|
|
|
// get to the hash node
|
|
dwErr = HshQueryObjectRef(
|
|
g_lstIntfHashes.pHnGUID,
|
|
wszGuid,
|
|
&pNode);
|
|
// if there is such a context
|
|
// in the current hash, it needs to go away
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
// remove this node from the Guid hash. We are already in its critical section
|
|
dwErr = HshRemoveObjectRef(
|
|
g_lstIntfHashes.pHnGUID,
|
|
pNode,
|
|
&pIntfContext,
|
|
&g_lstIntfHashes.pHnGUID);
|
|
// this is expected to succeed
|
|
DbgAssert((dwErr == ERROR_SUCCESS,
|
|
"Error %d while removing node 0x%p from GUID hash!!",
|
|
dwErr,
|
|
pNode));
|
|
}
|
|
|
|
// if the context is not in the Guids hash, it is nowhere else
|
|
// so go next only in case of success.
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
PINTF_CONTEXT pIntfContextDup;
|
|
|
|
// remove the context from the linked list
|
|
RemoveEntryList(&pIntfContext->Link);
|
|
// and initialize the pointer.
|
|
InitializeListHead(&pIntfContext->Link);
|
|
// decrement the global interfaces count
|
|
g_lstIntfHashes.nNumIntfs--;
|
|
}
|
|
*ppIntfContext = pIntfContext;
|
|
|
|
DbgPrint((TRC_TRACK,"LstRemIntfFromHashes(->0x%p)]=%d",
|
|
*ppIntfContext,
|
|
dwErr));
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Returns an array of *pdwNumIntfs INTF_KEY_ENTRY elements.
|
|
// The INTF_KEY_ENTRY contains whatever information identifies
|
|
// uniquely an adapter. Currently it includes just the GUID in
|
|
// the format "{guid}"
|
|
DWORD
|
|
LstGetIntfsKeyInfo(PINTF_KEY_ENTRY pIntfs, LPDWORD pdwNumIntfs)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
UINT nIntfIdx;
|
|
PLIST_ENTRY pEntry;
|
|
|
|
DbgPrint((TRC_TRACK,"[LstGetIntfsKeyInfo(0x%p,%d)", pIntfs, *pdwNumIntfs));
|
|
|
|
// lock the hash during enumeration
|
|
EnterCriticalSection(&g_lstIntfHashes.csMutex);
|
|
|
|
for (pEntry = g_lstIntfHashes.lstIntfs.Flink, nIntfIdx = 0;
|
|
pEntry != &g_lstIntfHashes.lstIntfs && nIntfIdx < *pdwNumIntfs;
|
|
pEntry = pEntry->Flink, nIntfIdx++)
|
|
{
|
|
PINTF_CONTEXT pIntfContext;
|
|
|
|
// no need to lock this context since we're already holding the hashes.
|
|
// no one can destroy the interface context now
|
|
pIntfContext = CONTAINING_RECORD(pEntry, INTF_CONTEXT, Link);
|
|
if (pIntfContext->wszGuid != NULL)
|
|
{
|
|
pIntfs[nIntfIdx].wszGuid = RpcCAlloc((wcslen(pIntfContext->wszGuid)+1)*sizeof(WCHAR));
|
|
if (pIntfs[nIntfIdx].wszGuid == NULL)
|
|
{
|
|
dwErr = GetLastError();
|
|
goto exit;
|
|
}
|
|
wcscpy(pIntfs[nIntfIdx].wszGuid, pIntfContext->wszGuid);
|
|
}
|
|
else
|
|
{
|
|
pIntfs[nIntfIdx].wszGuid = NULL;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
// unlock the hash now
|
|
LeaveCriticalSection(&g_lstIntfHashes.csMutex);
|
|
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
UINT i;
|
|
// if an error occured, rollback whatever we already did
|
|
for (i = 0; i<nIntfIdx; i++)
|
|
{
|
|
// nIntfIdx points to the entry that couldn't be allocated
|
|
if (pIntfs[i].wszGuid != NULL)
|
|
{
|
|
RpcFree(pIntfs[i].wszGuid);
|
|
pIntfs[i].wszGuid = NULL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// in case of success, update pdwNumIntfs with the actual
|
|
// number we could retrieve (it can be only less or equal)
|
|
*pdwNumIntfs = nIntfIdx;
|
|
}
|
|
DbgPrint((TRC_TRACK, "LstGetIntfsKeyInfo]=%d", dwErr));
|
|
return dwErr;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Returns requested information on the specified adapter.
|
|
// [in] dwInFlags specifies the information requested. (see
|
|
// bitmasks INTF_*
|
|
// [in] pIntfEntry should contain the GUID of the adapter
|
|
// [out] pIntfEntry contains all the requested information that
|
|
// could be successfully retrieved.
|
|
// [out] pdwOutFlags provides an indication on the info that
|
|
// was successfully retrieved
|
|
DWORD
|
|
LstQueryInterface(
|
|
DWORD dwInFlags,
|
|
PINTF_ENTRY pIntfEntry,
|
|
LPDWORD pdwOutFlags)
|
|
{
|
|
DWORD dwErr = ERROR_FILE_NOT_FOUND;
|
|
|
|
PHASH_NODE pNode = NULL;
|
|
PINTF_CONTEXT pIntfContext;
|
|
DWORD dwOutFlags = 0;
|
|
|
|
DbgPrint((TRC_TRACK, "[LstQueryInterface"));
|
|
|
|
if (g_lstIntfHashes.bValid)
|
|
{
|
|
EnterCriticalSection(&g_lstIntfHashes.csMutex);
|
|
dwErr = HshQueryObjectRef(
|
|
g_lstIntfHashes.pHnGUID,
|
|
pIntfEntry->wszGuid,
|
|
&pNode);
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
pIntfContext = pNode->pObject;
|
|
// bump up the reference counter since we're going
|
|
// to work with this object
|
|
LstRccsReference(pIntfContext);
|
|
}
|
|
LeaveCriticalSection(&g_lstIntfHashes.csMutex);
|
|
}
|
|
else
|
|
dwErr = ERROR_ARENA_TRASHED;
|
|
|
|
// a failure at this point, means there was no context
|
|
// to lock so we can safely go to 'exit'
|
|
if (dwErr != ERROR_SUCCESS)
|
|
goto exit;
|
|
|
|
// Lock the context now
|
|
LstRccsLock(pIntfContext);
|
|
|
|
// we can safely assume any living INTF_CONTEXT will have the correct
|
|
// information for all the NDIS parameters below. So return them
|
|
// unconditionally to the caller
|
|
if ((dwInFlags & INTF_DESCR) &&
|
|
(pIntfContext->wszDescr) != NULL)
|
|
{
|
|
pIntfEntry->wszDescr = RpcCAlloc(sizeof(WCHAR)*(wcslen(pIntfContext->wszDescr)+1));
|
|
if (pIntfEntry->wszDescr != NULL)
|
|
{
|
|
wcscpy(pIntfEntry->wszDescr, pIntfContext->wszDescr);
|
|
dwOutFlags |= INTF_DESCR;
|
|
}
|
|
else
|
|
dwErr = GetLastError();
|
|
}
|
|
if (dwInFlags & INTF_NDISMEDIA)
|
|
{
|
|
pIntfEntry->ulMediaState = pIntfContext->ulMediaState;
|
|
pIntfEntry->ulMediaType = pIntfContext->ulMediaType;
|
|
pIntfEntry->ulPhysicalMediaType = pIntfContext->ulPhysicalMediaType;
|
|
dwOutFlags |= INTF_NDISMEDIA;
|
|
}
|
|
if (dwInFlags & INTF_ALL_FLAGS)
|
|
{
|
|
DWORD dwActualFlags = dwInFlags & INTF_ALL_FLAGS;
|
|
pIntfEntry->dwCtlFlags = pIntfContext->dwCtlFlags & dwActualFlags;
|
|
dwOutFlags |= dwActualFlags;
|
|
}
|
|
// copy out the StSSIDList if requested
|
|
if (dwInFlags & INTF_PREFLIST)
|
|
{
|
|
pIntfEntry->rdStSSIDList.dwDataLen = 0;
|
|
pIntfEntry->rdStSSIDList.pData = NULL;
|
|
// it could happen we don't have any static entry. If so, dwOutFlags
|
|
// needs to be set correctly saying "success"
|
|
if (pIntfContext->pwzcPList != NULL)
|
|
{
|
|
UINT nBytes;
|
|
// see how much memory is needed to store all the static SSIDs
|
|
nBytes = FIELD_OFFSET(WZC_802_11_CONFIG_LIST, Config) +
|
|
pIntfContext->pwzcPList->NumberOfItems * sizeof(WZC_WLAN_CONFIG);
|
|
// allocate buffer large enough for all static SSIDs
|
|
pIntfEntry->rdStSSIDList.pData = RpcCAlloc(nBytes);
|
|
if (pIntfEntry->rdStSSIDList.pData != NULL)
|
|
{
|
|
// set the memory size in this RAW_DATA
|
|
pIntfEntry->rdStSSIDList.dwDataLen = nBytes;
|
|
// copy the whole WZC_802_11_CONFIG_LIST of static SSIDs
|
|
CopyMemory(
|
|
pIntfEntry->rdStSSIDList.pData,
|
|
pIntfContext->pwzcPList,
|
|
nBytes);
|
|
// mark "success"
|
|
dwOutFlags |= INTF_PREFLIST;
|
|
}
|
|
else if (dwErr == ERROR_SUCCESS)
|
|
dwErr = GetLastError();
|
|
}
|
|
else
|
|
{
|
|
// still, if no static SSID defined, this is seen as "success"
|
|
dwOutFlags |= INTF_PREFLIST;
|
|
}
|
|
}
|
|
|
|
// the 802.11 parameters are valid only if the context's state is not {SSr}
|
|
if (pIntfContext->pfnStateHandler != StateSoftResetFn)
|
|
{
|
|
if (dwInFlags & INTF_INFRAMODE)
|
|
{
|
|
pIntfEntry->nInfraMode = pIntfContext->wzcCurrent.InfrastructureMode;
|
|
dwOutFlags |= INTF_INFRAMODE;
|
|
}
|
|
if (dwInFlags & INTF_AUTHMODE)
|
|
{
|
|
pIntfEntry->nAuthMode = pIntfContext->wzcCurrent.AuthenticationMode;
|
|
dwOutFlags |= INTF_AUTHMODE;
|
|
}
|
|
if (dwInFlags & INTF_WEPSTATUS)
|
|
{
|
|
pIntfEntry->nWepStatus = pIntfContext->wzcCurrent.Privacy;
|
|
dwOutFlags |= INTF_WEPSTATUS;
|
|
}
|
|
|
|
// copy out the BSSID if requested
|
|
if (dwInFlags & INTF_BSSID)
|
|
{
|
|
pIntfEntry->rdBSSID.dwDataLen = 0;
|
|
pIntfEntry->rdBSSID.pData = RpcCAlloc(sizeof(NDIS_802_11_MAC_ADDRESS));
|
|
if (pIntfEntry->rdBSSID.pData != NULL)
|
|
{
|
|
pIntfEntry->rdBSSID.dwDataLen = sizeof(NDIS_802_11_MAC_ADDRESS);
|
|
CopyMemory(
|
|
pIntfEntry->rdBSSID.pData,
|
|
&pIntfContext->wzcCurrent.MacAddress,
|
|
pIntfEntry->rdBSSID.dwDataLen);
|
|
dwOutFlags |= INTF_BSSID;
|
|
}
|
|
else if (dwErr == ERROR_SUCCESS)
|
|
dwErr = GetLastError();
|
|
}
|
|
|
|
// copy out the SSID if requested
|
|
if (dwInFlags & INTF_SSID)
|
|
{
|
|
pIntfEntry->rdSSID.dwDataLen = 0;
|
|
pIntfEntry->rdSSID.pData = NULL;
|
|
// normally there should be an SSID so set the dwOutFlags
|
|
// for this field only if it exists
|
|
if (pIntfContext->wzcCurrent.Ssid.SsidLength != 0)
|
|
{
|
|
pIntfEntry->rdSSID.pData = RpcCAlloc(pIntfContext->wzcCurrent.Ssid.SsidLength);
|
|
if (pIntfEntry->rdSSID.pData != NULL)
|
|
{
|
|
pIntfEntry->rdSSID.dwDataLen = pIntfContext->wzcCurrent.Ssid.SsidLength;
|
|
CopyMemory(
|
|
pIntfEntry->rdSSID.pData,
|
|
pIntfContext->wzcCurrent.Ssid.Ssid,
|
|
pIntfContext->wzcCurrent.Ssid.SsidLength);
|
|
dwOutFlags |= INTF_SSID;
|
|
}
|
|
else if (dwErr == ERROR_SUCCESS)
|
|
dwErr = GetLastError();
|
|
}
|
|
}
|
|
|
|
// copy out the BSSIDList if requested
|
|
if (dwInFlags & INTF_BSSIDLIST)
|
|
{
|
|
pIntfEntry->rdBSSIDList.dwDataLen = 0;
|
|
pIntfEntry->rdBSSIDList.pData = NULL;
|
|
// normally there should be a visible list so set the dwOutFlags
|
|
// for this field only if it exists
|
|
if (pIntfContext->pwzcVList != NULL)
|
|
{
|
|
UINT nBytes;
|
|
|
|
// see how much memory is needed to store all the configurations
|
|
nBytes = FIELD_OFFSET(WZC_802_11_CONFIG_LIST, Config) +
|
|
pIntfContext->pwzcVList->NumberOfItems * sizeof(WZC_WLAN_CONFIG);
|
|
// allocate buffer large enough to hold all the configurations
|
|
pIntfEntry->rdBSSIDList.pData = RpcCAlloc(nBytes);
|
|
if (pIntfEntry->rdBSSIDList.pData != NULL)
|
|
{
|
|
// set the memory size in this RAW_DATA
|
|
pIntfEntry->rdBSSIDList.dwDataLen = nBytes;
|
|
// copy the whole WZC_802_11_CONFIG_LIST
|
|
CopyMemory(
|
|
pIntfEntry->rdBSSIDList.pData,
|
|
pIntfContext->pwzcVList,
|
|
nBytes);
|
|
dwOutFlags |= INTF_BSSIDLIST;
|
|
}
|
|
else if (dwErr == ERROR_SUCCESS)
|
|
dwErr = GetLastError();
|
|
}
|
|
}
|
|
}
|
|
// if the context's state is {SSr} and some OIDs are requested, don't fail, but the bits
|
|
// corresponding to the OIDs will all be nulled out. This is the indication of "pending"
|
|
|
|
LstRccsUnlockUnref(pIntfContext);
|
|
|
|
exit:
|
|
if (pdwOutFlags != NULL)
|
|
{
|
|
*pdwOutFlags = dwOutFlags;
|
|
DbgPrint((TRC_GENERIC,"Sending OutFlags = 0x%x", *pdwOutFlags));
|
|
}
|
|
|
|
DbgPrint((TRC_TRACK, "LstQueryInterface]=%d", dwErr));
|
|
return dwErr;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Sets the specified parameters on the specified adapter.
|
|
// [in] dwInFlags specifies the parameters to be set. (see
|
|
// bitmasks INTF_*
|
|
// [in] pIntfEntry should contain the GUID of the adapter and
|
|
// all the additional parameters to be set as specified
|
|
// in dwInFlags
|
|
// [out] pdwOutFlags provides an indication on the params that
|
|
// were successfully set to the adapter
|
|
// Each parameter for which the driver says that was set successfully
|
|
// is copied into the interface's context.
|
|
DWORD
|
|
LstSetInterface(
|
|
DWORD dwInFlags,
|
|
PINTF_ENTRY pIntfEntry,
|
|
LPDWORD pdwOutFlags)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
DWORD dwLErr;
|
|
PHASH_NODE pNode = NULL;
|
|
PINTF_CONTEXT pIntfContext;
|
|
DWORD dwOutFlags = 0;
|
|
|
|
DbgPrint((TRC_TRACK, "[LstSetInterface"));
|
|
|
|
if (pIntfEntry->wszGuid == NULL)
|
|
{
|
|
if (g_wzcInternalCtxt.bValid)
|
|
{
|
|
EnterCriticalSection(&g_wzcInternalCtxt.csContext);
|
|
pIntfContext = g_wzcInternalCtxt.pIntfTemplate;
|
|
LstRccsReference(pIntfContext);
|
|
LeaveCriticalSection(&g_wzcInternalCtxt.csContext);
|
|
}
|
|
else
|
|
dwErr = ERROR_ARENA_TRASHED;
|
|
}
|
|
else
|
|
{
|
|
if (g_lstIntfHashes.bValid)
|
|
{
|
|
EnterCriticalSection(&g_lstIntfHashes.csMutex);
|
|
dwErr = HshQueryObjectRef(
|
|
g_lstIntfHashes.pHnGUID,
|
|
pIntfEntry->wszGuid,
|
|
&pNode);
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
pIntfContext = pNode->pObject;
|
|
LstRccsReference(pIntfContext);
|
|
}
|
|
LeaveCriticalSection(&g_lstIntfHashes.csMutex);
|
|
}
|
|
else
|
|
dwErr = ERROR_ARENA_TRASHED;
|
|
}
|
|
|
|
// a failure at this point, means there was no context
|
|
// to lock so we can safely go to 'exit'
|
|
if (dwErr != ERROR_SUCCESS)
|
|
goto exit;
|
|
|
|
LstRccsLock(pIntfContext);
|
|
|
|
// 1) Set the new public Control flags, if specified
|
|
if (dwInFlags & INTF_ALL_FLAGS)
|
|
{
|
|
DWORD dwActualFlags = dwInFlags & INTF_ALL_FLAGS;
|
|
DWORD dwSupp = (pIntfContext->dwCtlFlags & INTFCTL_OIDSSUPP);
|
|
|
|
pIntfContext->dwCtlFlags &= ~dwActualFlags;
|
|
pIntfContext->dwCtlFlags |= pIntfEntry->dwCtlFlags & dwActualFlags;
|
|
// retain the original INTFCTL_OIDSSUPP bit
|
|
pIntfContext->dwCtlFlags |= dwSupp;
|
|
dwOutFlags |= dwActualFlags;
|
|
}
|
|
|
|
// 2) copy the list of Static SSID (if requested to be set) as below:
|
|
// Allocate the memory needed for the new static SSIDs list (if needed)
|
|
// If successful, copy in the new buffer the new list of static SSIDs, clear up
|
|
// whatever old list we had and put the new one in the interface's context
|
|
if (dwInFlags & INTF_PREFLIST)
|
|
{
|
|
PWZC_802_11_CONFIG_LIST pNewPList;
|
|
|
|
// MemCAlloc handles the case when size is 0 (returns NULL)
|
|
pNewPList = (PWZC_802_11_CONFIG_LIST)MemCAlloc(pIntfEntry->rdStSSIDList.dwDataLen);
|
|
if (pIntfEntry->rdStSSIDList.dwDataLen != 0 && pNewPList == NULL)
|
|
{
|
|
dwLErr = GetLastError();
|
|
}
|
|
else
|
|
{
|
|
// .. copy the data in the new buffer if there is any
|
|
if (pNewPList != NULL)
|
|
{
|
|
CopyMemory(
|
|
pNewPList,
|
|
pIntfEntry->rdStSSIDList.pData,
|
|
pIntfEntry->rdStSSIDList.dwDataLen);
|
|
}
|
|
// set the data in the Interface's context
|
|
MemFree(pIntfContext->pwzcPList);
|
|
pIntfContext->pwzcPList = pNewPList;
|
|
|
|
// if this is not referring to the template object..
|
|
if (pIntfContext->wszGuid != NULL)
|
|
{
|
|
//..let 802.1X know about the change. (don't care about the return value)
|
|
ElWZCCfgChangeHandler(
|
|
pIntfContext->wszGuid,
|
|
pIntfContext->pwzcPList);
|
|
}
|
|
|
|
dwOutFlags |= INTF_PREFLIST;
|
|
dwLErr = ERROR_SUCCESS;
|
|
}
|
|
|
|
if (dwErr == ERROR_SUCCESS)
|
|
dwErr = dwLErr;
|
|
}
|
|
|
|
// if there is anything more to set to this interface
|
|
if (dwInFlags & ~(INTF_PREFLIST|INTF_ALL_FLAGS))
|
|
{
|
|
// and the control flag INTFCTL_ENABLED doesn't allow this
|
|
if (!(pIntfContext->dwCtlFlags & INTFCTL_ENABLED))
|
|
{
|
|
// signal "request refused" error
|
|
dwLErr = ERROR_REQUEST_REFUSED;
|
|
}
|
|
else
|
|
{
|
|
DWORD dwLOutFlags;
|
|
|
|
// else go and set the oids
|
|
dwLErr = DevioSetIntfOIDs(
|
|
pIntfContext,
|
|
pIntfEntry,
|
|
dwInFlags,
|
|
&dwLOutFlags);
|
|
|
|
dwOutFlags |= dwLOutFlags;
|
|
}
|
|
|
|
if (dwErr == ERROR_SUCCESS)
|
|
dwErr = dwLErr;
|
|
}
|
|
|
|
// log the user preference
|
|
DbLogWzcInfo(WZCSVC_USR_CFGCHANGE, pIntfContext);
|
|
|
|
// act on the changes..
|
|
dwLErr = LstActOnChanges(dwOutFlags, pIntfContext);
|
|
if (dwErr == ERROR_SUCCESS)
|
|
dwErr = dwLErr;
|
|
|
|
LstRccsUnlockUnref(pIntfContext);
|
|
|
|
exit:
|
|
if (pdwOutFlags != NULL)
|
|
*pdwOutFlags = dwOutFlags;
|
|
|
|
DbgPrint((TRC_TRACK, "LstSetInterface]=%d", dwErr));
|
|
return dwErr;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Checks whether interface changes should cause the interface to be
|
|
// reinserted in the state machine and it does so if needed.
|
|
// [in] dwChangedFlags indicates what the changes are. (see
|
|
// bitmasks INTF_*)
|
|
// [in] pIntfContext context of the interface being changed.
|
|
DWORD
|
|
LstActOnChanges(
|
|
DWORD dwChangedFlags,
|
|
PINTF_CONTEXT pIntfContext)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
DWORD dwLFlags = INTF_LIST_SCAN;
|
|
BOOL bAltered = FALSE;
|
|
|
|
DbgPrint((TRC_TRACK, "[LstActOnChanges(0x08x, %p)", dwChangedFlags, pIntfContext));
|
|
|
|
// if the changes involve the list of preferred networks or the control flags
|
|
// then we should act on these changes..
|
|
if (dwChangedFlags & (INTF_PREFLIST|INTF_ALL_FLAGS))
|
|
{
|
|
// if this is not the interface template object then just reset this interface
|
|
if (pIntfContext->wszGuid != NULL)
|
|
{
|
|
// some interface changed, apply the template again on top of it
|
|
if (g_wzcInternalCtxt.bValid)
|
|
{
|
|
PINTF_CONTEXT pIntfTContext;
|
|
EnterCriticalSection(&g_wzcInternalCtxt.csContext);
|
|
pIntfTContext = g_wzcInternalCtxt.pIntfTemplate;
|
|
LstRccsReference(pIntfTContext);
|
|
LeaveCriticalSection(&g_wzcInternalCtxt.csContext);
|
|
|
|
LstRccsLock(pIntfTContext);
|
|
dwErr = LstApplyTemplate(
|
|
pIntfTContext,
|
|
pIntfContext,
|
|
&bAltered);
|
|
LstRccsUnlockUnref(pIntfTContext);
|
|
}
|
|
|
|
// if any of the control flags or the static list changed,
|
|
// these settings should go into the registry now
|
|
StoSaveIntfConfig(NULL, pIntfContext);
|
|
|
|
// since we're resetting the state machine, turn back on the "signal" flag
|
|
pIntfContext->dwCtlFlags |= INTFCTL_INTERNAL_SIGNAL;
|
|
|
|
dwErr = StateDispatchEvent(
|
|
eEventCmdRefresh,
|
|
pIntfContext,
|
|
&dwLFlags);
|
|
|
|
// clear up the INTFCTL_INTERNAL_BLK_MEDIACONN bit since this is not a media sense handler
|
|
pIntfContext->dwCtlFlags &= ~INTFCTL_INTERNAL_BLK_MEDIACONN;
|
|
}
|
|
// if this is the interface template, then...
|
|
else
|
|
{
|
|
PLIST_ENTRY pEntry;
|
|
|
|
// since the template changed, save it to the registry here
|
|
dwErr = StoSaveIntfConfig(NULL, pIntfContext);
|
|
DbgAssert((dwErr == ERROR_SUCCESS,
|
|
"Error %d while storing the template to registry"));
|
|
|
|
// iterate through all the interfaces, apply the changes from the interface template
|
|
// and reset each of them
|
|
EnterCriticalSection(&g_lstIntfHashes.csMutex);
|
|
|
|
for (pEntry = g_lstIntfHashes.lstIntfs.Flink;
|
|
pEntry != &g_lstIntfHashes.lstIntfs;
|
|
pEntry = pEntry->Flink)
|
|
{
|
|
PINTF_CONTEXT pIntfLContext = CONTAINING_RECORD(pEntry, INTF_CONTEXT, Link);
|
|
LstRccsReference(pIntfLContext);
|
|
LstRccsLock(pIntfLContext);
|
|
|
|
// Merge the template settings into the interface's context
|
|
dwErr = LstApplyTemplate(
|
|
pIntfContext,
|
|
pIntfLContext,
|
|
NULL);
|
|
DbgAssert((dwErr == ERROR_SUCCESS,
|
|
"Error %d while applying template to interface %S",
|
|
dwErr, pIntfLContext->wszGuid));
|
|
|
|
// if any of the control flags or the static list changed,
|
|
// these settings should go into the registry now
|
|
StoSaveIntfConfig(NULL, pIntfLContext);
|
|
|
|
// since we're resetting the state machine, turn back on the "signal" flag
|
|
pIntfLContext->dwCtlFlags |= INTFCTL_INTERNAL_SIGNAL;
|
|
|
|
dwErr = StateDispatchEvent(
|
|
eEventCmdRefresh,
|
|
pIntfLContext,
|
|
&dwLFlags);
|
|
DbgAssert((dwErr == ERROR_SUCCESS,
|
|
"Error %d while resetting interface %S",
|
|
dwErr, pIntfLContext->wszGuid));
|
|
|
|
// clear up the INTFCTL_INTERNAL_BLK_MEDIACONN bit since this is not a media sense handler
|
|
pIntfLContext->dwCtlFlags &= ~INTFCTL_INTERNAL_BLK_MEDIACONN;
|
|
|
|
LstRccsUnlockUnref(pIntfLContext);
|
|
}
|
|
|
|
LeaveCriticalSection(&g_lstIntfHashes.csMutex);
|
|
}
|
|
}
|
|
|
|
if (dwErr == ERROR_SUCCESS && bAltered)
|
|
dwErr = ERROR_PARTIAL_COPY;
|
|
|
|
DbgPrint((TRC_TRACK, "LstActOnChanges]=%d", dwErr));
|
|
return dwErr;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Applies settings from the template context to the given interface context
|
|
// [in] dwChanges: flags indicating settings that should be applied.
|
|
// [in] pIntfTemplate: Interface template to pick settings from
|
|
// [in] pIntfContext: Interface context to apply template to.
|
|
DWORD
|
|
LstApplyTemplate(
|
|
PINTF_CONTEXT pIntfTemplate,
|
|
PINTF_CONTEXT pIntfContext,
|
|
LPBOOL pbAltered)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
PWZC_802_11_CONFIG_LIST pwzcTList = pIntfTemplate->pwzcPList;
|
|
PWZC_802_11_CONFIG_LIST pwzcPList = pIntfContext->pwzcPList;
|
|
PWZC_802_11_CONFIG_LIST pwzcRList = NULL; // resulting list
|
|
ENUM_SELCATEG iCtg;
|
|
UINT i, n, nCnt[7] = {0};
|
|
BOOL bAltered = FALSE;
|
|
PWZC_WLAN_CONFIG pTHInfra = NULL, pTHAdhoc = NULL; // head of Infra/Adhoc groups in the template list
|
|
PWZC_WLAN_CONFIG pPHInfra = NULL, pPHAdhoc = NULL; // head of Infra/Adhoc groups in the preferred list
|
|
PWZC_WLAN_CONFIG pOneTime = NULL; // pointer to the "one time configuration" if any
|
|
|
|
DbgPrint((TRC_TRACK,"[LstApplyTemplate(%p->%p)", pIntfTemplate, pIntfContext));
|
|
|
|
// apply the flags, if there are any provided
|
|
if (pIntfTemplate->dwCtlFlags & INTF_POLICY)
|
|
{
|
|
DWORD dwPFlags = (pIntfContext->dwCtlFlags & INTF_ALL_FLAGS) & ~(INTF_OIDSSUPP);
|
|
DWORD dwTFlags = (pIntfTemplate->dwCtlFlags & INTF_ALL_FLAGS) & ~(INTF_OIDSSUPP);
|
|
|
|
if (dwPFlags != dwTFlags)
|
|
{
|
|
// if the policy flags are different from the interface's flags then
|
|
// copy over just the "user" flag but don't overwrite the OIDSSUPP bit.
|
|
dwPFlags = (pIntfContext->dwCtlFlags & ~INTF_ALL_FLAGS) |
|
|
(pIntfTemplate->dwCtlFlags & INTF_ALL_FLAGS);
|
|
if (pIntfContext->dwCtlFlags & INTF_OIDSSUPP)
|
|
dwPFlags |= INTF_OIDSSUPP;
|
|
else
|
|
dwPFlags &= ~INTF_OIDSSUPP;
|
|
pIntfContext->dwCtlFlags = dwPFlags;
|
|
|
|
bAltered = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// currently policy could come only through the template. Consequently,
|
|
// if the template is not policy, local setting should not be policy either.
|
|
// Also, whatever the policy plumbs last, should be persisted.
|
|
pIntfContext->dwCtlFlags &= ~(INTF_POLICY|INTF_VOLATILE);
|
|
}
|
|
|
|
// check the interface's list of preferred networks
|
|
if (pwzcPList != NULL)
|
|
{
|
|
for (i = 0; i < pwzcPList->NumberOfItems; i++)
|
|
{
|
|
PWZC_WLAN_CONFIG pPConfig = &(pwzcPList->Config[i]);
|
|
|
|
// keep a pointer to the "one time config" if there is one.
|
|
if (i == pwzcPList->Index)
|
|
pOneTime = pPConfig;
|
|
|
|
// tag each entry in the preferred list with its respective category
|
|
if (pPConfig->InfrastructureMode == Ndis802_11Infrastructure)
|
|
{
|
|
if (pPHInfra == NULL)
|
|
pPHInfra = pPConfig;
|
|
iCtg = ePI;
|
|
}
|
|
else if (pPConfig->InfrastructureMode == Ndis802_11IBSS)
|
|
{
|
|
if (pPHAdhoc == NULL)
|
|
pPHAdhoc = pPConfig;
|
|
iCtg = ePA;
|
|
}
|
|
else
|
|
iCtg = eN;
|
|
|
|
// regardless the above logic, exclude this configuration from the result list in
|
|
// either of the two cases:
|
|
// - the config is marked "shadow": that is, it is irrelevant without a matching template
|
|
// configuration.
|
|
// - the config is marked "volatile": that is, it has to go away unless the template is saying
|
|
// otherwise.
|
|
// This test needs to be done here and not earlier, because we do need pPHInfra and pPHAdhoc
|
|
// to be set up correctly, taking into account all the configurations.
|
|
if (pPConfig->dwCtlFlags & (WZCCTL_INTERNAL_SHADOW|WZCCTL_VOLATILE))
|
|
iCtg = eN;
|
|
|
|
NWB_SET_SELCATEG(pPConfig, iCtg);
|
|
nCnt[iCtg]++;
|
|
}
|
|
}
|
|
|
|
// check the list of networks enforced by the template
|
|
if (pwzcTList != NULL)
|
|
{
|
|
for (i = 0; i < pwzcTList->NumberOfItems; i++)
|
|
{
|
|
PWZC_WLAN_CONFIG pTConfig = &(pwzcTList->Config[i]);
|
|
PWZC_WLAN_CONFIG pPConfig;
|
|
|
|
if (pTConfig->InfrastructureMode == Ndis802_11Infrastructure)
|
|
{
|
|
if (pTHInfra == NULL)
|
|
pTHInfra = pTConfig;
|
|
iCtg = eVPI;
|
|
}
|
|
else if (pTConfig->InfrastructureMode == Ndis802_11IBSS)
|
|
{
|
|
if (pTHAdhoc == NULL)
|
|
pTHAdhoc = pTConfig;
|
|
iCtg = eVPA;
|
|
}
|
|
else
|
|
{
|
|
iCtg = eN;
|
|
continue;
|
|
}
|
|
|
|
pPConfig = WzcFindConfig(pwzcPList, pTConfig, 0);
|
|
|
|
// if there is an equivalent preference for the given template...
|
|
if (pPConfig != NULL)
|
|
{
|
|
// if the template is policy, it should stomp over the preference
|
|
if (pTConfig->dwCtlFlags & WZCCTL_POLICY)
|
|
{
|
|
BOOL bWepOnlyDiff;
|
|
// if the configurations contents don't match ...
|
|
if (!WzcMatchConfig(pTConfig, pPConfig, &bWepOnlyDiff))
|
|
{
|
|
// even if the configs don't match, we need to pick up the
|
|
// WEP key from the one provided by the user and mark the template
|
|
// configuration as "shadow"-ed.
|
|
pTConfig->KeyIndex = pPConfig->KeyIndex;
|
|
pTConfig->KeyLength = pPConfig->KeyLength;
|
|
// the key length has already been checked!
|
|
DbgAssert((pTConfig->KeyLength <= WZCCTL_MAX_WEPK_MATERIAL, "WEP Key too large!!!"));
|
|
memcpy(pTConfig->KeyMaterial, pPConfig->KeyMaterial, pTConfig->KeyLength);
|
|
pTConfig->dwCtlFlags |= WZCCTL_INTERNAL_SHADOW;
|
|
|
|
// signal the user illegally attempted to alter the policy if these
|
|
// changes include more than just the WEP key.
|
|
if (!bWepOnlyDiff)
|
|
bAltered = TRUE;
|
|
}
|
|
// if the configurations do match check the order.
|
|
else
|
|
{
|
|
// if the offsets of the template & preferred in their respective
|
|
// groups are different, then it means the policy configuration have
|
|
// been reordered - not allowed, hence set the "Altered" bit.
|
|
if ((pTConfig->InfrastructureMode == Ndis802_11Infrastructure &&
|
|
(pTConfig - pTHInfra) != (pPConfig - pPHInfra)
|
|
) ||
|
|
(pTConfig->InfrastructureMode == Ndis802_11IBSS &&
|
|
(pTConfig - pTHAdhoc) != (pPConfig - pPHAdhoc)
|
|
)
|
|
)
|
|
{
|
|
bAltered = TRUE;
|
|
}
|
|
}
|
|
|
|
// also, if the policy is substituting the "one time config",
|
|
// make the "one time config" to become the policy config.
|
|
if (pOneTime == pPConfig)
|
|
pOneTime = pTConfig;
|
|
|
|
// push the template
|
|
NWB_SET_SELCATEG(pTConfig, iCtg);
|
|
nCnt[iCtg]++;
|
|
// and take out the conflicting preference
|
|
iCtg = NWB_GET_SELCATEG(pPConfig);
|
|
nCnt[iCtg]--;
|
|
NWB_SET_SELCATEG(pPConfig, eN);
|
|
nCnt[eN]++;
|
|
}
|
|
// this non-policy template and already has an equivalent preference.
|
|
// take it out then
|
|
else
|
|
{
|
|
iCtg = eN;
|
|
NWB_SET_SELCATEG(pTConfig, iCtg);
|
|
nCnt[iCtg]++;
|
|
}
|
|
}
|
|
// there is no equivalent preference for the given template...
|
|
else
|
|
{
|
|
// we don't have any preference for this template, so the template
|
|
// is just pumped into the preference list.
|
|
|
|
// if the template is a policy, it means the user deleted it and
|
|
// he shouldn't have done so. Set the "Altered" bit then.
|
|
if (pTConfig->dwCtlFlags & WZCCTL_POLICY)
|
|
bAltered = TRUE;
|
|
|
|
// just push the template no matter what.
|
|
NWB_SET_SELCATEG(pTConfig, iCtg);
|
|
nCnt[iCtg]++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// calculate the number of entries in the resulting list
|
|
n = 0;
|
|
for (iCtg=eVPI; iCtg < eN; iCtg++)
|
|
n += nCnt[iCtg];
|
|
|
|
// if there is not a single entry in the resulting list,
|
|
// get out now. pwzcRList is already NULL.
|
|
if (n == 0)
|
|
goto exit;
|
|
|
|
// ..allocate the new preferred list
|
|
pwzcRList = (PWZC_802_11_CONFIG_LIST)
|
|
MemCAlloc(FIELD_OFFSET(WZC_802_11_CONFIG_LIST, Config) + n * sizeof(WZC_WLAN_CONFIG));
|
|
if (pwzcRList == NULL)
|
|
{
|
|
dwErr = GetLastError();
|
|
goto exit;
|
|
}
|
|
// list is successfully allocated
|
|
pwzcRList->NumberOfItems = n;
|
|
pwzcRList->Index = n;
|
|
|
|
// now change the semantic of all counters to mean "indices in the selection list"
|
|
// for their respective group of entries
|
|
for (iCtg = eN-1; iCtg >= eVPI; iCtg--)
|
|
{
|
|
n -= nCnt[iCtg];
|
|
nCnt[iCtg] = n;
|
|
}
|
|
|
|
// copy over in the new list the entries enforced by the template
|
|
if (pwzcTList != NULL)
|
|
{
|
|
for (i = 0; i < pwzcTList->NumberOfItems; i++)
|
|
{
|
|
PWZC_WLAN_CONFIG pTConfig = &(pwzcTList->Config[i]);
|
|
|
|
iCtg = NWB_GET_SELCATEG(pTConfig);
|
|
if (iCtg != eN)
|
|
{
|
|
PWZC_WLAN_CONFIG pRConfig = &(pwzcRList->Config[nCnt[iCtg]]);
|
|
// copy the whole template configuration to the result list
|
|
memcpy(pRConfig, pTConfig, sizeof(WZC_WLAN_CONFIG));
|
|
// just for making sure, reset the 'deleted' flag as this is a brand new
|
|
// config that was never attempted.
|
|
pRConfig->dwCtlFlags &= ~WZCCTL_INTERNAL_DELETED;
|
|
|
|
// if the template configuration is marked as being shadowed..
|
|
if (pTConfig->dwCtlFlags & WZCCTL_INTERNAL_SHADOW)
|
|
{
|
|
// ..set it to the preferred configuration also..
|
|
pRConfig->dwCtlFlags |= WZCCTL_INTERNAL_SHADOW;
|
|
// ..and make sure the preferred configuration gets persisted
|
|
// since it contains user information..
|
|
pRConfig->dwCtlFlags &= ~WZCCTL_VOLATILE;
|
|
// leave the template configuration with the bit "shadow" since
|
|
// it has been altered. This way, if the template is subsequently
|
|
// "applied" the user config won't get the "volatile" bit set back
|
|
// and it will still be marked "shadow".
|
|
}
|
|
|
|
// if this is the "one time" config, adjust the Index to point to this entry's index
|
|
if (pOneTime == pTConfig)
|
|
pwzcRList->Index = nCnt[iCtg];
|
|
|
|
nCnt[iCtg]++;
|
|
}
|
|
// reset the selection category we have used for this resulting entry
|
|
NWB_SET_SELCATEG(pTConfig, 0);
|
|
}
|
|
}
|
|
|
|
// copy over in the new list the entries from the original list
|
|
if (pwzcPList != NULL)
|
|
{
|
|
for (i = 0; i < pwzcPList->NumberOfItems; i++)
|
|
{
|
|
PWZC_WLAN_CONFIG pPConfig = &(pwzcPList->Config[i]);
|
|
|
|
iCtg = NWB_GET_SELCATEG(pPConfig);
|
|
if (iCtg != eN)
|
|
{
|
|
PWZC_WLAN_CONFIG pRConfig = &(pwzcRList->Config[nCnt[iCtg]]);
|
|
// copy the whole preferred configuration to the result list
|
|
memcpy(pRConfig, pPConfig, sizeof(WZC_WLAN_CONFIG));
|
|
// just for making sure, reset the 'deleted' flag as this is a brand new
|
|
// config that was never attempted.
|
|
pRConfig->dwCtlFlags &= ~WZCCTL_INTERNAL_DELETED;
|
|
|
|
// if this is the "one time" config, adjust the Index to point to this entry's index
|
|
if (pOneTime == pPConfig)
|
|
pwzcRList->Index = nCnt[iCtg];
|
|
|
|
nCnt[iCtg]++;
|
|
}
|
|
// reset the selection category we have used for this preferred entry
|
|
NWB_SET_SELCATEG(pPConfig, 0);
|
|
}
|
|
}
|
|
|
|
exit:
|
|
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
// cleanup the original list and put in the new one
|
|
WzcCleanupWzcList(pIntfContext->pwzcPList);
|
|
pIntfContext->pwzcPList = pwzcRList;
|
|
}
|
|
|
|
if (pbAltered != NULL)
|
|
*pbAltered = bAltered;
|
|
|
|
DbgPrint((TRC_TRACK,"LstApplyTemplate]=%d", dwErr));
|
|
return dwErr;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Refreshes the specified parameters on the specified adapter.
|
|
// [in] dwInFlags specifies the parameters to be set. (see
|
|
// bitmasks INTF_* and INTF_RFSH_*)
|
|
// [in] pIntfEntry should contain the GUID of the adapter
|
|
// [out] pdwOutFlags provides an indication on the params that
|
|
// were successfully refreshed to the adapter
|
|
// Each parameter for which the driver says that was refreshed
|
|
// successfully is copied into the interface's context.
|
|
DWORD
|
|
LstRefreshInterface(
|
|
DWORD dwInFlags,
|
|
PINTF_ENTRY pIntfEntry,
|
|
LPDWORD pdwOutFlags)
|
|
{
|
|
DWORD dwErr, dwLErr;
|
|
PHASH_NODE pNode = NULL;
|
|
DWORD dwOutFlags = 0;
|
|
PINTF_CONTEXT pIntfContext;
|
|
|
|
DbgPrint((TRC_TRACK, "[LstRefreshInterface"));
|
|
|
|
if (g_lstIntfHashes.bValid)
|
|
{
|
|
EnterCriticalSection(&g_lstIntfHashes.csMutex);
|
|
dwErr = HshQueryObjectRef(
|
|
g_lstIntfHashes.pHnGUID,
|
|
pIntfEntry->wszGuid,
|
|
&pNode);
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
pIntfContext = pNode->pObject;
|
|
LstRccsReference(pIntfContext);
|
|
}
|
|
LeaveCriticalSection(&g_lstIntfHashes.csMutex);
|
|
}
|
|
else
|
|
dwErr = ERROR_ARENA_TRASHED;
|
|
|
|
// the interface needs to exist in order to refresh it
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
LstRccsLock(pIntfContext);
|
|
|
|
// if description is requested to be refreshed, do it now
|
|
if (dwInFlags & INTF_DESCR)
|
|
{
|
|
CHAR QueryBuffer[QUERY_BUFFER_SIZE];
|
|
PNDISUIO_QUERY_BINDING pBinding;
|
|
RAW_DATA rdBuffer;
|
|
|
|
// get first the binding structure for this interface
|
|
rdBuffer.dwDataLen = sizeof(QueryBuffer);
|
|
rdBuffer.pData = QueryBuffer;
|
|
pBinding = (PNDISUIO_QUERY_BINDING)rdBuffer.pData;
|
|
|
|
dwLErr = DevioGetInterfaceBindingByGuid(
|
|
INVALID_HANDLE_VALUE, // the call will open Ndisuio locally
|
|
pIntfContext->wszGuid, // interface GUID as "{guid}"
|
|
&rdBuffer);
|
|
// regardless of success, lets clean the current description
|
|
MemFree(pIntfContext->wszDescr);
|
|
pIntfContext->wszDescr = NULL;
|
|
|
|
// if everything went fine
|
|
if (dwLErr == ERROR_SUCCESS)
|
|
{
|
|
LPWSTR wszName;
|
|
DWORD dwNameLen;
|
|
|
|
// Copy the interface's description.name
|
|
wszName = (LPWSTR)((LPBYTE)pBinding + pBinding->DeviceDescrOffset);
|
|
// the DeviceDescrLength is in bytes and includes the null terminator
|
|
dwNameLen = pBinding->DeviceDescrLength;
|
|
if (dwNameLen > 0)
|
|
{
|
|
pIntfContext->wszDescr = MemCAlloc(dwNameLen);
|
|
if (pIntfContext->wszGuid == NULL)
|
|
dwErr = GetLastError();
|
|
else
|
|
wcscpy(pIntfContext->wszDescr, wszName);
|
|
}
|
|
}
|
|
// if all went fine, mark it out
|
|
if (dwLErr == ERROR_SUCCESS)
|
|
dwOutFlags |= INTF_DESCR;
|
|
|
|
if (dwErr == ERROR_SUCCESS)
|
|
dwErr = dwLErr;
|
|
}
|
|
|
|
// refresh any ndis settings if requested
|
|
if (dwInFlags & INTF_NDISMEDIA)
|
|
{
|
|
dwLErr = DevioGetIntfStats(pIntfContext);
|
|
if (dwLErr == ERROR_SUCCESS)
|
|
dwOutFlags |= INTF_NDISMEDIA;
|
|
|
|
if (dwErr == ERROR_SUCCESS)
|
|
dwErr = dwLErr;
|
|
}
|
|
|
|
if (dwInFlags & INTF_ALL_OIDS)
|
|
{
|
|
DWORD dwLFlags = dwInFlags;
|
|
|
|
// feed the state machine with the "refresh command" for this context
|
|
dwLErr = StateDispatchEvent(eEventCmdRefresh, pIntfContext, &dwLFlags);
|
|
|
|
// clear up the INTFCTL_INTERNAL_BLK_MEDIACONN bit since this is not a media sense handler
|
|
pIntfContext->dwCtlFlags &= ~INTFCTL_INTERNAL_BLK_MEDIACONN;
|
|
|
|
if (dwLErr == ERROR_SUCCESS)
|
|
dwOutFlags |= dwLFlags;
|
|
if (dwErr == ERROR_SUCCESS)
|
|
dwErr = dwLErr;
|
|
}
|
|
|
|
LstRccsUnlockUnref(pIntfContext);
|
|
}
|
|
|
|
if (pdwOutFlags != NULL)
|
|
*pdwOutFlags = dwOutFlags;
|
|
|
|
DbgPrint((TRC_TRACK, "LstRefreshInterface]=%d", dwErr));
|
|
return dwErr;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Builds the list of configurations to be tried from the list of visible
|
|
// configurations, the list of preferred configurations and based on the
|
|
// interface's mode (Auto/Infra/Adhoc) and flags (is the service enabled?,
|
|
// fallback to visible?).
|
|
// [in] pIntfContext: Interface for which is done the selection
|
|
// [out] ppwzcSList: pointer to the list of selected configurations
|
|
//-----------------------------------------------------------
|
|
// Builds the list of configurations to be tried from the list of visible
|
|
// configurations, the list of preferred configurations and based on the
|
|
// interface's mode (Auto/Infra/Adhoc) and flags (is the service enabled?,
|
|
// fallback to visible?).
|
|
// [in] pIntfContext: Interface for which is done the selection
|
|
// [out] ppwzcSList: pointer to the list of selected configurations
|
|
DWORD
|
|
LstBuildSelectList(
|
|
PINTF_CONTEXT pIntfContext,
|
|
PWZC_802_11_CONFIG_LIST *ppwzcSList)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
UINT i, n;
|
|
UINT nCnt[7] = {0};
|
|
ENUM_SELCATEG iVCtg, iPCtg, iCtg;
|
|
PWZC_WLAN_CONFIG pCrtSConfig = NULL;
|
|
|
|
DbgPrint((TRC_TRACK,"[LstBuildSelectList(0x%p)", pIntfContext));
|
|
DbgAssert((pIntfContext != NULL, "(null) Interface context in LstBuildSelectList"));
|
|
DbgAssert((ppwzcSList != NULL, "invalid (null) out param"));
|
|
|
|
// set the pointer to the selection list to NULL
|
|
(*ppwzcSList) = NULL;
|
|
|
|
// for each entry in the visible list (if any), if the entry is probable to be included
|
|
// in the selection set (either as Visible Infra or Visible Adhoc) set the category
|
|
// attribute to point to the corresponding set and ++ the corresponding counter.
|
|
// if the entry is not going to be included, set the same byte to eN (neutral)
|
|
if (pIntfContext->pwzcVList)
|
|
{
|
|
for (i=0; i < pIntfContext->pwzcVList->NumberOfItems; i++)
|
|
{
|
|
PWZC_WLAN_CONFIG pVConfig = &(pIntfContext->pwzcVList->Config[i]);
|
|
// the visible list might contain several APs for the same network.
|
|
// Make sure we exclude the duplicates from the selection list.
|
|
PWZC_WLAN_CONFIG pVDup = WzcFindConfig(pIntfContext->pwzcVList, pVConfig, i+1);
|
|
|
|
// don't even consider this visible network if:
|
|
// - another duplicate exists further in the list, or
|
|
// - "automatically connect to non-preferred network" is not selected or
|
|
// - its network type (infra / ad hoc) doesn't match the type selected in the intf config or
|
|
// - the entry is blocked in the "blocked configurations" list (pwzcBList)
|
|
if ((pVDup != NULL) ||
|
|
!(pIntfContext->dwCtlFlags & INTFCTL_FALLBACK) ||
|
|
(((pIntfContext->dwCtlFlags & INTFCTL_CM_MASK) != Ndis802_11AutoUnknown) &&
|
|
((pIntfContext->dwCtlFlags & INTFCTL_CM_MASK) != pVConfig->InfrastructureMode)) ||
|
|
WzcFindConfig(pIntfContext->pwzcBList, pVConfig, 0) != NULL)
|
|
iVCtg = eN;
|
|
else if (pVConfig->InfrastructureMode == Ndis802_11Infrastructure)
|
|
iVCtg = eVI;
|
|
else if (pVConfig->InfrastructureMode == Ndis802_11IBSS)
|
|
iVCtg = eVA;
|
|
else
|
|
iVCtg = eN;
|
|
|
|
NWB_SET_SELCATEG(pVConfig, iVCtg);
|
|
nCnt[iVCtg]++;
|
|
}
|
|
}
|
|
|
|
// Locate the current successful configuration (if any) in the preferred list. This config
|
|
// should be marked Visible, regardless it is or not present in the visible list.
|
|
if (pIntfContext->pwzcSList != NULL &&
|
|
pIntfContext->pwzcSList->Index < pIntfContext->pwzcSList->NumberOfItems)
|
|
{
|
|
PWZC_WLAN_CONFIG pCrtConfig;
|
|
|
|
pCrtConfig = &(pIntfContext->pwzcSList->Config[pIntfContext->pwzcSList->Index]);
|
|
|
|
if (!(pCrtConfig->dwCtlFlags & WZCCTL_INTERNAL_DELETED))
|
|
pCrtSConfig = WzcFindConfig(pIntfContext->pwzcPList, pCrtConfig, 0);
|
|
}
|
|
|
|
// for each entry in the preferred list (if any), if the entry matches the interface's mode
|
|
// and is a "visible" one, put it in either eVPI or eVPA category and pull out the corresponding
|
|
// visible entry from eVI or eVA or eN (if that entry was not supposed to be included in the selection).
|
|
// If the entry is not "visible" put it either in ePI (only if the interface doesn't fallback to
|
|
// visible) or in ePA category.
|
|
if (pIntfContext->pwzcPList != NULL)
|
|
{
|
|
for (i=0; i < pIntfContext->pwzcPList->NumberOfItems; i++)
|
|
{
|
|
PWZC_WLAN_CONFIG pPConfig = &(pIntfContext->pwzcPList->Config[i]);
|
|
|
|
// don't even consider this preferred network if:
|
|
// - its network type (infra / ad hoc) doesn't match the type selected in the intf config or
|
|
// - the entry is blocked in the "blocked configurations" list (pwzcBList)
|
|
if ((((pIntfContext->dwCtlFlags & INTFCTL_CM_MASK) != Ndis802_11AutoUnknown) &&
|
|
((pIntfContext->dwCtlFlags & INTFCTL_CM_MASK) != pPConfig->InfrastructureMode)) ||
|
|
WzcFindConfig(pIntfContext->pwzcBList, pPConfig, 0) != NULL)
|
|
{
|
|
iPCtg = eN;
|
|
}
|
|
else
|
|
{
|
|
PWZC_WLAN_CONFIG pVConfig = WzcFindConfig(pIntfContext->pwzcVList, pPConfig, 0);
|
|
|
|
if (pPConfig == pCrtSConfig || pVConfig != NULL)
|
|
{
|
|
// this preferred entry is either the current one or visible,
|
|
// so point it either to eVPI or eVPA
|
|
if (pPConfig->InfrastructureMode == Ndis802_11Infrastructure)
|
|
iPCtg = eVPI;
|
|
else if (pPConfig->InfrastructureMode == Ndis802_11IBSS)
|
|
iPCtg = eVPA;
|
|
else
|
|
iPCtg = eN;
|
|
|
|
if (pVConfig != NULL)
|
|
{
|
|
// the corresponding visible entry (if any) has to be pulled out from whichever
|
|
// category it was in and has to be put in eN (neutral)
|
|
nCnt[NWB_GET_SELCATEG(pVConfig)]--;
|
|
iVCtg = eN;
|
|
NWB_SET_SELCATEG(pVConfig, iVCtg);
|
|
nCnt[iVCtg]++;
|
|
}
|
|
else
|
|
{
|
|
DbgPrint((TRC_TRACK, "Non-visible crt config raised to visible categ %d.", iPCtg));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// this preferred entry is not visible, so either point it to ePI or to ePA.
|
|
if (pPConfig->InfrastructureMode == Ndis802_11Infrastructure)
|
|
iPCtg = ePI;
|
|
else if (pPConfig->InfrastructureMode == Ndis802_11IBSS)
|
|
iPCtg = ePA;
|
|
else
|
|
iPCtg = eN;
|
|
}
|
|
}
|
|
NWB_SET_SELCATEG(pPConfig, iPCtg);
|
|
nCnt[iPCtg]++;
|
|
}
|
|
}
|
|
|
|
// calculate the number of entries in the selection list
|
|
n = 0;
|
|
for (iCtg=eVPI; iCtg < eN; iCtg++)
|
|
n += nCnt[iCtg];
|
|
|
|
// if there are any entries to copy afterall..
|
|
if (n != 0)
|
|
{
|
|
// ..allocate the selection list
|
|
(*ppwzcSList) = (PWZC_802_11_CONFIG_LIST)
|
|
MemCAlloc(FIELD_OFFSET(WZC_802_11_CONFIG_LIST, Config) + n * sizeof(WZC_WLAN_CONFIG));
|
|
if ((*ppwzcSList) == NULL)
|
|
{
|
|
dwErr = GetLastError();
|
|
goto exit;
|
|
}
|
|
(*ppwzcSList)->NumberOfItems = n;
|
|
(*ppwzcSList)->Index = n;
|
|
|
|
// now change the semantic of all counters to mean "indices in the selection list"
|
|
// for their respective group of entries
|
|
for (iCtg = eN-1; iCtg >= eVPI; iCtg--)
|
|
{
|
|
n -= nCnt[iCtg];
|
|
nCnt[iCtg] = n;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
// copy first the entries from the preferred list into the selection list,
|
|
// at the index corresponding to their categories.
|
|
if (pIntfContext->pwzcPList != NULL)
|
|
{
|
|
for (i=0; i < pIntfContext->pwzcPList->NumberOfItems; i++)
|
|
{
|
|
PWZC_WLAN_CONFIG pPConfig = &(pIntfContext->pwzcPList->Config[i]);
|
|
|
|
// get the category for this preferred configuration
|
|
iCtg = NWB_GET_SELCATEG(pPConfig);
|
|
// if we have a selection list to copy into, and the entry is supposed
|
|
// to be copied (not neutral) do it here
|
|
if ((*ppwzcSList) != NULL && iCtg != eN)
|
|
{
|
|
PWZC_WLAN_CONFIG pSConfig = &((*ppwzcSList)->Config[nCnt[iCtg]]);
|
|
// copy the whole preferred configuration (including the selection category
|
|
// & authentication mode) to the selection list
|
|
memcpy(pSConfig, pPConfig, sizeof(WZC_WLAN_CONFIG));
|
|
// just for making sure, reset the 'deleted' flag as this is a brand new
|
|
// config that was never attempted.
|
|
pSConfig->dwCtlFlags &= ~WZCCTL_INTERNAL_DELETED;
|
|
// the remaining attributes (selection category, authentication mode) should be
|
|
// left untouched.
|
|
|
|
// make sure we propagate the 'start from index' if the preferred list shows like
|
|
// a one time connect is requested
|
|
if (i == pIntfContext->pwzcPList->Index)
|
|
(*ppwzcSList)->Index = nCnt[iCtg];
|
|
|
|
nCnt[iCtg]++;
|
|
}
|
|
// reset the selection category we have used for this preferred entry
|
|
NWB_SET_SELCATEG(pPConfig, 0);
|
|
}
|
|
}
|
|
|
|
// next, copy the entries from the visible list into the selection list,
|
|
// at the index corresponding to their categories.
|
|
if (pIntfContext->pwzcVList != NULL)
|
|
{
|
|
for (i=0; i < pIntfContext->pwzcVList->NumberOfItems; i++)
|
|
{
|
|
PWZC_WLAN_CONFIG pVConfig = &(pIntfContext->pwzcVList->Config[i]);
|
|
|
|
iCtg = NWB_GET_SELCATEG(pVConfig);
|
|
// if we have a selection list to copy into, and the entry is supposed
|
|
// to be copied (not neutral) do it here
|
|
if ((*ppwzcSList) != NULL && iCtg != eN)
|
|
{
|
|
PWZC_WLAN_CONFIG pSConfig = &((*ppwzcSList)->Config[nCnt[iCtg]]);
|
|
|
|
// copy the whole visible configuration (including its selection category)
|
|
// to the selection set (for visible entries, authentication mode is 0 by default
|
|
// since this information is not provided by the nic/driver)
|
|
memcpy(pSConfig, pVConfig, sizeof(WZC_WLAN_CONFIG));
|
|
// just for making sure, reset the 'deleted' flag as this is a brand new
|
|
// config that was never attempted.
|
|
pSConfig->dwCtlFlags &= ~WZCCTL_INTERNAL_DELETED;
|
|
// bump up the index for this entry's category
|
|
nCnt[iCtg]++;
|
|
}
|
|
// reset the selection category we have used for this visible entry
|
|
NWB_SET_SELCATEG(pVConfig, 0);
|
|
}
|
|
}
|
|
|
|
DbgPrint((TRC_TRACK,"LstBuildSelectList]=%d", dwErr));
|
|
return dwErr;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Checks whether the list of selected configurations has changed such
|
|
// that it is required to replumb the selection.
|
|
// [in] pIntfContext: Interface for which is done the selection
|
|
// [in] pwzcSList: new selection list to check the configuration against
|
|
// [out] pnSelIdx: if selection changed, provides the index where to start iterate from
|
|
// Returns: TRUE if replumbing is required. In this case, pnSelIdx is
|
|
// set to the configuration to start iterate from.
|
|
BOOL
|
|
LstChangedSelectList(
|
|
PINTF_CONTEXT pIntfContext,
|
|
PWZC_802_11_CONFIG_LIST pwzcNSList,
|
|
LPUINT pnSelIdx)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
DbgPrint((TRC_TRACK,"[LstChangedSelectList(0x%p)", pIntfContext));
|
|
DbgAssert((pnSelIdx != NULL,"invalid (null) pointer to out param"));
|
|
|
|
// before anything, zero out the index for the current selected network
|
|
*pnSelIdx = 0;
|
|
|
|
// if there is no configuration the current selected list,
|
|
// it means either we're just initializing the context or we failed all the
|
|
// other configs. Either way, we need to replumb the card according to the
|
|
// new selection list (if that one is also empty, we will follow the path
|
|
// {SQ}->{SIter}->{SF})
|
|
if (pIntfContext->pwzcSList == NULL ||
|
|
pIntfContext->pwzcSList->NumberOfItems == 0 ||
|
|
pwzcNSList == NULL ||
|
|
pwzcNSList->NumberOfItems == 0)
|
|
{
|
|
DbgPrint((TRC_STATE, "SelList changed? YES; the current/new selection list is empty"));
|
|
|
|
// since we're starting fresh, make sure to propagate the "one time connect" index, if any
|
|
if (pwzcNSList != NULL && pwzcNSList->Index < pwzcNSList->NumberOfItems)
|
|
*pnSelIdx = pwzcNSList->Index;
|
|
|
|
bRet = TRUE;
|
|
}
|
|
else // we do have an old SList we need to look at
|
|
{
|
|
PWZC_WLAN_CONFIG pSConfig; // current sucessful configuration
|
|
PWZC_WLAN_CONFIG pNSConfig; // successful configuration in the new selection list
|
|
|
|
DbgAssert((pIntfContext->pwzcSList->Index < pIntfContext->pwzcSList->NumberOfItems,
|
|
"Selection index %d points outside SList[0..%d]",
|
|
pIntfContext->pwzcSList->Index,
|
|
pIntfContext->pwzcSList->NumberOfItems));
|
|
|
|
// get a pointer to the current successful configuration
|
|
pSConfig = &(pIntfContext->pwzcSList->Config[pIntfContext->pwzcSList->Index]);
|
|
|
|
// as the first thing, let's check for the "one time connect". If this is requested,
|
|
// the one time config has to match with the current selected config. Otherwise this
|
|
// is a change already.
|
|
if (pwzcNSList->Index < pwzcNSList->NumberOfItems)
|
|
{
|
|
DbgPrint((TRC_STATE, "SList changed? Yes, \"one time connect\" is requested."));
|
|
// in this case, we do mark this as a "change". Otherwise it is difficult to keep
|
|
// the association to the "one time" connect for more than a scan cycle (other changes
|
|
// will take precedence to the next round, when "one time" connect flag won't be there
|
|
// anymore
|
|
*pnSelIdx = pwzcNSList->Index;
|
|
bRet = TRUE;
|
|
}
|
|
|
|
// if it is not decided yet whether it is a change (that is this is not a "one time connect")...
|
|
if (!bRet)
|
|
{
|
|
// search for the crt successful config into the new selection list.
|
|
pNSConfig = WzcFindConfig(pwzcNSList, pSConfig, 0);
|
|
if (pNSConfig == NULL)
|
|
{
|
|
UINT i;
|
|
ENUM_SELCATEG iSCtg;
|
|
|
|
DbgPrint((TRC_STATE, "SList changed? Don't know yet. The current config is not in the NSList"));
|
|
|
|
// the crt successful config is not in the new selection list. If the crt selection is
|
|
// marked as being of the "preferred" kind, there is no other way it could disappear
|
|
// other than being explicitly removed from the preferred list. In this case, yes,
|
|
// this is a change.
|
|
iSCtg = NWB_GET_SELCATEG(pSConfig);
|
|
if (iSCtg != eVI && iSCtg != eVA)
|
|
{
|
|
DbgPrint((TRC_STATE, "SList changed? Yes. The current preferred network has been removed."));
|
|
bRet = TRUE;
|
|
*pnSelIdx = 0; // iterate from the very beginning.
|
|
}
|
|
|
|
// In all the remaining cases (VI or VA), we need to check each of the new selected configurations
|
|
// if it doesn't prevail the current successful one.
|
|
for (i = 0; !bRet && i < pwzcNSList->NumberOfItems; i++)
|
|
{
|
|
PWZC_WLAN_CONFIG pNConfig, pConfig;
|
|
|
|
// get the new configuration and search it into the current selection list
|
|
pNConfig = &(pwzcNSList->Config[i]);
|
|
pConfig = WzcFindConfig(pIntfContext->pwzcSList, pNConfig, 0);
|
|
|
|
// if the new selected configuration was not tried before either because
|
|
// it just showed up or because we didn't get to try it previously,
|
|
// then it is a potential better candidate
|
|
if (pConfig == NULL || pSConfig < pConfig)
|
|
{
|
|
ENUM_SELCATEG iNSCtg;
|
|
|
|
// get the category for the new config
|
|
iNSCtg = NWB_GET_SELCATEG(pNConfig);
|
|
|
|
// if the new configuration has a prevailing category, we should
|
|
// definitely replumb starting from here
|
|
if (iNSCtg < iSCtg)
|
|
{
|
|
DbgPrint((TRC_STATE,"SList changed? YES; a config with a better category has been detected."));
|
|
bRet = TRUE;
|
|
*pnSelIdx = i;
|
|
}
|
|
// remember: here, the current selected config can only be VI or VA. That is, if the category of
|
|
// any newcomer in the selection list is even equal or greater that the current category, there
|
|
// is absolutely no point in moving out of here.
|
|
}
|
|
// there is a matching config which we tried before. We do acknowledge
|
|
// a change if the the two configs actually don't have matching content!
|
|
else if (!WzcMatchConfig(pNConfig, pConfig, NULL))
|
|
{
|
|
DbgPrint((TRC_STATE,"SList changed? YES; a better config failed before but it has been altered."));
|
|
bRet = TRUE;
|
|
*pnSelIdx = i;
|
|
}
|
|
}
|
|
}
|
|
else // the current selected network is still in the new selection list (pNSConfig)
|
|
{
|
|
UINT i;
|
|
|
|
// for each config in the new selection list, try to match it with an existent
|
|
// configuration in the crt selection list
|
|
for (i = 0; !bRet && i < pwzcNSList->NumberOfItems; i++)
|
|
{
|
|
PWZC_WLAN_CONFIG pNConfig, pConfig;
|
|
ENUM_SELCATEG iNSCtg, iSCtg;
|
|
|
|
// if we are already at the current successful configuration this means
|
|
// we didn't find any new config to justify replumbing the interface
|
|
pNConfig = &(pwzcNSList->Config[i]);
|
|
if (pNConfig == pNSConfig)
|
|
{
|
|
bRet = !WzcMatchConfig(pNConfig, pSConfig, NULL);
|
|
if (bRet)
|
|
DbgPrint((TRC_STATE,"SList changed? YES; no better config found, but the current one has been altered."));
|
|
else
|
|
DbgPrint((TRC_STATE, "SList changed? NO; there is no new config that was not tried yet"));
|
|
break;
|
|
}
|
|
|
|
// get the category for the config in the new list
|
|
iNSCtg = NWB_GET_SELCATEG(pNConfig);
|
|
// search the configuration from the new selection list into the old selection list
|
|
pConfig = WzcFindConfig(pIntfContext->pwzcSList, pNConfig, 0);
|
|
|
|
// if this is either a brand new config, or one that has
|
|
// been raised in front of the current selection...
|
|
if (pConfig == NULL || pSConfig < pConfig)
|
|
{
|
|
// ...if the category is different, or is the same as the one of the successful config
|
|
// but is of a "preferred" kind, then it means the list has changed.
|
|
if (iNSCtg != NWB_GET_SELCATEG(pNSConfig) || (iNSCtg != eVI && iNSCtg != eVA))
|
|
{
|
|
DbgPrint((TRC_STATE,"SList changed? YES: there is a new config of a different or preferred category"));
|
|
bRet = TRUE;
|
|
*pnSelIdx = i;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// there is a matching entry in the old selection list, in front of the current
|
|
// successful configuration. This means the configuration has been tried before and
|
|
// failed. However, it could happen that the configuration was tried when it was
|
|
// not visible and now it is visible. In such a case, we should attempt replumbing
|
|
iSCtg = NWB_GET_SELCATEG(pConfig);
|
|
if (iNSCtg != iSCtg && (iSCtg == ePI || iSCtg == ePA))
|
|
{
|
|
DbgPrint((TRC_STATE,"SList changed? YES: a better config failed before but its categ changed from %d to %d",
|
|
iSCtg, iNSCtg));
|
|
bRet = TRUE;
|
|
*pnSelIdx = i;
|
|
}
|
|
else if (!WzcMatchConfig(pNConfig, pConfig, NULL))
|
|
{
|
|
DbgPrint((TRC_STATE,"SList changed? YES; a better config failed before but it has been altered."));
|
|
bRet = TRUE;
|
|
*pnSelIdx = i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DbgPrint((TRC_TRACK,"LstChangedSelectList]=%s", bRet ? "TRUE" : "FALSE"));
|
|
return bRet;
|
|
}
|
|
|
|
// fake WEP key to be used if there is no key set (and obviously web = disabled)
|
|
// and the remote guy requires privacy. This is a 104bit key.
|
|
BYTE g_chFakeKeyMaterial[] = {0x56, 0x09, 0x08, 0x98, 0x4D, 0x08, 0x11, 0x66, 0x42, 0x03, 0x01, 0x67, 0x66};
|
|
|
|
//-----------------------------------------------------------
|
|
// Plumbs the interface with the selected configuration as it is pointed
|
|
// out by pwzcSList fields in the pIntfContext. Optional, it can
|
|
// return in ppSelSSID the configuration that was plumbed down
|
|
// [in] pIntfContext: Interface context identifying ctl flags & the selected SSID
|
|
// [out] ppndSelSSID: pointer to the SSID that is being plumbed down.
|
|
DWORD
|
|
LstSetSelectedConfig(
|
|
PINTF_CONTEXT pIntfContext,
|
|
PWZC_WLAN_CONFIG *ppndSelSSID)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
PWZC_WLAN_CONFIG pSConfig;
|
|
INTF_ENTRY IntfEntry = {0};
|
|
DWORD dwInFlags, dwOutFlags;
|
|
BYTE chBuffer[sizeof(NDIS_802_11_WEP) + WZCCTL_MAX_WEPK_MATERIAL - 1];
|
|
BOOL bFakeWKey = FALSE; // flag indicating whether the fake WEP key is needed
|
|
|
|
DbgPrint((TRC_TRACK, "[LstSetSelectedConfig(0x%p..)", pIntfContext));
|
|
DbgAssert((pIntfContext != NULL, "(null) interface context in LstSetSelectedConfig"));
|
|
|
|
if (pIntfContext->pwzcSList == NULL ||
|
|
pIntfContext->pwzcSList->Index >= pIntfContext->pwzcSList->NumberOfItems)
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
goto exit;
|
|
}
|
|
// get a pointer to the configuration to set down to the card.
|
|
pSConfig = &(pIntfContext->pwzcSList->Config[pIntfContext->pwzcSList->Index]);
|
|
|
|
// build the IntfEntry object that will specify what exactly goes down to the card
|
|
dwInFlags = INTF_AUTHMODE | INTF_INFRAMODE | INTF_SSID;
|
|
// authentication mode
|
|
//IntfEntry.nAuthMode = NWB_GET_AUTHMODE(pSConfig);
|
|
IntfEntry.nAuthMode = pSConfig->AuthenticationMode;
|
|
// infrastructure mode
|
|
IntfEntry.nInfraMode = pSConfig->InfrastructureMode;
|
|
// SSID
|
|
IntfEntry.rdSSID.dwDataLen = pSConfig->Ssid.SsidLength;
|
|
IntfEntry.rdSSID.pData = pSConfig->Ssid.Ssid;
|
|
|
|
// if the configuration to be plumbed down requires the presence of a WEP Key...
|
|
if (pSConfig->Privacy || IntfEntry.nAuthMode != Ndis802_11AuthModeOpen)
|
|
{
|
|
// if there is a WEP key provided in this configuration plumb it down
|
|
if (pSConfig->dwCtlFlags & WZCCTL_WEPK_PRESENT)
|
|
{
|
|
PNDIS_802_11_WEP pndUserWKey = (PNDIS_802_11_WEP)chBuffer;
|
|
|
|
// build the ndis WEP key structure from the user's key
|
|
// the key is a "transmit" key, regardless the index
|
|
pndUserWKey->KeyIndex = 0x80000000 | pSConfig->KeyIndex;
|
|
pndUserWKey->KeyLength = pSConfig->KeyLength;
|
|
memcpy(pndUserWKey->KeyMaterial, pSConfig->KeyMaterial, WZCCTL_MAX_WEPK_MATERIAL);
|
|
pndUserWKey->Length = sizeof(NDIS_802_11_WEP) + pndUserWKey->KeyLength - 1;
|
|
|
|
// TODO: here is where we should decrypt inplace the WEP key
|
|
{
|
|
UINT i;
|
|
for (i = 0; i < WZCCTL_MAX_WEPK_MATERIAL; i++)
|
|
pndUserWKey->KeyMaterial[i] ^= g_chFakeKeyMaterial[(7*i)%13];
|
|
}
|
|
|
|
// and ask for it to be set down
|
|
IntfEntry.rdCtrlData.dwDataLen = pndUserWKey->Length;
|
|
IntfEntry.rdCtrlData.pData = (LPBYTE)pndUserWKey;
|
|
dwInFlags |= INTF_ADDWEPKEY;
|
|
|
|
DbgPrint((TRC_GENERIC,"Plumbing down the User WEP txKey [idx:%d,len:%d]",
|
|
pSConfig->KeyIndex,
|
|
pSConfig->KeyLength));
|
|
}
|
|
// if a WEP Key is needed but none is provided for this configuration...
|
|
else
|
|
{
|
|
// ...first thing to do is to ask the driver to reload its defaults.
|
|
dwErr = DevioSetEnumOID(
|
|
pIntfContext->hIntf,
|
|
OID_802_11_RELOAD_DEFAULTS,
|
|
(DWORD)Ndis802_11ReloadWEPKeys);
|
|
DbgAssert((dwErr == ERROR_SUCCESS, "Failed setting OID_802_11_RELOAD_DEFAULTS"));
|
|
// need to check if reloading the defaults fixed the issue (not having a key)
|
|
dwErr = DevioRefreshIntfOIDs(
|
|
pIntfContext,
|
|
INTF_WEPSTATUS,
|
|
NULL);
|
|
DbgAssert((dwErr == ERROR_SUCCESS, "Failed refreshing OID_802_11_WEP_STATUS"));
|
|
|
|
// if even after reloading the defaults, a key is still absent, then
|
|
// set down the hardcoded key.
|
|
if (dwErr == ERROR_SUCCESS &&
|
|
pIntfContext->wzcCurrent.Privacy == Ndis802_11WEPKeyAbsent)
|
|
{
|
|
PNDIS_802_11_WEP pndFakeWKey = (PNDIS_802_11_WEP)chBuffer;
|
|
|
|
// we should set the hardcoded WEP key
|
|
pndFakeWKey->KeyIndex = 0x80000000;
|
|
pndFakeWKey->KeyLength = 5; // the fake key has to be the smallest possible (40bit)
|
|
dwErr = WzcRndGenBuffer(pndFakeWKey->KeyMaterial, pndFakeWKey->KeyLength, 0, 255);
|
|
DbgAssert((dwErr == ERROR_SUCCESS, "Failed to generate the random fake wep key"));
|
|
pndFakeWKey->Length = sizeof(NDIS_802_11_WEP) + pndFakeWKey->KeyLength - 1;
|
|
|
|
// and ask for it to be set down
|
|
IntfEntry.rdCtrlData.dwDataLen = pndFakeWKey->Length;
|
|
IntfEntry.rdCtrlData.pData = (LPBYTE)pndFakeWKey;
|
|
dwInFlags |= INTF_ADDWEPKEY;
|
|
bFakeWKey = TRUE;
|
|
DbgPrint((TRC_GENERIC,"Plumbing down the Fake WEP txKey [len:%d]",
|
|
IntfEntry.rdCtrlData.dwDataLen));
|
|
}
|
|
}
|
|
|
|
// now enable WEP only if privacy is required and the current settings
|
|
// show the WEP is not enabled
|
|
if (pSConfig->Privacy && pIntfContext->wzcCurrent.Privacy != Ndis802_11WEPEnabled)
|
|
{
|
|
// and also we should enable WEP if it shows as not being
|
|
// already enabled
|
|
IntfEntry.nWepStatus = Ndis802_11WEPEnabled;
|
|
dwInFlags |= INTF_WEPSTATUS;
|
|
}
|
|
}
|
|
|
|
// if the configuration to be plumbed doesn't require privacy but currently
|
|
// WEP is enabled, disable it.
|
|
if (!pSConfig->Privacy && pIntfContext->wzcCurrent.Privacy == Ndis802_11WEPEnabled)
|
|
{
|
|
IntfEntry.nWepStatus = Ndis802_11WEPDisabled;
|
|
dwInFlags |= INTF_WEPSTATUS;
|
|
}
|
|
|
|
// if everything is fine so far...
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
// ...go and plumb the card with the settings below
|
|
dwErr = DevioSetIntfOIDs(
|
|
pIntfContext,
|
|
&IntfEntry,
|
|
dwInFlags,
|
|
&dwOutFlags);
|
|
// if we attempted to change the WEP Key...
|
|
if (dwInFlags & INTF_ADDWEPKEY)
|
|
{
|
|
//.. and the operation succeeded..
|
|
if (dwOutFlags & INTF_ADDWEPKEY)
|
|
{
|
|
// then either set the "fake key" flag - if it was a fake key..
|
|
if (bFakeWKey)
|
|
pIntfContext->dwCtlFlags |= INTFCTL_INTERNAL_FAKE_WKEY;
|
|
//..or reset it if we put a "real" key
|
|
else
|
|
pIntfContext->dwCtlFlags &= ~INTFCTL_INTERNAL_FAKE_WKEY;
|
|
}
|
|
// if plumbing down the key failed, leave the "fake key" flag as
|
|
// it is since there were no changes made.
|
|
}
|
|
// ...or if we didn't need to plumb a WEP key, reset the flag
|
|
else
|
|
{
|
|
pIntfContext->dwCtlFlags &= ~INTFCTL_INTERNAL_FAKE_WKEY;
|
|
}
|
|
}
|
|
|
|
if (dwErr != ERROR_SUCCESS)
|
|
DbLogWzcError(WZCSVC_ERR_CFG_PLUMB,
|
|
pIntfContext,
|
|
DbLogFmtSSID(0, &(pSConfig->Ssid)),
|
|
dwErr);
|
|
|
|
exit:
|
|
DbgPrint((TRC_TRACK, "LstSetSelectedConfig]=%d", dwErr));
|
|
return dwErr;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// PnP notification handler
|
|
// [in/out] ppIntfContext: Pointer to the Interface context for which
|
|
// the notification was received
|
|
// [in] dwNotifCode: Notification code (WZCNOTIF_*)
|
|
// [in] wszDeviceKey: Key info on the device for which the notification
|
|
// was received
|
|
DWORD
|
|
LstNotificationHandler(
|
|
PINTF_CONTEXT *ppIntfContext,
|
|
DWORD dwNotifCode,
|
|
LPWSTR wszDeviceKey)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
PINTF_CONTEXT pIntfContext = *ppIntfContext;
|
|
|
|
DbgPrint((TRC_TRACK,"[LstNotificationHandler(0x%p, %d, %S)",
|
|
pIntfContext,
|
|
dwNotifCode,
|
|
wszDeviceKey));
|
|
|
|
if ((dwNotifCode == WZCNOTIF_DEVICE_ARRIVAL || dwNotifCode == WZCNOTIF_ADAPTER_BIND) &&
|
|
pIntfContext == NULL)
|
|
{
|
|
CHAR QueryBuffer[QUERY_BUFFER_SIZE];
|
|
PNDISUIO_QUERY_BINDING pQueryBinding;
|
|
RAW_DATA rdBuffer;
|
|
|
|
// get first the binding structure for this interface
|
|
rdBuffer.dwDataLen = sizeof(QueryBuffer);
|
|
rdBuffer.pData = QueryBuffer;
|
|
pQueryBinding = (PNDISUIO_QUERY_BINDING)rdBuffer.pData;
|
|
|
|
dwErr = DevioGetInterfaceBindingByGuid(
|
|
INVALID_HANDLE_VALUE, // the call will open Ndisuio locally
|
|
wszDeviceKey, // interface GUID as "{guid}"
|
|
&rdBuffer);
|
|
// if everything went fine
|
|
if (dwErr != ERROR_SUCCESS)
|
|
goto exit;
|
|
|
|
// go build the INTF_CONTEXT structure, based on
|
|
// the binding information (key info for the adapter)
|
|
dwErr = LstConstructIntfContext(
|
|
pQueryBinding,
|
|
&pIntfContext);
|
|
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
// increase its ref count and lock it up here
|
|
LstRccsReference(pIntfContext);
|
|
LstRccsLock(pIntfContext);
|
|
|
|
// add it to the hashes
|
|
dwErr = LstAddIntfToHashes(pIntfContext);
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = StateDispatchEvent(
|
|
eEventAdd,
|
|
pIntfContext,
|
|
NULL);
|
|
}
|
|
// if for any reason hashing or dispatching failed, cleanup the context here
|
|
if (dwErr != ERROR_SUCCESS)
|
|
LstRemoveIntfContext(pIntfContext);
|
|
|
|
// release the context here
|
|
LstRccsUnlockUnref(pIntfContext);
|
|
}
|
|
|
|
// it could happen that a context was created but it turned out to be a non-wireless
|
|
// adapter. In this case all memory has been freed up, but pIntfContext remained
|
|
// non-null. We need to set this pointer back to null as it will be passed up.
|
|
if (dwErr != ERROR_SUCCESS)
|
|
pIntfContext = NULL;
|
|
}
|
|
|
|
// either for arrival or removal, we attempt to remove any identical context
|
|
// If it is about an arrival, we shouldn't have any duplicate but who knows
|
|
if ((dwNotifCode == WZCNOTIF_DEVICE_REMOVAL || dwNotifCode == WZCNOTIF_ADAPTER_UNBIND) &&
|
|
pIntfContext != NULL)
|
|
{
|
|
// increase its ref count and lock it up here
|
|
LstRccsReference(pIntfContext);
|
|
LstRccsLock(pIntfContext);
|
|
|
|
DbLogWzcInfo(WZCSVC_EVENT_REMOVE, pIntfContext,
|
|
pIntfContext->wszDescr);
|
|
|
|
// save the interface's settings to the registry
|
|
dwErr = StoSaveIntfConfig(NULL, pIntfContext);
|
|
DbgAssert((dwErr == ERROR_SUCCESS,
|
|
"StoSaveIntfConfig failed for Intf context 0x%p",
|
|
pIntfContext));
|
|
|
|
// prepare this context for destruction
|
|
LstRemoveIntfContext(pIntfContext);
|
|
|
|
// at this point, there are no other timer routines that are going to be fired. Whatever
|
|
// has been already fired ++ed the reference counter already so there is no risk to delete
|
|
// the data prematurely (when unref-ing this context). Also the timer has been deleted, but
|
|
// before doing so the timer handle has been set to INVALID_HANDLE_VALUE so there is no risk
|
|
// some other thread is trying to set a deleted timer (besides, we're still holding the
|
|
// context's critical section hence there can be no such other thread competing here).
|
|
|
|
// release the context here
|
|
LstRccsUnlockUnref(pIntfContext);
|
|
|
|
// since the resulting IntfContext is passed back to the caller,
|
|
// make the local pointer NULL (it will be returned later in the out param)
|
|
pIntfContext = NULL;
|
|
}
|
|
|
|
// for media connect & disconnect..
|
|
if (dwNotifCode == WZCNOTIF_MEDIA_CONNECT || dwNotifCode == WZCNOTIF_MEDIA_DISCONNECT)
|
|
{
|
|
// NOTE: keep in mind, pIntfContext is valid because we're in the critical section
|
|
// for the hashes.
|
|
//
|
|
// if there is a context under Zero Conf control, dispatch the event to the
|
|
// state machine
|
|
if (pIntfContext != NULL)
|
|
{
|
|
// first lock the context since the state machine deals only with locked contexts
|
|
LstRccsReference(pIntfContext);
|
|
LstRccsLock(pIntfContext);
|
|
|
|
dwErr = StateDispatchEvent(
|
|
dwNotifCode == WZCNOTIF_MEDIA_CONNECT ? eEventConnect : eEventDisconnect,
|
|
pIntfContext,
|
|
NULL);
|
|
|
|
LstRccsUnlockUnref(pIntfContext);
|
|
}
|
|
else
|
|
{
|
|
dwErr = ERROR_FILE_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
*ppIntfContext = pIntfContext;
|
|
DbgPrint((TRC_TRACK,"LstNotificationHandler]=%d", dwErr));
|
|
return dwErr;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Application Command call.
|
|
// [in] dwHandle: key for identifying the context (state) to which this cmd is referring
|
|
// [in] dwCmdCode: Command code (one of the WZCCMD_* contants)
|
|
// [in] wszIntfGuid: the guid of the interface to which this cmd is addressed
|
|
// [in] prdUserData: Application data associated to this command
|
|
DWORD
|
|
LstCmdInterface(
|
|
DWORD dwHandle,
|
|
DWORD dwCmdCode,
|
|
LPWSTR wszIntfGuid,
|
|
PRAW_DATA prdUserData)
|
|
{
|
|
DWORD dwErr = ERROR_FILE_NOT_FOUND;
|
|
PHASH_NODE pNode = NULL;
|
|
PINTF_CONTEXT pIntfContext;
|
|
|
|
DbgPrint((TRC_TRACK, "[LstCmdInterface(hdl=0x%x, cmd=0x%x,...)", dwHandle, dwCmdCode));
|
|
|
|
if (g_lstIntfHashes.bValid)
|
|
{
|
|
EnterCriticalSection(&g_lstIntfHashes.csMutex);
|
|
dwErr = HshQueryObjectRef(
|
|
g_lstIntfHashes.pHnGUID,
|
|
wszIntfGuid,
|
|
&pNode);
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
pIntfContext = pNode->pObject;
|
|
// bump up the reference counter since we're going
|
|
// to work with this object
|
|
LstRccsReference(pIntfContext);
|
|
}
|
|
LeaveCriticalSection(&g_lstIntfHashes.csMutex);
|
|
}
|
|
else
|
|
dwErr = ERROR_ARENA_TRASHED;
|
|
|
|
// a failure at this point, means there was no context
|
|
// to lock so we can safely go to 'exit'
|
|
if (dwErr != ERROR_SUCCESS)
|
|
goto exit;
|
|
|
|
// Lock the context now
|
|
LstRccsLock(pIntfContext);
|
|
|
|
// don't do any processing if the handle passed down with the
|
|
// command doesn't match the session handle (meaning the command
|
|
// refers to the right iteration loop).
|
|
if (dwCmdCode == WZCCMD_HARD_RESET ||
|
|
dwHandle == pIntfContext->dwSessionHandle)
|
|
{
|
|
ESTATE_EVENT StateEvent;
|
|
BOOL bIgnore = FALSE; // tells whether the state machine needs to be kicked
|
|
// for this command.
|
|
BOOL bCopy = TRUE; // tells whether the user data needs to be copied
|
|
// in the successful config context.
|
|
DWORD dwRefreshOIDs = 0;
|
|
LPVOID pEventData = NULL;
|
|
PWZC_WLAN_CONFIG pSConfig = NULL;
|
|
|
|
// translate the command code to the internal event
|
|
switch (dwCmdCode)
|
|
{
|
|
case WZCCMD_HARD_RESET:
|
|
bCopy = FALSE; // no need to copy anything on hard reset!
|
|
StateEvent = eEventCmdReset;
|
|
break;
|
|
case WZCCMD_SOFT_RESET:
|
|
StateEvent = eEventCmdRefresh;
|
|
dwRefreshOIDs = INTF_LIST_SCAN;
|
|
pEventData = &dwRefreshOIDs;
|
|
break;
|
|
case WZCCMD_CFG_NEXT:
|
|
StateEvent = eEventCmdCfgNext;
|
|
break;
|
|
case WZCCMD_CFG_DELETE:
|
|
StateEvent = eEventCmdCfgDelete;
|
|
break;
|
|
case WZCCMD_CFG_NOOP:
|
|
StateEvent = eEventCmdCfgNoop;
|
|
break;
|
|
case WZCCMD_CFG_SETDATA:
|
|
bIgnore = TRUE;
|
|
break;
|
|
case WZCCMD_SKEY_QUERY:
|
|
bIgnore = TRUE; bCopy = FALSE;
|
|
dwErr = ERROR_SUCCESS;
|
|
if (prdUserData == NULL)
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
if (pIntfContext->pSecSessionKeys == NULL)
|
|
{
|
|
prdUserData->dwDataLen = 0;
|
|
}
|
|
else if (prdUserData->dwDataLen < sizeof(SESSION_KEYS))
|
|
{
|
|
prdUserData->dwDataLen = sizeof(SESSION_KEYS);
|
|
dwErr = ERROR_MORE_DATA;
|
|
}
|
|
else
|
|
{
|
|
PSESSION_KEYS pSK = (PSESSION_KEYS) prdUserData->pData;
|
|
dwErr = WzcSSKDecrypt(pIntfContext->pSecSessionKeys, pSK);
|
|
}
|
|
}
|
|
break;
|
|
case WZCCMD_SKEY_SET:
|
|
bIgnore = TRUE; bCopy = FALSE;
|
|
dwErr = ERROR_SUCCESS;
|
|
if (prdUserData == NULL)
|
|
{
|
|
WzcSSKFree(pIntfContext->pSecSessionKeys);
|
|
pIntfContext->pSecSessionKeys = NULL;
|
|
}
|
|
else if (prdUserData->dwDataLen != sizeof(SESSION_KEYS))
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
if (pIntfContext->pSecSessionKeys == NULL)
|
|
{
|
|
pIntfContext->pSecSessionKeys = MemCAlloc(sizeof(SEC_SESSION_KEYS));
|
|
if (pIntfContext->pSecSessionKeys == NULL)
|
|
dwErr = GetLastError();
|
|
}
|
|
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
PSESSION_KEYS pSK = (PSESSION_KEYS) prdUserData->pData;
|
|
WzcSSKClean(pIntfContext->pSecSessionKeys);
|
|
dwErr = WzcSSKEncrypt(pIntfContext->pSecSessionKeys, pSK);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
// just in case we were just asked to set the BLOB (and we did this already)
|
|
// or some bogus code came in, no event will be dispatched to the state machine
|
|
bIgnore = TRUE;
|
|
break;
|
|
}
|
|
|
|
// copy down the user data to the config currently selected
|
|
if (bCopy && pIntfContext->pwzcSList != NULL &&
|
|
pIntfContext->pwzcSList->Index < pIntfContext->pwzcSList->NumberOfItems)
|
|
{
|
|
pSConfig = &(pIntfContext->pwzcSList->Config[pIntfContext->pwzcSList->Index]);
|
|
|
|
// if whatever buffer we already have is not large enough, clean it out
|
|
if (prdUserData == NULL || pSConfig->rdUserData.dwDataLen < prdUserData->dwDataLen)
|
|
{
|
|
MemFree(pSConfig->rdUserData.pData);
|
|
pSConfig->rdUserData.pData = NULL;
|
|
pSConfig->rdUserData.dwDataLen = 0;
|
|
}
|
|
|
|
// if a new buffer will be needed, allocate it here.
|
|
if (prdUserData != NULL && prdUserData->dwDataLen > pSConfig->rdUserData.dwDataLen)
|
|
{
|
|
pSConfig->rdUserData.pData = MemCAlloc(prdUserData->dwDataLen);
|
|
if (pSConfig->rdUserData.pData == NULL)
|
|
{
|
|
dwErr = GetLastError();
|
|
goto exit;
|
|
}
|
|
pSConfig->rdUserData.dwDataLen = prdUserData->dwDataLen;
|
|
}
|
|
|
|
// if there is any user data to store, do it here
|
|
if (prdUserData != NULL && prdUserData->dwDataLen > 0)
|
|
memcpy(pSConfig->rdUserData.pData, prdUserData->pData, prdUserData->dwDataLen);
|
|
}
|
|
|
|
|
|
// if this command is not to be ignored, dispatch the
|
|
// corresponding state event to the state machine dispatcher.
|
|
if (!bIgnore)
|
|
{
|
|
dwErr = StateDispatchEvent(
|
|
StateEvent,
|
|
pIntfContext,
|
|
pEventData);
|
|
|
|
// clear up the INTFCTL_INTERNAL_BLK_MEDIACONN bit since this is not a media sense handler
|
|
pIntfContext->dwCtlFlags &= ~INTFCTL_INTERNAL_BLK_MEDIACONN;
|
|
}
|
|
}
|
|
|
|
// Unlock the context now
|
|
LstRccsUnlockUnref(pIntfContext);
|
|
|
|
exit:
|
|
DbgPrint((TRC_TRACK, "LstCmdInterface]=%d", dwErr));
|
|
return dwErr;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Network Connection's status query
|
|
// [in] wszIntfGuid: the guid of the interface to which this cmd is addressed
|
|
// [out] pncs: network connection status, if controlled by WZC.
|
|
HRESULT
|
|
LstQueryGUIDNCStatus(
|
|
LPWSTR wszIntfGuid,
|
|
NETCON_STATUS *pncs)
|
|
{
|
|
DWORD dwErr = ERROR_FILE_NOT_FOUND;
|
|
HRESULT hr = S_FALSE;
|
|
PHASH_NODE pNode = NULL;
|
|
PINTF_CONTEXT pIntfContext;
|
|
|
|
DbgPrint((TRC_TRACK, "[LstQueryGUIDNCStatus(%S)", wszIntfGuid));
|
|
|
|
if (g_lstIntfHashes.bValid)
|
|
{
|
|
EnterCriticalSection(&g_lstIntfHashes.csMutex);
|
|
dwErr = HshQueryObjectRef(
|
|
g_lstIntfHashes.pHnGUID,
|
|
wszIntfGuid,
|
|
&pNode);
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
pIntfContext = pNode->pObject;
|
|
// bump up the reference counter since we're going
|
|
// to work with this object
|
|
LstRccsReference(pIntfContext);
|
|
}
|
|
LeaveCriticalSection(&g_lstIntfHashes.csMutex);
|
|
}
|
|
else
|
|
dwErr = ERROR_ARENA_TRASHED;
|
|
|
|
// a failure at this point, means there was no context
|
|
// to lock so we can safely go to 'exit'
|
|
if (dwErr != ERROR_SUCCESS)
|
|
goto exit;
|
|
|
|
// Lock the context now
|
|
LstRccsLock(pIntfContext);
|
|
|
|
// we control the state only if WZC is enabled and the adapter is
|
|
// anything else but connected. Otherwise the upper layer protocols
|
|
// are in control.
|
|
//
|
|
// For now (WinXP client RTM), Zero Config should report to NETMAN only the
|
|
// disconnected state. This is to fix bug #401130 which is NETSHELL displaying
|
|
// the bogus SSID from the {SF} state, while the IP address is lost and until
|
|
// the media disconnect is received (10 seconds later).
|
|
if (pIntfContext->dwCtlFlags & INTFCTL_ENABLED &&
|
|
pIntfContext->dwCtlFlags & INTFCTL_OIDSSUPP &&
|
|
pIntfContext->ncStatus != NCS_CONNECTED)
|
|
{
|
|
*pncs = NCS_MEDIA_DISCONNECTED;
|
|
hr = S_OK;
|
|
}
|
|
|
|
// Unlock the context now
|
|
LstRccsUnlockUnref(pIntfContext);
|
|
|
|
exit:
|
|
DbgPrint((TRC_TRACK, "LstQueryGUIDNCStatus]=%d", dwErr));
|
|
return hr;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Generate the initial dynamic session keys.
|
|
// [in] pIntfContext: Interface context containing the material for initial key generation.
|
|
DWORD
|
|
LstGenInitialSessionKeys(
|
|
PINTF_CONTEXT pIntfContext)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
PWZC_WLAN_CONFIG pSConfig = NULL;
|
|
NDIS_802_11_MAC_ADDRESS ndMAC[2] = {0};
|
|
SESSION_KEYS SessionKeys;
|
|
UCHAR KeyMaterial[WZCCTL_MAX_WEPK_MATERIAL];
|
|
|
|
if (pIntfContext->pwzcSList != NULL &&
|
|
pIntfContext->pwzcSList->Index < pIntfContext->pwzcSList->NumberOfItems)
|
|
{
|
|
pSConfig = &(pIntfContext->pwzcSList->Config[pIntfContext->pwzcSList->Index]);
|
|
}
|
|
|
|
if (pSConfig != NULL && pSConfig->dwCtlFlags & WZCCTL_WEPK_PRESENT)
|
|
{
|
|
// get the random info needed for the key generation (RemoteMAC | LocalMAC ).
|
|
pSConfig = &(pIntfContext->pwzcSList->Config[pIntfContext->pwzcSList->Index]);
|
|
memcpy(&ndMAC[0], &pSConfig->MacAddress, sizeof(NDIS_802_11_MAC_ADDRESS));
|
|
memcpy(&ndMAC[1], &pIntfContext->ndLocalMac, sizeof(NDIS_802_11_MAC_ADDRESS));
|
|
|
|
// generate dynamic keys starting from unscrambled WEP
|
|
{
|
|
UINT i;
|
|
for (i = 0; i < WZCCTL_MAX_WEPK_MATERIAL; i++)
|
|
KeyMaterial[i] = pSConfig->KeyMaterial[i] ^ g_chFakeKeyMaterial[(7*i)%13];
|
|
}
|
|
|
|
dwErr = GenerateDynamicKeys(
|
|
KeyMaterial,
|
|
pSConfig->KeyLength,
|
|
(LPBYTE)&ndMAC[0],
|
|
sizeof(ndMAC),
|
|
pSConfig->KeyLength,
|
|
&SessionKeys);
|
|
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
WzcSSKFree(pIntfContext->pSecSessionKeys);
|
|
pIntfContext->pSecSessionKeys = MemCAlloc(sizeof(SEC_SESSION_KEYS));
|
|
if (pIntfContext->pSecSessionKeys == NULL)
|
|
{
|
|
dwErr = GetLastError();
|
|
}
|
|
else
|
|
{
|
|
dwErr = WzcSSKEncrypt(pIntfContext->pSecSessionKeys, &SessionKeys);
|
|
}
|
|
}
|
|
}
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Updates the list of blocked configurations with the selected configurations
|
|
// that were blocked at this round by the upper layer (marked with WZCCTL_INTERNAL_BLOCKED
|
|
// in the list of selected configurations)
|
|
// [in] pIntfContext: Interface context containing the configurations lists
|
|
DWORD
|
|
LstUpdateBlockedList(
|
|
PINTF_CONTEXT pIntfContext)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
UINT i, nBlocked = 0;
|
|
PWZC_802_11_CONFIG_LIST pNewBList = NULL;
|
|
PWZC_WLAN_CONFIG pConfig;
|
|
BOOL bChanged = FALSE;
|
|
|
|
DbgPrint((TRC_TRACK, "[LstUpdateBlockedList(0x%p)", pIntfContext));
|
|
|
|
// the first thing is to count how many blocked configurations we have
|
|
// check first the current blocked list for blocked configs still "alive"
|
|
if (pIntfContext->pwzcBList != NULL)
|
|
{
|
|
for (i=0; i < pIntfContext->pwzcBList->NumberOfItems; i++)
|
|
{
|
|
if (pIntfContext->pwzcBList->Config[i].Reserved[0] > 0)
|
|
nBlocked++;
|
|
else
|
|
bChanged = TRUE; // this entry is going to be removed!
|
|
}
|
|
}
|
|
|
|
// check now how many configs are going to be blocked from the current selection list
|
|
// NOTE: the entries from the SList are guaranteed not to duplicate entries in the BList
|
|
// If an entry is in the BList it means it was excluded from being added to the SList
|
|
// when the SList was created.
|
|
if (pIntfContext->pwzcSList != NULL)
|
|
{
|
|
for (i=0; i < pIntfContext->pwzcSList->NumberOfItems; i++)
|
|
{
|
|
if (pIntfContext->pwzcSList->Config[i].dwCtlFlags & WZCCTL_INTERNAL_BLOCKED)
|
|
{
|
|
nBlocked++;
|
|
bChanged = TRUE; // a new entry becomes blocked
|
|
}
|
|
}
|
|
}
|
|
|
|
// if we found there are no blocked entries, nor in the original list not in the current
|
|
// (failed) selection list, just go out successfully - it means the original pwzcBList
|
|
// is already NULL and it should remain this way
|
|
if (nBlocked == 0)
|
|
goto exit;
|
|
|
|
pNewBList = (PWZC_802_11_CONFIG_LIST)
|
|
MemCAlloc(FIELD_OFFSET(WZC_802_11_CONFIG_LIST, Config) + nBlocked * sizeof(WZC_WLAN_CONFIG));
|
|
|
|
// on memory allocation error, get out with the error code
|
|
if (pNewBList == NULL)
|
|
{
|
|
dwErr = GetLastError();
|
|
goto exit;
|
|
}
|
|
|
|
// if originally there were some alive blocked entries, copy them over to the new list
|
|
if (pIntfContext->pwzcBList != NULL)
|
|
{
|
|
for (i=0; i < pIntfContext->pwzcBList->NumberOfItems && nBlocked > 0; i++)
|
|
{
|
|
pConfig = &(pIntfContext->pwzcBList->Config[i]);
|
|
|
|
if (pConfig->Reserved[0] > 0)
|
|
{
|
|
memcpy(&(pNewBList->Config[pNewBList->NumberOfItems]),
|
|
pConfig,
|
|
sizeof(WZC_WLAN_CONFIG));
|
|
// make sure the copy doesn't include any "user" data:
|
|
pConfig->rdUserData.pData = NULL;
|
|
pConfig->rdUserData.dwDataLen = 0;
|
|
// don't touch anything from this blocked configuration. TTL goes down
|
|
// by itself with each scan (if network is not available)
|
|
pNewBList->NumberOfItems++;
|
|
// make sure we are breaking the loop if we have no storage for any potential
|
|
// blocked configuration. This shouldn't happen since we were counting these first
|
|
// and the whole context is locked, but ... it doesn't hurt
|
|
nBlocked--;
|
|
}
|
|
}
|
|
}
|
|
|
|
// now copy over the new blocked entries, if any
|
|
if (pIntfContext->pwzcSList != NULL)
|
|
{
|
|
for (i=0; i < pIntfContext->pwzcSList->NumberOfItems && nBlocked > 0; i++)
|
|
{
|
|
pConfig = &(pIntfContext->pwzcSList->Config[i]);
|
|
|
|
if (pConfig->dwCtlFlags & WZCCTL_INTERNAL_BLOCKED)
|
|
{
|
|
memcpy(&(pNewBList->Config[pNewBList->NumberOfItems]),
|
|
pConfig,
|
|
sizeof(WZC_WLAN_CONFIG));
|
|
// make sure the copy doesn't include any "user" data:
|
|
pConfig->rdUserData.pData = NULL;
|
|
pConfig->rdUserData.dwDataLen = 0;
|
|
// make sure to set the initial TTL for the new blocked configuration
|
|
pNewBList->Config[pNewBList->NumberOfItems].Reserved[0] = WZC_INTERNAL_BLOCKED_TTL;
|
|
pNewBList->NumberOfItems++;
|
|
// make sure we are breaking the loop if we have no storage for any potential
|
|
// blocked configuration. This shouldn't happen since we were counting these first
|
|
// and the whole context is locked, but ... it doesn't hurt
|
|
nBlocked--;
|
|
}
|
|
}
|
|
}
|
|
|
|
// everything is ok - nothing can fail further, so make pNewBList the official pBList
|
|
WzcCleanupWzcList(pIntfContext->pwzcBList);
|
|
pIntfContext->pwzcBList = pNewBList;
|
|
|
|
if (bChanged)
|
|
{
|
|
DbLogWzcInfo(WZCSVC_BLIST_CHANGED,
|
|
pIntfContext,
|
|
pIntfContext->pwzcBList != NULL ? pIntfContext->pwzcBList->NumberOfItems : 0);
|
|
}
|
|
|
|
exit:
|
|
DbgPrint((TRC_TRACK, "LstUpdateBlockedList]=%d", dwErr));
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// Checks each of the entries in the locked list against the visible list. If the
|
|
// entry is visible, its TTL is reset. If it is not, its TTL is decremented. If the
|
|
// TTL becomes 0, the entry is taken out of the list.
|
|
// [in] pIntfContext: Interface context containing the configurations lists
|
|
DWORD
|
|
LstDeprecateBlockedList(
|
|
PINTF_CONTEXT pIntfContext)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
UINT i;
|
|
PWZC_WLAN_CONFIG pConfig, pVConfig;
|
|
BOOL bChanged = FALSE;
|
|
|
|
DbgPrint((TRC_TRACK, "[LstDeprecateBlockedList(0x%p)", pIntfContext));
|
|
|
|
// nothing to do if there is no list of blocked entries
|
|
if (pIntfContext->pwzcBList == NULL)
|
|
goto exit;
|
|
|
|
for (i=0; i < pIntfContext->pwzcBList->NumberOfItems; i++)
|
|
{
|
|
pConfig = &(pIntfContext->pwzcBList->Config[i]);
|
|
|
|
// if the blocked entry appears to be visible, reset its TTL
|
|
if (WzcFindConfig(pIntfContext->pwzcVList, pConfig, 0) != NULL)
|
|
pConfig->Reserved[0] = WZC_INTERNAL_BLOCKED_TTL;
|
|
else // else decrement its TTL
|
|
pConfig->Reserved[0]--;
|
|
|
|
// if the TTL got to 0, the entry needs to be removed from the list
|
|
// (exchange with the very last one and the list is made 1 entry shorted)
|
|
if (pConfig->Reserved[0] == 0)
|
|
{
|
|
UINT nLastIdx = pIntfContext->pwzcBList->NumberOfItems - 1;
|
|
// if this is not the very last entry, exchange it with the last one
|
|
// but first clean it out since it will be unreachable for WzcCleanupWzcList()
|
|
MemFree(pConfig->rdUserData.pData);
|
|
|
|
if (i != nLastIdx)
|
|
{
|
|
memcpy(pConfig, &(pIntfContext->pwzcBList->Config[nLastIdx]), sizeof(WZC_WLAN_CONFIG));
|
|
}
|
|
// make the list one entry shorter since the removed entry is now at the end
|
|
pIntfContext->pwzcBList->NumberOfItems--;
|
|
// next time stay on the same index as at this iteration.
|
|
i--;
|
|
// now since this went away, note the change
|
|
bChanged = TRUE;
|
|
}
|
|
}
|
|
|
|
if (bChanged)
|
|
{
|
|
DbLogWzcInfo(WZCSVC_BLIST_CHANGED,
|
|
pIntfContext,
|
|
pIntfContext->pwzcBList->NumberOfItems);
|
|
}
|
|
|
|
exit:
|
|
DbgPrint((TRC_TRACK, "LstDeprecateBlockedList]=%d", dwErr));
|
|
|
|
return dwErr;
|
|
}
|