Leaked source code of windows server 2003
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

#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;
}