2851 lines
82 KiB
C
2851 lines
82 KiB
C
|
/*++
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|