/*++ 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; }