Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

2850 lines
82 KiB

/*++
Copyright (c) 2000, Microsoft Corporation
Module Name:
eldeviceio.c
Abstract:
This module contains implementations for media-management and device I/O.
The routines declared here operate asynchronously on the handles
associated with an I/O completion port opened on the ndis uio driver.
Revision History:
sachins, Apr 23 2000, Created
--*/
#include "pcheapol.h"
#pragma hdrstop
// NDISUIO constants
CHAR NdisuioDevice[] = "\\\\.\\\\Ndisuio";
CHAR * pNdisuioDevice = &NdisuioDevice[0];
WCHAR cwszNDISUIOProtocolName[] = L"NDISUIO";
WORD g_wEtherType8021X= 0x8E88;
//
// ElMediaInit
//
// Description:
//
// Called on EAPOL service startup to initialize all the media related events
// and callback functions
//
//
// Arguments:
//
// Return Values:
//
DWORD
ElMediaInit (
)
{
DWORD dwIndex = 0;
DWORD dwRetCode = NO_ERROR;
TRACE0 (INIT, "ElMediaInit: Entered");
do
{
// Create Global Interface lock
if (dwRetCode = CREATE_READ_WRITE_LOCK(&(g_ITFLock), "ITF") != NO_ERROR)
{
TRACE1(EAPOL, "ElMediaInit: Error (%ld) in creating g_ITFLock read-write-lock", dwRetCode);
break;
}
// Initialize NLA locks
if (dwRetCode = CREATE_READ_WRITE_LOCK(&(g_NLALock), "NLA") != NO_ERROR)
{
TRACE1(EAPOL, "ElMediaInit: Error (%ld) in creating g_NLALock read-write-lock", dwRetCode);
break;
}
// Initialize EAPOL structures
if ((dwRetCode = ElInitializeEAPOL()) != NO_ERROR)
{
TRACE1(INIT, "ElMediaInit: ElInitializeEAPOL failed with dwRetCode = %d",
dwRetCode );
break;
}
else
{
// TRACE0(INIT, "ElMediaInit: ElInitializeEAPOL successful");
g_dwModulesStarted |= EAPOL_MODULE_STARTED;
}
// Initialize interface hash bucket table
g_ITFTable.pITFBuckets = (ITF_BUCKET *) MALLOC (INTF_TABLE_BUCKETS * sizeof (ITF_BUCKET));
if (g_ITFTable.pITFBuckets == NULL)
{
TRACE0 (DEVICE, "Error in allocation memory for ITF buckets");
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
break;
}
for (dwIndex=0; dwIndex < INTF_TABLE_BUCKETS; dwIndex++)
{
g_ITFTable.pITFBuckets[dwIndex].pItf=NULL;
}
// Indicate logon/logoff notifications can be accepted
g_dwModulesStarted |= LOGON_MODULE_STARTED;
// Check if service was delayed in starting, start user logon
ElCheckUserLoggedOn ();
// Check if the user-context process is ready to be notified
if ((dwRetCode = ElCheckUserModuleReady ()) == ERROR_BAD_IMPERSONATION_LEVEL)
{
break;
}
// Enumerate all the interfaces and start EAPOL state machine
// on interfaces which are of LAN type
if ((dwRetCode = ElEnumAndOpenInterfaces (NULL, NULL, 0, NULL)) != NO_ERROR)
{
TRACE1(INIT, "ElMediaInit: ElEnumAndOpenInterfaces failed with dwRetCode = %d",
dwRetCode );
break;
}
else
{
// TRACE0(INIT, "ElMediaInit: ElEnumAndOpenInterfaces successful");
}
#ifndef ZEROCONFIG_LINKED
// Register for Media Sense detection of MEDIA_CONNECT and
// MEDIA_DISCONNECT of interfaces
if ((dwRetCode = ElMediaSenseRegister (TRUE)) != NO_ERROR)
{
TRACE1(INIT, "ElMediaInit: ElMediaSenseRegister failed with dwRetCode = %d",
dwRetCode );
break;
}
else
{
g_dwModulesStarted |= WMI_MODULE_STARTED;
// TRACE0(INIT, "ElMediaInit: ElMediaSenseRegister successful");
}
// Register for detecting protocol BIND and UNBIND
if ((dwRetCode = ElBindingsNotificationRegister (TRUE)) != NO_ERROR)
{
TRACE1(INIT, "ElMediaInit: ElBindingsNotificationRegister failed with dwRetCode = %d",
dwRetCode );
break;
}
else
{
g_dwModulesStarted |= BINDINGS_MODULE_STARTED;
// TRACE0(INIT, "ElMediaInit: ElBindingsNotificationRegister successful");
}
// Register for device notifications. We are interested in LAN
// interfaces coming and going.
if ((dwRetCode = ElDeviceNotificationRegister (TRUE)) != NO_ERROR)
{
TRACE1(INIT, "ElMediaInit: ElDeviceNotificationRegister failed with dwRetCode = %d",
dwRetCode );
break;
}
else
{
g_dwModulesStarted |= DEVICE_NOTIF_STARTED;
// TRACE0(INIT, "ElMediaInit: ElDeviceNotificationRegister successful");
}
#endif // ZEROCONFIG_LINKED
} while (FALSE);
if (dwRetCode == NO_ERROR)
{
TRACE0(INIT, "ElMediaInit successful");
}
else
{
TRACE1(INIT, "ElMediaInit failed with error %ld",
dwRetCode);
}
return dwRetCode;
}
//
// ElMediaDeInit
//
// Description:
//
// Called on EAPOL service shutdown to de-initialize all the media
// related events and callback functions
//
//
// Arguments:
//
// Return Values:
//
DWORD
ElMediaDeInit (
)
{
LONG lLocalWorkerThreads = 0;
DWORD dwIndex = 0;
EAPOL_ITF *pITFWalker = NULL, *pITF = NULL;
DWORD dwRetCode = NO_ERROR;
TRACE0 (INIT, "ElMediaDeInit: Entered");
// Indicate logon/logoff notifications will not be accepted anymore
g_dwModulesStarted &= ~LOGON_MODULE_STARTED;
#ifndef ZEROCONFIG_LINKED
// DeRegister Media Sense detection of MEDIA_CONNECT and MEDIA_DISCONNECT
// of interfaces
if (g_dwModulesStarted & WMI_MODULE_STARTED)
{
if ((dwRetCode = ElMediaSenseRegister (FALSE)) != NO_ERROR )
{
TRACE1(INIT, "ElMediaDeInit: ElMediaSenseRegister failed with dwRetCode = %d",
dwRetCode );
// log
}
else
{
// TRACE0(INIT, "ElMediaDeInit: ElMediaSenseRegister successful");
}
g_dwModulesStarted &= ~WMI_MODULE_STARTED;
}
// Deregister detecting protocol BIND and UNBIND
if (g_dwModulesStarted & BINDINGS_MODULE_STARTED)
{
if ((dwRetCode = ElBindingsNotificationRegister (FALSE)) != NO_ERROR)
{
TRACE1(INIT, "ElMediaDeInit: ElBindingsNotificationRegister failed with dwRetCode = %d",
dwRetCode );
// log
}
else
{
g_dwModulesStarted &= ~BINDINGS_MODULE_STARTED;
// TRACE0(INIT, "ElMediaDeInit: ElBindingsNotificationRegister successful");
}
}
// Deregister device notifications that may have been posted
if (g_dwModulesStarted & DEVICE_NOTIF_STARTED)
{
if ((dwRetCode = ElDeviceNotificationRegister (FALSE)) != NO_ERROR)
{
TRACE1(INIT, "ElMediaDeInit: ElDeviceNotificationRegister failed with dwRetCode = %d",
dwRetCode );
// log
}
else
{
// TRACE0(INIT, "ElMediaDeInit: ElDeviceNotificationRegister successful");
}
g_dwModulesStarted &= ~DEVICE_NOTIF_STARTED;
}
#endif // ZEROCONFIG_LINKED
// Wait for all the related threads to die
// viz. MediaSense, BindingsNotification, DeviceNotification,
// Registry-watch for EAP-configuration change,
// Registry-watch for EAPOL-parameter change
do
{
lLocalWorkerThreads = 0;
lLocalWorkerThreads = InterlockedCompareExchange (
&g_lWorkerThreads,
0,
0);
if (lLocalWorkerThreads == 0)
{
TRACE0 (INIT, "ElMediaDeInit: No worker threads alive, exiting");
TRACE2 (INIT, "ElMediaDeInit: (%ld) - (%ld) worker threads still alive",
lLocalWorkerThreads, g_lWorkerThreads);
break;
}
TRACE2 (INIT, "ElMediaDeInit: (%ld) - (%ld) worker threads still alive, sleeping zzz... ",
lLocalWorkerThreads, g_lWorkerThreads);
Sleep (1000);
}
while (TRUE);
// Shutdown EAPOL state machine
if (g_dwModulesStarted & EAPOL_MODULE_STARTED)
{
if ((dwRetCode = ElEAPOLDeInit()) != NO_ERROR)
{
TRACE1(INIT, "ElMediaDeInit: ElEAPOLDeInit failed with dwRetCode = %d",
dwRetCode );
// log
}
else
{
TRACE0(INIT, "ElMediaDeInit: ElEAPOLDeInit successful");
}
g_dwModulesStarted &= ~EAPOL_MODULE_STARTED;
}
// Free the interface table
if (READ_WRITE_LOCK_CREATED(&(g_ITFLock)))
{
ACQUIRE_WRITE_LOCK (&(g_ITFLock));
if (g_ITFTable.pITFBuckets != NULL)
{
for (dwIndex = 0; dwIndex < INTF_TABLE_BUCKETS; dwIndex++)
{
for (pITFWalker = g_ITFTable.pITFBuckets[dwIndex].pItf;
pITFWalker != NULL;
/* NOTHING */
)
{
pITF = pITFWalker;
pITFWalker = pITFWalker->pNext;
if (pITF->pwszInterfaceDesc)
{
FREE (pITF->pwszInterfaceDesc);
}
if (pITF->pwszInterfaceGUID)
{
FREE (pITF->pwszInterfaceGUID);
}
if (pITF)
{
FREE (pITF);
}
}
}
FREE(g_ITFTable.pITFBuckets);
}
ZeroMemory (&g_ITFTable, sizeof (g_ITFTable));
RELEASE_WRITE_LOCK (&(g_ITFLock));
// Delete ITF table lock
DELETE_READ_WRITE_LOCK(&(g_ITFLock));
}
if (READ_WRITE_LOCK_CREATED(&(g_NLALock)))
{
// Delete NLA lock
DELETE_READ_WRITE_LOCK(&(g_NLALock));
}
TRACE0(INIT, "ElMediaDeInit completed");
return dwRetCode;
}
#ifdef ZEROCONFIG_LINKED
//
// ElMediaEventsHandler
//
// Description:
//
// Function called by WZC Service to signal various media events
//
// Arguments:
// pwzcDeviceNotif - Pointer to WZC_DEVICE_NOTIF structure
//
// Return values:
// NO_ERROR - Successful
// non-zero - Error
//
DWORD
ElMediaEventsHandler (
IN PWZC_DEVICE_NOTIF pwzcDeviceNotif
)
{
DWORD dwDummyValue = NO_ERROR;
DWORD dwRetCode = NO_ERROR;
do
{
TRACE0 (DEVICE, "ElMediaEventsHandler entered");
if (pwzcDeviceNotif == NULL)
{
break;
}
switch (pwzcDeviceNotif->dwEventType)
{
case WZCNOTIF_DEVICE_ARRIVAL:
TRACE0 (DEVICE, "ElMediaEventsHandler: Calling ElDeviceNotificationHandler ");
ElDeviceNotificationHandler (
(VOID *)&(pwzcDeviceNotif->dbDeviceIntf),
DBT_DEVICEARRIVAL
);
break;
case WZCNOTIF_DEVICE_REMOVAL:
TRACE0 (DEVICE, "ElMediaEventsHandler: Calling ElDeviceNotificationHandler ");
ElDeviceNotificationHandler (
(VOID *)&(pwzcDeviceNotif->dbDeviceIntf),
DBT_DEVICEREMOVECOMPLETE
);
break;
case WZCNOTIF_ADAPTER_BIND:
TRACE0 (DEVICE, "ElMediaEventsHandler: Calling ElBindingsNotificationCallback ");
ElBindingsNotificationCallback (
&(pwzcDeviceNotif->wmiNodeHdr),
0
);
break;
case WZCNOTIF_ADAPTER_UNBIND:
TRACE0 (DEVICE, "ElMediaEventsHandler: Calling ElBindingsNotificationCallback ");
ElBindingsNotificationCallback (
&(pwzcDeviceNotif->wmiNodeHdr),
0
);
break;
case WZCNOTIF_MEDIA_CONNECT:
TRACE0 (DEVICE, "ElMediaEventsHandler: Calling ElMediaSenseCallback ");
ElMediaSenseCallback (
&(pwzcDeviceNotif->wmiNodeHdr),
0
);
break;
case WZCNOTIF_MEDIA_DISCONNECT:
TRACE0 (DEVICE, "ElMediaEventsHandler: Calling ElMediaSenseCallback ");
ElMediaSenseCallback (
&(pwzcDeviceNotif->wmiNodeHdr),
0
);
break;
case WZCNOTIF_WZC_CONNECT:
TRACE0 (DEVICE, "ElMediaEventsHandler: Calling ElZeroConfigEvent ");
ElZeroConfigEvent (
pwzcDeviceNotif->wzcConfig.dwSessionHdl,
pwzcDeviceNotif->wzcConfig.wszGuid,
pwzcDeviceNotif->wzcConfig.ndSSID,
&(pwzcDeviceNotif->wzcConfig.rdEventData)
);
break;
default:
break;
}
}
while (FALSE);
return dwRetCode;
}
#endif // ZEROCONFIG_LINKED
//
// ElMediaSenseRegister
//
// Description:
//
// Function called to register CallBack function with WMI
// for MEDIA_CONNECT/MEDIA_DISCONNECT events
//
// Arguments:
// fRegister - True = Register for Media Sense
// False = Deregister Media Sense requests
// Return values:
// NO_ERROR - Successful
// non-zero - Error
//
DWORD
ElMediaSenseRegister (
IN BOOL fRegister
)
{
DWORD dwRetCode = NO_ERROR;
PVOID pvDeliveryInfo = ElMediaSenseCallback;
dwRetCode = WmiNotificationRegistration (
(LPGUID)(&GUID_NDIS_STATUS_MEDIA_CONNECT),
(BOOLEAN)fRegister,
pvDeliveryInfo,
(ULONG_PTR)NULL,
NOTIFICATION_CALLBACK_DIRECT );
if (dwRetCode != NO_ERROR)
{
TRACE1(INIT, "ElMediaSenseRegister: Error %d in WmiNotificationRegistration:GUID_NDIS_STATUS_MEDIA_CONNECT", dwRetCode);
return( dwRetCode );
}
dwRetCode = WmiNotificationRegistration (
(LPGUID)(&GUID_NDIS_STATUS_MEDIA_DISCONNECT),
(BOOLEAN)fRegister,
pvDeliveryInfo,
(ULONG_PTR)NULL,
NOTIFICATION_CALLBACK_DIRECT );
if (dwRetCode != NO_ERROR)
{
TRACE1(INIT, "ElMediaSenseRegister: Error %d in WmiNotificationRegistration:GUID_NDIS_STATUS_MEDIA_DISCONNECT", dwRetCode);
return( dwRetCode );
}
TRACE1 (INIT, "ElMediaSenseRegister - completed with RetCode %d", dwRetCode);
return( dwRetCode );
}
//
// ElDeviceNotificationRegister
//
// Description:
//
// Function called to register for device addition/removal notifications
//
// Arguments:
// fRegister - True = Register for Device Notifications
// False = Deregister Device Notifications
//
// Return values:
// NO_ERROR - Successful
// non-zero - Error
//
DWORD
ElDeviceNotificationRegister (
IN BOOL fRegister
)
{
HANDLE hDeviceNotification = NULL;
DWORD dwRetCode = NO_ERROR;
#ifdef EAPOL_SERVICE
DEV_BROADCAST_DEVICEINTERFACE PnPFilter;
if (fRegister)
{
ZeroMemory (&PnPFilter, sizeof(PnPFilter));
PnPFilter.dbcc_size = sizeof(PnPFilter);
PnPFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
PnPFilter.dbcc_classguid = GUID_NDIS_LAN_CLASS;
g_hDeviceNotification = RegisterDeviceNotification (
(HANDLE)g_hServiceStatus,
&PnPFilter,
DEVICE_NOTIFY_SERVICE_HANDLE );
if (g_hDeviceNotification == NULL)
{
dwRetCode = GetLastError();
TRACE1 (DEVICE, "ElDeviceNotificationRegister failed with error %ld",
dwRetCode);
}
}
else
{
if (g_hDeviceNotification != NULL)
{
if (!UnregisterDeviceNotification (
g_hDeviceNotification
))
{
dwRetCode = GetLastError();
TRACE1 (DEVICE, "ElDeviceNotificationRegister: Unregister failed with error (%ld)",
dwRetCode);
}
}
}
#endif
return dwRetCode;
}
//
// ElBindingsNotificationRegister
//
// Description:
//
// Function called to register CallBack function with WMI
// for protocol bind/unbind
//
// Arguments:
// fRegister - True = Register for Media Sense
// False = Deregister Media Sense requests
// Return values:
// NO_ERROR - Successful
// non-zero - Error
//
DWORD
ElBindingsNotificationRegister (
IN BOOL fRegister
)
{
DWORD dwRetCode = NO_ERROR;
PVOID pvDeliveryInfo = ElBindingsNotificationCallback;
dwRetCode = WmiNotificationRegistration (
(LPGUID)(&GUID_NDIS_NOTIFY_BIND),
(BOOLEAN)fRegister,
pvDeliveryInfo,
(ULONG_PTR)NULL,
NOTIFICATION_CALLBACK_DIRECT );
if (dwRetCode != NO_ERROR)
{
TRACE1(INIT, "ElBindingsNotificationRegister: Error %d in WmiNotificationRegistration:GUID_NDIS_NOTIFY_BIND", dwRetCode);
return( dwRetCode );
}
dwRetCode = WmiNotificationRegistration (
(LPGUID)(&GUID_NDIS_NOTIFY_UNBIND),
(BOOLEAN)fRegister,
pvDeliveryInfo,
(ULONG_PTR)NULL,
NOTIFICATION_CALLBACK_DIRECT );
if (dwRetCode != NO_ERROR)
{
TRACE1(INIT, "ElBindingsNotificationRegister: Error %d in WmiNotificationRegistration:GUID_NDIS_NOTIFY_BIND", dwRetCode);
return( dwRetCode );
}
TRACE1 (INIT, "ElBindingsNotificationRegister - completed with RetCode %d", dwRetCode);
return( dwRetCode );
}
//
// ElDeviceNotificationHandler
//
// Description:
//
// Function called to handle device notifications for interface addition/
// removal
//
// Arguments:
// lpEventData - interface information
// dwEventType - notification type
//
DWORD
ElDeviceNotificationHandler (
IN VOID *lpEventData,
IN DWORD dwEventType
)
{
DWORD dwEventStatus = 0;
DEV_BROADCAST_DEVICEINTERFACE *pInfo =
(DEV_BROADCAST_DEVICEINTERFACE *) lpEventData;
PVOID pvBuffer = NULL;
BOOLEAN fDecrWorkerThreadCount = TRUE;
DWORD dwRetCode = NO_ERROR;
InterlockedIncrement (&g_lWorkerThreads);
TRACE0 (DEVICE, "ElDeviceNotificationHandler entered");
do
{
if (g_hEventTerminateEAPOL == NULL)
{
break;
}
if (!(g_dwModulesStarted & ALL_MODULES_STARTED))
{
TRACE0 (DEVICE, "ElDeviceNotificationHandler: Received notification before module started");
break;
}
// Check if have already gone through EAPOLCleanUp before
if ((dwEventStatus = WaitForSingleObject (
g_hEventTerminateEAPOL,
0)) == WAIT_FAILED)
{
dwRetCode = GetLastError ();
TRACE1(INIT, "ElDeviceNotificationHandler: WaitForSingleObject failed with error %ld, Terminating !!!",
dwRetCode);
// log
break;
}
if (dwEventStatus == WAIT_OBJECT_0)
{
TRACE0(INIT, "ElDeviceNotificationHandler: g_hEventTerminateEAPOL already signaled, returning");
break;
}
if (lpEventData == NULL)
{
dwRetCode = ERROR_INVALID_DATA;
TRACE0 (DEVICE, "ElDeviceNotificationHandler: lpEventData == NULL");
break;
}
if (pInfo->dbcc_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
{
TRACE0 (DEVICE, "ElDeviceNotificationHandler: Event for Interface type");
if ((pvBuffer = MALLOC (pInfo->dbcc_size + 16)) == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (DEVICE, "ElDeviceNotificationHandler: MALLOC failed for pvBuffer");
break;
}
*((DWORD *)pvBuffer) = dwEventType;
memcpy ((PBYTE)pvBuffer + 8, (PBYTE)pInfo, pInfo->dbcc_size);
if (!QueueUserWorkItem (
(LPTHREAD_START_ROUTINE)ElDeviceNotificationHandlerWorker,
pvBuffer,
WT_EXECUTELONGFUNCTION))
{
dwRetCode = GetLastError();
TRACE1 (DEVICE, "ElDeviceNotificationHandler: QueueUserWorkItem failed with error %ld",
dwRetCode);
break;
}
else
{
fDecrWorkerThreadCount = FALSE;
}
}
else
{
TRACE0 (DEVICE, "ElDeviceNotificationHandler: Event NOT for Interface type");
}
}
while (FALSE);
TRACE1 (DEVICE, "ElDeviceNotificationHandler completed with retcode %ld",
dwRetCode);
if (dwRetCode != NO_ERROR)
{
if (pvBuffer != NULL)
{
FREE (pvBuffer);
}
}
if (fDecrWorkerThreadCount)
{
InterlockedDecrement (&g_lWorkerThreads);
}
return dwRetCode;
}
//
// ElDeviceNotificationHandlerWorker
//
// Description:
//
// Worker function for ElDeviceNotificationHandlerWorker
//
// Arguments:
// pvContext - interface information
//
DWORD
WINAPI
ElDeviceNotificationHandlerWorker (
IN PVOID pvContext
)
{
HANDLE hDevice = NULL;
DEV_BROADCAST_DEVICEINTERFACE *pInfo = NULL;
DWORD dwEventType = 0;
DWORD dwRetCode = NO_ERROR;
TRACE0 (DEVICE, "ElDeviceNotificationHandlerWorker: Entered");
do
{
if (pvContext == NULL)
{
TRACE0 (DEVICE, "ElDeviceNotificationHandlerWorker: pvContext == NULL");
break;
}
if (!(g_dwModulesStarted & ALL_MODULES_STARTED))
{
TRACE0 (DEVICE, "ElDeviceNotificationHandlerWorker: Received notification before module started");
break;
}
dwEventType = *((DWORD *) pvContext);
pInfo = (DEV_BROADCAST_DEVICEINTERFACE*)((PBYTE)pvContext + 8);
if ((dwEventType == DBT_DEVICEARRIVAL) ||
(dwEventType == DBT_DEVICEREMOVECOMPLETE))
{
// Extract GUID from the \Device\GUID string
WCHAR *pwszGUIDStart = NULL;
WCHAR *pwszGUIDEnd = NULL;
TRACE0 (DEVICE, "ElDeviceNotificationHandlerWorker: Interface arr/rem");
pwszGUIDStart = wcsrchr( pInfo->dbcc_name, L'{' );
pwszGUIDEnd = wcsrchr( pInfo->dbcc_name, L'}' );
if ((pwszGUIDStart != NULL) && (pwszGUIDEnd != NULL) &&
((pwszGUIDEnd- pwszGUIDStart) == (GUID_STRING_LEN_WITH_TERM-2)))
{
*(pwszGUIDEnd + 1) = L'\0';
TRACE1 (DEVICE, "ElDeviceNotificationHandlerWorker: For interface %ws",
pwszGUIDStart);
// Interface was added
if (dwEventType == DBT_DEVICEARRIVAL)
{
TRACE0(DEVICE, "ElDeviceNotificationHandlerWorker: Callback for device addition");
if ((dwRetCode = ElEnumAndOpenInterfaces (
NULL, pwszGUIDStart, 0, NULL)) != NO_ERROR)
{
TRACE1 (DEVICE, "ElDeviceNotificationHandlerWorker: ElEnumAndOpenInterfaces returned error %ld",
dwRetCode);
}
}
else
{
TRACE0(DEVICE, "ElDeviceNotificationHandlerWorker: Callback for device removal");
if ((dwRetCode = ElShutdownInterface (pwszGUIDStart))
!= NO_ERROR)
{
TRACE1 (DEVICE, "ElDeviceNotificationHandlerWorker: ElShutdownInterface failed with error %ld",
dwRetCode);
}
if ((dwRetCode = ElEnumAndUpdateRegistryInterfaceList ()) != NO_ERROR)
{
TRACE1 (DEVICE, "ElDeviceNotificationHandlerWorker: ElEnumAndUpdateRegistryInterfaceList failed with error %ld",
dwRetCode);
}
}
}
else
{
dwRetCode = ERROR_INVALID_PARAMETER;
break;
}
}
else
{
TRACE0 (DEVICE, "ElDeviceNotificationHandlerWorker: Event type is is NOT device arr/rem");
}
}
while (FALSE);
if (pvContext != NULL)
{
FREE (pvContext);
}
TRACE1 (DEVICE, "ElDeviceNotificationHandlerWorker completed with retcode %ld",
dwRetCode);
InterlockedDecrement (&g_lWorkerThreads);
return 0;
}
//
// ElMediaSenseCallback
//
// Description:
//
// Callback function called by WMI on MEDIA_CONNECT/MEDIA_DISCONNECT
// events
//
// Arguments:
// pWnodeHeader - Pointer to information returned by the event
// uiNotificationContext - unused
//
// Return values:
// NO_ERROR - Success
// non-zero - Error
//
VOID
CALLBACK
ElMediaSenseCallback (
IN PWNODE_HEADER pWnodeHeader,
IN UINT_PTR uiNotificationContext
)
{
DWORD dwEventStatus = 0;
PVOID pvBuffer = NULL;
BOOLEAN fDecrWorkerThreadCount = TRUE;
DWORD dwRetCode = NO_ERROR;
InterlockedIncrement (&g_lWorkerThreads);
TRACE0 (DEVICE, "ElMediaSenseCallback: Entered");
do
{
if (g_hEventTerminateEAPOL == NULL)
{
break;
}
if (!(g_dwModulesStarted & ALL_MODULES_STARTED))
{
TRACE0 (DEVICE, "ElMediaSenseCallback: Received notification before module started");
break;
}
// Check if have already gone through EAPOLCleanUp before
if (( dwEventStatus = WaitForSingleObject (
g_hEventTerminateEAPOL,
0)) == WAIT_FAILED)
{
dwRetCode = GetLastError ();
TRACE1 (INIT, "ElMediaSenseCallback: WaitForSingleObject failed with error %ld, Terminating !!!",
dwRetCode);
// log
break;
}
if (dwEventStatus == WAIT_OBJECT_0)
{
dwRetCode = NO_ERROR;
TRACE0 (INIT, "ElMediaSenseCallback: g_hEventTerminateEAPOL already signaled, returning");
break;
}
if (pWnodeHeader == NULL)
{
dwRetCode = ERROR_INVALID_DATA;
TRACE0 (DEVICE, "ElMediaSenseCallback: pWnodeHeader == NULL");
break;
}
if ((pvBuffer = MALLOC (pWnodeHeader->BufferSize)) == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (DEVICE, "ElMediaSenseCallback: MALLOC failed for pvBuffer");
break;
}
memcpy ((PVOID)pvBuffer, (PVOID)pWnodeHeader, pWnodeHeader->BufferSize);
if (!QueueUserWorkItem (
(LPTHREAD_START_ROUTINE)ElMediaSenseCallbackWorker,
pvBuffer,
WT_EXECUTELONGFUNCTION))
{
dwRetCode = GetLastError();
TRACE1 (DEVICE, "ElMediaSenseCallback: QueueUserWorkItem failed with error %ld",
dwRetCode);
// log
break;
}
else
{
fDecrWorkerThreadCount = FALSE;
}
}
while (FALSE);
if (dwRetCode != NO_ERROR)
{
TRACE1 (DEVICE, "ElMediaSenseCallback: Failed with error %ld",
dwRetCode);
if (pvBuffer != NULL)
{
FREE (pvBuffer);
}
}
if (fDecrWorkerThreadCount)
{
InterlockedDecrement (&g_lWorkerThreads);
}
}
//
// ElMediaSenseCallbackWorker
//
// Description:
//
// Worker function for ElMediaSenseCallback and executes in a separate
// thread
//
// Arguments:
// pvContext - Pointer to information returned by the media-sense event
//
// Return values:
// NO_ERROR - Success
// non-zero - Error
//
DWORD
WINAPI
ElMediaSenseCallbackWorker (
IN PVOID pvContext
)
{
PWNODE_HEADER pWnodeHeader = (PWNODE_HEADER)pvContext;
PWNODE_SINGLE_INSTANCE pWnode = (PWNODE_SINGLE_INSTANCE)pWnodeHeader;
WCHAR *pwsName = NULL;
WCHAR *pwszDeviceName = NULL;
WCHAR *pwsGUIDString = NULL;
WCHAR *pwszDeviceGUID = NULL;
WCHAR *pwszGUIDStart = NULL, *pwszGUIDEnd = NULL;
DWORD dwGUIDLen = 0;
USHORT cpsLength;
EAPOL_ITF *pITF;
EAPOL_PCB *pPCB = NULL;
DWORD dwRetCode = NO_ERROR;
do
{
#ifdef EAPOL_SERVICE
if ((g_ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING)
||
(g_ServiceStatus.dwCurrentState == SERVICE_STOPPED))
{
TRACE0 (DEVICE, "ElMediaSenseCallbackWorker: Callback received while service was stopping");
break;
}
#endif // EAPOL_SERVICE
if (pWnodeHeader == NULL)
{
TRACE0 (DEVICE, "ElMediaSenseCallbackWorker: Callback received with NULL NDIS interface details");
break;
}
pwsName = (PWCHAR)RtlOffsetToPointer(
pWnode,
pWnode->OffsetInstanceName );
pwsGUIDString = (PWCHAR)RtlOffsetToPointer(
pWnode,
pWnode->DataBlockOffset );
cpsLength = (SHORT)( *((SHORT *)pwsName) );
if (!(pwszDeviceName = (WCHAR *) MALLOC ((cpsLength+1)*sizeof(WCHAR))))
{
TRACE0 (DEVICE, "ElMediaSenseCallbackWorker: Error in Memory allocation for pszDeviceName");
break;
}
memcpy ((CHAR *)pwszDeviceName, (CHAR *)pwsName+sizeof(SHORT), cpsLength);
pwszDeviceName[cpsLength] = L'\0';
pwszGUIDStart = wcschr (pwsGUIDString, L'{');
pwszGUIDEnd = wcschr (pwsGUIDString, L'}');
if ((pwszGUIDStart == NULL) || (pwszGUIDEnd == NULL) || ((pwszGUIDEnd - pwszGUIDStart) != (GUID_STRING_LEN_WITH_TERM-2)))
{
TRACE0 (DEVICE, "ElMediaSenseCallbackWorker: GUID not constructed correctly");
dwRetCode = ERROR_INVALID_PARAMETER;
break;
}
dwGUIDLen = GUID_STRING_LEN_WITH_TERM;
pwszDeviceGUID = NULL;
if ((pwszDeviceGUID = MALLOC (dwGUIDLen * sizeof (WCHAR))) == NULL)
{
TRACE0 (DEVICE, "ElMediaSenseCallbackWorker: MALLOC failed for pwszDeviceGUID");
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
break;
}
memcpy ((VOID *)pwszDeviceGUID, (VOID *)pwszGUIDStart, ((dwGUIDLen-1)*sizeof(WCHAR)));
pwszDeviceGUID[dwGUIDLen-1] = L'\0';
TRACE3 (DEVICE, "ElMediaSenseCallbackWorker: For interface (%ws), GUID (%ws), length of block = %d",
pwszDeviceName, pwszDeviceGUID, cpsLength);
//
// Get the information for the media disconnect.
//
if (memcmp( &(pWnodeHeader->Guid),
&GUID_NDIS_STATUS_MEDIA_DISCONNECT,
sizeof(GUID)) == 0)
{
// MEDIA DISCONNECT callback
DbLogPCBEvent (DBLOG_CATEG_INFO, NULL, EAPOL_MEDIA_DISCONNECT, pwszDeviceName);
// Check if EAPOL was actually started on this interface
// Verify by checking existence of corresponding entry in hash table
TRACE0(DEVICE, "ElMediaSenseCallbackWorker: Callback for sense disconnect");
ACQUIRE_WRITE_LOCK (&(g_PCBLock));
pPCB = ElGetPCBPointerFromPortGUID (pwszDeviceGUID);
if (pPCB != NULL)
{
ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
if ((dwRetCode = FSMDisconnected (pPCB, NULL)) != NO_ERROR)
{
TRACE1 (DEVICE, "ElMediaSenseCallbackWorker: FSMDisconnected failed with error %ld",
dwRetCode);
}
else
{
TRACE1 (DEVICE, "ElMediaSenseCallbackWorker: Port marked disconnected %ws",
pwszDeviceName);
}
RELEASE_WRITE_LOCK (&(pPCB->rwLock));
}
RELEASE_WRITE_LOCK (&(g_PCBLock));
}
else
{
if (memcmp( &(pWnodeHeader->Guid),
&GUID_NDIS_STATUS_MEDIA_CONNECT,
sizeof(GUID)) == 0)
{
// MEDIA CONNECT callback
DbLogPCBEvent (DBLOG_CATEG_INFO, NULL, EAPOL_MEDIA_CONNECT, pwszDeviceName);
TRACE0(DEVICE, "ElMediaSenseCallbackWorker: Callback for sense connect");
if ((dwRetCode = ElEnumAndOpenInterfaces (
NULL, pwszDeviceGUID, 0, NULL))
!= NO_ERROR)
{
TRACE1 (DEVICE, "ElMediaSenseCallbackWorker: ElEnumAndOpenInterfaces returned error %ld",
dwRetCode);
}
}
}
}
while (FALSE);
TRACE1 (DEVICE, "ElMediaSenseCallbackWorker: processed, RetCode = %ld", dwRetCode);
if (pWnodeHeader != NULL)
{
FREE (pWnodeHeader);
}
if (pwszDeviceName != NULL)
{
FREE (pwszDeviceName);
}
if (pwszDeviceGUID != NULL)
{
FREE (pwszDeviceGUID);
}
InterlockedDecrement (&g_lWorkerThreads);
return 0;
}
//
// ElBindingsNotificationCallback
//
// Description:
//
// Callback function called by WMI on protocol bind/unbind
// events
//
// Arguments:
// pWnodeHeader - Pointer to information returned by the event
// uiNotificationContext - unused
//
// Return values:
// NO_ERROR - Success
// non-zero - Error
//
VOID
CALLBACK
ElBindingsNotificationCallback (
IN PWNODE_HEADER pWnodeHeader,
IN UINT_PTR uiNotificationContext
)
{
DWORD dwEventStatus = 0;
PVOID pvBuffer = NULL;
BOOLEAN fDecrWorkerThreadCount = TRUE;
DWORD dwRetCode = NO_ERROR;
InterlockedIncrement (&g_lWorkerThreads);
TRACE0 (DEVICE, "ElBindingsNotificationCallback: Entered");
do
{
if (g_hEventTerminateEAPOL == NULL)
{
break;
}
if (!(g_dwModulesStarted & ALL_MODULES_STARTED))
{
TRACE0 (DEVICE, "ElBindingsNotificationCallback: Received notification before module started");
break;
}
// Check if have already gone through EAPOLCleanUp before
if (( dwEventStatus = WaitForSingleObject (
g_hEventTerminateEAPOL,
0)) == WAIT_FAILED)
{
dwRetCode = GetLastError ();
TRACE1 (INIT, "ElBindingsNotificationCallback: WaitForSingleObject failed with error %ld, Terminating !!!",
dwRetCode);
break;
}
if (dwEventStatus == WAIT_OBJECT_0)
{
dwRetCode = NO_ERROR;
TRACE0 (INIT, "ElBindingsNotificationCallback: g_hEventTerminateEAPOL already signaled, returning");
break;
}
if (pWnodeHeader == NULL)
{
dwRetCode = ERROR_INVALID_DATA;
TRACE0 (DEVICE, "ElBindingsNotificationCallback: pWnodeHeader == NULL");
break;
}
if ((pvBuffer = MALLOC (pWnodeHeader->BufferSize)) == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (DEVICE, "ElBindingsNotificationCallback: MALLOC failed for pvBuffer");
break;
}
memcpy ((PVOID)pvBuffer, (PVOID)pWnodeHeader, pWnodeHeader->BufferSize);
if (!QueueUserWorkItem (
(LPTHREAD_START_ROUTINE)ElBindingsNotificationCallbackWorker,
pvBuffer,
WT_EXECUTELONGFUNCTION))
{
dwRetCode = GetLastError();
TRACE1 (DEVICE, "ElBindingsNotificationCallback: QueueUserWorkItem failed with error %ld",
dwRetCode);
// log
break;
}
else
{
fDecrWorkerThreadCount = FALSE;
}
}
while (FALSE);
if (dwRetCode != NO_ERROR)
{
TRACE1 (DEVICE, "ElBindingsNotificationCallback: Failed with error %ld",
dwRetCode);
if (pvBuffer != NULL)
{
FREE (pvBuffer);
}
}
if (fDecrWorkerThreadCount)
{
InterlockedDecrement (&g_lWorkerThreads);
}
}
//
// ElBindingsNotificationCallbackWorker
//
// Description:
//
// Worker function for ElBindingsNotificationCallback and executes in a separate
// thread
//
// Arguments:
// pvContext - Pointer to information returned by the protocol bind/unbind
// event
//
// Return values:
// NO_ERROR - Success
// non-zero - Error
//
DWORD
WINAPI
ElBindingsNotificationCallbackWorker (
IN PVOID pvContext
)
{
PWNODE_HEADER pWnodeHeader = (PWNODE_HEADER)pvContext;
PWNODE_SINGLE_INSTANCE pWnode = (PWNODE_SINGLE_INSTANCE)pWnodeHeader;
WCHAR *pwsName = NULL;
WCHAR *pwszDeviceGUID = NULL;
WCHAR *pwszGUIDStart = NULL, *pwszGUIDEnd = NULL;
DWORD dwGUIDLen = 0;
WCHAR *pwsTransportName = NULL;
WCHAR *pwszDeviceName = NULL;
USHORT cpsLength;
EAPOL_ITF *pITF = NULL;
EAPOL_PCB *pPCB = NULL;
DWORD dwRetCode = NO_ERROR;
do
{
#ifdef EAPOL_SERVICE
if ((g_ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING)
||
(g_ServiceStatus.dwCurrentState == SERVICE_STOPPED))
{
TRACE0 (DEVICE, "ElBindingsNotificationCallbackWorker: Callback received while service was stopping");
break;
}
#endif // EAPOL_SERVICE
if (pWnodeHeader == NULL)
{
TRACE0 (DEVICE, "ElBindingsNotificationCallbackWorker: Callback received with NULL NDIS interface details");
break;
}
pwsName = (PWCHAR)RtlOffsetToPointer(
pWnode,
pWnode->OffsetInstanceName );
pwsTransportName = (PWCHAR)RtlOffsetToPointer(
pWnode,
pWnode->DataBlockOffset );
if (wcsncmp (cwszNDISUIOProtocolName, pwsTransportName, wcslen (cwszNDISUIOProtocolName)))
{
TRACE1 (DEVICE, "ElBindingsNotificationCallbackWorker: Protocol binding (%ws) not for NDISUIO",
pwsTransportName);
break;
}
// Get the length of the device name string and null terminate it
cpsLength = (SHORT)( *((SHORT *)pwsName) );
if (!(pwszDeviceName = (WCHAR *) MALLOC ((cpsLength+1)*sizeof(WCHAR))))
{
TRACE0 (DEVICE, "ElBindingsNotificationCallbackWorker: Error in Memory allocation for pwszDeviceName");
break;
}
memcpy ((CHAR *)pwszDeviceName, (CHAR *)pwsName+sizeof(SHORT), cpsLength);
pwszDeviceName[cpsLength] = L'\0';
pwszDeviceGUID = pwsTransportName + wcslen(cwszNDISUIOProtocolName) + 1;
pwszGUIDStart = wcschr (pwszDeviceGUID, L'{');
pwszGUIDEnd = wcschr (pwszDeviceGUID, L'}');
pwszDeviceGUID = NULL;
if ((pwszGUIDStart == NULL) || (pwszGUIDEnd == NULL) || ((pwszGUIDEnd - pwszGUIDStart) != (GUID_STRING_LEN_WITH_TERM-2)))
{
TRACE0 (DEVICE, "ElBindingsNotificationCallbackWorker: GUID not constructed correctly");
dwRetCode = ERROR_INVALID_PARAMETER;
break;
}
dwGUIDLen = GUID_STRING_LEN_WITH_TERM;
if ((pwszDeviceGUID = MALLOC (dwGUIDLen * sizeof (WCHAR))) == NULL)
{
TRACE0 (DEVICE, "ElBindingsNotificationCallbackWorker: MALLOC failed for pwszDeviceGUID");
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
break;
}
memcpy ((VOID *)pwszDeviceGUID, (VOID *)pwszGUIDStart, ((dwGUIDLen-1)*sizeof(WCHAR)));
pwszDeviceGUID[dwGUIDLen-1] = L'\0';
TRACE2 (DEVICE, "ElBindingsNotificationCallbackWorker: For interface = %ws, guid=%ws",
pwszDeviceName, pwszDeviceGUID);
//
// Get the information for the protocol UNBIND
//
if (memcmp( &(pWnodeHeader->Guid),
&GUID_NDIS_NOTIFY_UNBIND,
sizeof(GUID)) == 0)
{
// Protocol UNBIND callback
DbLogPCBEvent (DBLOG_CATEG_INFO, NULL, EAPOL_NDISUIO_UNBIND, pwszDeviceName);
TRACE0(DEVICE, "ElBindingsNotificationCallbackWorker: Callback for protocol unbind");
if ((dwRetCode = ElShutdownInterface (pwszDeviceGUID)) != ERROR)
{
TRACE2 (DEVICE, "ElBindingsNotificationCallbackWorker: ElShutdownInterface failed with error %ld for (%ws)",
dwRetCode, pwszDeviceGUID);
}
if ((dwRetCode = ElEnumAndUpdateRegistryInterfaceList ()) != NO_ERROR)
{
TRACE1 (DEVICE, "ElBindingsNotificationCallbackWorker: ElEnumAndUpdateRegistryInterfaceList failed with error %ld",
dwRetCode);
}
}
else
{
if (memcmp( &(pWnodeHeader->Guid),
&GUID_NDIS_NOTIFY_BIND,
sizeof(GUID)) == 0)
{
// protocol BIND callback
DbLogPCBEvent (DBLOG_CATEG_INFO, NULL, EAPOL_NDISUIO_BIND, pwszDeviceName);
TRACE0(DEVICE, "ElBindingsNotificationCallbackWorker: Callback for protocol BIND");
if ((dwRetCode = ElEnumAndOpenInterfaces (
NULL, pwszDeviceGUID, 0, NULL))
!= NO_ERROR)
{
TRACE1 (DEVICE, "ElBindingsNotificationCallbackWorker: ElEnumAndOpenInterfaces returned error %ld",
dwRetCode);
}
}
}
}
while (FALSE);
TRACE1 (DEVICE, "ElBindingsNotificationCallbackWorker: processed, RetCode = %ld", dwRetCode);
if (pWnodeHeader != NULL)
{
FREE (pWnodeHeader);
}
if (pwszDeviceName != NULL)
{
FREE (pwszDeviceName);
}
if (pwszDeviceGUID != NULL)
{
FREE (pwszDeviceGUID);
}
InterlockedDecrement (&g_lWorkerThreads);
return 0;
}
//
// ElEnumAndOpenInterfaces
//
// Description:
//
// Enumerates interfaces and intializes EAPOL on desired ones.
//
// If EAPOL is to be started on an interface, it opens a handle to
// the NDISUIO driver, calls EAPOL to create and initialize PCB for the
// interface, and finally adds an entry to the interface hashtable.
//
// If pwszDesiredGUID is not NULL, all interfaces are enumerated, but
// EAPOL will be initialized only on the interface whose GUID matches.
//
// If pwszDesiredDescription is not NULL, all interfaces are enumerated, but
// EAPOL will be initialized only on the interface whose description matches.
//
// If pwszDesiredGUID and pwszDescription are both NULL, all interfaces are
// enumerated. EAPOL will be initialized only on all interfaces that
// does have an entry in the interface hashtable.
//
//
// Arguments:
// pwszDesiredDescription - Interface Description on which EAPOL is to
// be started
// pwszDesiredGUID - Interface GUID on which EAPOL is to be started
//
// Return values:
// NO_ERROR - Success
// non-zero - Error
//
DWORD
ElEnumAndOpenInterfaces (
WCHAR *pwszDesiredDescription,
WCHAR *pwszDesiredGUID,
DWORD dwHandle,
PRAW_DATA prdUserData
)
{
CHAR EnumerateBuffer[256];
PNDIS_ENUM_INTF Interfaces = NULL;
BYTE *pbNdisuioEnumBuffer = NULL;
DWORD dwNdisuioEnumBufferSize = 0;
HANDLE hDevice = NULL;
BOOL fSearchByDescription = FALSE;
BOOL fSearchByGUID = FALSE;
DWORD dwEapTypeToBeUsed = DEFAULT_EAP_TYPE;
WCHAR cwsDummyBuffer[256], *pDummyPtr = NULL;
WCHAR *pwszGUIDStart = NULL;
EAPOL_PCB *pPCB = NULL;
BOOL fPCBExists = FALSE;
BOOL fPCBReferenced = FALSE;
DWORD dwAvailableInterfaces = 0;
EAPOL_INTF_PARAMS EapolIntfParams;
DWORD dwRetCode = NO_ERROR;
TRACE2 (DEVICE, "ElEnumAndOpenInterfaces: DeviceDesc = %ws, GUID = %ws",
pwszDesiredDescription, pwszDesiredGUID);
ACQUIRE_WRITE_LOCK (&(g_ITFLock));
if (pwszDesiredGUID == NULL)
{
if (pwszDesiredDescription != NULL)
{
fSearchByDescription = TRUE;
}
}
else
{
if (pwszDesiredDescription != NULL)
{
RELEASE_WRITE_LOCK (&(g_ITFLock));
return ERROR;
}
fSearchByGUID = TRUE;
}
ZeroMemory (EnumerateBuffer, 256);
Interfaces = (PNDIS_ENUM_INTF)EnumerateBuffer;
//
// Allocate amount of memory as instructed by NdisEnumerateInterfaces
// once the API allows querying of bytes required
//
Interfaces->TotalInterfaces = 0;
Interfaces->AvailableInterfaces = 0;
Interfaces->BytesNeeded = 0;
if (!NdisEnumerateInterfaces(Interfaces, 256))
{
RELEASE_WRITE_LOCK (&(g_ITFLock));
dwRetCode = GetLastError ();
TRACE1 (DEVICE, "ElEnumAndOpenInterfaces: NdisEnumerateInterfaces failed with error %ld",
dwRetCode);
return dwRetCode;
}
dwNdisuioEnumBufferSize = (Interfaces->BytesNeeded + 7) & 0xfffffff8;
dwAvailableInterfaces = Interfaces->AvailableInterfaces;
if (dwNdisuioEnumBufferSize == 0)
{
RELEASE_WRITE_LOCK (&(g_ITFLock));
TRACE0 (DEVICE, "ElEnumAndOpenInterfaces: MALLOC skipped for pbNdisuioEnumBuffer as dwNdisuioEnumBufferSize == 0");
dwRetCode = NO_ERROR;
return dwRetCode;
}
pbNdisuioEnumBuffer = (BYTE *) MALLOC (4*dwNdisuioEnumBufferSize);
if (pbNdisuioEnumBuffer == NULL)
{
RELEASE_WRITE_LOCK (&(g_ITFLock));
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (DEVICE, "ElEnumAndOpenInterfaces: MALLOC failed for pbNdisuioEnumBuffer");
return dwRetCode;
}
Interfaces = (PNDIS_ENUM_INTF)pbNdisuioEnumBuffer;
// Enumerate all the interfaces present on the machine
if ((dwRetCode = ElNdisuioEnumerateInterfaces (
Interfaces,
dwAvailableInterfaces,
4*dwNdisuioEnumBufferSize)) == NO_ERROR)
{
UNICODE_STRING *pInterfaceName = NULL;
UNICODE_STRING *pInterfaceDescription = NULL;
DWORD i;
// Update the interface list in the registry that NDISUIO has bound to.
// The current interface list is just overwritten into the registry.
if ((dwRetCode = ElUpdateRegistryInterfaceList (Interfaces))
!= NO_ERROR)
{
TRACE1 (DEVICE, "ElEnumAndOpenInterfaces: ElUpdateInterfaceList failed with error =%ld",
dwRetCode);
dwRetCode = NO_ERROR;
// log
}
for (i=0; i < Interfaces->TotalInterfaces; i++)
{
fPCBExists = fPCBReferenced = FALSE;
if ((dwRetCode != NO_ERROR) &&
(fSearchByDescription || fSearchByGUID))
{
break;
}
else
{
dwRetCode = NO_ERROR;
}
if (Interfaces->Interface[i].DeviceName.Buffer != NULL)
{
pInterfaceName = &(Interfaces->Interface[i].DeviceName);
}
else
{
TRACE0(INIT, "NdisEnumerateInterfaces: Device Name was NULL");
continue;
}
TRACE1(INIT, "Device: %ws", pInterfaceName->Buffer);
if (Interfaces->Interface[i].DeviceDescription.Buffer != NULL)
{
pInterfaceDescription = &(Interfaces->Interface[i].DeviceDescription);
}
else
{
TRACE0(INIT, "NdisEnumerateInterfaces: Device Description was NULL");
continue;
}
TRACE1(INIT, "Description: %ws", pInterfaceDescription->Buffer);
// EAPOL requested be started only a particular
// interface
if (fSearchByDescription)
{
if (wcscmp (pInterfaceDescription->Buffer,
pwszDesiredDescription)
!= 0)
{
// No match, continue with next interface
continue;
}
TRACE1 (DEVICE, "ElEnumAndOpenInterfaces: Found interface after enumeration %ws", pInterfaceDescription->Buffer);
}
if (fSearchByGUID)
{
if (wcsstr (pInterfaceName->Buffer,
pwszDesiredGUID)
== NULL)
{
// No match, continue with next interface
continue;
}
TRACE1 (DEVICE, "ElEnumAndOpenInterfaces: Found interface after enumeration %ws", pInterfaceName->Buffer);
}
{
// Extract GUID-string out of device name
WCHAR *pwszGUIDEnd = NULL;
WCHAR *pwszGUID = NULL;
WCHAR wchGUIDSaveLast;
pwszGUID = pInterfaceName->Buffer;
pwszGUIDStart = wcschr( pwszGUID, L'{' );
pwszGUIDEnd = wcschr( pwszGUID, L'}' );
if (pwszGUIDStart != NULL)
{
wchGUIDSaveLast = *(pwszGUIDEnd+1);
*(pwszGUIDEnd+1) = (WCHAR)NULL;
}
// Verify if a PCB already exists for the interface
// This is possible if no media disconnect was received
// after the initial media connect
pPCB = NULL;
hDevice = NULL;
ACQUIRE_WRITE_LOCK (&(g_PCBLock));
if ((pPCB = ElGetPCBPointerFromPortGUID (pwszGUIDStart)) != NULL)
{
if (EAPOL_REFERENCE_PORT (pPCB))
{
fPCBReferenced = TRUE;
}
}
RELEASE_WRITE_LOCK (&(g_PCBLock));
// Restore interface buffer
*(pwszGUIDEnd+1) = wchGUIDSaveLast;
if (pPCB != NULL)
{
// Point to existing handle
hDevice = pPCB->hPort;
fPCBExists = TRUE;
dwRetCode = NO_ERROR;
TRACE0 (INIT, "ElEnumAndOpenInterfaces: Found PCB already existing for interface");
}
else
{
TRACE0 (INIT, "ElEnumAndOpenInterfaces: Did NOT find PCB already existing for interface");
// Open handle to ndisuio driver
if ((dwRetCode = ElOpenInterfaceHandle (
pInterfaceName->Buffer,
&hDevice
)) != NO_ERROR)
{
TRACE1 (INIT, "ElEnumAndOpenInterfaces: ElOpenInterfaceHandle failed with error = %d\n",
dwRetCode );
}
}
*(pwszGUIDEnd+1) = (CHAR)NULL;
}
if (dwRetCode != NO_ERROR)
{
TRACE0 (INIT, "ElEnumAndOpenInterfaces: Failed to open handle");
continue;
}
else
{
// Create EAPOL PCB and start state machine
if ((dwRetCode = ElCreatePort (
hDevice,
pwszGUIDStart,
pInterfaceDescription->Buffer,
dwHandle,
prdUserData
)) != NO_ERROR)
{
TRACE1 (DEVICE, "ElEnumAndOpenInterfaces: Error in CreatePort = %d", dwRetCode);
if (fPCBExists)
{
if (dwRetCode = ElShutdownInterface (
pPCB->pwszDeviceGUID
) != NO_ERROR)
{
TRACE1 (DEVICE, "ElEnumAndOpenInterfaces: ElShutdownInterface handle 1 failed with error %ld",
dwRetCode);
}
if (fPCBReferenced)
{
EAPOL_DEREFERENCE_PORT (pPCB);
}
}
else
{
// Close the handle just opened to the ndisuio driver
if ((dwRetCode = ElCloseInterfaceHandle (
hDevice,
pwszGUIDStart)) != NO_ERROR)
{
TRACE1 (DEVICE,
"ElEnumAndOpenInterfaces: Error in ElCloseInterfaceHandle %d",
dwRetCode);
}
}
// Continue with the next interface
continue;
}
else
{
TRACE0 (DEVICE, "ElEnumAndOpenInterfaces: CreatePort successful");
// If PCB already existed, do not add to the hash
// table
if (fPCBExists)
{
TRACE0 (DEVICE, "ElEnumAndOpenInterfaces: PCB already existed, skipping Interface hash table addition");
fPCBExists = FALSE;
if (fPCBReferenced)
{
EAPOL_DEREFERENCE_PORT (pPCB);
}
continue;
}
if ((dwRetCode = ElCreateInterfaceEntry (
pwszGUIDStart,
pInterfaceDescription->Buffer
)) != NO_ERROR)
{
// Could not create new interface entry
// Delete Port entry created for this GUID
if ((dwRetCode = ElDeletePort (
pwszGUIDStart,
&hDevice)) != NO_ERROR)
{
TRACE1 (DEVICE, "ElEnumAndOpenInterfaces: Error in deleting port for %ws",
pwszGUIDStart);
// log
}
// Close the handle to the NDISUIO driver
if ((dwRetCode = ElCloseInterfaceHandle (
hDevice,
pwszGUIDStart)) != NO_ERROR)
{
TRACE1 (DEVICE,
"ElEnumAndOpenInterfaces: Error in ElCloseInterfaceHandle %d",
dwRetCode);
// log
}
}
}
}
} // for (i=0; i < Interfaces
}
else
{
TRACE1(INIT, "ElEnumAndOpenInterfaces: ElNdisuioEnumerateInterfaces failed with error %d",
dwRetCode);
}
TRACE1(INIT, "ElEnumAndOpenInterfaces: Completed with retcode = %d",
dwRetCode);
if (pbNdisuioEnumBuffer != NULL)
{
FREE(pbNdisuioEnumBuffer);
}
RELEASE_WRITE_LOCK (&(g_ITFLock));
return dwRetCode;
}
//
// ElOpenInterfaceHandle
//
// Description:
//
// Function called to open handle to the NDISUIO driver for an interface.
//
// Arguments:
// DeviceName - Identifier for the interface is of the
// form \Device\{GUID String}
// phDevice - Output pointer to handle of NDISUIO driver for
// the interface
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
DWORD
ElOpenInterfaceHandle (
IN WCHAR *pwszDeviceName,
OUT HANDLE *phDevice
)
{
DWORD dwDesiredAccess;
DWORD dwShareMode;
LPSECURITY_ATTRIBUTES lpSecurityAttributes = NULL;
DWORD dwCreationDistribution;
DWORD dwFlagsAndAttributes;
HANDLE hTemplateFile;
HANDLE hHandle = INVALID_HANDLE_VALUE;
DWORD dwRetCode = NO_ERROR;
WCHAR wNdisDeviceName[MAX_NDIS_DEVICE_NAME_LEN];
INT wNameLength;
INT NameLength = wcslen(pwszDeviceName);
DWORD dwBytesReturned;
USHORT wEthernetType = g_wEtherType8021X;
INT i;
dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
dwCreationDistribution = OPEN_EXISTING;
dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED;
hTemplateFile = (HANDLE)INVALID_HANDLE_VALUE;
TRACE1 (INIT, "ElOpenInterfaceHandle: Opening handle for %ws",
pwszDeviceName);
do
{
// Convert to unicode string - non-localized...
wNameLength = 0;
for (i = 0; (i < NameLength) && (i < MAX_NDIS_DEVICE_NAME_LEN-1); i++)
{
wNdisDeviceName[i] = (WCHAR)pwszDeviceName[i];
wNameLength++;
}
wNdisDeviceName[i] = L'\0';
TRACE1(DEVICE, "ElOpenInterfaceHandle: Trying to access NDIS Device: %ws\n",
wNdisDeviceName);
// --ft: Replace these calls to Ndisuio with the calls to the opened handles hash.
//hHandle = CreateFileA(
// pNdisuioDevice,
// dwDesiredAccess,
// dwShareMode,
// lpSecurityAttributes,
// dwCreationDistribution,
// dwFlagsAndAttributes,
// hTemplateFile
// );
//
//if (hHandle == INVALID_HANDLE_VALUE)
//{
// *phDevice = NULL;
// dwRetCode = GetLastError();
// TRACE1 (INIT, "ElOpenInterfaceHandle: Failed in CreateFile with error %d", dwRetCode);
// break;
//}
//else
//{
// *phDevice = hHandle;
//}
//
//if (!(DeviceIoControl(
// *phDevice,
// IOCTL_NDISUIO_OPEN_DEVICE,
// (LPVOID)&wNdisDeviceName[0],
// wNameLength*sizeof(WCHAR),
// NULL,
// 0,
// &dwBytesReturned,
// NULL)))
//
//{
// *phDevice = NULL;
// if ((dwRetCode = GetLastError()) == 0)
// {
// dwRetCode = ERROR_IO_DEVICE;
// }
// TRACE1(DEVICE, "ElOpenInterfaceHandle: Error in accessing NDIS Device: %ws", wNdisDeviceName);
// break;
//}
// The call below goes to the opened handles hash which takes care of
// sharing the handles. EAPOL doesn't have to care about anyone else
// using this handle - the sharing hash keeps a ref count for the handle
// such that the callers can just call OpenIntfHandle & CloseIntfHandle
// whenever they wish.
dwRetCode = OpenIntfHandle(
wNdisDeviceName,
&hHandle);
if (dwRetCode != ERROR_SUCCESS)
{
TRACE1(DEVICE, "ElOpenInterfaceHandle: Error in OpenIntfHandle(%ws)", wNdisDeviceName);
break;
}
*phDevice = hHandle;
TRACE2(DEVICE, "ElOpenInterfaceHandle: OpenIntfHandle(%ws) = %d", wNdisDeviceName, *phDevice);
// IOCTL down the Ethernet type
if (!(DeviceIoControl(
*phDevice,
IOCTL_NDISUIO_SET_ETHER_TYPE,
(LPVOID)&wEthernetType,
sizeof(USHORT),
NULL,
0,
&dwBytesReturned,
NULL)))
{
*phDevice = NULL;
if ((dwRetCode = GetLastError()) == 0)
{
dwRetCode = ERROR_IO_DEVICE;
}
TRACE1(DEVICE, "ElOpenInterfaceHandle: Error in ioctling ETHER type : %ws", wNdisDeviceName);
break;
}
// Bind for asynchronous I/O handling of Read/Write data
// Depending on whether it is completion for Readfile() or WriteFile()
// ElIoCompletionRoutine will call ElReadCompletionRoutine
// or ElWriteCompletionRoutine
if (!BindIoCompletionCallback(
*phDevice,
ElIoCompletionRoutine,
0
))
{
dwRetCode = GetLastError();
if (dwRetCode != ERROR_INVALID_PARAMETER)
{
*phDevice = NULL;
TRACE1 (DEVICE, "ElOpenInterfaceHandle: Error in BindIoCompletionCallBac %d", dwRetCode);
break;
}
else
{
TRACE0 (DEVICE, "ElOpenInterfaceHandle: BindIoCompletionCallback already done !!!");
dwRetCode = NO_ERROR;
}
}
} while (FALSE);
// Cleanup if there is error
if (dwRetCode != NO_ERROR)
{
if (hHandle != INVALID_HANDLE_VALUE)
{
// --ft: if anything bad happened, don't overwrite the dwRetCode - we're interested
// what the first error was, not the error that might have happened when we
// tried to close the hHandle.
// Note: ElCloseInterfaceHandle understands the Guid both decorated and un-decorated
if (ElCloseInterfaceHandle(hHandle, pwszDeviceName) != ERROR_SUCCESS)
{
TRACE1 (INIT, "ElOpenInterfaceHandle: Error in CloseHandle %d", dwRetCode);
}
}
}
TRACE2 (INIT, "ElOpenInterfaceHandle: Opened handle %p with dwRetCode %d", *phDevice, dwRetCode);
return (dwRetCode);
}
//
// ElCloseInterfaceHandle
//
// Description:
//
// Function called to close handle to NDISUIO driver for an interface
//
// Arguments:
// hDevice - Handle to NDISUIO device for the interface
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
DWORD
ElCloseInterfaceHandle (
IN HANDLE hDevice,
IN LPWSTR pwszDeviceGuid
)
{
DWORD dwRetCode = ERROR_SUCCESS;
WCHAR wNdisDeviceName[MAX_NDIS_DEVICE_NAME_LEN];
TRACE2 (DEVICE, "ElCloseInterfaceHandle(0x%x,%ws) entered", hDevice, pwszDeviceGuid);
ZeroMemory (wNdisDeviceName, MAX_NDIS_DEVICE_NAME_LEN);
// if first char in the Guid is '\' then we assume the GUID format is
// '\DEVICE\{...}'. We do just the UNICODE conversion then
if (pwszDeviceGuid[0] == '\\')
{
wcscpy (wNdisDeviceName, pwszDeviceGuid);
}
// else, we assume the Guid is un-decorated, and we add the decorations.
else
{
wcscpy(wNdisDeviceName, L"\\DEVICE\\");
wcsncat(wNdisDeviceName, pwszDeviceGuid, MAX_NDIS_DEVICE_NAME_LEN - 8);
wNdisDeviceName[MAX_NDIS_DEVICE_NAME_LEN-1]=L'\0';
}
// --ft: For now, don't go directly to Ndisuio to close handles. Instead,
// go to the opened handles hash. This takes care of all the handle sharing
// problem.
dwRetCode = CloseIntfHandle(wNdisDeviceName);
//if (!CloseHandle(hDevice))
//{
// dwRetCode = GetLastError();
//}
if (dwRetCode != ERROR_SUCCESS)
{
TRACE1 (INIT, "ElCloseInterfaceHandle: Error in CloseHandle %d",
dwRetCode);
}
return dwRetCode;
}
//
// ElReadFromInterface
//
// Description:
//
// Function called to perform Overlapped read on handle to NDISUIO driver
//
// Arguments:
// hDevice - Handle to NDISUIO driver for this interface
// pElBuffer - Context buffer
// dwBufferLength - Bytes to be read
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
DWORD
ElReadFromInterface (
IN HANDLE hDevice,
IN PEAPOL_BUFFER pElBuffer,
IN DWORD dwBufferLength
)
{
DWORD dwRetCode = NO_ERROR;
if (!ReadFile (
hDevice,
pElBuffer->pBuffer,
dwBufferLength,
NULL,
&pElBuffer->Overlapped
))
{
dwRetCode = GetLastError();
if (dwRetCode == ERROR_IO_PENDING)
{
// Pending status is fine, we are doing OVERLAPPED read
dwRetCode = NO_ERROR;
}
else
{
TRACE1 (DEVICE, "ElReadFromInterface: ReadFile failed with error %d",
dwRetCode);
}
}
return dwRetCode;
}
//
// ElWriteToInterface
//
// Description:
//
// Function called to perform Overlapped write on handle to NDISUIO driver
//
// Arguments:
// hDevice - Handle to NDISUIO device for this interface
// pElBuffer - Context buffer
// dwBufferLength - Bytes to be written
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
DWORD
ElWriteToInterface (
IN HANDLE hDevice,
IN PEAPOL_BUFFER pElBuffer,
IN DWORD dwBufferLength
)
{
DWORD dwRetCode = NO_ERROR;
TRACE0 (DEVICE, "ElWriteToInterface entered");
if (!WriteFile (
hDevice,
pElBuffer->pBuffer,
dwBufferLength,
NULL,
&pElBuffer->Overlapped
))
{
dwRetCode = GetLastError();
if (dwRetCode == ERROR_IO_PENDING)
{
// Pending status is fine, we are doing OVERLAPPED write
dwRetCode = NO_ERROR;
}
else
{
TRACE1 (DEVICE, "ElWriteToInterface: WriteFile failed with error %d",
dwRetCode);
}
}
TRACE1 (DEVICE, "ElWriteToInterface completed, RetCode = %d", dwRetCode);
return dwRetCode;
}
//
// ElHashInterfaceDescToBucket
//
// Description:
//
// Function called to convert Friendly name of interface into interface hash
// table index.
//
// Arguments:
// pwszInterfaceDesc - Friendly name of the interface
//
// Return values:
// Hash table index between from 0 to INTF_TABLE_BUCKETS-1
//
DWORD
ElHashInterfaceDescToBucket (
IN WCHAR *pwszInterfaceDesc
)
{
return ((DWORD)((_wtol(pwszInterfaceDesc)) % INTF_TABLE_BUCKETS));
}
//
// ElGetITFPointerFromInterfaceDesc
//
// Description:
//
// Function called to convert Friendly name of interface to ITF entry pointer
//
// Arguments:
// pwszInterfaceDesc - Friendly name of the interface
//
// Return values:
// Pointer to interface entry in hash table
//
PEAPOL_ITF
ElGetITFPointerFromInterfaceDesc (
IN WCHAR *pwszInterfaceDesc
)
{
EAPOL_ITF *pITFWalker = NULL;
DWORD dwIndex;
INT i=0;
TRACE1 (DEVICE, "ElGetITFPointerFromInterfaceDesc: Desc = %ws", pwszInterfaceDesc);
if (pwszInterfaceDesc == NULL)
{
return (NULL);
}
dwIndex = ElHashInterfaceDescToBucket (pwszInterfaceDesc);
TRACE1 (DEVICE, "ElGetITFPointerFromItfDesc: Index %d", dwIndex);
for (pITFWalker = g_ITFTable.pITFBuckets[dwIndex].pItf;
pITFWalker != NULL;
pITFWalker = pITFWalker->pNext
)
{
if (wcsncmp (pITFWalker->pwszInterfaceDesc, pwszInterfaceDesc, wcslen(pwszInterfaceDesc)) == 0)
{
return pITFWalker;
}
}
return (NULL);
}
//
// ElRemoveITFFromTable
//
// Description:
//
// Function called to remove an interface entry from the interface hash
// table
//
// Arguments:
// pITF - Point to the Interface entry in the hash table
//
// Return values:
//
VOID
ElRemoveITFFromTable (
IN EAPOL_ITF *pITF
)
{
DWORD dwIndex;
EAPOL_ITF *pITFWalker = NULL;
EAPOL_ITF *pITFTemp = NULL;
if (pITF == NULL)
{
TRACE0 (EAPOL, "ElRemoveITFFromTable: Deleting NULL ITF, returning");
return;
}
dwIndex = ElHashInterfaceDescToBucket (pITF->pwszInterfaceDesc);
pITFWalker = g_ITFTable.pITFBuckets[dwIndex].pItf;
pITFTemp = pITFWalker;
while (pITFTemp != NULL)
{
if (wcsncmp (pITFTemp->pwszInterfaceGUID,
pITF->pwszInterfaceGUID, wcslen(pITF->pwszInterfaceGUID)) == 0)
{
// Entry is at head of list in table
if (pITFTemp == g_ITFTable.pITFBuckets[dwIndex].pItf)
{
g_ITFTable.pITFBuckets[dwIndex].pItf = pITFTemp->pNext;
}
else
{
// Entry is inside list in table
pITFWalker->pNext = pITFTemp->pNext;
}
break;
}
pITFWalker = pITFTemp;
pITFTemp = pITFWalker->pNext;
}
return;
}
//
// ElNdisuioEnumerateInterfaces
//
// Description:
//
// Function called to enumerate the interfaces on which NDISUIO is bound
//
// Arguments:
// pItfBuffer - Pointer to buffer which will hold interface details
// dwAvailableInterfaces - Number of interfaces for which details can
// be held in pItfBuffer
// dwBufferSize - Number of bytes in pItfBuffer
//
// Return values:
//
DWORD
ElNdisuioEnumerateInterfaces (
IN OUT PNDIS_ENUM_INTF pItfBuffer,
IN DWORD dwAvailableInterfaces,
IN DWORD dwBufferSize
)
{
DWORD dwDesiredAccess;
DWORD dwShareMode;
LPSECURITY_ATTRIBUTES lpSecurityAttributes = NULL;
DWORD dwCreationDistribution;
DWORD dwFlagsAndAttributes;
HANDLE hTemplateFile;
HANDLE hHandle;
DWORD dwBytesReturned = 0;
INT i;
CHAR Buf[1024];
DWORD BufLength = sizeof(Buf);
DWORD BytesWritten = 0;
PNDISUIO_QUERY_BINDING pQueryBinding = NULL;
PCHAR pTempBuf = NULL;
DWORD dwRetCode = NO_ERROR;
dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
dwCreationDistribution = OPEN_EXISTING;
dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED;
hTemplateFile = (HANDLE)INVALID_HANDLE_VALUE;
TRACE0 (DEVICE, "ElNdisuioEnumerateInterfaces: Opening handle");
do
{
hHandle = CreateFileA (
pNdisuioDevice,
dwDesiredAccess,
dwShareMode,
lpSecurityAttributes,
dwCreationDistribution,
0,
NULL
);
if (hHandle == INVALID_HANDLE_VALUE)
{
dwRetCode = GetLastError();
TRACE1 (DEVICE, "ElNdisuioEnumerateInterfaces: Failed in CreateFile with error %d", dwRetCode);
break;
}
// Send IOCTL to ensure NDISUIO binds to all relevant interfaces
if (!DeviceIoControl (
hHandle,
IOCTL_NDISUIO_BIND_WAIT,
NULL,
0,
NULL,
0,
&dwBytesReturned,
NULL))
{
dwRetCode = GetLastError();
TRACE1 (DEVICE, "ElNdisuioEnumerateInterfaces: Failed in DeviceIoCoontrol NDISUIO_BIND_WAIT with error %d", dwRetCode);
break;
}
pQueryBinding = (PNDISUIO_QUERY_BINDING)Buf;
pTempBuf = (PBYTE)pItfBuffer + dwBufferSize;
i = 0;
for (pQueryBinding->BindingIndex = i;
pQueryBinding->BindingIndex < dwAvailableInterfaces;
pQueryBinding->BindingIndex = ++i)
{
// Query for one interface at a time
if (DeviceIoControl (
hHandle,
IOCTL_NDISUIO_QUERY_BINDING,
pQueryBinding,
sizeof(NDISUIO_QUERY_BINDING),
Buf,
BufLength,
&BytesWritten,
NULL))
{
TRACE3 (DEVICE, "NdisuioEnumerateInterfaces: NDISUIO bound to: (%ld) %ws\n - %ws\n",
pQueryBinding->BindingIndex,
(PUCHAR)pQueryBinding + pQueryBinding->DeviceNameOffset,
(PUCHAR)pQueryBinding + pQueryBinding->DeviceDescrOffset);
pTempBuf = pTempBuf - ((pQueryBinding->DeviceNameLength + 7) & 0xfffffff8);
if (((PBYTE)pTempBuf - (PBYTE)&pItfBuffer->Interface[pItfBuffer->TotalInterfaces]) <= 0)
{
// Going beyond start of buffer, Error
TRACE0 (DEVICE, "NdisuioEnumerateInterfaces: DeviceName: Memory being corrupted !!!");
dwRetCode = ERROR_INVALID_DATA;
break;
}
pItfBuffer->Interface[pItfBuffer->TotalInterfaces].DeviceName.Buffer = (PWCHAR) pTempBuf;
memcpy ((BYTE *)(pItfBuffer->Interface[pItfBuffer->TotalInterfaces].DeviceName.Buffer), (BYTE *)((PUCHAR)pQueryBinding + pQueryBinding->DeviceNameOffset), (pQueryBinding->DeviceNameLength ));
pItfBuffer->Interface[pItfBuffer->TotalInterfaces].DeviceName.Length = (SHORT) ( pQueryBinding->DeviceNameLength );
pItfBuffer->Interface[pItfBuffer->TotalInterfaces].DeviceName.MaximumLength = (SHORT) ( pQueryBinding->DeviceNameLength );
pTempBuf = pTempBuf - ((pQueryBinding->DeviceDescrLength + 7) & 0xfffffff8);;
if (((PBYTE)pTempBuf - (PBYTE)&pItfBuffer->Interface[pItfBuffer->TotalInterfaces]) <= 0)
{
// Going beyond start of buffer, Error
TRACE0 (DEVICE, "NdisuioEnumerateInterfaces: DeviceDescr: Memory being corrupted !!!");
dwRetCode = ERROR_INVALID_DATA;
break;
}
pItfBuffer->Interface[pItfBuffer->TotalInterfaces].DeviceDescription.Buffer = (PWCHAR) pTempBuf;
memcpy ((pItfBuffer->Interface[pItfBuffer->TotalInterfaces].DeviceDescription.Buffer), (PWCHAR)((PUCHAR)pQueryBinding + pQueryBinding->DeviceDescrOffset), (pQueryBinding->DeviceDescrLength ));
pItfBuffer->Interface[pItfBuffer->TotalInterfaces].DeviceDescription.Length = (SHORT) (pQueryBinding->DeviceDescrLength );
pItfBuffer->Interface[pItfBuffer->TotalInterfaces].DeviceDescription.MaximumLength = (SHORT) (pQueryBinding->DeviceDescrLength );
pItfBuffer->TotalInterfaces++;
memset(Buf, 0, BufLength);
}
else
{
dwRetCode = GetLastError ();
if (dwRetCode != ERROR_NO_MORE_ITEMS)
{
TRACE1 (DEVICE, "ElNdisuioEnumerateInterfaces: DeviceIoControl terminated for with IOCTL_NDISUIO_QUERY_BINDING with error %ld",
dwRetCode);
}
else
{
// Reset error, since it only indicates end-of-list
dwRetCode = NO_ERROR;
TRACE0 (DEVICE, "ElNdisuioEnumerateInterfaces: DeviceIoControl IOCTL_NDISUIO_QUERY_BINDING has no more entries");
}
break;
}
}
} while (FALSE);
// Cleanup
if (hHandle != INVALID_HANDLE_VALUE)
{
if (!CloseHandle(hHandle))
{
dwRetCode = GetLastError();
TRACE1 (DEVICE, "ElNdisuioEnumerateInterfaces: Error in CloseHandle %d", dwRetCode);
}
}
return dwRetCode;
}
//
// ElShutdownInterface
//
// Description:
//
// Function called to stop EAPOL state machine, close handle to NDISUIO and
// remove existence of the interface from the module
//
// Arguments:
// pwszDeviceGUID - Pointer to interface GUID
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
DWORD
ElShutdownInterface (
IN WCHAR *pwszDeviceGUID
)
{
WCHAR *pwszGUID = NULL;
EAPOL_PCB *pPCB = NULL;
EAPOL_ITF *pITF = NULL;
HANDLE hDevice = NULL;
DWORD dwRetCode = NO_ERROR;
do
{
TRACE1 (DEVICE, "ElShutdownInterface: Called for interface removal for %ws",
pwszGUID);
pwszGUID = MALLOC ( (wcslen (pwszDeviceGUID) + 1) * sizeof(WCHAR));
if (pwszGUID == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (DEVICE, "ElShutdownInterface: MALLOC failed for pwszGUID");
break;
}
wcscpy (pwszGUID, pwszDeviceGUID);
ACQUIRE_WRITE_LOCK (&(g_ITFLock));
// Check if EAPOL was actually started on this interface
// Verify by checking existence of corresponding
// entry in hash table
ACQUIRE_WRITE_LOCK (&(g_PCBLock));
if ((pPCB = ElGetPCBPointerFromPortGUID(pwszGUID))
!= NULL)
{
RELEASE_WRITE_LOCK (&(g_PCBLock));
TRACE0 (DEVICE, "ElShutdownInterface: Found PCB entry for interface");
if ((pITF = ElGetITFPointerFromInterfaceDesc(
pPCB->pwszFriendlyName))
== NULL)
{
TRACE0 (DEVICE, "ElShutdownInterface: Did not find ITF entry when PCB exits, HOW BIZARRE !!!");
}
if ((dwRetCode = ElDeletePort (
pwszGUID,
&hDevice)) != NO_ERROR)
{
TRACE1 (DEVICE, "ElShutdownInterface: Error in deleting port for %ws",
pPCB->pwszDeviceGUID);
}
// Remove interface entry from interface table
if (pITF != NULL)
{
ElRemoveITFFromTable(pITF);
if (pITF->pwszInterfaceDesc)
{
FREE (pITF->pwszInterfaceDesc);
}
if (pITF->pwszInterfaceGUID)
{
FREE (pITF->pwszInterfaceGUID);
}
if (pITF)
{
FREE (pITF);
}
}
// Close the handle to the NDISUIO driver
if (hDevice != NULL)
{
if ((dwRetCode = ElCloseInterfaceHandle (hDevice, pwszGUID))
!= NO_ERROR)
{
TRACE1 (DEVICE,
"ElShutdownInterface: Error in ElCloseInterfaceHandle %d",
dwRetCode);
}
}
TRACE1 (DEVICE, "ElShutdownInterface: Port deleted (%ws)",
pwszGUID);
}
else
{
RELEASE_WRITE_LOCK (&(g_PCBLock));
// Ignore device removal
TRACE0 (DEVICE, "ElShutdownInterface: ElGetPCBPointerFromPortGUID did not find any matching entry, ignoring interface REMOVAL");
}
RELEASE_WRITE_LOCK (&(g_ITFLock));
} while (FALSE);
if (pwszGUID != NULL)
{
FREE (pwszGUID);
}
return dwRetCode;
}
//
// ElCreateInterfaceEntry
//
// Description:
//
// Function called to create an entry in the global interface table
//
// Arguments:
// pwszInterfaceGUID - Pointer to interface GUID
// pwszInterfaceDescription - Pointer to interface Description
//
// Return values:
// NO_ERROR - success
// non-zero - error
//
DWORD
ElCreateInterfaceEntry (
IN WCHAR *pwszInterfaceGUID,
IN WCHAR *pwszInterfaceDescription
)
{
EAPOL_ITF * pNewITF = NULL;
DWORD dwIndex = 0;
DWORD dwRetCode = NO_ERROR;
do
{
dwIndex = ElHashInterfaceDescToBucket (pwszInterfaceDescription);
pNewITF = (PEAPOL_ITF) MALLOC (sizeof (EAPOL_ITF));
if (pNewITF == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
break;
}
pNewITF->pwszInterfaceGUID =
(WCHAR *) MALLOC ((wcslen(pwszInterfaceGUID) + 1)*sizeof(WCHAR));
if (pNewITF->pwszInterfaceGUID == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
break;
}
pNewITF->pwszInterfaceDesc =
(WCHAR *) MALLOC ((wcslen(pwszInterfaceDescription) + 1)*sizeof(WCHAR));
if (pNewITF->pwszInterfaceDesc == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
break;
}
wcscpy (pNewITF->pwszInterfaceGUID, pwszInterfaceGUID);
wcscpy (pNewITF->pwszInterfaceDesc, pwszInterfaceDescription);
pNewITF->pNext = g_ITFTable.pITFBuckets[dwIndex].pItf;
g_ITFTable.pITFBuckets[dwIndex].pItf = pNewITF;
TRACE3 (DEVICE, "ElCreateInterfaceEntry: Added to hash table GUID= %ws : Desc= %ws at Index=%d",
pNewITF->pwszInterfaceGUID,
pNewITF->pwszInterfaceDesc,
dwIndex
);
}
while (FALSE);
if (dwRetCode != NO_ERROR)
{
if (pNewITF)
{
if (pNewITF->pwszInterfaceDesc)
{
FREE (pNewITF->pwszInterfaceDesc);
}
if (pNewITF->pwszInterfaceGUID)
{
FREE (pNewITF->pwszInterfaceGUID);
}
FREE (pNewITF);
}
}
return dwRetCode;
}