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.

2771 lines
82 KiB

  1. /*++
  2. Copyright (c) 1999, Microsoft Corporation
  3. Module Name:
  4. elprotocol.c
  5. Abstract:
  6. This module implements functions related to EAPOL
  7. protocol
  8. Revision History:
  9. sachins, Apr 30 2000, Created
  10. --*/
  11. #include "pcheapol.h"
  12. #pragma hdrstop
  13. #define EAPOL_SERVICE
  14. #ifndef EAPOL_SERVICE
  15. HRESULT
  16. EAPOLMANAuthenticationStarted (
  17. REFGUID InterfaceId
  18. );
  19. HRESULT
  20. EAPOLMANAuthenticationSucceeded (
  21. REFGUID InterfaceId
  22. );
  23. HRESULT
  24. EAPOLMANAuthenticationFailed (
  25. REFGUID InterfaceId,
  26. DWORD dwType
  27. );
  28. HRESULT EAPOLMANNotification(
  29. REFGUID InterfaceId,
  30. LPWSTR szwNotificationMessage,
  31. DWORD dwType
  32. );
  33. #endif
  34. //
  35. // ElProcessReceivedPacket
  36. //
  37. // Description:
  38. //
  39. // Function called to process data received from the NDISUIO driver.
  40. // The EAPOL packet is extracted and further processing is done.
  41. //
  42. //
  43. // Arguments:
  44. // pvContext - Context buffer which is a pointer to EAPOL_BUFFER structure
  45. //
  46. // Return Values:
  47. //
  48. VOID
  49. ElProcessReceivedPacket (
  50. IN PVOID pvContext
  51. )
  52. {
  53. EAPOL_PCB *pPCB = NULL;
  54. EAPOL_BUFFER *pEapolBuffer = NULL;
  55. DWORD dwLength = 0;
  56. ETH_HEADER *pEthHdr = NULL;
  57. EAPOL_PACKET *pEapolPkt = NULL;
  58. EAPOL_PACKET_D8 *pEapolPktD8 = NULL;
  59. BOOLEAN fRemoteEnd8021XD8 = FALSE;
  60. PPP_EAP_PACKET *pEapPkt = NULL;
  61. BYTE *pBuffer;
  62. BOOLEAN ReqId = FALSE; // EAPOL state machine local variables
  63. BOOLEAN ReqAuth = FALSE;
  64. BOOLEAN EapSuccess = FALSE;
  65. BOOLEAN EapFail = FALSE;
  66. BOOLEAN RxKey = FALSE;
  67. GUID DeviceGuid;
  68. EAPOL_PACKET_D8_D7 DummyHeader;
  69. DWORD dwRetCode = NO_ERROR;
  70. if (pvContext == NULL)
  71. {
  72. TRACE0 (EAPOL, "ProcessReceivedPacket: Critical error, Context is NULL");
  73. return;
  74. }
  75. pEapolBuffer = (EAPOL_BUFFER *)pvContext;
  76. pPCB = (EAPOL_PCB *)pEapolBuffer->pvContext;
  77. dwLength = pEapolBuffer->dwBytesTransferred;
  78. pBuffer = (BYTE *)pEapolBuffer->pBuffer;
  79. TRACE1 (EAPOL, "ProcessReceivedPacket entered, length = %ld", dwLength);
  80. do
  81. {
  82. // The Port was verified to be active before the workitem
  83. // was queued. But do a double-check
  84. ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
  85. if (!EAPOL_PORT_ACTIVE(pPCB))
  86. {
  87. TRACE1 (EAPOL, "ProcessReceivedPacket: Port %s not active",
  88. pPCB->pszDeviceGUID);
  89. RELEASE_WRITE_LOCK (&(pPCB->rwLock));
  90. FREE (pEapolBuffer);
  91. break;
  92. }
  93. RELEASE_WRITE_LOCK (&(pPCB->rwLock));
  94. // Validate packet length
  95. // Should be atleast ETH_HEADER and first 4 required bytes of
  96. // EAPOL_PACKET
  97. if (dwLength < (sizeof(ETH_HEADER) + 4))
  98. {
  99. TRACE2 (EAPOL, "ProcessReceivedPacket: Packet length %ld is less than minimum required %d. Ignoring packet",
  100. dwLength, (sizeof(ETH_HEADER) + 4));
  101. FREE (pEapolBuffer);
  102. dwRetCode = ERROR_INVALID_PACKET_LENGTH_OR_ID;
  103. break;
  104. }
  105. // Validate Destination MAC Address
  106. // Compare with MAC address got during MEDIA_CONNECT
  107. #if 0
  108. pEthHdr = (ETH_HEADER *)pBuffer;
  109. if ((memcmp ((BYTE *)pEthHdr->bSrcAddr,
  110. (BYTE *)pPCB->bDestMacAddr,
  111. SIZE_MAC_ADDR)) != 0)
  112. {
  113. TRACE2 (EAPOL, "ProcessReceivedPacket: Dest MAC address %s does not match PAE address %s. Ignoring packet",
  114. pEthHdr->SrcAddr,
  115. pPCB->bDestMacAddr);
  116. FREE (pEapolBuffer);
  117. dwRetCode = ERROR_INVALID_ADDRESS;
  118. break;
  119. }
  120. #endif
  121. // Verify if the packet contains a 802.1P tag. If so, skip the 4 bytes
  122. // after the src+dest mac addresses
  123. if ((WireToHostFormat16(pBuffer + sizeof(ETH_HEADER)) == EAPOL_8021P_TAG_TYPE))
  124. {
  125. pEapolPkt = (EAPOL_PACKET *)(pBuffer + sizeof(ETH_HEADER) + 4);
  126. }
  127. else
  128. {
  129. pEapolPkt = (EAPOL_PACKET *)(pBuffer + sizeof(ETH_HEADER));
  130. }
  131. // Validate Ethernet type in the incoming packet
  132. // It should be the same as the one defined for the
  133. // current port
  134. if (memcmp ((BYTE *)pEapolPkt->EthernetType, (BYTE *)pPCB->bEtherType,
  135. SIZE_ETHERNET_TYPE) != 0)
  136. {
  137. TRACE2 (EAPOL, "ProcessReceivedPacket: Packet PAE type %s does not match expected type %s. Ignoring packet",
  138. pEapolPkt->EthernetType,
  139. pPCB->bEtherType);
  140. FREE (pEapolBuffer);
  141. dwRetCode = ERROR_INVALID_PACKET_LENGTH_OR_ID;
  142. break;
  143. }
  144. // EAPOL packet type should be valid
  145. if ((pEapolPkt->PacketType != EAP_Packet) &&
  146. (pEapolPkt->PacketType != EAPOL_Start) &&
  147. (pEapolPkt->PacketType != EAPOL_Logoff) &&
  148. (pEapolPkt->PacketType != EAPOL_Key))
  149. {
  150. TRACE1 (EAPOL, "ProcessReceivedPacket: Invalid EAPOL packet type %d. Ignoring packet",
  151. pEapolPkt->PacketType);
  152. FREE (pEapolBuffer);
  153. dwRetCode = ERROR_INVALID_PACKET;
  154. break;
  155. }
  156. // Determine the value of local EAPOL state variables
  157. if (pEapolPkt->PacketType == EAP_Packet)
  158. {
  159. TRACE0 (EAPOL, "ProcessReceivedPacket: EAP_Packet");
  160. // Validate length of packet for EAP
  161. // Should be atleast (ETH_HEADER+EAPOL_PACKET)
  162. if (dwLength < (sizeof (ETH_HEADER) + sizeof (EAPOL_PACKET)))
  163. {
  164. TRACE1 (EAPOL, "ProcessReceivedPacket: Invalid length of EAP packet %d. Ignoring packet",
  165. dwLength);
  166. FREE (pEapolBuffer);
  167. dwRetCode = ERROR_INVALID_PACKET_LENGTH_OR_ID;
  168. break;
  169. }
  170. // Determine if the packet is draft 8 or not
  171. pEapolPktD8 = (EAPOL_PACKET_D8 *)pEapolPkt;
  172. pEapPkt = (PPP_EAP_PACKET *)pEapolPktD8->PacketBody;
  173. switch (WireToHostFormat16(pEapolPktD8->AuthResultCode))
  174. {
  175. case AUTH_Continuing:
  176. if (pEapPkt->Code == EAPCODE_Request)
  177. {
  178. fRemoteEnd8021XD8 = TRUE;
  179. }
  180. break;
  181. case AUTH_Authorized:
  182. if (pEapPkt->Code == EAPCODE_Success)
  183. {
  184. fRemoteEnd8021XD8 = TRUE;
  185. }
  186. break;
  187. case AUTH_Unauthorized:
  188. if ((pEapPkt->Code == EAPCODE_Failure) ||
  189. (pEapPkt->Code == EAPCODE_Success))
  190. {
  191. fRemoteEnd8021XD8 = TRUE;
  192. }
  193. break;
  194. }
  195. if (fRemoteEnd8021XD8 && (WireToHostFormat16(pEapolPktD8->PacketBodyLength) != 0))
  196. {
  197. TRACE0 (EAPOL, "ProcessReceivedPacket: Packet received DRAFT 8 format");
  198. pPCB->fRemoteEnd8021XD8 = TRUE;
  199. memcpy (DummyHeader.AuthResultCode, pEapolPktD8->AuthResultCode,
  200. 2);
  201. memcpy (DummyHeader.EthernetType, pEapolPktD8->EthernetType,
  202. 2);
  203. DummyHeader.ProtocolVersion = pEapolPktD8->ProtocolVersion;
  204. DummyHeader.PacketType = pEapolPktD8->PacketType;
  205. memcpy ((BYTE *)pEapolPktD8, (BYTE *)&DummyHeader, 6);
  206. pEapolPkt = (EAPOL_PACKET *)((BYTE *)pEapolPktD8 + 2);
  207. }
  208. else
  209. {
  210. pPCB->fRemoteEnd8021XD8 = FALSE;
  211. TRACE0 (EAPOL, "ProcessReceivedPacket: Packet received PRE-DRAFT 8 format");
  212. }
  213. pEapPkt = (PPP_EAP_PACKET *)pEapolPkt->PacketBody;
  214. if (pEapPkt->Code == EAPCODE_Request)
  215. {
  216. // Validate length of packet for EAP-Request packet
  217. // Should be atleast (ETH_HEADER+EAPOL_PACKET-1+PPP_EAP_PACKET)
  218. if (dwLength < (sizeof (ETH_HEADER) + sizeof(EAPOL_PACKET)-1
  219. + sizeof (PPP_EAP_PACKET)))
  220. {
  221. TRACE1 (EAPOL, "ProcessReceivedPacket: Invalid length of EAP Request packet %d. Ignoring packet",
  222. dwLength);
  223. FREE (pEapolBuffer);
  224. dwRetCode = ERROR_INVALID_PACKET_LENGTH_OR_ID;
  225. break;
  226. }
  227. if (pEapPkt->Data[0] == EAPTYPE_Identity)
  228. {
  229. pPCB->fIsRemoteEndEAPOLAware = TRUE;
  230. ReqId = TRUE;
  231. }
  232. else
  233. {
  234. ReqAuth = TRUE;
  235. }
  236. }
  237. else if (pEapPkt->Code == EAPCODE_Success)
  238. {
  239. EapSuccess = TRUE;
  240. }
  241. else if (pEapPkt->Code == EAPCODE_Failure)
  242. {
  243. EapFail = TRUE;
  244. }
  245. else
  246. {
  247. // Invalid type
  248. TRACE1 (EAPOL, "ProcessReceivedPacket: Invalid EAP packet type %d. Ignoring packet",
  249. pEapPkt->Code);
  250. FREE (pEapolBuffer);
  251. dwRetCode = ERROR_INVALID_PACKET;
  252. break;
  253. }
  254. }
  255. else
  256. {
  257. TRACE0 (EAPOL, "ProcessReceivedPacket: != EAP_Packet");
  258. if (pEapolPkt->PacketType == EAPOL_Key)
  259. {
  260. TRACE0 (EAPOL, "ProcessReceivedPacket: == EAPOL_Key");
  261. RxKey = TRUE;
  262. // Determine if the packet is draft 8 or not
  263. pEapolPktD8 = (EAPOL_PACKET_D8 *)pEapolPkt;
  264. // In pre-draft 8, PacketBodyLength cannot be '0'
  265. // If it is zero, it is draft 8 packet format
  266. if (WireToHostFormat16(pEapolPktD8->AuthResultCode)
  267. == AUTH_Continuing)
  268. {
  269. pPCB->fRemoteEnd8021XD8 = TRUE;
  270. memcpy (DummyHeader.AuthResultCode,
  271. pEapolPktD8->AuthResultCode,
  272. 2);
  273. memcpy (DummyHeader.EthernetType,
  274. pEapolPktD8->EthernetType,
  275. 2);
  276. DummyHeader.ProtocolVersion = pEapolPktD8->ProtocolVersion;
  277. DummyHeader.PacketType = pEapolPktD8->PacketType;
  278. memcpy ((BYTE *)pEapolPktD8, (BYTE *)&DummyHeader, 6);
  279. pEapolPkt = (EAPOL_PACKET *)((BYTE *)pEapolPktD8 + 2);
  280. }
  281. else
  282. {
  283. pPCB->fRemoteEnd8021XD8 = FALSE;
  284. TRACE0 (EAPOL, "ProcessReceivedPacket: EAPOL_Key Packet received PRE-DRAFT 8 format");
  285. }
  286. }
  287. }
  288. //
  289. // NOTE:
  290. // Should we check values of EAP type
  291. //
  292. // Checking value of PCB fields now
  293. ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
  294. switch (pPCB->State)
  295. {
  296. // ReqId, ReqAuth, EapSuccess, EapFail, RxKey are inherently
  297. // mutually exclusive
  298. // No checks will be made to verify this
  299. // Also, assumption is being made that in any state, maximum
  300. // one timer may be active on the port.
  301. case EAPOLSTATE_LOGOFF:
  302. // Only a User Logon event can get the port out of
  303. // LOGOFF state
  304. TRACE0 (EAPOL, "ProcessReceivedPacket: LOGOFF state, Ignoing packet");
  305. break;
  306. case EAPOLSTATE_DISCONNECTED:
  307. // Only a Media Connect event can get the port out of
  308. // DISCONNECTED state
  309. TRACE0 (EAPOL, "ProcessReceivedPacket: DISCONNECTED state, Ignoing packet");
  310. break;
  311. case EAPOLSTATE_CONNECTING:
  312. TRACE0 (EAPOL, "ProcessReceivedPacket: EAPOLSTATE_CONNECTING");
  313. if (ReqId | EapSuccess | EapFail)
  314. {
  315. // Deactivate current timer
  316. RESTART_TIMER (pPCB->hTimer,
  317. INFINITE_SECONDS,
  318. "PCB",
  319. &dwRetCode);
  320. if (dwRetCode != NO_ERROR)
  321. {
  322. break;
  323. }
  324. }
  325. if (EapSuccess)
  326. {
  327. if ((dwRetCode = ElProcessEapSuccess (pPCB,
  328. pEapolPkt)) != NO_ERROR)
  329. {
  330. break;
  331. }
  332. }
  333. else
  334. if (EapFail)
  335. {
  336. if ((dwRetCode = ElProcessEapFail (pPCB,
  337. pEapolPkt)) != NO_ERROR)
  338. {
  339. break;
  340. }
  341. }
  342. else
  343. if (ReqId)
  344. {
  345. if ((dwRetCode = FSMAcquired (pPCB,
  346. pEapolPkt)) != NO_ERROR)
  347. {
  348. break;
  349. }
  350. }
  351. break;
  352. case EAPOLSTATE_ACQUIRED:
  353. TRACE0 (EAPOL, "ProcessReceivedPacket: EAPOLSTATE_ACQUIRED");
  354. if (ReqId | ReqAuth | EapSuccess | EapFail)
  355. {
  356. // Deactivate current timer
  357. RESTART_TIMER (pPCB->hTimer,
  358. INFINITE_SECONDS,
  359. "PCB",
  360. &dwRetCode);
  361. if (dwRetCode != NO_ERROR)
  362. {
  363. break;
  364. }
  365. }
  366. if (EapSuccess)
  367. {
  368. if ((dwRetCode = ElProcessEapSuccess (pPCB,
  369. pEapolPkt)) != NO_ERROR)
  370. {
  371. break;
  372. }
  373. }
  374. else
  375. if (EapFail)
  376. {
  377. if ((dwRetCode = ElProcessEapFail (pPCB,
  378. pEapolPkt)) != NO_ERROR)
  379. {
  380. break;
  381. }
  382. }
  383. else
  384. if (ReqId)
  385. {
  386. if ((dwRetCode = FSMAcquired (pPCB,
  387. pEapolPkt)) != NO_ERROR)
  388. {
  389. break;
  390. }
  391. }
  392. else
  393. if (ReqAuth)
  394. {
  395. if ((dwRetCode = FSMAuthenticating (pPCB,
  396. pEapolPkt)) != NO_ERROR)
  397. {
  398. break;
  399. }
  400. }
  401. break;
  402. case EAPOLSTATE_AUTHENTICATING:
  403. TRACE0 (EAPOL, "ProcessReceivedPacket: EAPOLSTATE_AUTHENTICATING");
  404. // Common timer deletion
  405. if (ReqAuth | ReqId | EapSuccess | EapFail)
  406. {
  407. // Deactivate current timer
  408. RESTART_TIMER (pPCB->hTimer,
  409. INFINITE_SECONDS,
  410. "PCB",
  411. &dwRetCode);
  412. if (dwRetCode != NO_ERROR)
  413. {
  414. break;
  415. }
  416. if (ReqId)
  417. {
  418. if ((dwRetCode = FSMAcquired (pPCB,
  419. pEapolPkt)) != NO_ERROR)
  420. {
  421. break;
  422. }
  423. }
  424. else
  425. {
  426. if ((dwRetCode = FSMAuthenticating (pPCB,
  427. pEapolPkt)) != NO_ERROR)
  428. {
  429. break;
  430. }
  431. }
  432. }
  433. // Continue further processing
  434. if (EapSuccess | EapFail)
  435. {
  436. // Auth timer will have restarted in FSMAuthenticating
  437. // Deactivate the timer
  438. RESTART_TIMER (pPCB->hTimer,
  439. INFINITE_SECONDS,
  440. "PCB",
  441. &dwRetCode);
  442. if (dwRetCode != NO_ERROR)
  443. {
  444. break;
  445. }
  446. // If the packet received was a EAP-Success, go into
  447. // AUTHENTICATED state
  448. if (EapSuccess)
  449. {
  450. if ((dwRetCode = ElProcessEapSuccess (pPCB,
  451. pEapolPkt)) != NO_ERROR)
  452. {
  453. break;
  454. }
  455. }
  456. else
  457. // If the packet received was a EAP-Failure, go into
  458. // HELD state
  459. if (EapFail)
  460. {
  461. if ((dwRetCode = ElProcessEapFail (pPCB,
  462. pEapolPkt)) != NO_ERROR)
  463. {
  464. break;
  465. }
  466. }
  467. }
  468. break;
  469. case EAPOLSTATE_HELD:
  470. TRACE0 (EAPOL, "ProcessReceivedPacket: HELD state, Ignoring packet");
  471. if (ReqId)
  472. {
  473. // Deactivate current timer
  474. RESTART_TIMER (pPCB->hTimer,
  475. INFINITE_SECONDS,
  476. "PCB",
  477. &dwRetCode);
  478. if (dwRetCode != NO_ERROR)
  479. {
  480. break;
  481. }
  482. if ((dwRetCode = FSMAcquired (pPCB,
  483. pEapolPkt)) != NO_ERROR)
  484. {
  485. break;
  486. }
  487. }
  488. break;
  489. case EAPOLSTATE_AUTHENTICATED:
  490. TRACE0 (EAPOL, "ProcessReceivedPacket: STATE_AUTHENTICATED");
  491. if (ReqId)
  492. {
  493. if ((dwRetCode = FSMAcquired (pPCB,
  494. pEapolPkt)) != NO_ERROR)
  495. {
  496. break;
  497. }
  498. }
  499. else
  500. if (RxKey)
  501. {
  502. if ((dwRetCode = FSMRxKey (pPCB,
  503. pEapolPkt)) != NO_ERROR)
  504. {
  505. break;
  506. }
  507. }
  508. break;
  509. default:
  510. TRACE0 (EAPOL, "ProcessReceivedPacket: Critical Error. Invalid state, Ignoring packet");
  511. break;
  512. }
  513. // Only packet passing through switch statement will be freed here
  514. FREE (pEapolBuffer);
  515. RELEASE_WRITE_LOCK (&(pPCB->rwLock));
  516. } while (FALSE);
  517. // Post a new read request, ignoring errors
  518. ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
  519. if (!EAPOL_PORT_ACTIVE(pPCB))
  520. {
  521. TRACE1 (EAPOL, "ProcessReceivedPacket: Port %s not active, not reposting read request",
  522. pPCB->pszDeviceGUID);
  523. // Port is not active, release Context buffer
  524. RELEASE_WRITE_LOCK (&(pPCB->rwLock));
  525. }
  526. else
  527. {
  528. TRACE1 (EAPOL, "ProcessReceivedPacket: Reposting buffer on port %s",
  529. pPCB->pszDeviceGUID);
  530. RELEASE_WRITE_LOCK (&(pPCB->rwLock));
  531. // ElReadFromPort creates a new context buffer, adds a ref count,
  532. // and posts the read request
  533. if ((dwRetCode = ElReadFromPort (
  534. pPCB,
  535. NULL,
  536. 0
  537. )) != NO_ERROR)
  538. {
  539. TRACE1 (EAPOL, "ProcessReceivedPacket: Critical error: ElReadFromPort error %d",
  540. dwRetCode);
  541. // LOG
  542. }
  543. }
  544. // Dereference ref count held for the read that was just processed
  545. EAPOL_DEREFERENCE_PORT(pPCB);
  546. TRACE2 (EAPOL, "ProcessReceivedPacket: pPCB= %p, RefCnt = %ld",
  547. pPCB, pPCB->dwRefCount);
  548. TRACE0 (EAPOL, "ProcessReceivedPacket exit");
  549. return;
  550. }
  551. //
  552. // FSMDisconnected
  553. //
  554. // Description:
  555. // Function called when media disconnect occurs
  556. //
  557. // Arguments:
  558. // pPCB - Pointer to PCB for the port on which media disconnect occurs
  559. //
  560. // Return values:
  561. // NO_ERROR - success
  562. // non-zero - error
  563. //
  564. DWORD
  565. FSMDisconnected (
  566. IN EAPOL_PCB *pPCB
  567. )
  568. {
  569. DWORD dwRetCode = NO_ERROR;
  570. TRACE1 (EAPOL, "FSMDisconnected entered for port %s", pPCB->pszFriendlyName);
  571. do
  572. {
  573. } while (FALSE);
  574. TRACE1 (EAPOL, "Setting state DISCONNECTED for port %s", pPCB->pszFriendlyName);
  575. pPCB->State = EAPOLSTATE_DISCONNECTED;
  576. // Free Identity buffer
  577. if (pPCB->pszIdentity != NULL)
  578. {
  579. FREE (pPCB->pszIdentity);
  580. pPCB->pszIdentity = NULL;
  581. }
  582. // Free Password buffer
  583. if (pPCB->pszPassword != NULL)
  584. {
  585. FREE (pPCB->pszPassword);
  586. pPCB->pszPassword = NULL;
  587. }
  588. // Free user-specific data in the PCB
  589. if (pPCB->pCustomAuthUserData != NULL)
  590. {
  591. FREE (pPCB->pCustomAuthUserData);
  592. pPCB->pCustomAuthUserData = NULL;
  593. }
  594. // Free connection data, though it is common to all users
  595. if (pPCB->pCustomAuthConnData != NULL)
  596. {
  597. FREE (pPCB->pCustomAuthConnData);
  598. pPCB->pCustomAuthConnData = NULL;
  599. }
  600. // Free SSID
  601. if (pPCB->pszSSID != NULL)
  602. {
  603. FREE (pPCB->pszSSID);
  604. pPCB->pszSSID = NULL;
  605. }
  606. pPCB->fGotUserIdentity = FALSE;
  607. TRACE1 (EAPOL, "FSMDisconnected completed for port %s", pPCB->pszFriendlyName);
  608. return dwRetCode;
  609. }
  610. //
  611. // FSMLogoff
  612. //
  613. // Description:
  614. // Function called to send out EAPOL_Logoff packet. Usually triggered by
  615. // user logging off.
  616. //
  617. // Arguments:
  618. // pPCB - Pointer to PCB for the port on which logoff packet is to be
  619. // sent out
  620. //
  621. // Return values:
  622. // NO_ERROR - success
  623. // non-zero - error
  624. //
  625. DWORD
  626. FSMLogoff (
  627. IN EAPOL_PCB *pPCB
  628. )
  629. {
  630. EAPOL_PACKET *pEapolPkt = NULL;
  631. DWORD dwRetCode = NO_ERROR;
  632. TRACE1 (EAPOL, "FSMLogoff entered for port %s", pPCB->pszFriendlyName);
  633. do
  634. {
  635. // Allocate new buffer
  636. pEapolPkt = (EAPOL_PACKET *) MALLOC (sizeof (EAPOL_PACKET));
  637. if (pEapolPkt == NULL)
  638. {
  639. TRACE0 (EAPOL, "FSMLogoff: Error in allocating memory for EAPOL packet");
  640. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  641. break;
  642. }
  643. // Fill in fields
  644. memcpy ((BYTE *)pEapolPkt->EthernetType,
  645. (BYTE *)pPCB->bEtherType,
  646. SIZE_ETHERNET_TYPE);
  647. pEapolPkt->ProtocolVersion = pPCB->bProtocolVersion;
  648. pEapolPkt->PacketType = EAPOL_Logoff;
  649. HostToWireFormat16 ((WORD)0, (BYTE *)pEapolPkt->PacketBodyLength);
  650. // Send packet out on the port
  651. dwRetCode = ElWriteToPort (pPCB,
  652. (CHAR *)pEapolPkt,
  653. sizeof (EAPOL_PACKET));
  654. if (dwRetCode != NO_ERROR)
  655. {
  656. TRACE1 (EAPOL, "FSMLogoff: Error in writing Logoff pkt to port %ld",
  657. dwRetCode);
  658. break;
  659. }
  660. // Mark that EAPOL_Logoff was sent out on the port
  661. pPCB->dwLogoffSent = 1;
  662. } while (FALSE);
  663. TRACE1 (EAPOL, "Setting state LOGOFF for port %s", pPCB->pszFriendlyName);
  664. pPCB->State = EAPOLSTATE_LOGOFF;
  665. // Free Identity buffer
  666. if (pPCB->pszIdentity != NULL)
  667. {
  668. FREE (pPCB->pszIdentity);
  669. pPCB->pszIdentity = NULL;
  670. }
  671. // Free Password buffer
  672. if (pPCB->pszPassword != NULL)
  673. {
  674. FREE (pPCB->pszPassword);
  675. pPCB->pszPassword = NULL;
  676. }
  677. // Free user-specific data in the PCB
  678. if (pPCB->pCustomAuthUserData != NULL)
  679. {
  680. FREE (pPCB->pCustomAuthUserData);
  681. pPCB->pCustomAuthUserData = NULL;
  682. }
  683. // Free connection data, though it is common to all users
  684. if (pPCB->pCustomAuthConnData != NULL)
  685. {
  686. FREE (pPCB->pCustomAuthConnData);
  687. pPCB->pCustomAuthConnData = NULL;
  688. }
  689. // Free SSID
  690. if (pPCB->pszSSID != NULL)
  691. {
  692. FREE (pPCB->pszSSID);
  693. pPCB->pszSSID = NULL;
  694. }
  695. pPCB->fGotUserIdentity = FALSE;
  696. if (pEapolPkt != NULL)
  697. {
  698. FREE (pEapolPkt);
  699. pEapolPkt = NULL;
  700. }
  701. TRACE1 (EAPOL, "FSMLogoff completed for port %s", pPCB->pszFriendlyName);
  702. return dwRetCode;
  703. }
  704. //
  705. // FSMConnecting
  706. //
  707. // Description:
  708. //
  709. // Funtion called to send out EAPOL_Start packet. If MaxStart EAPOL_Start
  710. // packets have been sent out, State Machine moves to Authenticated state
  711. //
  712. // Arguments:
  713. // pPCB - Pointer to the PCB for the port on which Start packet is
  714. // to be sent out
  715. //
  716. // Return values:
  717. // NO_ERROR - success
  718. // non-zero - error
  719. //
  720. DWORD
  721. FSMConnecting (
  722. IN EAPOL_PCB *pPCB
  723. )
  724. {
  725. EAPOL_PACKET *pEapolPkt = NULL;
  726. DWORD dwStartInterval = 0;
  727. GUID DeviceGuid;
  728. DWORD dwRetCode = NO_ERROR;
  729. TRACE1 (EAPOL, "FSMConnecting entered for port %s", pPCB->pszFriendlyName);
  730. #ifndef EAPOL_SERVICE
  731. ElStringToGuid (pPCB->pszDeviceGUID, &DeviceGuid);
  732. (VOID)EAPOLMANAuthenticationStarted (&DeviceGuid);
  733. #endif
  734. do
  735. {
  736. if (pPCB->State == EAPOLSTATE_CONNECTING)
  737. {
  738. // If PCB->State was Connecting earlier, increment ulStartCount
  739. // else set ulStartCount to zero
  740. // Did not receive Req/Id
  741. if ((++(pPCB->ulStartCount)) > pPCB->EapolConfig.dwmaxStart)
  742. {
  743. // Deactivate start timer
  744. RESTART_TIMER (pPCB->hTimer,
  745. INFINITE_SECONDS,
  746. "PCB",
  747. &dwRetCode);
  748. if (dwRetCode != NO_ERROR)
  749. {
  750. break;
  751. }
  752. TRACE0 (EAPOL, "FSMConnecting: Sent out maxStart with no response, Setting AUTHENTICATED state");
  753. // Sent out enough EAPOL_Starts
  754. // Go into authenticated state
  755. if ((dwRetCode = FSMAuthenticated (pPCB,
  756. pEapolPkt)) != NO_ERROR)
  757. {
  758. TRACE1 (EAPOL, "FSMConnecting: Error in FSMAuthenticated %ld",
  759. dwRetCode);
  760. break;
  761. }
  762. #ifndef EAPOL_SERVICE
  763. // Display change of status using sys tray balloon
  764. // on interface icon
  765. ElStringToGuid (pPCB->pszDeviceGUID, &DeviceGuid);
  766. (VOID)EAPOLMANAuthenticationSucceeded (&DeviceGuid);
  767. #endif
  768. // No need to send out more EAPOL_Start packets
  769. // Reset start packet count
  770. pPCB->ulStartCount = 0;
  771. pPCB->fIsRemoteEndEAPOLAware = FALSE;
  772. break;
  773. }
  774. }
  775. else
  776. {
  777. pPCB->ulStartCount++;
  778. }
  779. // If user is not logged in, send out EAPOL_Start packets
  780. // at intervals of 1 second each. This is used to detect if the
  781. // interface is on a secure network or not.
  782. // If user is logged in, use the configured value for the
  783. // StartPeriod as the interval
  784. //if (!pPCB->fUserLoggedIn)
  785. if (!g_fUserLoggedOn)
  786. {
  787. dwStartInterval = EAPOL_INIT_START_PERIOD; // 1 second
  788. }
  789. else
  790. {
  791. dwStartInterval = pPCB->EapolConfig.dwstartPeriod;
  792. }
  793. // Restart timer with startPeriod
  794. // Even if error occurs, timeout will happen
  795. // Else, we won't be able to get out of connecting state
  796. RESTART_TIMER (pPCB->hTimer,
  797. dwStartInterval,
  798. "PCB",
  799. &dwRetCode);
  800. if (dwRetCode != NO_ERROR)
  801. {
  802. TRACE1 (EAPOL, "FSMConnecting: Error in RESTART_TIMER %ld",
  803. dwRetCode);
  804. break;
  805. }
  806. // Send out EAPOL_Start
  807. // Allocate new buffer
  808. pEapolPkt = (EAPOL_PACKET *) MALLOC (sizeof(EAPOL_PACKET));
  809. if (pEapolPkt == NULL)
  810. {
  811. TRACE0 (EAPOL, "FSMConnecting: Error in allocating memory for EAPOL packet");
  812. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  813. break;
  814. }
  815. // ISSUE:
  816. // Does Authenticator side also ignore data beyond PacketType
  817. // as the supplicant side does?
  818. memcpy ((BYTE *)pEapolPkt->EthernetType,
  819. (BYTE *)pPCB->bEtherType,
  820. SIZE_ETHERNET_TYPE);
  821. pEapolPkt->ProtocolVersion = pPCB->bProtocolVersion;
  822. pEapolPkt->PacketType = EAPOL_Start;
  823. HostToWireFormat16 ((WORD)0, (BYTE *)pEapolPkt->PacketBodyLength);
  824. // Send packet out on the port
  825. dwRetCode = ElWriteToPort (pPCB,
  826. (CHAR *)pEapolPkt,
  827. sizeof (EAPOL_PACKET));
  828. if (dwRetCode != NO_ERROR)
  829. {
  830. TRACE1 (EAPOL, "FSMConnecting: Error in writing Start Pkt to port %ld",
  831. dwRetCode);
  832. break;
  833. }
  834. TRACE1 (EAPOL, "Setting state CONNECTING for port %s", pPCB->pszFriendlyName);
  835. pPCB->State = EAPOLSTATE_CONNECTING;
  836. SET_EAPOL_START_TIMER(pPCB);
  837. } while (FALSE);
  838. if (pEapolPkt != NULL)
  839. {
  840. FREE (pEapolPkt);
  841. }
  842. TRACE1 (EAPOL, "FSMConnecting completed for port %s", pPCB->pszFriendlyName);
  843. return dwRetCode;
  844. }
  845. //
  846. // FSMAcquired
  847. //
  848. // Description:
  849. // Function called when the port receives a EAP-Request/Identity packet.
  850. // EAP processing of the packet occurs and a EAP-Response/Identity may
  851. // be sent out by EAP if required.
  852. //
  853. //
  854. // Arguments:
  855. // pPCB - Pointer to the PCB for the port on which data is being
  856. // processed
  857. // pEapolPkt - Pointer to EAPOL packet that was received
  858. //
  859. // Return values:
  860. // NO_ERROR - success
  861. // non-zero - error
  862. //
  863. DWORD
  864. FSMAcquired (
  865. IN EAPOL_PCB *pPCB,
  866. IN EAPOL_PACKET *pEapolPkt
  867. )
  868. {
  869. DWORD dwComputerNameLen = 0;
  870. GUID DeviceGuid;
  871. DWORD dwRetCode= NO_ERROR;
  872. TRACE1 (EAPOL, "FSMAcquired entered for port %s", pPCB->pszFriendlyName);
  873. #ifndef EAPOL_SERVICE
  874. ElStringToGuid (pPCB->pszDeviceGUID, &DeviceGuid);
  875. (VOID)EAPOLMANAuthenticationStarted (&DeviceGuid);
  876. #endif
  877. do
  878. {
  879. // Indicate to EAP=Dll to cleanup any leftovers from earlier
  880. // authentication. This is to take care of cases where errors
  881. // occured in the earlier authentication and cleanup wasn't done
  882. if ((dwRetCode = ElEapEnd (pPCB)) != NO_ERROR)
  883. {
  884. TRACE1 (EAPOL, "FSMAcquired: Error in ElEapEnd = %ld",
  885. dwRetCode);
  886. break;
  887. }
  888. // Restart timer with authPeriod
  889. // Even if there is error in ElEapWork, the authtimer timeout
  890. // should happen
  891. RESTART_TIMER (pPCB->hTimer,
  892. pPCB->EapolConfig.dwauthPeriod,
  893. "PCB",
  894. &dwRetCode);
  895. if (dwRetCode != NO_ERROR)
  896. {
  897. TRACE1 (EAPOL, "FSMAcquired: Error in RESTART_TIMER %ld",
  898. dwRetCode);
  899. break;
  900. }
  901. // Since an EAP Req-ID was received, reset EAPOL_Start count
  902. pPCB->ulStartCount = 0;
  903. // If current received EAP Id is the same the previous EAP Id
  904. // send the last EAPOL packet again
  905. if (((PPP_EAP_PACKET *)pEapolPkt->PacketBody)->Id ==
  906. pPCB->dwPreviousId)
  907. {
  908. TRACE0 (EAPOL, "FSMAcquired: Re-xmitting EAP_Packet to port");
  909. dwRetCode = ElWriteToPort (pPCB,
  910. (CHAR *)pPCB->pbPreviousEAPOLPkt,
  911. pPCB->dwSizeOfPreviousEAPOLPkt);
  912. if (dwRetCode != NO_ERROR)
  913. {
  914. TRACE1 (EAPOL, "FSMAcquired: Error in writing re-xmitted EAP_Packet to port %ld",
  915. dwRetCode);
  916. break;
  917. }
  918. }
  919. else
  920. {
  921. // Process the EAP packet
  922. // ElEapWork will send out response if required
  923. if (( dwRetCode = ElEapWork (
  924. pPCB,
  925. (PPP_EAP_PACKET *)pEapolPkt->PacketBody
  926. )) != NO_ERROR)
  927. {
  928. TRACE1 (EAPOL, "FSMAcquired: Error in ElEapWork %ld",
  929. dwRetCode);
  930. break;
  931. }
  932. }
  933. TRACE1 (EAPOL, "Setting state ACQUIRED for port %s", pPCB->pszFriendlyName);
  934. SET_EAPOL_AUTH_TIMER(pPCB);
  935. pPCB->State = EAPOLSTATE_ACQUIRED;
  936. } while (FALSE);
  937. TRACE1 (EAPOL, "FSMAcquired completed for port %s", pPCB->pszFriendlyName);
  938. return dwRetCode;
  939. }
  940. //
  941. // FSMAuthenticating
  942. //
  943. // Description:
  944. //
  945. // Function called when an non EAP-Request/Identity packet is received on the
  946. // port. EAP processing of the data occurs.
  947. //
  948. // Arguments:
  949. // pPCB - Pointer to the PCB for the port on which data is being
  950. // processed
  951. // pEapolPkt - Pointer to EAPOL packet that was received
  952. //
  953. // Return values:
  954. // NO_ERROR - success
  955. // non-zero - error
  956. //
  957. DWORD
  958. FSMAuthenticating (
  959. IN EAPOL_PCB *pPCB,
  960. IN EAPOL_PACKET *pEapolPkt
  961. )
  962. {
  963. GUID DeviceGuid;
  964. DWORD dwRetCode = NO_ERROR;
  965. TRACE1 (EAPOL, "FSMAuthenticating entered for port %s", pPCB->pszFriendlyName);
  966. #ifndef EAPOL_SERVICE
  967. ElStringToGuid (pPCB->pszDeviceGUID, &DeviceGuid);
  968. (VOID)EAPOLMANAuthenticationStarted (&DeviceGuid);
  969. #endif
  970. do
  971. {
  972. // Restart timer with authPeriod
  973. // Even if there is error in ElEapWork, the authtimer timeout
  974. // should happen
  975. RESTART_TIMER (pPCB->hTimer,
  976. pPCB->EapolConfig.dwauthPeriod,
  977. "PCB",
  978. &dwRetCode);
  979. if (dwRetCode != NO_ERROR)
  980. {
  981. TRACE1 (EAPOL, "FSMAuthenticating: Error in RESTART_TIMER %ld",
  982. dwRetCode);
  983. break;
  984. }
  985. // If current received EAP Id is the same the previous EAP Id
  986. // send the last EAPOL packet again
  987. // For EAPCODE_Success and EAPCODE_Failure, the value of id field
  988. // will not be increment, Refer to EAP RFC
  989. if ((((PPP_EAP_PACKET *)pEapolPkt->PacketBody)->Id
  990. == pPCB->dwPreviousId) &&
  991. (((PPP_EAP_PACKET *)pEapolPkt->PacketBody)->Code
  992. != EAPCODE_Success) &&
  993. (((PPP_EAP_PACKET *)pEapolPkt->PacketBody)->Code
  994. != EAPCODE_Failure))
  995. {
  996. TRACE0 (EAPOL, "FSMAcquired: Re-xmitting EAP_Packet to port");
  997. dwRetCode = ElWriteToPort (pPCB,
  998. (CHAR *)pPCB->pbPreviousEAPOLPkt,
  999. pPCB->dwSizeOfPreviousEAPOLPkt);
  1000. if (dwRetCode != NO_ERROR)
  1001. {
  1002. TRACE1 (EAPOL, "FSMAcquired: Error in writing re-xmitted EAP_Packet to port = %ld",
  1003. dwRetCode);
  1004. break;
  1005. }
  1006. }
  1007. else
  1008. {
  1009. // Process the EAP packet
  1010. // ElEapWork will send out response if required
  1011. if (( dwRetCode = ElEapWork (
  1012. pPCB,
  1013. (PPP_EAP_PACKET *)pEapolPkt->PacketBody
  1014. )) != NO_ERROR)
  1015. {
  1016. TRACE1 (EAPOL, "FSMAuthenticating: Error in ElEapWork %ld",
  1017. dwRetCode);
  1018. break;
  1019. }
  1020. }
  1021. TRACE1 (EAPOL, "Setting state AUTHENTICATING for port %s", pPCB->pszFriendlyName);
  1022. SET_EAPOL_AUTH_TIMER(pPCB);
  1023. pPCB->State = EAPOLSTATE_AUTHENTICATING;
  1024. } while (FALSE);
  1025. TRACE1 (EAPOL, "FSMAuthenticating completed for port %s", pPCB->pszFriendlyName);
  1026. return dwRetCode;
  1027. }
  1028. //
  1029. // FSMHeld
  1030. //
  1031. // Description:
  1032. // Function called when a EAP-Failure packet is received in the
  1033. // Authenticating state. State machine is held for heldPeriod before
  1034. // re-authentication can occur.
  1035. //
  1036. // Arguments:
  1037. // pPCB - Pointer to the PCB for the port on which data is being
  1038. // processed
  1039. //
  1040. // Return values:
  1041. // NO_ERROR - success
  1042. // non-zero - error
  1043. //
  1044. DWORD
  1045. FSMHeld (
  1046. IN EAPOL_PCB *pPCB
  1047. )
  1048. {
  1049. DWORD dwRetCode = NO_ERROR;
  1050. TRACE1 (EAPOL, "FSMHeld entered for port %s", pPCB->pszFriendlyName);
  1051. do
  1052. {
  1053. #ifdef DRAFT7
  1054. if (g_dwMachineAuthEnabled)
  1055. {
  1056. #endif
  1057. pPCB->dwAuthFailCount++;
  1058. if (pPCB->dwAuthFailCount <= EAPOL_MAX_AUTH_FAIL_COUNT)
  1059. {
  1060. TRACE1 (EAPOL, "Restarting Held timer with time value = %ld",
  1061. pPCB->EapolConfig.dwheldPeriod);
  1062. // Restart timer with heldPeriod
  1063. RESTART_TIMER (pPCB->hTimer,
  1064. pPCB->EapolConfig.dwheldPeriod,
  1065. "PCB",
  1066. &dwRetCode);
  1067. }
  1068. else
  1069. {
  1070. TRACE1 (EAPOL, "Restarting Held timer with extended time value = %ld",
  1071. (pPCB->dwAuthFailCount * (pPCB->EapolConfig.dwheldPeriod)));
  1072. // Restart timer with heldPeriod times pPCB->dwAuthFailCount
  1073. RESTART_TIMER (pPCB->hTimer,
  1074. ((pPCB->dwAuthFailCount) * (pPCB->EapolConfig.dwheldPeriod)),
  1075. "PCB",
  1076. &dwRetCode);
  1077. }
  1078. #ifdef DRAFT7
  1079. }
  1080. else
  1081. {
  1082. TRACE1 (EAPOL, "Restarting Held timer with time value = %ld",
  1083. pPCB->EapolConfig.dwheldPeriod);
  1084. // Restart timer with heldPeriod
  1085. RESTART_TIMER (pPCB->hTimer,
  1086. pPCB->EapolConfig.dwheldPeriod,
  1087. "PCB",
  1088. &dwRetCode);
  1089. } // g_dwMachineAuthEnabled
  1090. #endif
  1091. if (dwRetCode != NO_ERROR)
  1092. {
  1093. TRACE1 (EAPOL, "FSMHeld: Error in RESTART_TIMER %ld",
  1094. dwRetCode);
  1095. break;
  1096. }
  1097. // Free Identity buffer
  1098. if (pPCB->pszIdentity != NULL)
  1099. {
  1100. FREE (pPCB->pszIdentity);
  1101. pPCB->pszIdentity = NULL;
  1102. }
  1103. // Free Password buffer
  1104. if (pPCB->pszPassword != NULL)
  1105. {
  1106. FREE (pPCB->pszPassword);
  1107. pPCB->pszPassword = NULL;
  1108. }
  1109. // Free user-specific data in the PCB
  1110. if (pPCB->pCustomAuthUserData != NULL)
  1111. {
  1112. FREE (pPCB->pCustomAuthUserData);
  1113. pPCB->pCustomAuthUserData = NULL;
  1114. }
  1115. // Free connection data
  1116. if (pPCB->pCustomAuthConnData != NULL)
  1117. {
  1118. FREE (pPCB->pCustomAuthConnData);
  1119. pPCB->pCustomAuthConnData = NULL;
  1120. }
  1121. // Since there has been an error in credentials, start afresh
  1122. // the authentication. Credentials may have changed e.g. certs
  1123. // may be renewed, MD5 credentials corrected etc.
  1124. pPCB->fGotUserIdentity = FALSE;
  1125. TRACE1 (EAPOL, "Setting state HELD for port %s", pPCB->pszFriendlyName);
  1126. pPCB->State = EAPOLSTATE_HELD;
  1127. SET_EAPOL_HELD_TIMER(pPCB);
  1128. TRACE1 (EAPOL, "FSMHeld: Port %s set to HELD state",
  1129. pPCB->pszDeviceGUID);
  1130. } while (FALSE);
  1131. TRACE1 (EAPOL, "FSMHeld completed for port %s", pPCB->pszFriendlyName);
  1132. return dwRetCode;
  1133. }
  1134. //
  1135. // FSMAuthenticated
  1136. //
  1137. // Description:
  1138. //
  1139. // Function called when a EAP-Success packet is received or MaxStart
  1140. // EAPOL_Startpackets have been sent out, but no EAP-Request/Identity
  1141. // packets were received. If EAP-Success packet is request, DHCP client
  1142. // is restarted to get a new IP address.
  1143. //
  1144. // Arguments:
  1145. // pPCB - Pointer to the PCB for the port on which data is being
  1146. // processed
  1147. // pEapolPkt - Pointer to EAPOL packet that was received
  1148. //
  1149. // Return values:
  1150. // NO_ERROR - success
  1151. // non-zero - error
  1152. //
  1153. DWORD
  1154. FSMAuthenticated (
  1155. IN EAPOL_PCB *pPCB,
  1156. IN EAPOL_PACKET *pEapolPkt
  1157. )
  1158. {
  1159. DHCP_PNP_CHANGE DhcpPnpChange;
  1160. DWORD dwRetCode = NO_ERROR;
  1161. TRACE1 (EAPOL, "FSMAuthenticated entered for port %s",
  1162. pPCB->pszFriendlyName);
  1163. do
  1164. {
  1165. // Shutdown earlier EAP session
  1166. ElEapEnd (pPCB);
  1167. // Call DHCP only if state machine went through authentication
  1168. // If FSM is getting AUTHENTICATED by default, don't call DHCP
  1169. // if (pPCB->ulStartCount < pPCB->EapolConfig.dwmaxStart)
  1170. {
  1171. // Call DHCP to do PnP
  1172. ZeroMemory(&DhcpPnpChange, sizeof(DHCP_PNP_CHANGE));
  1173. DhcpPnpChange.Version = DHCP_PNP_CHANGE_VERSION_0;
  1174. if ((dwRetCode = DhcpHandlePnPEvent(0,
  1175. DHCP_CALLER_TCPUI,
  1176. NULL,
  1177. //pPCB->pszDeviceGUID,
  1178. &DhcpPnpChange,
  1179. NULL)) != NO_ERROR)
  1180. {
  1181. TRACE1 (EAPOL, "FSMAuthenticated: DHCPHandlePnPEvent returned error %ld",
  1182. dwRetCode);
  1183. break;
  1184. }
  1185. TRACE0 (EAPOL, "FSMAuthenticated: DHCPHandlePnPEvent successful");
  1186. }
  1187. TRACE1 (EAPOL, "Setting state AUTHENTICATED for port %s", pPCB->pszFriendlyName);
  1188. pPCB->State = EAPOLSTATE_AUTHENTICATED;
  1189. } while (FALSE);
  1190. TRACE1 (EAPOL, "FSMAuthenticated completed for port %s", pPCB->pszFriendlyName);
  1191. return dwRetCode;
  1192. }
  1193. //
  1194. // FSMRxKey
  1195. //
  1196. // Description:
  1197. // Function called when an EAPOL-Key packet is received in the
  1198. // Authenticated state. The WEP key is decrypted and
  1199. // plumbed down to the NIC driver.
  1200. //
  1201. // Arguments:
  1202. // pPCB - Pointer to the PCB for the port on which data is being
  1203. // processed
  1204. // pEapolPkt - Pointer to EAPOL packet that was received
  1205. //
  1206. // Return values:
  1207. // NO_ERROR - success
  1208. // non-zero - error
  1209. //
  1210. DWORD
  1211. FSMRxKey (
  1212. IN EAPOL_PCB *pPCB,
  1213. IN EAPOL_PACKET *pEapolPkt
  1214. )
  1215. {
  1216. EAPOL_KEY_DESC *pKeyDesc = NULL;
  1217. EAPOL_KEY_DESC_D8 *pKeyDesc_D8 = NULL;
  1218. EAPOL_PACKET_D8 EapolPktD8;
  1219. EAPOL_PACKET_D8 *pEapolPktD8 = NULL;
  1220. ULONGLONG ullReplayCheck = 0;
  1221. BYTE bReplayCheck[8];
  1222. BYTE *pbMD5EapolPkt = NULL;
  1223. DWORD dwMD5EapolPktLen = 0;
  1224. MD5_CTX MD5Context;
  1225. DWORD dwEapPktLen = 0;
  1226. DWORD dwIndex = 0;
  1227. BYTE bHMACMD5HashBuffer[MD5DIGESTLEN];
  1228. RC4_KEYSTRUCT rc4key;
  1229. BYTE bKeyBuffer[48];
  1230. BYTE *pbKeyToBePlumbed = NULL;
  1231. DWORD dwKeyLength = 0;
  1232. NDIS_802_11_WEP *pNdisWEPKey = NULL;
  1233. DWORD dwRetCode = NO_ERROR;
  1234. TRACE1 (EAPOL, "FSMRxKey entered for port %s", pPCB->pszFriendlyName);
  1235. do
  1236. {
  1237. if (!pPCB->fRemoteEnd8021XD8)
  1238. {
  1239. // DRAFT 7
  1240. pKeyDesc = (EAPOL_KEY_DESC *)pEapolPkt->PacketBody;
  1241. dwKeyLength = WireToHostFormat16 (pKeyDesc->KeyLength);
  1242. TRACE4 (EAPOL, "Signature Type = %ld, \n Encrypt Type = %ld, \n KeyLength = %ld, \n KeyIndex = %ld",
  1243. pKeyDesc->SignatureType,
  1244. pKeyDesc->EncryptType,
  1245. dwKeyLength,
  1246. pKeyDesc->KeyIndex
  1247. );
  1248. // For Draft 8, do not check for non-existing fields
  1249. if (pKeyDesc->SignatureType != 1)
  1250. {
  1251. TRACE1 (EAPOL, "FSMRxKey: Invalid signature type = %ld",
  1252. pKeyDesc->SignatureType);
  1253. // log
  1254. break;
  1255. }
  1256. if (pKeyDesc->EncryptType != 1)
  1257. {
  1258. TRACE1 (EAPOL, "FSMRxKey: Invalid encryption type = %ld",
  1259. pKeyDesc->EncryptType);
  1260. // log
  1261. break;
  1262. }
  1263. memcpy ((BYTE *)bReplayCheck,
  1264. (BYTE *)pKeyDesc->ReplayCounter,
  1265. 8*sizeof(BYTE));
  1266. ullReplayCheck = ((*((PBYTE)(bReplayCheck)+0) << 56) +
  1267. (*((PBYTE)(bReplayCheck)+1) << 48) +
  1268. (*((PBYTE)(bReplayCheck)+2) << 40) +
  1269. (*((PBYTE)(bReplayCheck)+3) << 32) +
  1270. (*((PBYTE)(bReplayCheck)+4) << 24) +
  1271. (*((PBYTE)(bReplayCheck)+5) << 16) +
  1272. (*((PBYTE)(bReplayCheck)+6) << 8) +
  1273. (*((PBYTE)(bReplayCheck)+7)));
  1274. //
  1275. // Check validity of Key message using the ReplayCounter field
  1276. // Verify if it is in sync with the last ReplayCounter value
  1277. // received
  1278. //
  1279. TRACE0 (EAPOL, "Incoming Replay counter ======= ");
  1280. EAPOL_DUMPBA ((BYTE *)&ullReplayCheck, 8);
  1281. TRACE0 (EAPOL, "Last Replay counter ======= ");
  1282. EAPOL_DUMPBA ((BYTE *)&(pPCB->ullLastReplayCounter), 8);
  1283. if (ullReplayCheck <= pPCB->ullLastReplayCounter)
  1284. {
  1285. TRACE0 (EAPOL, "FSMRxKey: Replay counter is not in sync, something is wrong");
  1286. // log
  1287. break;
  1288. }
  1289. // If valid ReplayCounter, save it in the PCB for future check
  1290. pPCB->ullLastReplayCounter = ullReplayCheck;
  1291. TRACE0 (EAPOL, "Replay counter in desc ======");
  1292. EAPOL_DUMPBA (pKeyDesc->ReplayCounter, 8);
  1293. //
  1294. // Verify if the MD5 hash generated on the EAPOL packet,
  1295. // with Signature nulled out, is the same as the signature
  1296. // Use the MPPERecv key as the secret
  1297. //
  1298. dwEapPktLen = WireToHostFormat16 (pEapolPkt->PacketBodyLength);
  1299. dwMD5EapolPktLen = sizeof (EAPOL_PACKET) - sizeof(pEapolPkt->EthernetType) - 1 + dwEapPktLen;
  1300. if ((pbMD5EapolPkt = (BYTE *) MALLOC (dwMD5EapolPktLen)) == NULL)
  1301. {
  1302. TRACE0 (EAPOL, "FSMRxKey: Error in MALLOC for pbMD5EapolPkt");
  1303. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  1304. break;
  1305. }
  1306. memcpy ((BYTE *)pbMD5EapolPkt, (BYTE *)pEapolPkt+sizeof(pEapolPkt->EthernetType), dwMD5EapolPktLen);
  1307. //
  1308. // Null out the signature in the key descriptor copy, to calculate
  1309. // the hash on the supplicant side
  1310. //
  1311. ZeroMemory ((BYTE *)(pbMD5EapolPkt
  1312. - sizeof(pEapolPkt->EthernetType) +
  1313. sizeof(EAPOL_PACKET) - 1 + // pEapolPkt->Body
  1314. sizeof(EAPOL_KEY_DESC)- // End of EAPOL_KEY_DESC
  1315. MD5DIGESTLEN-1), // Signature field
  1316. MD5DIGESTLEN);
  1317. (VOID) ElGetHMACMD5Digest (
  1318. pbMD5EapolPkt,
  1319. dwMD5EapolPktLen,
  1320. pPCB->pbMPPERecvKey,
  1321. pPCB->dwMPPERecvKeyLength,
  1322. bHMACMD5HashBuffer
  1323. );
  1324. TRACE0 (EAPOL, "FSMRxKey: MD5 Hash body ==");
  1325. EAPOL_DUMPBA (pbMD5EapolPkt, dwMD5EapolPktLen);
  1326. TRACE0 (EAPOL, "FSMRxKey: MD5 Hash secret ==");
  1327. EAPOL_DUMPBA (pPCB->pbMPPERecvKey, pPCB->dwMPPERecvKeyLength);
  1328. TRACE0 (EAPOL, "FSMRxKey: MD5 Hash generated by Supplicant");
  1329. EAPOL_DUMPBA (bHMACMD5HashBuffer, MD5DIGESTLEN);
  1330. TRACE0 (EAPOL, "FSMRxKey: Signature sent in EAPOL_KEY_DESC");
  1331. EAPOL_DUMPBA (pKeyDesc->KeySignature, MD5DIGESTLEN);
  1332. //
  1333. // Check if HMAC-MD5 hash in received packet is what is expected
  1334. //
  1335. if (memcmp (bHMACMD5HashBuffer, pKeyDesc->KeySignature, MD5DIGESTLEN) != 0)
  1336. {
  1337. TRACE0 (EAPOL, "FSMRxKey: Signature in Key Desc does not match, potential security attack");
  1338. // log
  1339. break;
  1340. }
  1341. //
  1342. // Decrypt the multicast WEP key if it has been provided
  1343. //
  1344. // Check if there is Key Material (5/16 bytes) at the end of
  1345. // the Key Descriptor
  1346. if (WireToHostFormat16 (pEapolPkt->PacketBodyLength) > sizeof (EAPOL_KEY_DESC))
  1347. {
  1348. memcpy ((BYTE *)bKeyBuffer, (BYTE *)pKeyDesc->Key_IV, 16);
  1349. memcpy ((BYTE *)&bKeyBuffer[16], (BYTE *)pPCB->pbMPPESendKey, 32);
  1350. rc4_key (&rc4key, 48, bKeyBuffer);
  1351. rc4 (&rc4key, dwKeyLength, pKeyDesc->Key);
  1352. TRACE0 (EAPOL, " ========= The multicast key is ============= ");
  1353. EAPOL_DUMPBA (pKeyDesc->Key, dwKeyLength);
  1354. // Use the unencrypted key in the Key Desc as the encryption key
  1355. pbKeyToBePlumbed = pKeyDesc->Key;
  1356. }
  1357. else
  1358. {
  1359. // Use the MPPESend key as the encryption key
  1360. pbKeyToBePlumbed = (BYTE *)pPCB->pbMPPESendKey;
  1361. }
  1362. if ((pNdisWEPKey = MALLOC ( sizeof(NDIS_802_11_WEP)-1+dwKeyLength ))
  1363. == NULL)
  1364. {
  1365. TRACE0 (EAPOL, "FSMRxKey: MALLOC failed for pNdisWEPKey");
  1366. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  1367. break;
  1368. }
  1369. pNdisWEPKey->Length = sizeof(NDIS_802_11_WEP) - 1 + dwKeyLength;
  1370. memcpy ((BYTE *)pNdisWEPKey->KeyMaterial, (BYTE *)pbKeyToBePlumbed,
  1371. dwKeyLength);
  1372. pNdisWEPKey->KeyLength = dwKeyLength;
  1373. // Create the long index out of the byte index got from AP
  1374. // If MSB in byte is set, set MSB in ulong format
  1375. if (pKeyDesc->KeyIndex & 0x80)
  1376. {
  1377. pNdisWEPKey->KeyIndex = 0x80000000;
  1378. }
  1379. else
  1380. {
  1381. pNdisWEPKey->KeyIndex = 0x00000000;
  1382. }
  1383. pNdisWEPKey->KeyIndex |= (pKeyDesc->KeyIndex & 0x03);
  1384. TRACE1 (ANY, "FSMRxKey: Key Index is %x", pNdisWEPKey->KeyIndex);
  1385. // Use NDISUIO to plumb the key to the driver
  1386. if ((dwRetCode = ElNdisuioSetOIDValue (
  1387. pPCB->hPort,
  1388. OID_802_11_ADD_WEP,
  1389. (BYTE *)pNdisWEPKey,
  1390. pNdisWEPKey->Length)) != NO_ERROR)
  1391. {
  1392. TRACE1 (PORT, "FSMRxKey: ElNdisuioSetOIDValue failed with error %ld",
  1393. dwRetCode);
  1394. }
  1395. }
  1396. else
  1397. {
  1398. // DRAFT 8
  1399. // Point beyond Signature Type for structure alignment
  1400. pKeyDesc_D8 = (EAPOL_KEY_DESC_D8 *)(pEapolPkt->PacketBody);
  1401. dwKeyLength = WireToHostFormat16 (pKeyDesc_D8->KeyLength);
  1402. TRACE3 (EAPOL, "Descriptor type = %ld, \n KeyLength = %ld, \n KeyIndex = %ld",
  1403. pKeyDesc_D8->DescriptorType,
  1404. dwKeyLength,
  1405. pKeyDesc_D8->KeyIndex
  1406. );
  1407. memcpy ((BYTE *)bReplayCheck,
  1408. (BYTE *)pKeyDesc_D8->ReplayCounter,
  1409. 8*sizeof(BYTE));
  1410. ullReplayCheck = ((*((PBYTE)(bReplayCheck)+0) << 56) +
  1411. (*((PBYTE)(bReplayCheck)+1) << 48) +
  1412. (*((PBYTE)(bReplayCheck)+2) << 40) +
  1413. (*((PBYTE)(bReplayCheck)+3) << 32) +
  1414. (*((PBYTE)(bReplayCheck)+4) << 24) +
  1415. (*((PBYTE)(bReplayCheck)+5) << 16) +
  1416. (*((PBYTE)(bReplayCheck)+6) << 8) +
  1417. (*((PBYTE)(bReplayCheck)+7)));
  1418. //
  1419. // Check validity of Key message using the ReplayCounter field
  1420. // Verify if it is in sync with the last ReplayCounter value
  1421. // received
  1422. //
  1423. TRACE0 (EAPOL, "Incoming Replay counter ======= ");
  1424. EAPOL_DUMPBA ((BYTE *)&ullReplayCheck, 8);
  1425. TRACE0 (EAPOL, "Last Replay counter ======= ");
  1426. EAPOL_DUMPBA ((BYTE *)&(pPCB->ullLastReplayCounter), 8);
  1427. if (ullReplayCheck < pPCB->ullLastReplayCounter)
  1428. {
  1429. TRACE0 (EAPOL, "FSMRxKey: Replay counter is not in sync, something is wrong");
  1430. // log
  1431. break;
  1432. }
  1433. // If valid ReplayCounter, save it in the PCB for future check
  1434. pPCB->ullLastReplayCounter = ullReplayCheck;
  1435. TRACE1 (EAPOL, "Replay counter ======= %lx", ullReplayCheck);
  1436. TRACE0 (EAPOL, "Replay counter in desc ======");
  1437. EAPOL_DUMPBA (pKeyDesc_D8->ReplayCounter, 8);
  1438. //
  1439. // Verify if the MD5 hash generated on the EAPOL packet,
  1440. // with Signature nulled out, is the same as the signature
  1441. // Use the MPPERecv key as the secret
  1442. //
  1443. {
  1444. ZeroMemory (&EapolPktD8, sizeof (EAPOL_PACKET_D8));
  1445. memcpy (EapolPktD8.EthernetType, pEapolPkt->EthernetType, 2);
  1446. EapolPktD8.ProtocolVersion = pEapolPkt->ProtocolVersion;
  1447. EapolPktD8.PacketType = pEapolPkt->PacketType;
  1448. memcpy (EapolPktD8.PacketBodyLength, pEapolPkt->PacketBodyLength,
  1449. 2);
  1450. memcpy ((BYTE *)&(EapolPktD8.AuthResultCode), (BYTE *)pEapolPkt - 2, 2);
  1451. memcpy ((BYTE *)pEapolPkt - 2, (BYTE *)&EapolPktD8,
  1452. sizeof(EAPOL_PACKET_D8)-1);
  1453. pEapolPktD8 = (EAPOL_PACKET_D8 *)((BYTE *)pEapolPkt - 2);
  1454. }
  1455. dwEapPktLen = WireToHostFormat16 (pEapolPktD8->PacketBodyLength);
  1456. dwMD5EapolPktLen = sizeof (EAPOL_PACKET_D8) - sizeof(pEapolPktD8->EthernetType) - 1 + dwEapPktLen;
  1457. if ((pbMD5EapolPkt = (BYTE *) MALLOC (dwMD5EapolPktLen)) == NULL)
  1458. {
  1459. TRACE0 (EAPOL, "FSMRxKey: Error in MALLOC for pbMD5EapolPkt");
  1460. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  1461. break;
  1462. }
  1463. memcpy ((BYTE *)pbMD5EapolPkt, (BYTE *)pEapolPktD8+sizeof(pEapolPktD8->EthernetType), dwMD5EapolPktLen);
  1464. //
  1465. // Null out the signature in the key descriptor copy, to calculate
  1466. // the hash on the supplicant side
  1467. //
  1468. // Draft 8 has different KEY_DESC size
  1469. ZeroMemory ((BYTE *)(pbMD5EapolPkt
  1470. - sizeof(pEapolPktD8->EthernetType) +
  1471. sizeof(EAPOL_PACKET_D8) - 1 + // pEapolPktD8->Body
  1472. sizeof(EAPOL_KEY_DESC_D8) - // End of EAPOL_KEY_DESC
  1473. MD5DIGESTLEN-1), // Signature field
  1474. MD5DIGESTLEN);
  1475. (VOID) ElGetHMACMD5Digest (
  1476. pbMD5EapolPkt,
  1477. dwMD5EapolPktLen,
  1478. pPCB->pbMPPERecvKey,
  1479. pPCB->dwMPPERecvKeyLength,
  1480. bHMACMD5HashBuffer
  1481. );
  1482. TRACE0 (EAPOL, "FSMRxKey: MD5 Hash body ==");
  1483. EAPOL_DUMPBA (pbMD5EapolPkt, dwMD5EapolPktLen);
  1484. TRACE0 (EAPOL, "FSMRxKey: MD5 Hash secret ==");
  1485. EAPOL_DUMPBA (pPCB->pbMPPERecvKey, pPCB->dwMPPERecvKeyLength);
  1486. TRACE0 (EAPOL, "FSMRxKey: MD5 Hash generated by Supplicant");
  1487. EAPOL_DUMPBA (bHMACMD5HashBuffer, MD5DIGESTLEN);
  1488. TRACE0 (EAPOL, "FSMRxKey: Signature sent in EAPOL_KEY_DESC");
  1489. EAPOL_DUMPBA (pKeyDesc_D8->KeySignature, MD5DIGESTLEN);
  1490. //
  1491. // Check if HMAC-MD5 hash in received packet is what is expected
  1492. //
  1493. if (memcmp (bHMACMD5HashBuffer, pKeyDesc_D8->KeySignature, MD5DIGESTLEN) != 0)
  1494. {
  1495. TRACE0 (EAPOL, "FSMRxKey: Signature in Key Desc does not match, potential security attack");
  1496. // log
  1497. break;
  1498. }
  1499. //
  1500. // Decrypt the multicast WEP key if it has been provided
  1501. //
  1502. // Check if there is Key Material (5/16 bytes) at the end of
  1503. // the Key Descriptor
  1504. if (WireToHostFormat16 (pEapolPktD8->PacketBodyLength) > sizeof (EAPOL_KEY_DESC))
  1505. {
  1506. memcpy ((BYTE *)bKeyBuffer, (BYTE *)pKeyDesc_D8->Key_IV, 16);
  1507. memcpy ((BYTE *)&bKeyBuffer[16], (BYTE *)pPCB->pbMPPESendKey, 32);
  1508. rc4_key (&rc4key, 48, bKeyBuffer);
  1509. rc4 (&rc4key, dwKeyLength, pKeyDesc_D8->Key);
  1510. TRACE0 (EAPOL, " ========= The multicast key is ============= ");
  1511. EAPOL_DUMPBA (pKeyDesc_D8->Key, dwKeyLength);
  1512. // Use the unencrypted key in the Key Desc as the encryption key
  1513. pbKeyToBePlumbed = pKeyDesc_D8->Key;
  1514. }
  1515. else
  1516. {
  1517. // Use the MPPESend key as the encryption key
  1518. pbKeyToBePlumbed = (BYTE *)pPCB->pbMPPESendKey;
  1519. }
  1520. if ((pNdisWEPKey = MALLOC ( sizeof(NDIS_802_11_WEP)-1+dwKeyLength ))
  1521. == NULL)
  1522. {
  1523. TRACE0 (EAPOL, "FSMRxKey: MALLOC failed for pNdisWEPKey");
  1524. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  1525. break;
  1526. }
  1527. pNdisWEPKey->Length = sizeof(NDIS_802_11_WEP) - 1 + dwKeyLength;
  1528. memcpy ((BYTE *)pNdisWEPKey->KeyMaterial, (BYTE *)pbKeyToBePlumbed,
  1529. dwKeyLength);
  1530. pNdisWEPKey->KeyLength = dwKeyLength;
  1531. // Create the long index out of the byte index got from AP
  1532. // If MSB in byte is set, set MSB in ulong format
  1533. if (pKeyDesc_D8->KeyIndex & 0x80)
  1534. {
  1535. pNdisWEPKey->KeyIndex = 0x80000000;
  1536. }
  1537. else
  1538. {
  1539. pNdisWEPKey->KeyIndex = 0x00000000;
  1540. }
  1541. pNdisWEPKey->KeyIndex |= (pKeyDesc_D8->KeyIndex & 0x03);
  1542. TRACE1 (ANY, "FSMRxKey: Key Index is %x", pNdisWEPKey->KeyIndex);
  1543. // Use NDISUIO to plumb the key to the driver
  1544. if ((dwRetCode = ElNdisuioSetOIDValue (
  1545. pPCB->hPort,
  1546. OID_802_11_ADD_WEP,
  1547. (BYTE *)pNdisWEPKey,
  1548. pNdisWEPKey->Length)) != NO_ERROR)
  1549. {
  1550. TRACE1 (PORT, "FSMRxKey: ElNdisuioSetOIDValue failed with error %ld",
  1551. dwRetCode);
  1552. }
  1553. }
  1554. } while (FALSE);
  1555. if (pbMD5EapolPkt != NULL)
  1556. {
  1557. FREE (pbMD5EapolPkt);
  1558. pbMD5EapolPkt = NULL;
  1559. }
  1560. if (pNdisWEPKey != NULL)
  1561. {
  1562. FREE (pNdisWEPKey);
  1563. pNdisWEPKey = NULL;
  1564. }
  1565. TRACE1 (EAPOL, "FSMRxKey completed for port %s", pPCB->pszFriendlyName);
  1566. return dwRetCode;
  1567. }
  1568. //
  1569. // ElTimeoutCallbackRoutine
  1570. //
  1571. // Description:
  1572. //
  1573. // Function called when any timer work item queued on the global timer
  1574. // queue expires. Depending on the state in which the port is when the timer
  1575. // expires, the port moves to the next state.
  1576. //
  1577. // Arguments:
  1578. // pvContext - Pointer to context. In this case, it is pointer to a PCB
  1579. // fTimerOfWaitFired - Unused
  1580. //
  1581. // Return values:
  1582. //
  1583. VOID
  1584. ElTimeoutCallbackRoutine (
  1585. IN PVOID pvContext,
  1586. IN BOOLEAN fTimerOfWaitFired
  1587. )
  1588. {
  1589. EAPOL_PCB *pPCB;
  1590. TRACE0 (EAPOL, "ElTimeoutCallbackRoutine entered");
  1591. do
  1592. {
  1593. // Context should not be NULL
  1594. if (pvContext == NULL)
  1595. {
  1596. TRACE0 (EAPOL, "ElTimeoutCallbackRoutine: pvContext is NULL. Invalid timeout callback");
  1597. break;
  1598. }
  1599. // PCB is guaranteed to exist until all timers are fired
  1600. // Verify if Port is still active
  1601. pPCB = (EAPOL_PCB *)pvContext;
  1602. ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
  1603. if (!EAPOL_PORT_ACTIVE(pPCB))
  1604. {
  1605. // Port is not active
  1606. RELEASE_WRITE_LOCK (&(pPCB->rwLock));
  1607. TRACE1 (PORT, "ElTimeoutCallbackRoutine: Port %s is inactive",
  1608. pPCB->pszDeviceGUID);
  1609. break;
  1610. }
  1611. // Check the timer has been changed
  1612. // If the current time is less than the programmed timeout on
  1613. // the PCB, either timer component has shot off timer earlier
  1614. // or the timer fired but someone changed it in the meanwhile
  1615. if (pPCB->ulTimeout > GetTickCount())
  1616. {
  1617. TRACE0 (EAPOL, "ElTimeoutCallbackRoutine: Timeout value has been changed or Timer fired earlier than required");
  1618. break;
  1619. }
  1620. // Check the current state of the state machine
  1621. // We can do additional checks such as flagging which timer was fired
  1622. // and in the timeout checking if the PCB state has remained the same
  1623. // Else bail out
  1624. switch (pPCB->State)
  1625. {
  1626. case EAPOLSTATE_CONNECTING:
  1627. if (!EAPOL_START_TIMER_SET(pPCB))
  1628. {
  1629. TRACE1 (EAPOL, "ElTimeoutCallbackRoutine: Wrong timeout %ld in Connecting state", CHECK_EAPOL_TIMER(pPCB));
  1630. break;
  1631. }
  1632. FSMConnecting(pPCB);
  1633. break;
  1634. case EAPOLSTATE_ACQUIRED:
  1635. if (!EAPOL_AUTH_TIMER_SET(pPCB))
  1636. {
  1637. TRACE1 (EAPOL, "ElTimeoutCallbackRoutine: Wrong timeout %ld in Acquired state", CHECK_EAPOL_TIMER(pPCB));
  1638. break;
  1639. }
  1640. FSMConnecting(pPCB);
  1641. break;
  1642. case EAPOLSTATE_AUTHENTICATING:
  1643. if (!EAPOL_AUTH_TIMER_SET(pPCB))
  1644. {
  1645. TRACE1 (EAPOL, "ElTimeoutCallbackRoutine: Wrong timeout %ld in Authenticating state", CHECK_EAPOL_TIMER(pPCB));
  1646. break;
  1647. }
  1648. FSMConnecting(pPCB);
  1649. break;
  1650. case EAPOLSTATE_HELD:
  1651. if (!EAPOL_HELD_TIMER_SET(pPCB))
  1652. {
  1653. TRACE1 (EAPOL, "ElTimeoutCallbackRoutine: Wrong timeout %ld in Held state", CHECK_EAPOL_TIMER(pPCB));
  1654. break;
  1655. }
  1656. FSMConnecting(pPCB);
  1657. break;
  1658. case EAPOLSTATE_DISCONNECTED:
  1659. TRACE0 (EAPOL, "ElTimeoutCallbackRoutine: No action in Disconnected state");
  1660. break;
  1661. case EAPOLSTATE_LOGOFF:
  1662. TRACE0 (EAPOL, "ElTimeoutCallbackRoutine: No action in Logoff state");
  1663. break;
  1664. default:
  1665. TRACE0 (EAPOL, "ElTimeoutCallbackRoutine: Critical Error. Invalid state after timer expires ");
  1666. break;
  1667. }
  1668. RELEASE_WRITE_LOCK (&(pPCB->rwLock));
  1669. } while (FALSE);
  1670. TRACE0 (EAPOL, "ElTimeoutCallbackRoutine completed");
  1671. return;
  1672. }
  1673. //
  1674. // ElEapWork
  1675. //
  1676. // Description:
  1677. //
  1678. // Function called when an EAPOL packet of type EAP_Packet is received
  1679. // The EAP packet is passed to the EAP module for processing.
  1680. // Depending on the result of the processing, a EAP Response packet
  1681. // is sent or the incoming packet is ignored.
  1682. //
  1683. // Input arguments:
  1684. // pPCB - Pointer to PCB for the port on which data is being processed
  1685. // pRecvPkt - Pointer to EAP packet in the data received from the remote end
  1686. //
  1687. // Return values:
  1688. // NO_ERROR - success
  1689. // non-zero - error
  1690. //
  1691. //
  1692. // ISSUE: Rewrite with do {} while(FALSE)
  1693. //
  1694. DWORD
  1695. ElEapWork (
  1696. IN EAPOL_PCB *pPCB,
  1697. IN PPP_EAP_PACKET *pRecvPkt
  1698. )
  1699. {
  1700. DWORD dwLength = 0;
  1701. ELEAP_RESULT EapResult;
  1702. PPP_EAP_PACKET *pSendPkt;
  1703. EAPOL_PACKET *pEapolPkt;
  1704. GUID DeviceGuid;
  1705. WCHAR awszNotificationMsg[MAX_NOTIFICATION_MSG_SIZE];
  1706. DWORD dwReceivedId = 0;
  1707. DWORD dwDraft8HdrIncr = 0;
  1708. DWORD dwRetCode = NO_ERROR;
  1709. //
  1710. // If the protocol has not been started yet, call ElEapBegin
  1711. //
  1712. if (!(pPCB->fEapInitialized))
  1713. {
  1714. if (ElEapBegin (pPCB) != NO_ERROR)
  1715. {
  1716. TRACE1 (EAPOL, "ElEapWork: Error in ElEapBegin = %ld", dwRetCode);
  1717. return dwRetCode;
  1718. }
  1719. }
  1720. ZeroMemory(&EapResult, sizeof(EapResult));
  1721. // Create buffer for EAPOL + EAP and pass pointer to EAP header
  1722. pEapolPkt = (EAPOL_PACKET *) MALLOC (MAX_EAPOL_BUFFER_SIZE);
  1723. TRACE1 (EAPOL, "ElEapWork: EapolPkt created at %p", pEapolPkt);
  1724. if (pEapolPkt == NULL)
  1725. {
  1726. TRACE0 (EAPOL, "ElEapWork: Error allocating EAP buffer");
  1727. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  1728. return dwRetCode;
  1729. }
  1730. // Point to EAP header
  1731. pSendPkt = (PPP_EAP_PACKET *)((PBYTE)pEapolPkt + sizeof (EAPOL_PACKET) - 1);
  1732. if (pRecvPkt != NULL)
  1733. {
  1734. dwReceivedId = pRecvPkt->Id;
  1735. }
  1736. if (pPCB->fRemoteEnd8021XD8)
  1737. {
  1738. // Account for 2 bytes of AuthResultCode
  1739. dwDraft8HdrIncr = 2;
  1740. }
  1741. dwRetCode = ElEapMakeMessage (pPCB,
  1742. pRecvPkt,
  1743. pSendPkt,
  1744. MAX_EAPOL_BUFFER_SIZE
  1745. - sizeof(EAPOL_PACKET) - 1 - dwDraft8HdrIncr,
  1746. &EapResult
  1747. );
  1748. // Notification message for the user
  1749. if (NULL != EapResult.pszReplyMessage)
  1750. {
  1751. // Free earlier notication with the PCB
  1752. if (pPCB->pszEapReplyMessage != NULL)
  1753. {
  1754. FREE (pPCB->pszEapReplyMessage);
  1755. pPCB->pszEapReplyMessage = NULL;
  1756. }
  1757. pPCB->pszEapReplyMessage = EapResult.pszReplyMessage;
  1758. // Notify user of message
  1759. #ifndef EAPOL_SERVICE
  1760. ZeroMemory (awszNotificationMsg, MAX_NOTIFICATION_MSG_SIZE);
  1761. if (0 == MultiByteToWideChar (
  1762. CP_ACP,
  1763. 0,
  1764. pPCB->pszEapReplyMessage,
  1765. -1,
  1766. awszNotificationMsg,
  1767. MAX_NOTIFICATION_MSG_SIZE))
  1768. {
  1769. dwRetCode = GetLastError();
  1770. TRACE2 (EAPOL,"MultiByteToWideChar(%s) failed: %d",
  1771. pPCB->pszEapReplyMessage,
  1772. dwRetCode);
  1773. FREE (pEapolPkt);
  1774. pEapolPkt = NULL;
  1775. return dwRetCode;
  1776. }
  1777. // Display notification message using sys tray balloon
  1778. // on interface icon
  1779. ElStringToGuid (pPCB->pszDeviceGUID, &DeviceGuid);
  1780. (VOID)EAPOLMANNotification (&DeviceGuid,
  1781. awszNotificationMsg,
  1782. 0);
  1783. #endif
  1784. TRACE1 (EAPOL, "ElEapWork: Notified user of EAP data = %s",
  1785. pPCB->pszEapReplyMessage);
  1786. }
  1787. if (dwRetCode != NO_ERROR)
  1788. {
  1789. switch (dwRetCode)
  1790. {
  1791. case ERROR_PPP_INVALID_PACKET:
  1792. TRACE0 (EAPOL, "ElEapWork: Silently discarding invalid auth packet");
  1793. break;
  1794. default:
  1795. TRACE1 (EAPOL, "ElEapWork: ElEapMakeMessage returned error %ld",
  1796. dwRetCode);
  1797. // NotifyCallerOfFailure (pPCB, dwRetCode);
  1798. break;
  1799. }
  1800. // Free up memory reserved for packet
  1801. FREE (pEapolPkt);
  1802. pEapolPkt = NULL;
  1803. return dwRetCode;
  1804. }
  1805. //
  1806. // Check to see if we have to save any user data
  1807. //
  1808. if (EapResult.fSaveUserData)
  1809. {
  1810. if ((dwRetCode = ElSetEapUserInfo (
  1811. pPCB->hUserToken,
  1812. pPCB->pszDeviceGUID,
  1813. pPCB->dwEapTypeToBeUsed,
  1814. pPCB->pszSSID,
  1815. EapResult.pUserData,
  1816. EapResult.dwSizeOfUserData)) != NO_ERROR)
  1817. {
  1818. TRACE1 (EAPOL, "ElEapWork: ElSetEapUserInfo failed with error = %d",
  1819. dwRetCode);
  1820. if (pEapolPkt != NULL)
  1821. {
  1822. FREE (pEapolPkt);
  1823. pEapolPkt = NULL;
  1824. }
  1825. return dwRetCode;
  1826. }
  1827. TRACE1 (EAPOL, "ElEapWork: Saved EAP data for user, dwRetCode = %d",
  1828. dwRetCode);
  1829. }
  1830. //
  1831. // Check to see if we have to save any connection data
  1832. //
  1833. if ((EapResult.fSaveConnectionData ) &&
  1834. ( 0 != EapResult.SetCustomAuthData.dwSizeOfConnectionData ) )
  1835. {
  1836. if ((dwRetCode = ElSetCustomAuthData (
  1837. pPCB->pszDeviceGUID,
  1838. pPCB->dwEapTypeToBeUsed,
  1839. pPCB->pszSSID,
  1840. EapResult.SetCustomAuthData.pConnectionData,
  1841. EapResult.SetCustomAuthData.dwSizeOfConnectionData
  1842. )) != NO_ERROR)
  1843. {
  1844. TRACE1 ( EAPOL, "ElEapWork: ElSetCustomAuthData failed with error = %d",
  1845. dwRetCode);
  1846. FREE (pEapolPkt);
  1847. pEapolPkt = NULL;
  1848. return dwRetCode;
  1849. }
  1850. TRACE0 ( EAPOL, "ElEapWork: Saved EAP data for connection" );
  1851. }
  1852. switch( EapResult.Action )
  1853. {
  1854. case ELEAP_Send:
  1855. case ELEAP_SendAndDone:
  1856. // Send out EAPOL packet
  1857. memcpy ((BYTE *)pEapolPkt->EthernetType,
  1858. (BYTE *)pPCB->bEtherType,
  1859. SIZE_ETHERNET_TYPE);
  1860. pEapolPkt->ProtocolVersion = pPCB->bProtocolVersion;
  1861. pEapolPkt->PacketType = EAP_Packet;
  1862. // The EAP packet length is in the packet returned back by
  1863. // the Dll MakeMessage
  1864. // In case of Notification and Identity Response, it is in
  1865. // EapResult.wSizeOfEapPkt
  1866. if (EapResult.wSizeOfEapPkt == 0)
  1867. {
  1868. EapResult.wSizeOfEapPkt =
  1869. WireToHostFormat16 (pSendPkt->Length);
  1870. }
  1871. HostToWireFormat16 ((WORD) EapResult.wSizeOfEapPkt,
  1872. (BYTE *)pEapolPkt->PacketBodyLength);
  1873. // Make a copy of the EAPOL packet in the PCB
  1874. // Will be used during retransmission
  1875. if (pPCB->pbPreviousEAPOLPkt != NULL)
  1876. {
  1877. FREE (pPCB->pbPreviousEAPOLPkt);
  1878. }
  1879. pPCB->pbPreviousEAPOLPkt =
  1880. MALLOC (sizeof (EAPOL_PACKET)+EapResult.wSizeOfEapPkt-1);
  1881. if (pPCB->pbPreviousEAPOLPkt == NULL)
  1882. {
  1883. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  1884. TRACE0 (EAPOL, "ElEapWork: MALLOC failed for pbPreviousEAPOLPkt");
  1885. if (pEapolPkt != NULL)
  1886. {
  1887. FREE (pEapolPkt);
  1888. pEapolPkt = NULL;
  1889. }
  1890. return dwRetCode;
  1891. }
  1892. memcpy (pPCB->pbPreviousEAPOLPkt, pEapolPkt,
  1893. sizeof (EAPOL_PACKET)+EapResult.wSizeOfEapPkt-1);
  1894. pPCB->dwSizeOfPreviousEAPOLPkt =
  1895. sizeof (EAPOL_PACKET)+EapResult.wSizeOfEapPkt-1;
  1896. pPCB->dwPreviousId = dwReceivedId;
  1897. // Send packet out on the port
  1898. dwRetCode = ElWriteToPort (pPCB,
  1899. (CHAR *)pEapolPkt,
  1900. sizeof (EAPOL_PACKET)+EapResult.wSizeOfEapPkt-1);
  1901. if (dwRetCode != NO_ERROR)
  1902. {
  1903. TRACE1 (EAPOL, "ElEapWork: Error in writing EAP_Packet to port %ld",
  1904. dwRetCode);
  1905. if (pEapolPkt != NULL)
  1906. {
  1907. FREE (pEapolPkt);
  1908. pEapolPkt = NULL;
  1909. }
  1910. return dwRetCode;
  1911. }
  1912. if (pEapolPkt != NULL)
  1913. {
  1914. FREE (pEapolPkt);
  1915. pEapolPkt = NULL;
  1916. }
  1917. // More processing to be done?
  1918. // Supplicant side should not ever receive ELEAP_SendAndDone
  1919. // result code
  1920. if (EapResult.Action != ELEAP_SendAndDone)
  1921. {
  1922. break;
  1923. }
  1924. else
  1925. {
  1926. TRACE0 (EAPOL, "ElEapWork: ELEAP_SendAndDone wrong result received");
  1927. ASSERT(0);
  1928. }
  1929. case ELEAP_Done:
  1930. // Retrieve MPPE keys from the attributes information
  1931. // returned by EAP-TLS
  1932. switch (EapResult.dwError)
  1933. {
  1934. case NO_ERROR:
  1935. TRACE0 (EAPOL, "ElEapWork: Authentication was successful");
  1936. //
  1937. // If authentication was successful
  1938. //
  1939. dwRetCode = ElExtractMPPESendRecvKeys (
  1940. pPCB,
  1941. EapResult.pUserAttributes,
  1942. (BYTE*)&(EapResult.abChallenge),
  1943. (BYTE*)&(EapResult.abResponse));
  1944. if (dwRetCode != NO_ERROR)
  1945. {
  1946. FREE (pEapolPkt);
  1947. //NotifyCallerOfFailure (pPcb, dwRetCode);
  1948. return dwRetCode;
  1949. }
  1950. // ISSUE:
  1951. // Do we want to retain UserAttributes
  1952. // pPCB->pAuthProtocolAttributes = EapResult.pUserAttributes;
  1953. break;
  1954. default:
  1955. if (pEapolPkt != NULL)
  1956. {
  1957. FREE (pEapolPkt);
  1958. pEapolPkt = NULL;
  1959. }
  1960. TRACE0 (EAPOL, "ElEapWork: Authentication FAILED");
  1961. break;
  1962. }
  1963. // Free memory allocated for the packet, since no response
  1964. // is going to be sent out
  1965. if (pEapolPkt != NULL)
  1966. {
  1967. FREE (pEapolPkt);
  1968. pEapolPkt = NULL;
  1969. }
  1970. break;
  1971. case ELEAP_NoAction:
  1972. // Free memory allocated for the packet, since nothing
  1973. // is being done with it
  1974. if (pEapolPkt != NULL)
  1975. {
  1976. FREE (pEapolPkt);
  1977. pEapolPkt = NULL;
  1978. }
  1979. break;
  1980. default:
  1981. break;
  1982. }
  1983. if (pEapolPkt != NULL)
  1984. {
  1985. FREE (pEapolPkt);
  1986. pEapolPkt = NULL;
  1987. }
  1988. //
  1989. // Check to see if we have to bring up the InteractiveUI for EAP
  1990. // i.e. Server cert confirmation etc.
  1991. //
  1992. if (EapResult.fInvokeEapUI)
  1993. {
  1994. ElInvokeInteractiveUI (pPCB, &(EapResult.InvokeEapUIData));
  1995. }
  1996. return dwRetCode;
  1997. }
  1998. //
  1999. //
  2000. // ElExtractMPPESendRecvKeys
  2001. //
  2002. // Description:
  2003. // Function called if authentication was successful. The MPPE Send &
  2004. // Recv keys are extracted from the RAS_AUTH_ATTRIBUTE passed from
  2005. // the EAP DLL and stored in the PCB. The keys are used to decrypt
  2006. // the multicast WEP key and also are used for media-based encrypting.
  2007. //
  2008. // Return values
  2009. //
  2010. // NO_ERROR - Success
  2011. // Non-zero - Failure
  2012. //
  2013. DWORD
  2014. ElExtractMPPESendRecvKeys (
  2015. IN EAPOL_PCB *pPCB,
  2016. IN RAS_AUTH_ATTRIBUTE * pUserAttributes,
  2017. IN BYTE * pChallenge,
  2018. IN BYTE * pResponse
  2019. )
  2020. {
  2021. RAS_AUTH_ATTRIBUTE * pAttribute;
  2022. RAS_AUTH_ATTRIBUTE * pAttributeSendKey;
  2023. RAS_AUTH_ATTRIBUTE * pAttributeRecvKey;
  2024. DWORD dwRetCode = NO_ERROR;
  2025. DWORD dwEncryptionPolicy = 0;
  2026. DWORD dwEncryptionTypes = 0;
  2027. //
  2028. // Every time we get encryption keys, plumb them to the driver
  2029. //
  2030. do
  2031. {
  2032. pAttribute = ElAuthAttributeGetVendorSpecific (
  2033. 311, 12, pUserAttributes);
  2034. pAttributeSendKey = ElAuthAttributeGetVendorSpecific ( 311, 16,
  2035. pUserAttributes);
  2036. pAttributeRecvKey = ElAuthAttributeGetVendorSpecific ( 311, 17,
  2037. pUserAttributes);
  2038. if ((pAttributeSendKey != NULL)
  2039. && (pAttributeRecvKey != NULL))
  2040. {
  2041. //
  2042. // Set the MS-MPPE-Send-Key and MS-MPPE-Recv-Key with
  2043. // the ethernet driver
  2044. //
  2045. ULONG ulSendKeyLength = 0;
  2046. ULONG ulRecvKeyLength = 0;
  2047. // Based on PPP code
  2048. ulSendKeyLength = *(((BYTE*)(pAttributeSendKey->Value))+8);
  2049. ulRecvKeyLength = *(((BYTE*)(pAttributeRecvKey->Value))+8);
  2050. TRACE0 (EAPOL, "Send key = ");
  2051. EAPOL_DUMPBA (((BYTE*)(pAttributeSendKey->Value))+9,
  2052. ulSendKeyLength);
  2053. TRACE0 (EAPOL, "Recv key = ");
  2054. EAPOL_DUMPBA (((BYTE*)(pAttributeRecvKey->Value))+9,
  2055. ulRecvKeyLength);
  2056. pPCB->dwMPPESendKeyLength = ulSendKeyLength;
  2057. pPCB->dwMPPERecvKeyLength = ulRecvKeyLength;
  2058. //
  2059. // Copy MPPE Send and Receive Keys into the PCB for later usage
  2060. // These keys will be used to decrypt the global multicast key
  2061. // (if any).
  2062. //
  2063. if (pPCB->dwMPPESendKeyLength != 0)
  2064. {
  2065. if (pPCB->pbMPPESendKey != NULL)
  2066. {
  2067. FREE (pPCB->pbMPPESendKey);
  2068. pPCB->pbMPPESendKey = NULL;
  2069. }
  2070. if ((pPCB->pbMPPESendKey = MALLOC (pPCB->dwMPPESendKeyLength))
  2071. == NULL)
  2072. {
  2073. TRACE0 (EAPOL, "ElExtractMPPESendRecvKeys: Error in Malloc for SendKey");
  2074. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  2075. break;
  2076. }
  2077. memcpy (pPCB->pbMPPESendKey,
  2078. ((BYTE*)(pAttributeSendKey->Value))+9,
  2079. pPCB->dwMPPESendKeyLength);
  2080. }
  2081. if (pPCB->dwMPPERecvKeyLength != 0)
  2082. {
  2083. if (pPCB->pbMPPERecvKey != NULL)
  2084. {
  2085. FREE (pPCB->pbMPPERecvKey);
  2086. pPCB->pbMPPERecvKey = NULL;
  2087. }
  2088. if ((pPCB->pbMPPERecvKey = MALLOC (pPCB->dwMPPERecvKeyLength))
  2089. == NULL)
  2090. {
  2091. TRACE0 (EAPOL, "ElExtractMPPESendRecvKeys: Error in Malloc for RecvKey");
  2092. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  2093. break;
  2094. }
  2095. memcpy (pPCB->pbMPPERecvKey,
  2096. ((BYTE*)(pAttributeRecvKey->Value))+9,
  2097. pPCB->dwMPPERecvKeyLength);
  2098. }
  2099. TRACE0 (EAPOL,"MPPE-Send/Recv-Keys set");
  2100. }
  2101. else
  2102. {
  2103. TRACE0 (EAPOL, "ElExtractMPPESendRecvKeys: pAttributeSendKey or pAttributeRecvKey == NULL");
  2104. }
  2105. } while (FALSE);
  2106. if (dwRetCode != NO_ERROR)
  2107. {
  2108. if (pPCB->pbMPPESendKey != NULL)
  2109. {
  2110. FREE (pPCB->pbMPPESendKey);
  2111. pPCB->pbMPPESendKey = NULL;
  2112. }
  2113. if (pPCB->pbMPPERecvKey != NULL)
  2114. {
  2115. FREE (pPCB->pbMPPERecvKey);
  2116. pPCB->pbMPPERecvKey = NULL;
  2117. }
  2118. }
  2119. return( dwRetCode );
  2120. }
  2121. //
  2122. // ElProcessEapSuccess
  2123. //
  2124. // Description:
  2125. //
  2126. // Function called when an EAP_Success is received in any state
  2127. //
  2128. // Input arguments:
  2129. // pPCB - Pointer to PCB for the port on which data is being processed
  2130. // pEapolPkt - Pointer to EAPOL packet that was received
  2131. //
  2132. // Return values:
  2133. // NO_ERROR - success
  2134. // non-zero - error
  2135. //
  2136. DWORD
  2137. ElProcessEapSuccess (
  2138. IN EAPOL_PCB *pPCB,
  2139. IN EAPOL_PACKET *pEapolPkt
  2140. )
  2141. {
  2142. GUID DeviceGuid;
  2143. BOOLEAN fAuthenticateAndAuthorized = TRUE;
  2144. EAPOL_PACKET_D8_D7 *pDummyHeader;
  2145. DWORD dwRetCode = NO_ERROR;
  2146. TRACE0 (EAPOL, "ElProcessEapSuccess: Got EAPCODE_Success");
  2147. do
  2148. {
  2149. // Indicate to EAP=Dll to cleanup completed session
  2150. if ((dwRetCode = ElEapEnd (pPCB)) != NO_ERROR)
  2151. {
  2152. TRACE1 (EAPOL, "ProcessReceivedPacket: EapSuccess: Error in ElEapEnd = %ld",
  2153. dwRetCode);
  2154. break;
  2155. }
  2156. if (pPCB->fRemoteEnd8021XD8)
  2157. {
  2158. fAuthenticateAndAuthorized = FALSE;
  2159. pDummyHeader = (EAPOL_PACKET_D8_D7 *)((BYTE *)pEapolPkt - 2);
  2160. switch (WireToHostFormat16(pDummyHeader->AuthResultCode))
  2161. {
  2162. case AUTH_Authorized:
  2163. fAuthenticateAndAuthorized = TRUE;
  2164. break;
  2165. case AUTH_Unauthorized:
  2166. fAuthenticateAndAuthorized = FALSE;
  2167. break;
  2168. default:
  2169. fAuthenticateAndAuthorized = FALSE;
  2170. break;
  2171. }
  2172. }
  2173. if (fAuthenticateAndAuthorized)
  2174. {
  2175. TRACE0 (EAPOL, "ElProcessEapSuccess: Autho and Authen successful");
  2176. // Complete remaining processing i.e. DHCP
  2177. if ((dwRetCode = FSMAuthenticated (pPCB,
  2178. pEapolPkt)) != NO_ERROR)
  2179. {
  2180. break;
  2181. }
  2182. #ifndef EAPOL_SERVICE
  2183. // Display change of status using sys tray balloon
  2184. // on interface icon
  2185. ElStringToGuid (pPCB->pszDeviceGUID, &DeviceGuid);
  2186. (VOID)EAPOLMANAuthenticationSucceeded (&DeviceGuid);
  2187. #endif
  2188. }
  2189. else
  2190. {
  2191. TRACE0 (EAPOL, "ElProcessEapSuccess: Autho and Authen failed");
  2192. if ((dwRetCode = FSMHeld (pPCB)) != NO_ERROR)
  2193. {
  2194. break;
  2195. }
  2196. #ifndef EAPOL_SERVICE
  2197. // Display change of status using sys tray balloon
  2198. // on interface icon
  2199. ElStringToGuid (pPCB->pszDeviceGUID, &DeviceGuid);
  2200. (VOID)EAPOLMANAuthenticationFailed (&DeviceGuid, 0);
  2201. #endif
  2202. }
  2203. }
  2204. while (FALSE);
  2205. return dwRetCode;
  2206. }
  2207. //
  2208. // ElProcessEapFail
  2209. //
  2210. // Description:
  2211. //
  2212. // Function called when an EAP_Fail is received in any state
  2213. //
  2214. // Input arguments:
  2215. // pPCB - Pointer to PCB for the port on which data is being processed
  2216. // pEapolPkt - Pointer to EAPOL packet that was received
  2217. //
  2218. // Return values:
  2219. // NO_ERROR - success
  2220. // non-zero - error
  2221. //
  2222. DWORD
  2223. ElProcessEapFail (
  2224. IN EAPOL_PCB *pPCB,
  2225. IN EAPOL_PACKET *pEapolPkt
  2226. )
  2227. {
  2228. GUID DeviceGuid;
  2229. DWORD dwRetCode = NO_ERROR;
  2230. TRACE0 (EAPOL, "ElProcessEapFail: Got EAPCODE_Failure");
  2231. do
  2232. {
  2233. // Indicate to EAP=Dll to cleanup completed session
  2234. if ((dwRetCode = ElEapEnd (pPCB)) != NO_ERROR)
  2235. {
  2236. TRACE1 (EAPOL, "ElProcessEapFail: EapFail: Error in ElEapEnd = %ld",
  2237. dwRetCode);
  2238. break;
  2239. }
  2240. if ((dwRetCode = FSMHeld (pPCB)) != NO_ERROR)
  2241. {
  2242. break;
  2243. }
  2244. #ifndef EAPOL_SERVICE
  2245. // Display change of status using sys tray balloon
  2246. // on interface icon
  2247. ElStringToGuid (pPCB->pszDeviceGUID, &DeviceGuid);
  2248. (VOID)EAPOLMANAuthenticationFailed (&DeviceGuid, 0);
  2249. #endif
  2250. }
  2251. while (FALSE);
  2252. return dwRetCode;
  2253. }
  2254. #undef EAPOL_SERVICE