Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2435 lines
75 KiB

  1. /*++
  2. Copyright (c) 1999, Microsoft Corporation
  3. Module Name:
  4. elport.c
  5. Abstract:
  6. This module deals with the port management for EAPOL, r/w to ports
  7. Revision History:
  8. sachins, Apr 28 2000, Created
  9. --*/
  10. #include "pcheapol.h"
  11. #pragma hdrstop
  12. #include "intfhdl.h"
  13. BYTE g_bDefaultGroupMacAddr[]={0x01, 0x80, 0xc2, 0x00, 0x00, 0x03};
  14. BYTE g_bEtherType8021X[SIZE_ETHERNET_TYPE]={0x88, 0x8E};
  15. BYTE DEFAULT_8021X_VERSION=0x01;
  16. //
  17. // ElReadPerPortRegistryParams
  18. //
  19. // Description:
  20. //
  21. // Function called to read per port interface parameters from the registry
  22. //
  23. // Arguments:
  24. // pwszDeviceGUID - GUID-string for the port
  25. // pPCB - Pointer to PCB for the port
  26. //
  27. // Return values:
  28. // NO_ERROR - success
  29. // NON-zero - error
  30. //
  31. DWORD
  32. ElReadPerPortRegistryParams (
  33. IN WCHAR *pwszDeviceGUID,
  34. IN EAPOL_PCB *pPCB
  35. )
  36. {
  37. EAPOL_INTF_PARAMS EapolIntfParams;
  38. EAPOL_POLICY_PARAMS EAPOLPolicyParams = {0};
  39. DWORD dwSizeOfAuthData = 0;
  40. BYTE *pbAuthData = NULL;
  41. DWORD dwRetCode = NO_ERROR;
  42. do
  43. {
  44. // Set the Auth Mode and the Supplicant mode for the context
  45. pPCB->dwEAPOLAuthMode = g_dwEAPOLAuthMode;
  46. pPCB->dwSupplicantMode = g_dwSupplicantMode;
  47. // Read EAP type and default EAPOL state
  48. ZeroMemory ((BYTE *)&EapolIntfParams, sizeof(EAPOL_INTF_PARAMS));
  49. EapolIntfParams.dwVersion = EAPOL_CURRENT_VERSION;
  50. EapolIntfParams.dwEapFlags = DEFAULT_EAP_STATE;
  51. EapolIntfParams.dwEapType = DEFAULT_EAP_TYPE;
  52. if (pPCB->pSSID != NULL)
  53. {
  54. memcpy (EapolIntfParams.bSSID, pPCB->pSSID->Ssid, pPCB->pSSID->SsidLength);
  55. EapolIntfParams.dwSizeOfSSID = pPCB->pSSID->SsidLength;
  56. }
  57. if ((dwRetCode = ElGetInterfaceParams (
  58. pwszDeviceGUID,
  59. &EapolIntfParams
  60. )) != NO_ERROR)
  61. {
  62. TRACE1 (PORT, "ElReadPerPortRegistryParams: ElGetInterfaceParams failed with error %ld",
  63. dwRetCode);
  64. if (dwRetCode == ERROR_FILE_NOT_FOUND)
  65. {
  66. dwRetCode = NO_ERROR;
  67. }
  68. else
  69. {
  70. break;
  71. }
  72. }
  73. // Do version check here
  74. // If registry blob has a version not equal to latest version,
  75. // modify parameters to reflect default settings for current version
  76. if ((EapolIntfParams.dwVersion != EAPOL_CURRENT_VERSION) &&
  77. (EapolIntfParams.dwEapType == EAP_TYPE_TLS))
  78. {
  79. EapolIntfParams.dwVersion = EAPOL_CURRENT_VERSION;
  80. EapolIntfParams.dwEapFlags |= DEFAULT_MACHINE_AUTH_STATE;
  81. EapolIntfParams.dwEapFlags &= ~EAPOL_GUEST_AUTH_ENABLED;
  82. if ((dwRetCode = ElSetInterfaceParams (
  83. pwszDeviceGUID,
  84. &EapolIntfParams
  85. )) != NO_ERROR)
  86. {
  87. TRACE1 (PORT, "ElReadPerPortRegistryParams: ElSetInterfaceParams failed with error %ld, continuing",
  88. dwRetCode);
  89. dwRetCode = NO_ERROR;
  90. }
  91. }
  92. if ((pPCB->PhysicalMediumType == NdisPhysicalMediumWirelessLan) &&
  93. (EapolIntfParams.dwEapType == EAP_TYPE_MD5))
  94. {
  95. EapolIntfParams.dwEapType = EAP_TYPE_TLS;
  96. if ((dwRetCode = ElSetInterfaceParams (
  97. pwszDeviceGUID,
  98. &EapolIntfParams
  99. )) != NO_ERROR)
  100. {
  101. TRACE1 (PORT, "ElReadPerPortRegistryParams: ElSetInterfaceParams for TLS failed with error %ld, continuing",
  102. dwRetCode);
  103. dwRetCode = NO_ERROR;
  104. }
  105. }
  106. pPCB->dwEapFlags = EapolIntfParams.dwEapFlags;
  107. pPCB->dwEapTypeToBeUsed = EapolIntfParams.dwEapType;
  108. //
  109. // Query with zero-config and see if it is enabled on the interface
  110. // or not. If zero-config is disabled on the interface, 802.1x should
  111. // also be disabled
  112. //
  113. {
  114. DWORD dwErr = 0;
  115. INTF_ENTRY ZCIntfEntry = {0};
  116. ZCIntfEntry.wszGuid = pwszDeviceGUID;
  117. if ((dwErr = LstQueryInterface (
  118. INTF_ENABLED,
  119. &ZCIntfEntry,
  120. NULL
  121. )) == NO_ERROR)
  122. {
  123. if (!(ZCIntfEntry.dwCtlFlags & INTFCTL_ENABLED))
  124. {
  125. // TRACE0 (ANY, "LstQueryInterface returned Zero-configuration is disabled on network");
  126. pPCB->dwEapFlags &= ~EAPOL_ENABLED;
  127. }
  128. else
  129. {
  130. // TRACE0 (ANY, "LstQueryInterface returned Zero-configuration is enabled on network");
  131. }
  132. }
  133. else
  134. {
  135. if (dwErr != ERROR_FILE_NOT_FOUND)
  136. {
  137. TRACE1 (ANY, "LstQueryInterface failed with error (%ld)",
  138. dwErr);
  139. }
  140. }
  141. }
  142. // Get the size of the EAP blob
  143. if ((dwRetCode = ElGetCustomAuthData (
  144. pwszDeviceGUID,
  145. pPCB->dwEapTypeToBeUsed,
  146. (pPCB->pSSID)?pPCB->pSSID->SsidLength:0,
  147. (pPCB->pSSID)?pPCB->pSSID->Ssid:NULL,
  148. NULL,
  149. &dwSizeOfAuthData
  150. )) != NO_ERROR)
  151. {
  152. if (dwRetCode == ERROR_BUFFER_TOO_SMALL)
  153. {
  154. if (dwSizeOfAuthData <= 0)
  155. {
  156. // No EAP blob stored in the registry
  157. // Port can have NULL EAP blob
  158. pbAuthData = NULL;
  159. dwRetCode = NO_ERROR;
  160. }
  161. else
  162. {
  163. // Allocate memory to hold the blob
  164. pbAuthData = MALLOC (dwSizeOfAuthData);
  165. if (pbAuthData == NULL)
  166. {
  167. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  168. TRACE0 (USER, "ElReadPerPortRegistryParams: Error in memory allocation for EAP blob");
  169. break;
  170. }
  171. if ((dwRetCode = ElGetCustomAuthData (
  172. pwszDeviceGUID,
  173. pPCB->dwEapTypeToBeUsed,
  174. (pPCB->pSSID)?pPCB->pSSID->SsidLength:0,
  175. (pPCB->pSSID)?pPCB->pSSID->Ssid:NULL,
  176. pbAuthData,
  177. &dwSizeOfAuthData
  178. )) != NO_ERROR)
  179. {
  180. TRACE1 (USER, "ElReadPerPortRegistryParams: ElGetCustomAuthData failed with %ld",
  181. dwRetCode);
  182. break;
  183. }
  184. }
  185. if (pPCB->pCustomAuthConnData != NULL)
  186. {
  187. FREE (pPCB->pCustomAuthConnData);
  188. pPCB->pCustomAuthConnData = NULL;
  189. }
  190. pPCB->pCustomAuthConnData = MALLOC (dwSizeOfAuthData + sizeof (DWORD));
  191. if (pPCB->pCustomAuthConnData == NULL)
  192. {
  193. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  194. TRACE0 (EAPOL, "ElReadPerPortRegistryParams: MALLOC failed for pCustomAuthConnData");
  195. break;
  196. }
  197. pPCB->pCustomAuthConnData->dwSizeOfCustomAuthData = dwSizeOfAuthData;
  198. if ((dwSizeOfAuthData != 0) && (pbAuthData != NULL))
  199. {
  200. memcpy ((BYTE *)pPCB->pCustomAuthConnData->pbCustomAuthData,
  201. (BYTE *)pbAuthData, dwSizeOfAuthData);
  202. }
  203. }
  204. else
  205. {
  206. TRACE1 (USER, "ElReadPerPortRegistryParams: ElGetCustomAuthData size estimation failed with error %ld",
  207. dwRetCode);
  208. break;
  209. }
  210. }
  211. // Initialize Policy parameters not in EAPOL_INTF_PARAMS
  212. if ((dwRetCode = ElGetPolicyInterfaceParams (
  213. EapolIntfParams.dwSizeOfSSID,
  214. EapolIntfParams.bSSID,
  215. &EAPOLPolicyParams
  216. )) == NO_ERROR)
  217. {
  218. pPCB->dwEAPOLAuthMode = EAPOLPolicyParams.dwEAPOLAuthMode;
  219. pPCB->dwSupplicantMode = EAPOLPolicyParams.dwSupplicantMode;
  220. pPCB->EapolConfig.dwheldPeriod = EAPOLPolicyParams.dwheldPeriod;
  221. pPCB->EapolConfig.dwauthPeriod = EAPOLPolicyParams.dwauthPeriod;
  222. pPCB->EapolConfig.dwstartPeriod = EAPOLPolicyParams.dwstartPeriod;
  223. pPCB->EapolConfig.dwmaxStart = EAPOLPolicyParams.dwmaxStart;
  224. }
  225. else
  226. {
  227. if (dwRetCode != ERROR_FILE_NOT_FOUND)
  228. {
  229. TRACE1 (USER, "ElReadPerPortRegistryParams: ElGetPolicyInterfaceParams failed with error (%ld)",
  230. dwRetCode);
  231. }
  232. dwRetCode = NO_ERROR;
  233. }
  234. // Determine maximum fail count possible before being parked into failure
  235. // state (DISCONNECTED)
  236. switch (pPCB->dwEAPOLAuthMode)
  237. {
  238. case EAPOL_AUTH_MODE_0:
  239. case EAPOL_AUTH_MODE_1:
  240. if (g_fUserLoggedOn)
  241. {
  242. // When user is logged in, only user and guest will be tried
  243. pPCB->dwTotalMaxAuthFailCount = EAPOL_MAX_AUTH_FAIL_COUNT;
  244. pPCB->dwTotalMaxAuthFailCount += ((IS_GUEST_AUTH_ENABLED(pPCB->dwEapFlags))?1:0)*EAPOL_MAX_AUTH_FAIL_COUNT;
  245. }
  246. else
  247. {
  248. // When user is logged out, only machine and guest will be tried
  249. pPCB->dwTotalMaxAuthFailCount = ((IS_GUEST_AUTH_ENABLED(pPCB->dwEapFlags))?1:0)*EAPOL_MAX_AUTH_FAIL_COUNT;
  250. pPCB->dwTotalMaxAuthFailCount += ((IS_MACHINE_AUTH_ENABLED(pPCB->dwEapFlags))?1:0)*EAPOL_MAX_AUTH_FAIL_COUNT;
  251. }
  252. break;
  253. case EAPOL_AUTH_MODE_2:
  254. // In Mode 2, only machine and guest will be tried
  255. pPCB->dwTotalMaxAuthFailCount = ((IS_GUEST_AUTH_ENABLED(pPCB->dwEapFlags))?1:0)*EAPOL_MAX_AUTH_FAIL_COUNT;
  256. pPCB->dwTotalMaxAuthFailCount += ((IS_MACHINE_AUTH_ENABLED(pPCB->dwEapFlags))?1:0)*EAPOL_MAX_AUTH_FAIL_COUNT;
  257. break;
  258. }
  259. TRACE1 (PORT, "ElReadPerPortRegistryParams: dwTotalMaxAuthFailCount = (%ld)",
  260. pPCB->dwTotalMaxAuthFailCount);
  261. memcpy(pPCB->bEtherType, &g_bEtherType8021X[0], SIZE_ETHERNET_TYPE);
  262. pPCB->bProtocolVersion = DEFAULT_8021X_VERSION;
  263. }
  264. while (FALSE);
  265. if (pbAuthData != NULL)
  266. {
  267. FREE (pbAuthData);
  268. }
  269. return dwRetCode;
  270. }
  271. //
  272. // ElHashPortToBucket
  273. //
  274. // Description:
  275. //
  276. // Function called to convert Device GUID into PCB hash table index.
  277. //
  278. // Arguments:
  279. // pwszDeviceGUID - GUID-string for the port
  280. //
  281. // Return values:
  282. // PCB hash table index from 0 to PORT_TABLE_BUCKETS-1
  283. //
  284. DWORD
  285. ElHashPortToBucket (
  286. IN WCHAR *pwszDeviceGUID
  287. )
  288. {
  289. return ((DWORD)((_wtol(pwszDeviceGUID)) % PORT_TABLE_BUCKETS));
  290. }
  291. //
  292. // ElRemovePCBFromTable
  293. //
  294. // Description:
  295. //
  296. // Function called to remove a PCB from the Hash Bucket table
  297. // Delink it from the hash table, but do not free up the memory
  298. //
  299. // Arguments:
  300. // pPCB - Pointer to PCB entry to be removed
  301. //
  302. // Return values:
  303. //
  304. VOID
  305. ElRemovePCBFromTable (
  306. IN EAPOL_PCB *pPCB
  307. )
  308. {
  309. DWORD dwIndex;
  310. EAPOL_PCB *pPCBWalker = NULL;
  311. EAPOL_PCB *pPCBTemp = NULL;
  312. if (pPCB == NULL)
  313. {
  314. TRACE0 (PORT, "ElRemovePCBFromTable: Deleting NULL PCB, returning");
  315. return;
  316. }
  317. dwIndex = ElHashPortToBucket (pPCB->pwszDeviceGUID);
  318. pPCBWalker = g_PCBTable.pPCBBuckets[dwIndex].pPorts;
  319. pPCBTemp = pPCBWalker;
  320. while (pPCBTemp != NULL)
  321. {
  322. if (wcsncmp (pPCBTemp->pwszDeviceGUID,
  323. pPCB->pwszDeviceGUID, wcslen (pPCB->pwszDeviceGUID)) == 0)
  324. {
  325. // Entry is at head of list in table
  326. if (pPCBTemp == g_PCBTable.pPCBBuckets[dwIndex].pPorts)
  327. {
  328. g_PCBTable.pPCBBuckets[dwIndex].pPorts = pPCBTemp->pNext;
  329. }
  330. else
  331. {
  332. // Entry in inside list in table
  333. pPCBWalker->pNext = pPCBTemp->pNext;
  334. }
  335. break;
  336. }
  337. pPCBWalker = pPCBTemp;
  338. pPCBTemp = pPCBWalker->pNext;
  339. }
  340. return;
  341. }
  342. //
  343. // ElGetPCBPointerFromPortGUID
  344. //
  345. // Description:
  346. //
  347. // Function called to convert interface GUID to PCB pointer for the entry in
  348. // the PCB hash table
  349. //
  350. // Arguments:
  351. // pwszDeviceGUID - Identifier of the form GUID-String
  352. //
  353. // Return values:
  354. //
  355. PEAPOL_PCB
  356. ElGetPCBPointerFromPortGUID (
  357. IN WCHAR *pwszDeviceGUID
  358. )
  359. {
  360. EAPOL_PCB *pPCBWalker = NULL;
  361. DWORD dwIndex;
  362. // TRACE1 (PORT, "ElGetPCBPointerFromPortGUID: GUID %ws", pwszDeviceGUID);
  363. dwIndex = ElHashPortToBucket (pwszDeviceGUID);
  364. // TRACE1 (PORT, "ElGetPCBPointerFromPortGUID: Index %d", dwIndex);
  365. for (pPCBWalker = g_PCBTable.pPCBBuckets[dwIndex].pPorts;
  366. pPCBWalker != NULL;
  367. pPCBWalker = pPCBWalker->pNext
  368. )
  369. {
  370. if (wcslen(pPCBWalker->pwszDeviceGUID) == wcslen(pwszDeviceGUID))
  371. {
  372. if (wcsncmp (pPCBWalker->pwszDeviceGUID, pwszDeviceGUID, wcslen (pwszDeviceGUID)) == 0)
  373. {
  374. return pPCBWalker;
  375. }
  376. }
  377. }
  378. return (NULL);
  379. }
  380. //
  381. // ElInitializeEAPOL
  382. //
  383. // Description:
  384. //
  385. // Function to initialize EAPOL protocol module.
  386. // Global EAPOL parameters are read from the registry.
  387. // PCB hash table is initialized.
  388. // EAP protocol is intialized.
  389. //
  390. // Arguments:
  391. //
  392. // Return values:
  393. // NO_ERROR - success
  394. // non-zero - error
  395. //
  396. DWORD
  397. ElInitializeEAPOL (
  398. )
  399. {
  400. DWORD dwIndex;
  401. HANDLE hLocalTimerQueue = NULL;
  402. DWORD dwRetCode = NO_ERROR;
  403. do
  404. {
  405. // Initialize global config locks
  406. if (dwRetCode = CREATE_READ_WRITE_LOCK(&(g_EAPOLConfig), "CFG") != NO_ERROR)
  407. {
  408. TRACE1(PORT, "ElInitializeEAPOL: Error %d creating g_EAPOLConfig read-write-lock", dwRetCode);
  409. // LOG
  410. break;
  411. }
  412. // Read parameters stored in registry
  413. if ((dwRetCode = ElReadGlobalRegistryParams ()) != NO_ERROR)
  414. {
  415. TRACE1 (PORT, "ElInitializeEAPOL: ElReadGlobalRegistryParams failed with error = %ld",
  416. dwRetCode);
  417. dwRetCode = NO_ERROR;
  418. // Don't exit, since default values will be used
  419. }
  420. // Initialize Hash Bucket Table
  421. g_PCBTable.pPCBBuckets = (PCB_BUCKET *) MALLOC ( PORT_TABLE_BUCKETS * sizeof (PCB_BUCKET));
  422. if (g_PCBTable.pPCBBuckets == NULL)
  423. {
  424. TRACE0 (PORT, "ElInitializeEAPOL: Error in allocating memory for PCB buckets");
  425. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  426. break;
  427. }
  428. g_PCBTable.dwNumPCBBuckets = PORT_TABLE_BUCKETS;
  429. for (dwIndex=0; dwIndex < PORT_TABLE_BUCKETS; dwIndex++)
  430. {
  431. g_PCBTable.pPCBBuckets[dwIndex].pPorts=NULL;
  432. }
  433. // Initialize global locks
  434. if (dwRetCode = CREATE_READ_WRITE_LOCK(&(g_PCBLock), "PCB") != NO_ERROR)
  435. {
  436. TRACE1(PORT, "ElInitializeEAPOL: Error %d creating g_PCBLock read-write-lock", dwRetCode);
  437. // LOG
  438. break;
  439. }
  440. // Create global timer queue for the various EAPOL state machines
  441. if ((g_hTimerQueue = CreateTimerQueue()) == NULL)
  442. {
  443. dwRetCode = GetLastError();
  444. TRACE1(PORT, "ElInitializeEAPOL: Error %d creating timer queue", dwRetCode);
  445. break;
  446. }
  447. // Initialize EAP
  448. if ((dwRetCode = ElEapInit(TRUE)) != NO_ERROR)
  449. {
  450. TRACE1 (PORT, "ElInitializeEAPOL: Error in ElEapInit= %ld",
  451. dwRetCode);
  452. break;
  453. }
  454. } while (FALSE);
  455. if (dwRetCode != NO_ERROR)
  456. {
  457. if (g_PCBTable.pPCBBuckets != NULL)
  458. {
  459. FREE (g_PCBTable.pPCBBuckets);
  460. g_PCBTable.pPCBBuckets = NULL;
  461. }
  462. if (READ_WRITE_LOCK_CREATED(&(g_PCBLock)))
  463. {
  464. DELETE_READ_WRITE_LOCK(&(g_PCBLock));
  465. }
  466. if (READ_WRITE_LOCK_CREATED(&(g_EAPOLConfig)))
  467. {
  468. DELETE_READ_WRITE_LOCK(&(g_EAPOLConfig));
  469. }
  470. if (g_hTimerQueue != NULL)
  471. {
  472. hLocalTimerQueue = g_hTimerQueue;
  473. g_hTimerQueue = NULL;
  474. if (!DeleteTimerQueueEx(
  475. hLocalTimerQueue,
  476. INVALID_HANDLE_VALUE
  477. ))
  478. {
  479. dwRetCode = GetLastError();
  480. TRACE1 (PORT, "ElInitializeEAPOL: Error in DeleteTimerQueueEx = %d",
  481. dwRetCode);
  482. }
  483. }
  484. // DeInit EAP
  485. ElEapInit(FALSE);
  486. }
  487. TRACE1 (PORT, "ElInitializeEAPOL: Completed, RetCode = %ld", dwRetCode);
  488. return dwRetCode;
  489. }
  490. //
  491. // ElCreatePort
  492. //
  493. // Description:
  494. //
  495. // Function to initialize Port Control Block for a port and start EAPOL
  496. // on it. If the PCB already exists for the GUID, EAPOL state machine
  497. // is restarted for that port.
  498. //
  499. // Arguments:
  500. // hDevice - Handle to open NDISUIO driver on the interface
  501. // pwszGUID - Pointer to GUID-String for the interface
  502. // pwszFriendlyName - Friendly name of the interface
  503. //
  504. // Return values:
  505. // NO_ERROR - success
  506. // non-zero - error
  507. //
  508. DWORD
  509. ElCreatePort (
  510. IN HANDLE hDevice,
  511. IN WCHAR *pwszGUID,
  512. IN WCHAR *pwszFriendlyName,
  513. IN DWORD dwZeroConfigId,
  514. IN PRAW_DATA prdUserData
  515. )
  516. {
  517. EAPOL_PCB *pNewPCB;
  518. BOOL fPortToBeReStarted = FALSE;
  519. BOOL fPCBCreated = FALSE;
  520. DWORD dwIndex = 0;
  521. DWORD dwSizeofMacAddr = 0;
  522. DWORD dwSizeofSSID = 0;
  523. DWORD ulOidDataLength = 0;
  524. NIC_STATISTICS NicStatistics;
  525. EAPOL_ZC_INTF *pZCData = NULL;
  526. NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode = Ndis802_11InfrastructureMax;
  527. DWORD dwSizeOfInfrastructureMode = 0;
  528. DWORD dwRetCode = NO_ERROR;
  529. do
  530. {
  531. TRACE5 (PORT, "ElCreatePort: Entered for Handle=(%p), GUID=(%ws), Name=(%ws), ZCId=(%ld), UserData=(%p)",
  532. hDevice, pwszGUID, pwszFriendlyName, dwZeroConfigId, prdUserData);
  533. // See if the port already exists
  534. // If yes, initialize the state machine
  535. // Else, create a new port
  536. ACQUIRE_WRITE_LOCK (&g_PCBLock);
  537. pNewPCB = ElGetPCBPointerFromPortGUID (pwszGUID);
  538. if (pNewPCB != NULL)
  539. {
  540. // PCB found, restart EAPOL STATE machine
  541. fPortToBeReStarted = TRUE;
  542. }
  543. else
  544. {
  545. // PCB not found, create new PCB and initialize it
  546. TRACE1 (PORT, "ElCreatePort: No PCB found for %ws", pwszGUID);
  547. // Allocate and initialize a new PCB
  548. pNewPCB = (PEAPOL_PCB) MALLOC (sizeof(EAPOL_PCB));
  549. if (pNewPCB == NULL)
  550. {
  551. RELEASE_WRITE_LOCK (&g_PCBLock);
  552. TRACE0(PORT, "ElCreatePort: Error in memory allocation using MALLOC");
  553. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  554. return dwRetCode;
  555. }
  556. }
  557. // Get Media Statistics for the interface
  558. ZeroMemory ((PVOID)&NicStatistics, sizeof(NIC_STATISTICS));
  559. if ((dwRetCode = ElGetInterfaceNdisStatistics (
  560. pwszGUID,
  561. &NicStatistics
  562. )) != NO_ERROR)
  563. {
  564. RELEASE_WRITE_LOCK (&g_PCBLock);
  565. TRACE1(PORT, "ElCreatePort: ElGetInterfaceNdisStatistics failed with error %ld",
  566. dwRetCode);
  567. break;
  568. }
  569. if (fPortToBeReStarted)
  570. {
  571. if (NicStatistics.MediaState != MEDIA_STATE_CONNECTED)
  572. {
  573. RELEASE_WRITE_LOCK (&g_PCBLock);
  574. dwRetCode = ERROR_INVALID_STATE;
  575. TRACE1(PORT, "ElCreatePort: Invalid media status for port to be restarted = (%ld)",
  576. NicStatistics.MediaState);
  577. break;
  578. }
  579. }
  580. else
  581. {
  582. if ((NicStatistics.MediaState != MEDIA_STATE_CONNECTED) &&
  583. (NicStatistics.MediaState != MEDIA_STATE_DISCONNECTED))
  584. {
  585. RELEASE_WRITE_LOCK (&g_PCBLock);
  586. dwRetCode = ERROR_INVALID_STATE;
  587. TRACE1(PORT, "ElCreatePort: Invalid media status for port = (%ld)",
  588. NicStatistics.MediaState);
  589. break;
  590. }
  591. }
  592. pNewPCB->MediaState = NicStatistics.MediaState;
  593. pNewPCB->PhysicalMediumType = NicStatistics.PhysicalMediaType;
  594. if (fPortToBeReStarted)
  595. {
  596. // Only port state will be changed to CONNECTING
  597. // No read requests will be cancelled
  598. // Hence no new read request will be posted
  599. TRACE1 (PORT, "ElCreatePort: PCB found for %ws", pwszGUID);
  600. if ((dwRetCode = ElReStartPort (
  601. pNewPCB,
  602. dwZeroConfigId,
  603. prdUserData))
  604. != NO_ERROR)
  605. {
  606. TRACE1 (PORT, "ElCreatePort: Error in ElReStartPort = %d",
  607. dwRetCode);
  608. }
  609. RELEASE_WRITE_LOCK (&g_PCBLock);
  610. break;
  611. }
  612. else
  613. {
  614. // New Port Control Block created
  615. // PCB creation reference count
  616. pNewPCB->dwRefCount = 1;
  617. pNewPCB->hPort = hDevice;
  618. // Mark the port as active
  619. pNewPCB->dwFlags = EAPOL_PORT_FLAG_ACTIVE;
  620. if (wcslen(pwszGUID) > (GUID_STRING_LEN_WITH_TERM-1))
  621. {
  622. RELEASE_WRITE_LOCK (&g_PCBLock);
  623. TRACE0(PORT, "ElCreatePort: Invalid GUID for port");
  624. break;
  625. }
  626. pNewPCB->pwszDeviceGUID =
  627. (PWCHAR) MALLOC ((wcslen(pwszGUID) + 1)*sizeof(WCHAR));
  628. if (pNewPCB->pwszDeviceGUID == NULL)
  629. {
  630. RELEASE_WRITE_LOCK (&g_PCBLock);
  631. TRACE0(PORT, "ElCreatePort: Error in memory allocation for GUID");
  632. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  633. break;
  634. }
  635. wcscpy (pNewPCB->pwszDeviceGUID, pwszGUID);
  636. pNewPCB->pwszFriendlyName =
  637. (PWCHAR) MALLOC ((wcslen(pwszFriendlyName) + 1)*sizeof(WCHAR));
  638. if (pNewPCB->pwszFriendlyName == NULL)
  639. {
  640. RELEASE_WRITE_LOCK (&g_PCBLock);
  641. TRACE0(PORT, "ElCreatePort: Error in memory allocation for Friendly Name");
  642. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  643. break;
  644. }
  645. wcscpy (pNewPCB->pwszFriendlyName, pwszFriendlyName);
  646. // Get the Local Current Mac address
  647. dwSizeofMacAddr = SIZE_MAC_ADDR;
  648. if (dwRetCode = ElNdisuioQueryOIDValue (
  649. pNewPCB->hPort,
  650. OID_802_3_CURRENT_ADDRESS,
  651. pNewPCB->bSrcMacAddr,
  652. &dwSizeofMacAddr
  653. ) != NO_ERROR)
  654. {
  655. RELEASE_WRITE_LOCK (&g_PCBLock);
  656. TRACE1 (PORT, "ElCreatePort: ElNdisuioQueryOIDValue for OID_802_3_CURRENT_ADDRESS failed with error %ld",
  657. dwRetCode);
  658. break;
  659. }
  660. else
  661. {
  662. TRACE0 (PORT, "ElCreatePort: ElNdisuioQueryOIDValue for OID_802_3_CURRENT_ADDRESS successful");
  663. EAPOL_DUMPBA (pNewPCB->bSrcMacAddr, dwSizeofMacAddr);
  664. }
  665. if (pNewPCB->PhysicalMediumType == NdisPhysicalMediumWirelessLan)
  666. {
  667. // Query the BSSID and SSID if media_connect
  668. if (pNewPCB->MediaState == MEDIA_STATE_CONNECTED)
  669. {
  670. dwSizeOfInfrastructureMode = sizeof (InfrastructureMode);
  671. // Get the infrastructure mode
  672. // 802.1x cannot work on Adhoc networks
  673. if (dwRetCode = ElNdisuioQueryOIDValue (
  674. pNewPCB->hPort,
  675. OID_802_11_INFRASTRUCTURE_MODE,
  676. (BYTE *)&InfrastructureMode,
  677. &dwSizeOfInfrastructureMode
  678. ) != NO_ERROR)
  679. {
  680. RELEASE_WRITE_LOCK (&g_PCBLock);
  681. TRACE1 (PORT, "ElCreatePort: ElNdisuioQueryOIDValue for OID_802_11_INFRASTRUCTURE_MODE failed with error %ld",
  682. dwRetCode);
  683. break;
  684. }
  685. else
  686. {
  687. TRACE1 (PORT, "ElCreatePort: ElNdisuioQueryOIDValue for OID_802_11_INFRASTRUCTURE_MODE successful, Mode = (%ld)",
  688. InfrastructureMode);
  689. }
  690. if (InfrastructureMode != Ndis802_11Infrastructure)
  691. {
  692. dwRetCode = ERROR_NOT_SUPPORTED;
  693. RELEASE_WRITE_LOCK (&g_PCBLock);
  694. TRACE0 (PORT, "ElCreatePort: 802.1x cannot work on non-infrastructure networks");
  695. break;
  696. }
  697. // Get the Remote MAC address if possible
  698. dwSizeofMacAddr = SIZE_MAC_ADDR;
  699. if (dwRetCode = ElNdisuioQueryOIDValue (
  700. pNewPCB->hPort,
  701. OID_802_11_BSSID,
  702. pNewPCB->bDestMacAddr,
  703. &dwSizeofMacAddr
  704. ) != NO_ERROR)
  705. {
  706. RELEASE_WRITE_LOCK (&g_PCBLock);
  707. TRACE1 (PORT, "ElCreatePort: ElNdisuioQueryOIDValue for OID_802_11_BSSID failed with error %ld",
  708. dwRetCode);
  709. break;
  710. }
  711. else
  712. {
  713. TRACE0 (PORT, "ElCreatePort: ElNdisuioQueryOIDValue for OID_802_11_BSSID successful");
  714. EAPOL_DUMPBA (pNewPCB->bDestMacAddr, dwSizeofMacAddr);
  715. }
  716. if ((pNewPCB->pSSID = MALLOC (NDIS_802_11_SSID_LEN)) == NULL)
  717. {
  718. RELEASE_WRITE_LOCK (&g_PCBLock);
  719. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  720. TRACE0 (PORT, "ElCreatePort: MALLOC failed for pSSID");
  721. break;
  722. }
  723. dwSizeofSSID = NDIS_802_11_SSID_LEN;
  724. if (dwRetCode = ElNdisuioQueryOIDValue (
  725. pNewPCB->hPort,
  726. OID_802_11_SSID,
  727. (BYTE *)pNewPCB->pSSID,
  728. &dwSizeofSSID
  729. ) != NO_ERROR)
  730. {
  731. RELEASE_WRITE_LOCK (&g_PCBLock);
  732. TRACE1 (PORT, "ElCreatePort: ElNdisuioQueryOIDValue for OID_802_11_SSID failed with error %ld",
  733. dwRetCode);
  734. break;
  735. }
  736. else
  737. {
  738. if (pNewPCB->pSSID->SsidLength > MAX_SSID_LEN)
  739. {
  740. RELEASE_WRITE_LOCK (&g_PCBLock);
  741. dwRetCode = ERROR_INVALID_PARAMETER;
  742. TRACE0 (PORT, "ElCreatePort: ElNdisuioQueryOIDValue OID_802_11_SSID returned invalid SSID");
  743. break;
  744. }
  745. TRACE0 (PORT, "ElCreatePort: ElNdisuioQueryOIDValue for OID_802_11_SSID successful");
  746. EAPOL_DUMPBA (pNewPCB->pSSID->Ssid, pNewPCB->pSSID->SsidLength);
  747. }
  748. }
  749. }
  750. else
  751. {
  752. // Wired Lan
  753. // Copy default destination Mac address value
  754. memcpy(pNewPCB->bDestMacAddr, &g_bDefaultGroupMacAddr[0], SIZE_MAC_ADDR);
  755. // If destination MacAddress is going to be multicast
  756. // inform the driver to accept the packets to this address
  757. if ((dwRetCode = ElNdisuioSetOIDValue (
  758. pNewPCB->hPort,
  759. OID_802_3_MULTICAST_LIST,
  760. (BYTE *)&g_bDefaultGroupMacAddr[0],
  761. SIZE_MAC_ADDR))
  762. != NO_ERROR)
  763. {
  764. RELEASE_WRITE_LOCK (&g_PCBLock);
  765. TRACE1 (PORT, "ElCreatePort: ElNdisuioSetOIDValue for OID_802_3_MULTICAST_LIST failed with error %ld",
  766. dwRetCode);
  767. break;
  768. }
  769. else
  770. {
  771. TRACE0 (PORT, "ElCreatePort: ElNdisuioSetOIDValue for OID_802_3_MULTICAST_LIST successful");
  772. }
  773. }
  774. // Identity related initialization
  775. pNewPCB->PreviousAuthenticationType = EAPOL_UNAUTHENTICATED_ACCESS;
  776. pNewPCB->fGotUserIdentity = FALSE;
  777. if (prdUserData != NULL)
  778. {
  779. if ((prdUserData->dwDataLen >= sizeof (EAPOL_ZC_INTF))
  780. && (prdUserData->pData != NULL))
  781. {
  782. // Extract information stored with Zero-Config
  783. pZCData = (PEAPOL_ZC_INTF) prdUserData->pData;
  784. pNewPCB->dwAuthFailCount = pZCData->dwAuthFailCount;
  785. pNewPCB->PreviousAuthenticationType =
  786. pZCData->PreviousAuthenticationType;
  787. TRACE2 (PORT, "ElCreatePort: prdUserData: Authfailcount = %ld, PreviousAuthType = %ld",
  788. pZCData->dwAuthFailCount, pZCData->PreviousAuthenticationType);
  789. }
  790. else
  791. {
  792. // Reset for zeroed out prdUserData
  793. pNewPCB->dwAuthFailCount = 0;
  794. TRACE0 (PORT, "ElCreatePort: prdUserData not valid");
  795. }
  796. }
  797. pNewPCB->dwTotalMaxAuthFailCount = EAPOL_TOTAL_MAX_AUTH_FAIL_COUNT;
  798. pNewPCB->dwZeroConfigId = dwZeroConfigId;
  799. // Not yet received 802.1X packet from remote end
  800. pNewPCB->fIsRemoteEndEAPOLAware = FALSE;
  801. // EAPOL state machine variables
  802. pNewPCB->State = EAPOLSTATE_LOGOFF;
  803. // Create timer with very high due time and infinite period
  804. // Timer will be deleted when the port is deleted
  805. CREATE_TIMER (&(pNewPCB->hTimer),
  806. ElTimeoutCallbackRoutine,
  807. (PVOID)pNewPCB,
  808. INFINITE_SECONDS,
  809. "PCB",
  810. &dwRetCode);
  811. if (dwRetCode != NO_ERROR)
  812. {
  813. RELEASE_WRITE_LOCK (&g_PCBLock);
  814. TRACE1 (PORT, "ElCreatePort: Error in CREATE_TIMER %ld", dwRetCode);
  815. break;
  816. }
  817. // EAPOL_Start s that have been sent out
  818. pNewPCB->ulStartCount = 0;
  819. // Last received Id from the remote end
  820. pNewPCB->dwPreviousId = 256;
  821. ACQUIRE_WRITE_LOCK (&g_EAPOLConfig);
  822. pNewPCB->EapolConfig.dwheldPeriod = g_dwheldPeriod;
  823. pNewPCB->EapolConfig.dwauthPeriod = g_dwauthPeriod;
  824. pNewPCB->EapolConfig.dwstartPeriod = g_dwstartPeriod;
  825. pNewPCB->EapolConfig.dwmaxStart = g_dwmaxStart;
  826. RELEASE_WRITE_LOCK (&g_EAPOLConfig);
  827. // Initialize read-write lock
  828. if (dwRetCode = CREATE_READ_WRITE_LOCK(&(pNewPCB->rwLock), "EPL")
  829. != NO_ERROR)
  830. {
  831. RELEASE_WRITE_LOCK (&g_PCBLock);
  832. TRACE1(PORT, "ElCreatePort: Error %d creating read-write-lock",
  833. dwRetCode);
  834. // LOG
  835. break;
  836. }
  837. // Initialize registry connection auth data for this port
  838. // If connection data is not present for EAP-TLS and SSID="Default"
  839. // create the blob
  840. if ((dwRetCode = ElInitRegPortData (
  841. pNewPCB->pwszDeviceGUID
  842. )) != NO_ERROR)
  843. {
  844. RELEASE_WRITE_LOCK (&g_PCBLock);
  845. TRACE1 (PORT, "ElCreatePort: Error in ElInitRegPortData = %d",
  846. dwRetCode);
  847. break;
  848. }
  849. // Initialize per port information from registry
  850. if ((dwRetCode = ElReadPerPortRegistryParams(pwszGUID, pNewPCB)) != NO_ERROR)
  851. {
  852. RELEASE_WRITE_LOCK (&g_PCBLock);
  853. TRACE1(PORT, "ElCreatePort: ElReadPerPortRegistryParams failed with error %ld",
  854. dwRetCode);
  855. break;
  856. }
  857. switch (pNewPCB->dwSupplicantMode)
  858. {
  859. case SUPPLICANT_MODE_0:
  860. case SUPPLICANT_MODE_1:
  861. case SUPPLICANT_MODE_2:
  862. pNewPCB->fEAPOLTransmissionFlag = FALSE;
  863. break;
  864. case SUPPLICANT_MODE_3:
  865. pNewPCB->fEAPOLTransmissionFlag = TRUE;
  866. break;
  867. }
  868. // Unicast mode, can talk with peer without broadcast messages
  869. if (pNewPCB->PhysicalMediumType == NdisPhysicalMediumWirelessLan)
  870. {
  871. pNewPCB->fEAPOLTransmissionFlag = TRUE;
  872. }
  873. if ((!IS_EAPOL_ENABLED(pNewPCB->dwEapFlags)) ||
  874. (pNewPCB->dwSupplicantMode == SUPPLICANT_MODE_0))
  875. {
  876. TRACE0 (PORT, "ElCreatePort: Marking port as disabled");
  877. pNewPCB->dwFlags &= ~EAPOL_PORT_FLAG_ACTIVE;
  878. pNewPCB->dwFlags |= EAPOL_PORT_FLAG_DISABLED;
  879. }
  880. // Add one more for local access
  881. pNewPCB->dwRefCount += 1;
  882. // Insert NewPCB into PCB hash table
  883. dwIndex = ElHashPortToBucket (pwszGUID);
  884. pNewPCB->pNext = g_PCBTable.pPCBBuckets[dwIndex].pPorts;
  885. g_PCBTable.pPCBBuckets[dwIndex].pPorts = pNewPCB;
  886. pNewPCB->dwPortIndex = dwIndex;
  887. fPCBCreated = TRUE;
  888. RELEASE_WRITE_LOCK (&g_PCBLock);
  889. ACQUIRE_WRITE_LOCK (&(pNewPCB->rwLock));
  890. //
  891. // Post a read request on the port
  892. //
  893. // Initiate read operation on the port, since it is now active
  894. if (dwRetCode = ElReadFromPort (
  895. pNewPCB,
  896. NULL,
  897. 0
  898. )
  899. != NO_ERROR)
  900. {
  901. RELEASE_WRITE_LOCK (&(pNewPCB->rwLock));
  902. TRACE1 (PORT, "ElCreatePort: Error in ElReadFromPort = %d",
  903. dwRetCode);
  904. break;
  905. }
  906. //
  907. // Kick off EAPOL state machine
  908. //
  909. if ((pNewPCB->MediaState == MEDIA_STATE_CONNECTED) &&
  910. EAPOL_PORT_ACTIVE(pNewPCB))
  911. {
  912. // Set port to EAPOLSTATE_CONNECTING State
  913. // Send out EAPOL_Start Packets to detect if it is a secure
  914. // or non-secure LAN based on response received from remote end
  915. if ((dwRetCode = FSMConnecting (pNewPCB, NULL)) != NO_ERROR)
  916. {
  917. RELEASE_WRITE_LOCK (&(pNewPCB->rwLock));
  918. TRACE1 (PORT, "ElCreatePort: FSMConnecting failed with error %ld",
  919. dwRetCode);
  920. break;
  921. }
  922. }
  923. else
  924. {
  925. // Set port to EAPOLSTATE_DISCONNECTED State
  926. if ((dwRetCode = FSMDisconnected (pNewPCB, NULL)) != NO_ERROR)
  927. {
  928. RELEASE_WRITE_LOCK (&(pNewPCB->rwLock));
  929. TRACE1 (PORT, "ElCreatePort: FSMDisconnected failed with error %ld",
  930. dwRetCode);
  931. break;
  932. }
  933. }
  934. RELEASE_WRITE_LOCK (&(pNewPCB->rwLock));
  935. TRACE2 (PORT, "ElCreatePort: Completed for GUID= %ws, Name = %ws",
  936. pNewPCB->pwszDeviceGUID, pNewPCB->pwszFriendlyName);
  937. }
  938. }
  939. while (FALSE);
  940. // Remove the local access reference
  941. if (fPCBCreated)
  942. {
  943. EAPOL_DEREFERENCE_PORT(pNewPCB);
  944. }
  945. if (dwRetCode != NO_ERROR)
  946. {
  947. // If PCB was not being restarted
  948. if (!fPortToBeReStarted)
  949. {
  950. // If PCB was created
  951. if (fPCBCreated)
  952. {
  953. HANDLE hTempDevice;
  954. // Mark the Port as deleted. Cleanup if possible
  955. // Don't worry about return code
  956. ElDeletePort (
  957. pNewPCB->pwszDeviceGUID,
  958. &hDevice
  959. );
  960. }
  961. else
  962. {
  963. // Remove all partial traces of port creation
  964. if (pNewPCB->hTimer != NULL)
  965. {
  966. if (InterlockedCompareExchangePointer (
  967. &g_hTimerQueue,
  968. NULL,
  969. NULL
  970. ))
  971. {
  972. DWORD dwTmpRetCode = NO_ERROR;
  973. TRACE2 (PORT, "ElCreatePort: DeleteTimer (%p), queue (%p)",
  974. pNewPCB->hTimer, g_hTimerQueue);
  975. DELETE_TIMER (pNewPCB->hTimer, INVALID_HANDLE_VALUE,
  976. &dwTmpRetCode);
  977. if (dwTmpRetCode != NO_ERROR)
  978. {
  979. TRACE1 (PORT, "ElCreatePort: DeleteTimer failed with error %ld",
  980. dwTmpRetCode);
  981. }
  982. }
  983. }
  984. if (READ_WRITE_LOCK_CREATED(&(pNewPCB->rwLock)))
  985. {
  986. DELETE_READ_WRITE_LOCK(&(pNewPCB->rwLock));
  987. }
  988. if (pNewPCB->pwszDeviceGUID != NULL)
  989. {
  990. FREE(pNewPCB->pwszDeviceGUID);
  991. pNewPCB->pwszDeviceGUID = NULL;
  992. }
  993. if (pNewPCB->pwszFriendlyName != NULL)
  994. {
  995. FREE(pNewPCB->pwszFriendlyName);
  996. pNewPCB->pwszFriendlyName = NULL;
  997. }
  998. if (pNewPCB != NULL)
  999. {
  1000. ZeroMemory ((PVOID)pNewPCB, sizeof (EAPOL_PCB));
  1001. FREE (pNewPCB);
  1002. pNewPCB = NULL;
  1003. }
  1004. }
  1005. }
  1006. }
  1007. return dwRetCode;
  1008. }
  1009. //
  1010. // ElDeletePort
  1011. //
  1012. // Description:
  1013. //
  1014. // Function to stop EAPOL and delete PCB for a port.
  1015. // Returns back pointer to handle opened on the interface so that
  1016. // the handle can be closed by the interface management module.
  1017. //
  1018. // Input arguments:
  1019. // pwszDeviceGUID - GUID-String of the interface whose PCB needs to be
  1020. // deleted
  1021. // pHandle - Output: Handle to NDISUIO driver for this port
  1022. //
  1023. // Return values:
  1024. // NO_ERROR - success
  1025. // non-zero - error
  1026. //
  1027. DWORD
  1028. ElDeletePort (
  1029. IN WCHAR *pwszDeviceGUID,
  1030. OUT HANDLE *pHandle
  1031. )
  1032. {
  1033. EAPOL_PCB *pPCB = NULL;
  1034. HANDLE hTimer = NULL;
  1035. DWORD dwRetCode = NO_ERROR;
  1036. ACQUIRE_WRITE_LOCK (&(g_PCBLock));
  1037. // Verify if PCB exists for this GUID
  1038. TRACE1 (PORT, "ElDeletePort entered for GUID %ws", pwszDeviceGUID);
  1039. pPCB = ElGetPCBPointerFromPortGUID (pwszDeviceGUID);
  1040. if (pPCB == NULL)
  1041. {
  1042. RELEASE_WRITE_LOCK (&(g_PCBLock));
  1043. TRACE1 (PORT, "ElDeletePort: PCB not found entered for Port %s",
  1044. pwszDeviceGUID);
  1045. return ERROR_NO_SUCH_INTERFACE;
  1046. }
  1047. ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
  1048. // Make sure it isn't already deleted
  1049. if (EAPOL_PORT_DELETED(pPCB))
  1050. {
  1051. RELEASE_WRITE_LOCK (&(pPCB->rwLock));
  1052. RELEASE_WRITE_LOCK (&(g_PCBLock));
  1053. TRACE1 (PORT, "ElDeletePort: PCB already marked deleted for Port %ws",
  1054. pwszDeviceGUID);
  1055. return ERROR_NO_SUCH_INTERFACE;
  1056. }
  1057. InterlockedIncrement (&g_lPCBContextsAlive);
  1058. // Retain handle to NDISUIO device
  1059. *pHandle = pPCB->hPort;
  1060. // Mark the PCB as deleted and remove it from the hash bucket
  1061. pPCB->dwFlags = EAPOL_PORT_FLAG_DELETED;
  1062. ElRemovePCBFromTable(pPCB);
  1063. // Shutdown EAP
  1064. // Will always return NO_ERROR, so no check on return value
  1065. ElEapEnd (pPCB);
  1066. // Delete timer since PCB is not longer to be used
  1067. hTimer = pPCB->hTimer;
  1068. TRACE1 (PORT, "ElDeletePort: RefCount for port = %ld", pPCB->dwRefCount);
  1069. RELEASE_WRITE_LOCK (&(pPCB->rwLock));
  1070. if (InterlockedCompareExchangePointer (
  1071. &g_hTimerQueue,
  1072. NULL,
  1073. NULL
  1074. ))
  1075. {
  1076. TRACE2 (PORT, "ElDeletePort: DeleteTimer (%p), queue (%p)",
  1077. hTimer, g_hTimerQueue);
  1078. DELETE_TIMER (hTimer, INVALID_HANDLE_VALUE, &dwRetCode);
  1079. if (dwRetCode != NO_ERROR)
  1080. {
  1081. TRACE1 (PORT, "ElDeletePort: DeleteTimer failed with error %ld",
  1082. dwRetCode);
  1083. }
  1084. }
  1085. // If reference count is zero, perform final cleanup
  1086. EAPOL_DEREFERENCE_PORT (pPCB);
  1087. RELEASE_WRITE_LOCK (&(g_PCBLock));
  1088. return NO_ERROR;
  1089. }
  1090. //
  1091. // ElCleanupPort
  1092. //
  1093. // Description:
  1094. //
  1095. // Function called when the very last reference to a PCB
  1096. // is released. The PCB memory is released and zeroed out
  1097. //
  1098. // Arguments:
  1099. // pPCB - Pointer to port control block to be destroyed
  1100. //
  1101. //
  1102. VOID
  1103. ElCleanupPort (
  1104. IN PEAPOL_PCB pPCB
  1105. )
  1106. {
  1107. DWORD dwRetCode = NO_ERROR;
  1108. TRACE1 (PORT, "ElCleanupPort entered for %ws", pPCB->pwszDeviceGUID);
  1109. if (pPCB->pwszDeviceGUID != NULL)
  1110. {
  1111. FREE (pPCB->pwszDeviceGUID);
  1112. }
  1113. if (pPCB->pwszFriendlyName)
  1114. {
  1115. FREE (pPCB->pwszFriendlyName);
  1116. }
  1117. if (pPCB->pwszEapReplyMessage != NULL)
  1118. {
  1119. FREE (pPCB->pwszEapReplyMessage);
  1120. }
  1121. if (pPCB->pwszSSID != NULL)
  1122. {
  1123. FREE (pPCB->pwszSSID);
  1124. }
  1125. if (pPCB->pSSID != NULL)
  1126. {
  1127. FREE (pPCB->pSSID);
  1128. }
  1129. if (pPCB->EapUIData.pEapUIData != NULL)
  1130. {
  1131. FREE (pPCB->EapUIData.pEapUIData);
  1132. }
  1133. if (pPCB->MasterSecretSend.cbData != 0)
  1134. {
  1135. FREE (pPCB->MasterSecretSend.pbData);
  1136. pPCB->MasterSecretSend.cbData = 0;
  1137. pPCB->MasterSecretSend.pbData = NULL;
  1138. }
  1139. if (pPCB->MasterSecretRecv.cbData != 0)
  1140. {
  1141. FREE (pPCB->MasterSecretRecv.pbData);
  1142. pPCB->MasterSecretRecv.cbData = 0;
  1143. pPCB->MasterSecretRecv.pbData = NULL;
  1144. }
  1145. if (pPCB->MPPESendKey.cbData != 0)
  1146. {
  1147. FREE (pPCB->MPPESendKey.pbData);
  1148. pPCB->MPPESendKey.cbData = 0;
  1149. pPCB->MPPESendKey.pbData = NULL;
  1150. }
  1151. if (pPCB->MPPERecvKey.cbData != 0)
  1152. {
  1153. FREE (pPCB->MPPERecvKey.pbData);
  1154. pPCB->MPPERecvKey.cbData = 0;
  1155. pPCB->MPPERecvKey.pbData = NULL;
  1156. }
  1157. if (pPCB->hUserToken != NULL)
  1158. {
  1159. if (!CloseHandle (pPCB->hUserToken))
  1160. {
  1161. dwRetCode = GetLastError ();
  1162. TRACE1 (PORT, "ElCleanupPort: CloseHandle failed with error %ld",
  1163. dwRetCode);
  1164. dwRetCode = NO_ERROR;
  1165. }
  1166. }
  1167. pPCB->hUserToken = NULL;
  1168. if (pPCB->pszIdentity != NULL)
  1169. {
  1170. FREE (pPCB->pszIdentity);
  1171. }
  1172. if (pPCB->PasswordBlob.pbData != NULL)
  1173. {
  1174. FREE (pPCB->PasswordBlob.pbData);
  1175. }
  1176. if (pPCB->pCustomAuthUserData != NULL)
  1177. {
  1178. FREE (pPCB->pCustomAuthUserData);
  1179. }
  1180. if (pPCB->pCustomAuthConnData != NULL)
  1181. {
  1182. FREE (pPCB->pCustomAuthConnData);
  1183. }
  1184. if (pPCB->pbPreviousEAPOLPkt != NULL)
  1185. {
  1186. FREE (pPCB->pbPreviousEAPOLPkt);
  1187. }
  1188. if (READ_WRITE_LOCK_CREATED(&(pPCB->rwLock)))
  1189. {
  1190. DELETE_READ_WRITE_LOCK(&(pPCB->rwLock));
  1191. }
  1192. ZeroMemory ((PVOID)pPCB, sizeof(EAPOL_PCB));
  1193. FREE (pPCB);
  1194. pPCB = NULL;
  1195. InterlockedDecrement (&g_lPCBContextsAlive);
  1196. TRACE0 (PORT, "ElCleanupPort completed");
  1197. return;
  1198. }
  1199. //
  1200. // ElReStartPort
  1201. //
  1202. // Description:
  1203. //
  1204. // Function called to reset the EAPOL state machine to Connecting state
  1205. // This may be called due to:
  1206. // 1. From ElCreatePort, for an existing PCB
  1207. // 2. Configuration parameters may have changed. Initialization
  1208. // is required to allow new values to take effect.
  1209. // Initialization will take the EAPOL state to CONNECTING
  1210. //
  1211. // Arguments:
  1212. // pPCB - Pointer to port control block to be initialized
  1213. //
  1214. // Return values:
  1215. // NO_ERROR - success
  1216. // non-zero - error
  1217. //
  1218. DWORD
  1219. ElReStartPort (
  1220. IN EAPOL_PCB *pPCB,
  1221. IN DWORD dwZeroConfigId,
  1222. IN PRAW_DATA prdUserData
  1223. )
  1224. {
  1225. DWORD dwSizeofSSID = 0;
  1226. DWORD dwSizeofMacAddr = 0;
  1227. DWORD dwCurrenTickCount = 0;
  1228. EAPOL_ZC_INTF *pZCData = NULL;
  1229. NIC_STATISTICS NicStatistics;
  1230. NDIS_802_11_SSID PreviousSSID;
  1231. BOOLEAN fResetCredentials = TRUE;
  1232. BYTE bTmpDestMacAddr[SIZE_MAC_ADDR];
  1233. NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode = Ndis802_11InfrastructureMax;
  1234. DWORD dwSizeOfInfrastructureMode = 0;
  1235. DWORD dwRetCode = NO_ERROR;
  1236. TRACE1 (PORT, "ElReStartPort: Entered: Refcnt = %ld",
  1237. pPCB->dwRefCount);
  1238. do
  1239. {
  1240. ACQUIRE_WRITE_LOCK (&pPCB->rwLock);
  1241. if (EAPOL_PORT_DELETED(pPCB))
  1242. {
  1243. RELEASE_WRITE_LOCK (&(pPCB->rwLock));
  1244. TRACE1 (PORT, "ElReStartPort: PCB already marked deleted for Port %ws",
  1245. pPCB->pwszDeviceGUID);
  1246. break;
  1247. }
  1248. pPCB->dwFlags = EAPOL_PORT_FLAG_ACTIVE;
  1249. // Set current authentication mode, based on administrative setting
  1250. pPCB->PreviousAuthenticationType = EAPOL_UNAUTHENTICATED_ACCESS;
  1251. if (prdUserData != NULL)
  1252. {
  1253. if ((prdUserData->dwDataLen >= sizeof (EAPOL_ZC_INTF))
  1254. && (prdUserData->pData != NULL))
  1255. {
  1256. // Extract information stored with Zero-Config
  1257. pZCData = (PEAPOL_ZC_INTF) prdUserData->pData;
  1258. pPCB->dwAuthFailCount = pZCData->dwAuthFailCount;
  1259. pPCB->PreviousAuthenticationType =
  1260. pZCData->PreviousAuthenticationType;
  1261. TRACE2 (PORT, "ElReStartPort: prdUserData: Authfailcount = %ld, PreviousAuthType = %ld",
  1262. pZCData->dwAuthFailCount, pZCData->PreviousAuthenticationType);
  1263. }
  1264. else
  1265. {
  1266. // Reset for zeroed out prdUserData
  1267. pPCB->dwAuthFailCount = 0;
  1268. TRACE0 (PORT, "ElReStartPort: prdUserData not valid");
  1269. }
  1270. }
  1271. pPCB->EapUIState = 0;
  1272. pPCB->dwTotalMaxAuthFailCount = EAPOL_TOTAL_MAX_AUTH_FAIL_COUNT;
  1273. pPCB->dwZeroConfigId = dwZeroConfigId;
  1274. pPCB->ulStartCount = 0;
  1275. pPCB->dwPreviousId = 256;
  1276. pPCB->dwLogoffSent = 0;
  1277. pPCB->ullLastReplayCounter = 0;
  1278. pPCB->fAuthenticationOnNewNetwork = FALSE;
  1279. // Clean out CustomAuthData since EAP type may have changed
  1280. // During authentication, CustomAuthData for the connection will be
  1281. // picked up again
  1282. if (pPCB->pCustomAuthConnData != NULL)
  1283. {
  1284. FREE (pPCB->pCustomAuthConnData);
  1285. pPCB->pCustomAuthConnData = NULL;
  1286. }
  1287. // Parameters initialization
  1288. memcpy(pPCB->bEtherType, &g_bEtherType8021X[0], SIZE_ETHERNET_TYPE);
  1289. pPCB->bProtocolVersion = DEFAULT_8021X_VERSION;
  1290. // Not yet received 802.1X packet from remote end
  1291. pPCB->fIsRemoteEndEAPOLAware = FALSE;
  1292. // Set EAPOL timeout values
  1293. ACQUIRE_WRITE_LOCK (&g_EAPOLConfig);
  1294. pPCB->EapolConfig.dwheldPeriod = g_dwheldPeriod;
  1295. pPCB->EapolConfig.dwauthPeriod = g_dwauthPeriod;
  1296. pPCB->EapolConfig.dwstartPeriod = g_dwstartPeriod;
  1297. pPCB->EapolConfig.dwmaxStart = g_dwmaxStart;
  1298. RELEASE_WRITE_LOCK (&g_EAPOLConfig);
  1299. ZeroMemory ((PVOID)&NicStatistics, sizeof(NIC_STATISTICS));
  1300. if ((dwRetCode = ElGetInterfaceNdisStatistics (
  1301. pPCB->pwszDeviceGUID,
  1302. &NicStatistics
  1303. )) != NO_ERROR)
  1304. {
  1305. RELEASE_WRITE_LOCK (&pPCB->rwLock);
  1306. TRACE1(PORT, "ElReStartPort: ElGetInterfaceNdisStatistics failed with error %ld",
  1307. dwRetCode);
  1308. break;
  1309. }
  1310. pPCB->MediaState = NicStatistics.MediaState;
  1311. ZeroMemory ((BYTE *)&PreviousSSID, sizeof(NDIS_802_11_SSID));
  1312. if (pPCB->pSSID != NULL)
  1313. {
  1314. memcpy ((BYTE *)&PreviousSSID, (BYTE *)pPCB->pSSID,
  1315. sizeof(NDIS_802_11_SSID));
  1316. }
  1317. // Get the Remote Mac address if possible, since we may have roamed
  1318. if (pPCB->PhysicalMediumType == NdisPhysicalMediumWirelessLan)
  1319. {
  1320. // Since authentication is to be restarted, flag that transmit
  1321. // key was not received
  1322. pPCB->fTransmitKeyReceived = FALSE;
  1323. dwSizeOfInfrastructureMode = sizeof (InfrastructureMode);
  1324. // Get the infrastructure mode
  1325. // 802.1x cannot work on Adhoc networks
  1326. if (dwRetCode = ElNdisuioQueryOIDValue (
  1327. pPCB->hPort,
  1328. OID_802_11_INFRASTRUCTURE_MODE,
  1329. (BYTE *)&InfrastructureMode,
  1330. &dwSizeOfInfrastructureMode
  1331. ) != NO_ERROR)
  1332. {
  1333. RELEASE_WRITE_LOCK (&pPCB->rwLock);
  1334. TRACE1 (PORT, "ElReStartPort: ElNdisuioQueryOIDValue for OID_802_11_INFRASTRUCTURE_MODE failed with error %ld",
  1335. dwRetCode);
  1336. break;
  1337. }
  1338. else
  1339. {
  1340. TRACE1 (PORT, "ElReStartPort: ElNdisuioQueryOIDValue for OID_802_11_INFRASTRUCTURE_MODE successful, Mode = (%ld)",
  1341. InfrastructureMode);
  1342. }
  1343. if (InfrastructureMode != Ndis802_11Infrastructure)
  1344. {
  1345. dwRetCode = ERROR_NOT_SUPPORTED;
  1346. RELEASE_WRITE_LOCK (&pPCB->rwLock);
  1347. TRACE0 (PORT, "ElReStartPort: 802.1x cannot work on non-infrastructure networks");
  1348. break;
  1349. }
  1350. ZeroMemory (bTmpDestMacAddr, SIZE_MAC_ADDR);
  1351. dwSizeofMacAddr = SIZE_MAC_ADDR;
  1352. if (dwRetCode = ElNdisuioQueryOIDValue (
  1353. pPCB->hPort,
  1354. OID_802_11_BSSID,
  1355. bTmpDestMacAddr,
  1356. &dwSizeofMacAddr
  1357. ) != NO_ERROR)
  1358. {
  1359. RELEASE_WRITE_LOCK (&pPCB->rwLock);
  1360. TRACE1 (PORT, "ElReStartPort: ElNdisuioQueryOIDValue for OID_802_11_BSSID failed with error %ld",
  1361. dwRetCode);
  1362. break;
  1363. }
  1364. else
  1365. {
  1366. TRACE0 (PORT, "ElReStartPort: ElNdisuioQueryOIDValue for OID_802_11_BSSID successful");
  1367. EAPOL_DUMPBA (bTmpDestMacAddr, dwSizeofMacAddr);
  1368. }
  1369. memcpy (pPCB->bDestMacAddr, bTmpDestMacAddr, SIZE_MAC_ADDR);
  1370. // Query the SSID if media_connect
  1371. if (pPCB->pSSID != NULL)
  1372. {
  1373. FREE (pPCB->pSSID);
  1374. pPCB->pSSID = NULL;
  1375. }
  1376. if ((pPCB->pSSID = MALLOC (NDIS_802_11_SSID_LEN)) == NULL)
  1377. {
  1378. RELEASE_WRITE_LOCK (&pPCB->rwLock);
  1379. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  1380. TRACE0 (PORT, "ElReStartPort: MALLOC failed for pSSID");
  1381. break;
  1382. }
  1383. dwSizeofSSID = NDIS_802_11_SSID_LEN;
  1384. if (dwRetCode = ElNdisuioQueryOIDValue (
  1385. pPCB->hPort,
  1386. OID_802_11_SSID,
  1387. (BYTE *)pPCB->pSSID,
  1388. &dwSizeofSSID
  1389. ) != NO_ERROR)
  1390. {
  1391. RELEASE_WRITE_LOCK (&pPCB->rwLock);
  1392. TRACE1 (PORT, "ElReStartPort: ElNdisuioQueryOIDValue for OID_802_11_SSID failed with error %ld",
  1393. dwRetCode);
  1394. break;
  1395. }
  1396. else
  1397. {
  1398. if (pPCB->pSSID->SsidLength > MAX_SSID_LEN)
  1399. {
  1400. RELEASE_WRITE_LOCK (&pPCB->rwLock);
  1401. dwRetCode = ERROR_INVALID_PARAMETER;
  1402. TRACE0 (PORT, "ElReStartPort: ElNdisuioQueryOIDValue OID_802_11_SSID returned invalid SSID");
  1403. break;
  1404. }
  1405. TRACE0 (PORT, "ElReStartPort: ElNdisuioQueryOIDValue for OID_802_11_SSID successful");
  1406. EAPOL_DUMPBA (pPCB->pSSID->Ssid, pPCB->pSSID->SsidLength);
  1407. }
  1408. }
  1409. // Retain credentials if on same network
  1410. if (pPCB->pSSID != NULL)
  1411. {
  1412. if (!memcmp ((BYTE *)pPCB->pSSID, (BYTE *)&PreviousSSID,
  1413. sizeof(NDIS_802_11_SSID)))
  1414. {
  1415. fResetCredentials = FALSE;
  1416. }
  1417. }
  1418. if (fResetCredentials)
  1419. {
  1420. pPCB->fGotUserIdentity = FALSE;
  1421. if (pPCB->PasswordBlob.pbData != NULL)
  1422. {
  1423. FREE (pPCB->PasswordBlob.pbData);
  1424. pPCB->PasswordBlob.pbData = NULL;
  1425. pPCB->PasswordBlob.cbData = 0;
  1426. }
  1427. if (pPCB->hUserToken != NULL)
  1428. {
  1429. if (!CloseHandle (pPCB->hUserToken))
  1430. {
  1431. dwRetCode = GetLastError ();
  1432. TRACE1 (PORT, "ElReStartPort: CloseHandle failed with error %ld",
  1433. dwRetCode);
  1434. dwRetCode = NO_ERROR;
  1435. }
  1436. }
  1437. pPCB->hUserToken = NULL;
  1438. }
  1439. else
  1440. {
  1441. // If this is the same SSID refresh the Master Secret with the
  1442. // last copy of MPPE Keys. If re-keying has stomped on keys, this
  1443. // will ensure that with the new AP with IAPP, the keys will
  1444. // be same on the supplicant too
  1445. if ((dwRetCode = ElReloadMasterSecrets (pPCB)) != NO_ERROR)
  1446. {
  1447. RELEASE_WRITE_LOCK (&pPCB->rwLock);
  1448. TRACE1 (PORT, "ElReStartPort: ElReloadMasterSecret failed with error %ld",
  1449. dwRetCode);
  1450. break;
  1451. }
  1452. }
  1453. // Initialize per port information from registry
  1454. if ((dwRetCode = ElReadPerPortRegistryParams(pPCB->pwszDeviceGUID,
  1455. pPCB)) != NO_ERROR)
  1456. {
  1457. RELEASE_WRITE_LOCK (&pPCB->rwLock);
  1458. TRACE1(PORT, "ElReStartPort: ElReadPerPortRegistryParams failed with error %ld",
  1459. dwRetCode);
  1460. break;
  1461. }
  1462. // Set correct supplicant mode
  1463. switch (pPCB->dwSupplicantMode)
  1464. {
  1465. case SUPPLICANT_MODE_0:
  1466. case SUPPLICANT_MODE_1:
  1467. case SUPPLICANT_MODE_2:
  1468. pPCB->fEAPOLTransmissionFlag = FALSE;
  1469. break;
  1470. case SUPPLICANT_MODE_3:
  1471. pPCB->fEAPOLTransmissionFlag = TRUE;
  1472. break;
  1473. }
  1474. // Unicast mode, can talk with peer without broadcast messages
  1475. if (pPCB->PhysicalMediumType == NdisPhysicalMediumWirelessLan)
  1476. {
  1477. pPCB->fEAPOLTransmissionFlag = TRUE;
  1478. }
  1479. if ((!IS_EAPOL_ENABLED(pPCB->dwEapFlags)) ||
  1480. (pPCB->dwSupplicantMode == SUPPLICANT_MODE_0))
  1481. {
  1482. TRACE0 (PORT, "ElReStartPort: Marking port as disabled");
  1483. pPCB->dwFlags &= ~EAPOL_PORT_FLAG_ACTIVE;
  1484. pPCB->dwFlags |= EAPOL_PORT_FLAG_DISABLED;
  1485. }
  1486. if ((pPCB->MediaState == MEDIA_STATE_CONNECTED) &&
  1487. EAPOL_PORT_ACTIVE(pPCB))
  1488. {
  1489. // Set port to EAPOLSTATE_CONNECTING State
  1490. // Send out EAPOL_Start Packets to detect if it is a secure
  1491. // or non-secure LAN based on response received from remote end
  1492. if ((dwRetCode = FSMConnecting (pPCB, NULL)) != NO_ERROR)
  1493. {
  1494. RELEASE_WRITE_LOCK (&(pPCB->rwLock));
  1495. TRACE1 (PORT, "ElReStartPort: FSMConnecting failed with error %ld",
  1496. dwRetCode);
  1497. break;
  1498. }
  1499. }
  1500. else
  1501. {
  1502. // Set port to EAPOLSTATE_DISCONNECTED State
  1503. if ((dwRetCode = FSMDisconnected (pPCB, NULL)) != NO_ERROR)
  1504. {
  1505. RELEASE_WRITE_LOCK (&(pPCB->rwLock));
  1506. TRACE1 (PORT, "ElReStartPort: FSMDisconnected failed with error %ld",
  1507. dwRetCode);
  1508. break;
  1509. }
  1510. }
  1511. RELEASE_WRITE_LOCK (&pPCB->rwLock);
  1512. } while (FALSE);
  1513. return dwRetCode;
  1514. }
  1515. //
  1516. // ElEAPOLDeInit
  1517. //
  1518. // Description:
  1519. //
  1520. // Function called to shutdown EAPOL module
  1521. // Shutdown EAP.
  1522. // Cleanup all used memory
  1523. //
  1524. // Arguments:
  1525. //
  1526. // Return values:
  1527. // NO_ERROR - success
  1528. // non-zero - error
  1529. //
  1530. //
  1531. DWORD
  1532. ElEAPOLDeInit (
  1533. )
  1534. {
  1535. EAPOL_PCB *pPCBWalker = NULL;
  1536. EAPOL_PCB *pPCB = NULL;
  1537. DWORD dwIndex = 0;
  1538. HANDLE hLocalTimerQueue = NULL;
  1539. HANDLE hNULL = NULL;
  1540. HANDLE hTimer = NULL;
  1541. DWORD dwRetCode = NO_ERROR;
  1542. TRACE0 (PORT, "ElEAPOLDeInit entered");
  1543. do
  1544. {
  1545. // Walk the hash table
  1546. // Mark PCBs as deleted. Free PCBs which we can
  1547. ACQUIRE_WRITE_LOCK (&(g_PCBLock));
  1548. for (dwIndex = 0; dwIndex < PORT_TABLE_BUCKETS; dwIndex++)
  1549. {
  1550. pPCBWalker = g_PCBTable.pPCBBuckets[dwIndex].pPorts;
  1551. while (pPCBWalker != NULL)
  1552. {
  1553. pPCB = pPCBWalker;
  1554. pPCBWalker = pPCB->pNext;
  1555. ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
  1556. // Send out Logoff Packet so that no one else can
  1557. // ride on the connection
  1558. // If the mode does not allow EAPOL_Logoff packet to sent
  1559. // out, there is not much that can be done to break the
  1560. // connection
  1561. FSMLogoff (pPCB, NULL);
  1562. // Mark the PCB as deleted and remove it from the hash bucket
  1563. pPCB->dwFlags = EAPOL_PORT_FLAG_DELETED;
  1564. ElRemovePCBFromTable(pPCB);
  1565. // Shutdown EAP
  1566. ElEapEnd (pPCB);
  1567. hTimer = pPCB->hTimer;
  1568. RELEASE_WRITE_LOCK (&(pPCB->rwLock));
  1569. if (InterlockedCompareExchangePointer (
  1570. &g_hTimerQueue,
  1571. NULL,
  1572. NULL
  1573. ))
  1574. {
  1575. TRACE2 (PORT, "ElEAPOLDeInit: DeleteTimer (%p), queue (%p)",
  1576. hTimer, g_hTimerQueue);
  1577. DELETE_TIMER (hTimer, INVALID_HANDLE_VALUE, &dwRetCode);
  1578. if (dwRetCode != NO_ERROR)
  1579. {
  1580. TRACE1 (PORT, "ElEAPOLDeInit: DeleteTimer 1 failed with error %ld",
  1581. dwRetCode);
  1582. }
  1583. }
  1584. ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
  1585. // Close the handle to the NDISUIO driver
  1586. if ((dwRetCode = ElCloseInterfaceHandle (
  1587. pPCB->hPort,
  1588. pPCB->pwszDeviceGUID))
  1589. != NO_ERROR)
  1590. {
  1591. TRACE1 (DEVICE,
  1592. "ElEAPOLDeInit: Error in ElCloseInterfaceHandle %d",
  1593. dwRetCode);
  1594. }
  1595. RELEASE_WRITE_LOCK (&(pPCB->rwLock));
  1596. InterlockedIncrement (&g_lPCBContextsAlive);
  1597. EAPOL_DEREFERENCE_PORT (pPCB);
  1598. }
  1599. }
  1600. RELEASE_WRITE_LOCK (&(g_PCBLock));
  1601. do
  1602. {
  1603. TRACE1 (PORT, "ElEAPOLDeInit: Waiting for %ld PCB contexts to terminate ...",
  1604. g_lPCBContextsAlive);
  1605. Sleep (1000);
  1606. }
  1607. while (g_lPCBContextsAlive != 0);
  1608. // Delete EAPOL config lock
  1609. if (READ_WRITE_LOCK_CREATED(&(g_EAPOLConfig)))
  1610. {
  1611. DELETE_READ_WRITE_LOCK(&(g_EAPOLConfig));
  1612. }
  1613. // Delete global PCB table lock
  1614. if (READ_WRITE_LOCK_CREATED(&(g_PCBLock)))
  1615. {
  1616. DELETE_READ_WRITE_LOCK(&(g_PCBLock));
  1617. }
  1618. if (g_PCBTable.pPCBBuckets != NULL)
  1619. {
  1620. FREE (g_PCBTable.pPCBBuckets);
  1621. g_PCBTable.pPCBBuckets = NULL;
  1622. }
  1623. // Delete global timer queue
  1624. if (g_hTimerQueue != NULL)
  1625. {
  1626. hLocalTimerQueue = InterlockedExchangePointer (
  1627. &g_hTimerQueue,
  1628. hNULL
  1629. );
  1630. if (!DeleteTimerQueueEx(
  1631. hLocalTimerQueue,
  1632. INVALID_HANDLE_VALUE // Wait for ALL timer callbacks to complete
  1633. ))
  1634. {
  1635. dwRetCode = GetLastError();
  1636. TRACE1 (PORT, "ElEAPOLDeInit: Error in DeleteTimerQueueEx = %d",
  1637. dwRetCode);
  1638. }
  1639. }
  1640. // Un-initialize EAP
  1641. if ((dwRetCode = ElEapInit(FALSE)) != NO_ERROR)
  1642. {
  1643. TRACE1 (PORT, "ElEAPOLDeInit: Error in ElEapInit(FALSE) = %ld",
  1644. dwRetCode);
  1645. break;
  1646. }
  1647. } while (FALSE);
  1648. TRACE1 (PORT, "ElEAPOLDeInit completed, RetCode = %d", dwRetCode);
  1649. return dwRetCode;
  1650. }
  1651. //
  1652. // Currently Unsupported
  1653. // Read EAPOL statistics for the port
  1654. //
  1655. VOID
  1656. ElReadPortStatistics (
  1657. IN WCHAR *pwszDeviceGUID,
  1658. OUT PEAPOL_STATS pEapolStats
  1659. )
  1660. {
  1661. }
  1662. //
  1663. // Currently Unsupported
  1664. // Read EAPOL Port Configuration for the mentioned port
  1665. //
  1666. VOID
  1667. ElReadPortConfiguration (
  1668. IN WCHAR *pwszDeviceGUID,
  1669. OUT PEAPOL_CONFIG pEapolConfig
  1670. )
  1671. {
  1672. }
  1673. //
  1674. // Currently Unsupported
  1675. // Set EAPOL Port Configuration for the mentioned port
  1676. //
  1677. DWORD
  1678. ElSetPortConfiguration (
  1679. IN WCHAR *pwszDeviceGUID,
  1680. IN PEAPOL_CONFIG pEapolConfig
  1681. )
  1682. {
  1683. DWORD dwRetCode = NO_ERROR;
  1684. return dwRetCode;
  1685. }
  1686. //
  1687. // ElReadCompletionRoutine
  1688. //
  1689. // Description:
  1690. //
  1691. // This routine is invoked upon completion of an OVERLAPPED read operation
  1692. // on an interface on which EAPOL is running
  1693. //
  1694. // The message read is validated and processed, and if necessary,
  1695. // a reply is generated and sent out
  1696. //
  1697. // Arguments:
  1698. // dwError - Win32 status code for the I/O operation
  1699. //
  1700. // dwBytesTransferred - number of bytes in 'pEapolBuffer'
  1701. //
  1702. // pEapolBuffer - holds data read from the datagram socket
  1703. //
  1704. // Notes:
  1705. // A reference to the component will have been made on our behalf
  1706. // by ElReadPort(). Hence g_PCBLock, will not be required
  1707. // to be taken since current PCB existence is guaranteed
  1708. //
  1709. VOID
  1710. CALLBACK
  1711. ElReadCompletionRoutine (
  1712. DWORD dwError,
  1713. DWORD dwBytesReceived,
  1714. EAPOL_BUFFER *pEapolBuffer
  1715. )
  1716. {
  1717. EAPOL_PCB *pPCB;
  1718. DWORD dwRetCode;
  1719. pPCB = (EAPOL_PCB *)pEapolBuffer->pvContext;
  1720. TRACE1 (PORT, "ElReadCompletionRoutine entered, %ld bytes recvd",
  1721. dwBytesReceived);
  1722. do
  1723. {
  1724. if (dwError)
  1725. {
  1726. // Error in read request
  1727. TRACE2 (PORT, "ElReadCompletionRoutine: Error %d on port %ws",
  1728. dwError, pPCB->pwszDeviceGUID);
  1729. // Having a ref count from the read posted, guarantees existence
  1730. // of PCB. Hence no need to acquire g_PCBLock
  1731. ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
  1732. if (EAPOL_PORT_DELETED(pPCB))
  1733. {
  1734. TRACE1 (PORT, "ElReadCompletionRoutine: Port %ws not active",
  1735. pPCB->pwszDeviceGUID);
  1736. // Port is not active, release Context buffer
  1737. RELEASE_WRITE_LOCK (&(pPCB->rwLock));
  1738. FREE (pEapolBuffer);
  1739. }
  1740. else
  1741. {
  1742. TRACE1 (PORT, "ElReadCompletionRoutine: Reposting buffer on port %ws",
  1743. pPCB->pwszDeviceGUID);
  1744. // Repost buffer for another read operation
  1745. // Free the current buffer, ElReadFromPort creates a new
  1746. // buffer
  1747. FREE(pEapolBuffer);
  1748. if ((dwRetCode = ElReadFromPort (
  1749. pPCB,
  1750. NULL,
  1751. 0
  1752. )) != NO_ERROR)
  1753. {
  1754. RELEASE_WRITE_LOCK (&(pPCB->rwLock));
  1755. TRACE1 (PORT, "ElReadCompletionRoutine: ElReadFromPort 1 error %d",
  1756. dwRetCode);
  1757. break;
  1758. }
  1759. RELEASE_WRITE_LOCK (&(pPCB->rwLock));
  1760. }
  1761. break;
  1762. }
  1763. // Successful read completion
  1764. ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
  1765. if (EAPOL_PORT_DELETED(pPCB))
  1766. {
  1767. // Port is not active
  1768. RELEASE_WRITE_LOCK (&(pPCB->rwLock));
  1769. FREE (pEapolBuffer);
  1770. TRACE1 (PORT, "ElReadCompletionRoutine: Port %ws is inactive",
  1771. pPCB->pwszDeviceGUID);
  1772. break;
  1773. }
  1774. RELEASE_WRITE_LOCK (&(pPCB->rwLock));
  1775. // Queue a work item to the Thread Pool to execute in the
  1776. // I/O component. Callbacks from BindIoCompletionCallback do not
  1777. // guarantee to be running in I/O component. So, on a non I/O
  1778. // component thread may die while requests are pending.
  1779. // (Refer to Jeffrey Richter, pg 416, Programming Applications for
  1780. // Microsoft Windows, Fourth Edition
  1781. // pEapolBuffer will be the context for the function
  1782. // since it stores all relevant information for processing
  1783. // i.e. pBuffer, dwBytesTransferred, pContext => pPCB
  1784. InterlockedIncrement (&g_lWorkerThreads);
  1785. if (!QueueUserWorkItem (
  1786. (LPTHREAD_START_ROUTINE)ElProcessReceivedPacket,
  1787. (PVOID)pEapolBuffer,
  1788. WT_EXECUTELONGFUNCTION
  1789. ))
  1790. {
  1791. InterlockedDecrement (&g_lWorkerThreads);
  1792. FREE (pEapolBuffer);
  1793. dwRetCode = GetLastError();
  1794. TRACE1 (PORT, "ElReadCompletionRoutine: Critical error: QueueUserWorkItem failed with error %ld",
  1795. dwRetCode);
  1796. break;
  1797. }
  1798. else
  1799. {
  1800. //TRACE1 (PORT, "ElReadCompletionRoutine: QueueUserWorkItem work item queued for port %p",
  1801. //pPCB);
  1802. // The received packet has still not been processed.
  1803. // The ref count cannot be decrement, yet
  1804. return;
  1805. }
  1806. } while (FALSE);
  1807. TRACE2 (PORT, "ElReadCompletionRoutine: pPCB= %p, RefCnt = %ld",
  1808. pPCB, pPCB->dwRefCount);
  1809. // Decrement refcount for error cases
  1810. EAPOL_DEREFERENCE_PORT(pPCB);
  1811. }
  1812. //
  1813. // ElWriteCompletionRoutine
  1814. //
  1815. // Description:
  1816. //
  1817. // This routine is invoked upon completion of an OVERLAPPED write operation
  1818. // on an interface on which EAPOL is running.
  1819. //
  1820. //
  1821. // Arguments:
  1822. // dwError - Win32 status code for the I/O operation
  1823. //
  1824. // dwBytesTransferred - number of bytes sent out
  1825. //
  1826. // pEapolBuffer - buffer sent to the WriteFile command
  1827. //
  1828. // Notes:
  1829. // The reference count for the write operation is removed.
  1830. //
  1831. VOID
  1832. CALLBACK
  1833. ElWriteCompletionRoutine (
  1834. DWORD dwError,
  1835. DWORD dwBytesSent,
  1836. EAPOL_BUFFER *pEapolBuffer
  1837. )
  1838. {
  1839. PEAPOL_PCB pPCB = (PEAPOL_PCB)pEapolBuffer->pvContext;
  1840. TRACE2 (DEVICE, "ElWriteCompletionRoutine sent out %d bytes with error %d",
  1841. dwBytesSent, dwError);
  1842. // No need to acquire locks, since PCB existence is guaranteed
  1843. // by reference made when write was posted
  1844. EAPOL_DEREFERENCE_PORT(pPCB);
  1845. TRACE2 (PORT, "ElWriteCompletionRoutine: pPCB= %p, RefCnt = %ld",
  1846. pPCB, pPCB->dwRefCount);
  1847. FREE(pEapolBuffer);
  1848. return;
  1849. // Free Read/Write buffer area, if it is dynamically allocated
  1850. // We have static Read-write buffer for now
  1851. }
  1852. //
  1853. // ElIoCompletionRoutine
  1854. //
  1855. // Description:
  1856. //
  1857. // Callback function defined to BindIoCompletionCallback
  1858. // This routine is invoked by the I/O system upon completion of a read/write
  1859. // operation
  1860. // This routine in turn calls ElReadCompletionRoutine or
  1861. // ElWriteCompletionRoutine depending on what command invoked the
  1862. // I/O operation i.e. ReadFile or WriteFile
  1863. //
  1864. // Input arguments:
  1865. // dwError - system-supplied error code
  1866. // dwBytesTransferred - system-supplied byte-count
  1867. // lpOverlapped - called-supplied context area
  1868. //
  1869. // Return values:
  1870. //
  1871. VOID
  1872. CALLBACK
  1873. ElIoCompletionRoutine (
  1874. DWORD dwError,
  1875. DWORD dwBytesTransferred,
  1876. LPOVERLAPPED lpOverlapped
  1877. )
  1878. {
  1879. PEAPOL_BUFFER pBuffer = CONTAINING_RECORD (lpOverlapped, EAPOL_BUFFER, Overlapped);
  1880. TRACE1 (DEVICE, "ElIoCompletionRoutine called, %ld bytes xferred",
  1881. dwBytesTransferred);
  1882. pBuffer->dwErrorCode = dwError;
  1883. pBuffer->dwBytesTransferred = dwBytesTransferred;
  1884. pBuffer->CompletionRoutine (
  1885. pBuffer->dwErrorCode,
  1886. pBuffer->dwBytesTransferred,
  1887. pBuffer
  1888. );
  1889. return;
  1890. }
  1891. //
  1892. // ElReadFromPort
  1893. //
  1894. // Description:
  1895. //
  1896. // Function to read EAPOL packets from a port
  1897. //
  1898. // Arguments:
  1899. // pPCB - Pointer to PCB for port on which read is to be performed
  1900. // pBuffer - unused
  1901. // dwBufferLength - unused
  1902. //
  1903. // Return values:
  1904. //
  1905. // Locks:
  1906. // pPCB->rw_Lock should be acquired before calling this function
  1907. //
  1908. DWORD
  1909. ElReadFromPort (
  1910. IN PEAPOL_PCB pPCB,
  1911. IN PCHAR pBuffer,
  1912. IN DWORD dwBufferLength
  1913. )
  1914. {
  1915. PEAPOL_BUFFER pEapolBuffer;
  1916. DWORD dwRetCode = NO_ERROR;
  1917. TRACE0 (PORT, "ElReadFromPort entered");
  1918. // Allocate Context buffer
  1919. if ((pEapolBuffer = (PEAPOL_BUFFER) MALLOC (sizeof(EAPOL_BUFFER))) == NULL)
  1920. {
  1921. TRACE0 (PORT, "ElReadFromPort: Error in memory allocation");
  1922. return ERROR_NOT_ENOUGH_MEMORY;
  1923. }
  1924. // Initialize Context data used in Overlapped operations
  1925. pEapolBuffer->pvContext = (PVOID)pPCB;
  1926. pEapolBuffer->CompletionRoutine = ElReadCompletionRoutine;
  1927. // Make a reference to the port
  1928. // this reference is released in the completion routine
  1929. if (!EAPOL_REFERENCE_PORT(pPCB))
  1930. {
  1931. //RELEASE_WRITE_LOCK (&(g_PCBLock));
  1932. TRACE0 (PORT, "ElReadFromPort: Unable to obtain reference to port");
  1933. FREE (pEapolBuffer);
  1934. return ERROR_CAN_NOT_COMPLETE;
  1935. }
  1936. TRACE2 (DEVICE, "ElReadFromPort: pPCB = %p, RefCnt = %ld",
  1937. pPCB, pPCB->dwRefCount);
  1938. // Read from the NDISUIO interface corresponding to this port
  1939. if ((dwRetCode = ElReadFromInterface(
  1940. pPCB->hPort,
  1941. pEapolBuffer,
  1942. MAX_PACKET_SIZE - SIZE_ETHERNET_CRC
  1943. // read the maximum data possible
  1944. )) != NO_ERROR)
  1945. {
  1946. TRACE1 (DEVICE, "ElReadFromPort: Error in ElReadFromInterface = %d",
  1947. dwRetCode);
  1948. FREE(pEapolBuffer);
  1949. // Decrement refcount just incremented, since it will not be
  1950. // decremented in ReadCompletionRoutine which is not called
  1951. EAPOL_DEREFERENCE_PORT(pPCB);
  1952. TRACE2 (PORT, "ElReadFromPort: pPCB= %p, RefCnt = %ld",
  1953. pPCB, pPCB->dwRefCount);
  1954. }
  1955. return dwRetCode;
  1956. }
  1957. //
  1958. // ElWriteToPort
  1959. //
  1960. // Description:
  1961. //
  1962. // Function to write EAPOL packets to a port
  1963. //
  1964. // Input arguments:
  1965. // pPCB - Pointer to PCB for port on which write is to be performed
  1966. // pBuffer - Pointer to data to be sent out
  1967. // dwBufferLength - Number of bytes to be sent out
  1968. //
  1969. // Return values:
  1970. //
  1971. // Locks:
  1972. // pPCB->rw_Lock should be acquired before calling this function
  1973. //
  1974. DWORD
  1975. ElWriteToPort (
  1976. IN PEAPOL_PCB pPCB,
  1977. IN PCHAR pBuffer,
  1978. IN DWORD dwBufferLength
  1979. )
  1980. {
  1981. PEAPOL_BUFFER pEapolBuffer;
  1982. PETH_HEADER pEthHeader;
  1983. DWORD dwTotalBytes = 0;
  1984. DWORD dwRetCode = NO_ERROR;
  1985. TRACE1 (PORT, "ElWriteToPort entered: Pkt Length = %ld", dwBufferLength);
  1986. if ((pEapolBuffer = (PEAPOL_BUFFER) MALLOC (sizeof(EAPOL_BUFFER))) == NULL)
  1987. {
  1988. TRACE0 (PORT, "ElWriteToPort: Error in memory allocation");
  1989. return ERROR_NOT_ENOUGH_MEMORY;
  1990. }
  1991. // Initialize Context data used in Overlapped operations
  1992. pEapolBuffer->pvContext = (PVOID)pPCB;
  1993. pEapolBuffer->CompletionRoutine = ElWriteCompletionRoutine;
  1994. pEthHeader = (PETH_HEADER)pEapolBuffer->pBuffer;
  1995. // Copy the source MAC address and the destination MAC address
  1996. memcpy ((PBYTE)pEthHeader->bDstAddr,
  1997. (PBYTE)pPCB->bDestMacAddr,
  1998. SIZE_MAC_ADDR);
  1999. memcpy ((PBYTE)pEthHeader->bSrcAddr,
  2000. (PBYTE)pPCB->bSrcMacAddr,
  2001. SIZE_MAC_ADDR);
  2002. // Validate packet length
  2003. if ((dwBufferLength + sizeof(ETH_HEADER)) >
  2004. (MAX_PACKET_SIZE - SIZE_ETHERNET_CRC))
  2005. {
  2006. TRACE2 (PORT, "ElWriteToPort: Packetsize %d greater than maximum allowed",
  2007. dwBufferLength,
  2008. (MAX_PACKET_SIZE - SIZE_ETHERNET_CRC - sizeof(ETH_HEADER)));
  2009. FREE (pEapolBuffer);
  2010. return ERROR_BAD_LENGTH;
  2011. }
  2012. // Copy the EAPOL packet and body
  2013. if (pBuffer != NULL)
  2014. {
  2015. memcpy ((PBYTE)((PBYTE)pEapolBuffer->pBuffer+sizeof(ETH_HEADER)),
  2016. (PBYTE)pBuffer,
  2017. dwBufferLength);
  2018. }
  2019. dwTotalBytes = dwBufferLength + sizeof(ETH_HEADER);
  2020. ElParsePacket (pEapolBuffer->pBuffer, dwTotalBytes,
  2021. FALSE);
  2022. // Buffer will be released by calling function
  2023. // Write to the NDISUIO interface corresponding to this port
  2024. // Make a reference to the port
  2025. // this reference is released in the completion routine
  2026. if (!EAPOL_REFERENCE_PORT(pPCB))
  2027. {
  2028. TRACE0 (PORT, "ElWriteToPort: Unable to obtain reference to port");
  2029. FREE (pEapolBuffer);
  2030. return ERROR_CAN_NOT_COMPLETE;
  2031. }
  2032. else
  2033. {
  2034. TRACE2 (DEVICE, "ElWriteToPort: pPCB = %p, RefCnt = %ld",
  2035. pPCB, pPCB->dwRefCount);
  2036. if ((dwRetCode = ElWriteToInterface (
  2037. pPCB->hPort,
  2038. pEapolBuffer,
  2039. dwTotalBytes
  2040. )) != NO_ERROR)
  2041. {
  2042. FREE (pEapolBuffer);
  2043. TRACE1 (PORT, "ElWriteToPort: Error %d", dwRetCode);
  2044. // Decrement refcount incremented in this function,
  2045. // since it will not be decremented in WriteCompletionRoutine
  2046. // as it will never be called.
  2047. EAPOL_DEREFERENCE_PORT(pPCB);
  2048. TRACE2 (PORT, "ElWriteToPort: pPCB= %p, RefCnt = %ld",
  2049. pPCB, pPCB->dwRefCount);
  2050. return dwRetCode;
  2051. }
  2052. }
  2053. //TRACE1 (PORT, "ElWriteToPort completed, dwRetCode =%d", dwRetCode);
  2054. return dwRetCode;
  2055. }