]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/WifiConnectionManagerDxe/WifiConnectionMgrImpl.c
NetworkPkg: Add Wi-Fi Wpa3 support in WifiConnectManager
[mirror_edk2.git] / NetworkPkg / WifiConnectionManagerDxe / WifiConnectionMgrImpl.c
1 /** @file
2 The Mac Connection2 Protocol adapter functions for WiFi Connection Manager.
3
4 Copyright (c) 2019 - 2022, Intel Corporation. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "WifiConnectionMgrDxe.h"
11
12 EFI_EAP_TYPE mEapAuthMethod[] = {
13 EFI_EAP_TYPE_TTLS,
14 EFI_EAP_TYPE_PEAP,
15 EFI_EAP_TYPE_EAPTLS
16 };
17
18 EFI_EAP_TYPE mEapSecondAuthMethod[] = {
19 EFI_EAP_TYPE_MSCHAPV2
20 };
21
22 /**
23 The callback function for scan operation. This function updates networks
24 according to the latest scan result, and trigger UI refresh.
25
26 ASSERT when errors occur in config token.
27
28 @param[in] Event The GetNetworks token receive event.
29 @param[in] Context The context of the GetNetworks token.
30
31 **/
32 VOID
33 EFIAPI
34 WifiMgrOnScanFinished (
35 IN EFI_EVENT Event,
36 IN VOID *Context
37 )
38 {
39 EFI_STATUS Status;
40 WIFI_MGR_MAC_CONFIG_TOKEN *ConfigToken;
41 WIFI_MGR_DEVICE_DATA *Nic;
42 WIFI_MGR_NETWORK_PROFILE *Profile;
43 EFI_80211_NETWORK *Network;
44 UINTN DataSize;
45 EFI_80211_NETWORK_DESCRIPTION *NetworkDescription;
46 EFI_80211_GET_NETWORKS_RESULT *Result;
47 LIST_ENTRY *Entry;
48 UINT8 SecurityType;
49 BOOLEAN AKMSuiteSupported;
50 BOOLEAN CipherSuiteSupported;
51 CHAR8 *AsciiSSId;
52 UINTN Index;
53
54 ASSERT (Context != NULL);
55
56 ConfigToken = (WIFI_MGR_MAC_CONFIG_TOKEN *)Context;
57 ASSERT (ConfigToken->Nic != NULL);
58 ASSERT (ConfigToken->Type == TokenTypeGetNetworksToken);
59
60 //
61 // It is the GetNetworks token, set scan state to "ScanFinished"
62 //
63 ConfigToken->Nic->ScanState = WifiMgrScanFinished;
64
65 ASSERT (ConfigToken->Token.GetNetworksToken != NULL);
66 Result = ConfigToken->Token.GetNetworksToken->Result;
67 Nic = ConfigToken->Nic;
68
69 //
70 // Clean previous result, and update network list according to the scan result
71 //
72 Nic->AvailableCount = 0;
73
74 NET_LIST_FOR_EACH (Entry, &Nic->ProfileList) {
75 Profile = NET_LIST_USER_STRUCT_S (
76 Entry,
77 WIFI_MGR_NETWORK_PROFILE,
78 Link,
79 WIFI_MGR_PROFILE_SIGNATURE
80 );
81 Profile->IsAvailable = FALSE;
82 }
83
84 if (Result == NULL) {
85 gBS->SignalEvent (Nic->Private->NetworkListRefreshEvent);
86 WifiMgrFreeToken (ConfigToken);
87 return;
88 }
89
90 for (Index = 0; Index < Result->NumOfNetworkDesc; Index++) {
91 NetworkDescription = Result->NetworkDesc + Index;
92 if (NetworkDescription == NULL) {
93 continue;
94 }
95
96 Network = &NetworkDescription->Network;
97 if ((Network == NULL) || (Network->SSId.SSIdLen == 0)) {
98 continue;
99 }
100
101 Status = WifiMgrCheckRSN (
102 Network->AKMSuite,
103 Network->CipherSuite,
104 Nic,
105 &SecurityType,
106 &AKMSuiteSupported,
107 &CipherSuiteSupported
108 );
109 if (EFI_ERROR (Status)) {
110 SecurityType = SECURITY_TYPE_UNKNOWN;
111 AKMSuiteSupported = FALSE;
112 CipherSuiteSupported = FALSE;
113 }
114
115 AsciiSSId = (CHAR8 *)AllocateZeroPool (sizeof (CHAR8) * (Network->SSId.SSIdLen + 1));
116 if (AsciiSSId == NULL) {
117 continue;
118 }
119
120 CopyMem (AsciiSSId, (CHAR8 *)Network->SSId.SSId, sizeof (CHAR8) * Network->SSId.SSIdLen);
121 *(AsciiSSId + Network->SSId.SSIdLen) = '\0';
122
123 Profile = WifiMgrGetProfileByAsciiSSId (AsciiSSId, SecurityType, &Nic->ProfileList);
124 if (Profile == NULL) {
125 if (Nic->MaxProfileIndex >= NETWORK_LIST_COUNT_MAX) {
126 FreePool (AsciiSSId);
127 continue;
128 }
129
130 //
131 // Create a new profile
132 //
133 Profile = AllocateZeroPool (sizeof (WIFI_MGR_NETWORK_PROFILE));
134 if (Profile == NULL) {
135 FreePool (AsciiSSId);
136 continue;
137 }
138
139 Profile->Signature = WIFI_MGR_PROFILE_SIGNATURE;
140 Profile->NicIndex = Nic->NicIndex;
141 Profile->ProfileIndex = Nic->MaxProfileIndex + 1;
142 AsciiStrToUnicodeStrS (AsciiSSId, Profile->SSId, SSID_STORAGE_SIZE);
143 InsertTailList (&Nic->ProfileList, &Profile->Link);
144 Nic->MaxProfileIndex++;
145 }
146
147 FreePool (AsciiSSId);
148
149 //
150 // May receive duplicate networks in scan results, check if it has already
151 // been processed.
152 //
153 if (!Profile->IsAvailable) {
154 Profile->IsAvailable = TRUE;
155 Profile->SecurityType = SecurityType;
156 Profile->AKMSuiteSupported = AKMSuiteSupported;
157 Profile->CipherSuiteSupported = CipherSuiteSupported;
158 Profile->NetworkQuality = NetworkDescription->NetworkQuality;
159 Nic->AvailableCount++;
160
161 //
162 // Copy BSSType and SSId
163 //
164 CopyMem (&Profile->Network, Network, sizeof (EFI_80211_NETWORK));
165
166 //
167 // Copy AKMSuite list
168 //
169 if (Network->AKMSuite != NULL) {
170 if (Network->AKMSuite->AKMSuiteCount == 0) {
171 DataSize = sizeof (EFI_80211_AKM_SUITE_SELECTOR);
172 } else {
173 DataSize = sizeof (EFI_80211_AKM_SUITE_SELECTOR) + sizeof (EFI_80211_SUITE_SELECTOR)
174 * (Network->AKMSuite->AKMSuiteCount - 1);
175 }
176
177 Profile->Network.AKMSuite = (EFI_80211_AKM_SUITE_SELECTOR *)AllocateZeroPool (DataSize);
178 if (Profile->Network.AKMSuite == NULL) {
179 continue;
180 }
181
182 CopyMem (Profile->Network.AKMSuite, Network->AKMSuite, DataSize);
183 }
184
185 //
186 // Copy CipherSuite list
187 //
188 if (Network->CipherSuite != NULL) {
189 if (Network->CipherSuite->CipherSuiteCount == 0) {
190 DataSize = sizeof (EFI_80211_CIPHER_SUITE_SELECTOR);
191 } else {
192 DataSize = sizeof (EFI_80211_CIPHER_SUITE_SELECTOR) + sizeof (EFI_80211_SUITE_SELECTOR)
193 * (Network->CipherSuite->CipherSuiteCount - 1);
194 }
195
196 Profile->Network.CipherSuite = (EFI_80211_CIPHER_SUITE_SELECTOR *)AllocateZeroPool (DataSize);
197 if (Profile->Network.CipherSuite == NULL) {
198 continue;
199 }
200
201 CopyMem (Profile->Network.CipherSuite, Network->CipherSuite, DataSize);
202 }
203 } else {
204 //
205 // A duplicate network, update signal quality
206 //
207 if (Profile->NetworkQuality < NetworkDescription->NetworkQuality) {
208 Profile->NetworkQuality = NetworkDescription->NetworkQuality;
209 }
210
211 continue;
212 }
213 }
214
215 gBS->SignalEvent (Nic->Private->NetworkListRefreshEvent);
216
217 //
218 // The current connected network should always be available until disconnection
219 // happens in Wifi FW layer, even when it is not in this time's scan result.
220 //
221 if ((Nic->ConnectState == WifiMgrConnectedToAp) && (Nic->CurrentOperateNetwork != NULL)) {
222 if (!Nic->CurrentOperateNetwork->IsAvailable) {
223 Nic->CurrentOperateNetwork->IsAvailable = TRUE;
224 Nic->AvailableCount++;
225 }
226 }
227
228 WifiMgrFreeToken (ConfigToken);
229 }
230
231 /**
232 Start scan operation, and send out a token to collect available networks.
233
234 @param[in] Nic Pointer to the device data of the selected NIC.
235
236 @retval EFI_SUCCESS The operation is completed.
237 @retval EFI_ALREADY_STARTED A former scan operation is already ongoing.
238 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
239 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
240 @retval Other Errors Return errors when getting networks from low layer.
241
242 **/
243 EFI_STATUS
244 WifiMgrStartScan (
245 IN WIFI_MGR_DEVICE_DATA *Nic
246 )
247 {
248 EFI_STATUS Status;
249 EFI_TPL OldTpl;
250 WIFI_MGR_MAC_CONFIG_TOKEN *ConfigToken;
251 EFI_80211_GET_NETWORKS_TOKEN *GetNetworksToken;
252 UINT32 HiddenSSIdIndex;
253 UINT32 HiddenSSIdCount;
254 EFI_80211_SSID *HiddenSSIdList;
255 WIFI_HIDDEN_NETWORK_DATA *HiddenNetwork;
256 LIST_ENTRY *Entry;
257
258 if ((Nic == NULL) || (Nic->Wmp == NULL)) {
259 return EFI_INVALID_PARAMETER;
260 }
261
262 if (Nic->ScanState == WifiMgrScanning) {
263 return EFI_ALREADY_STARTED;
264 }
265
266 Nic->ScanState = WifiMgrScanning;
267 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
268 Status = EFI_SUCCESS;
269 HiddenSSIdList = NULL;
270 HiddenSSIdCount = Nic->Private->HiddenNetworkCount;
271 HiddenSSIdIndex = 0;
272
273 //
274 // create a new get network token
275 //
276 ConfigToken = AllocateZeroPool (sizeof (WIFI_MGR_MAC_CONFIG_TOKEN));
277 if (ConfigToken == NULL) {
278 gBS->RestoreTPL (OldTpl);
279 return EFI_OUT_OF_RESOURCES;
280 }
281
282 ConfigToken->Type = TokenTypeGetNetworksToken;
283 ConfigToken->Nic = Nic;
284 ConfigToken->Token.GetNetworksToken = AllocateZeroPool (sizeof (EFI_80211_GET_NETWORKS_TOKEN));
285 if (ConfigToken->Token.GetNetworksToken == NULL) {
286 WifiMgrFreeToken (ConfigToken);
287 gBS->RestoreTPL (OldTpl);
288 return EFI_OUT_OF_RESOURCES;
289 }
290
291 GetNetworksToken = ConfigToken->Token.GetNetworksToken;
292
293 //
294 // There are some hidden networks to scan, add them into scan list
295 //
296 if (HiddenSSIdCount > 0) {
297 HiddenSSIdList = AllocateZeroPool (HiddenSSIdCount * sizeof (EFI_80211_SSID));
298 if (HiddenSSIdList == NULL) {
299 WifiMgrFreeToken (ConfigToken);
300 gBS->RestoreTPL (OldTpl);
301 return EFI_OUT_OF_RESOURCES;
302 }
303
304 HiddenSSIdIndex = 0;
305 NET_LIST_FOR_EACH (Entry, &Nic->Private->HiddenNetworkList) {
306 HiddenNetwork = NET_LIST_USER_STRUCT_S (
307 Entry,
308 WIFI_HIDDEN_NETWORK_DATA,
309 Link,
310 WIFI_MGR_HIDDEN_NETWORK_SIGNATURE
311 );
312 HiddenSSIdList[HiddenSSIdIndex].SSIdLen = (UINT8)StrLen (HiddenNetwork->SSId);
313 UnicodeStrToAsciiStrS (
314 HiddenNetwork->SSId,
315 (CHAR8 *)HiddenSSIdList[HiddenSSIdIndex].SSId,
316 SSID_STORAGE_SIZE
317 );
318 HiddenSSIdIndex++;
319 }
320 GetNetworksToken->Data = AllocateZeroPool (
321 sizeof (EFI_80211_GET_NETWORKS_DATA) +
322 (HiddenSSIdCount - 1) * sizeof (EFI_80211_SSID)
323 );
324 if (GetNetworksToken->Data == NULL) {
325 FreePool (HiddenSSIdList);
326 WifiMgrFreeToken (ConfigToken);
327 gBS->RestoreTPL (OldTpl);
328 return EFI_OUT_OF_RESOURCES;
329 }
330
331 GetNetworksToken->Data->NumOfSSID = HiddenSSIdCount;
332 CopyMem (GetNetworksToken->Data->SSIDList, HiddenSSIdList, HiddenSSIdCount * sizeof (EFI_80211_SSID));
333 FreePool (HiddenSSIdList);
334 } else {
335 GetNetworksToken->Data = AllocateZeroPool (sizeof (EFI_80211_GET_NETWORKS_DATA));
336 if (GetNetworksToken->Data == NULL) {
337 WifiMgrFreeToken (ConfigToken);
338 gBS->RestoreTPL (OldTpl);
339 return EFI_OUT_OF_RESOURCES;
340 }
341
342 GetNetworksToken->Data->NumOfSSID = 0;
343 }
344
345 //
346 // Create a handle when scan process ends
347 //
348 Status = gBS->CreateEvent (
349 EVT_NOTIFY_SIGNAL,
350 TPL_CALLBACK,
351 WifiMgrOnScanFinished,
352 ConfigToken,
353 &GetNetworksToken->Event
354 );
355 if (EFI_ERROR (Status)) {
356 WifiMgrFreeToken (ConfigToken);
357 gBS->RestoreTPL (OldTpl);
358 return Status;
359 }
360
361 //
362 // Start scan ...
363 //
364 Status = Nic->Wmp->GetNetworks (Nic->Wmp, GetNetworksToken);
365 if (EFI_ERROR (Status)) {
366 Nic->ScanState = WifiMgrScanFinished;
367 WifiMgrFreeToken (ConfigToken);
368 gBS->RestoreTPL (OldTpl);
369 return Status;
370 }
371
372 gBS->RestoreTPL (OldTpl);
373 return EFI_SUCCESS;
374 }
375
376 /**
377 Configure password to supplicant before connecting to a secured network.
378
379 @param[in] Nic Pointer to the device data of the selected NIC.
380 @param[in] Profile The target network to be connected.
381
382 @retval EFI_SUCCESS The operation is completed.
383 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
384 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
385 @retval EFI_NOT_FOUND No valid password is found to configure.
386 @retval Other Errors Returned errors when setting data to supplicant.
387
388 **/
389 EFI_STATUS
390 WifiMgrConfigPassword (
391 IN WIFI_MGR_DEVICE_DATA *Nic,
392 IN WIFI_MGR_NETWORK_PROFILE *Profile
393 )
394 {
395 EFI_STATUS Status;
396 EFI_SUPPLICANT_PROTOCOL *Supplicant;
397 EFI_80211_SSID SSId;
398 UINT8 *AsciiPassword;
399
400 if ((Nic == NULL) || (Nic->Supplicant == NULL) || (Profile == NULL)) {
401 return EFI_INVALID_PARAMETER;
402 }
403
404 Supplicant = Nic->Supplicant;
405 //
406 // Set SSId to supplicant
407 //
408 SSId.SSIdLen = Profile->Network.SSId.SSIdLen;
409 CopyMem (SSId.SSId, Profile->Network.SSId.SSId, sizeof (Profile->Network.SSId.SSId));
410 Status = Supplicant->SetData (
411 Supplicant,
412 EfiSupplicant80211TargetSSIDName,
413 (VOID *)&SSId,
414 sizeof (EFI_80211_SSID)
415 );
416 if (EFI_ERROR (Status)) {
417 return Status;
418 }
419
420 //
421 // Set password to supplicant
422 //
423 if (StrLen (Profile->Password) < PASSWORD_MIN_LEN) {
424 return EFI_NOT_FOUND;
425 }
426
427 AsciiPassword = AllocateZeroPool ((StrLen (Profile->Password) + 1) * sizeof (UINT8));
428 if (AsciiPassword == NULL) {
429 return EFI_OUT_OF_RESOURCES;
430 }
431
432 UnicodeStrToAsciiStrS (Profile->Password, (CHAR8 *)AsciiPassword, PASSWORD_STORAGE_SIZE);
433 Status = Supplicant->SetData (
434 Supplicant,
435 EfiSupplicant80211PskPassword,
436 AsciiPassword,
437 (StrLen (Profile->Password) + 1) * sizeof (UINT8)
438 );
439 ZeroMem (AsciiPassword, AsciiStrLen ((CHAR8 *)AsciiPassword) + 1);
440 FreePool (AsciiPassword);
441
442 return Status;
443 }
444
445 /**
446 Conduct EAP configuration to supplicant before connecting to a EAP network.
447 Current WiFi Connection Manager only supports three kinds of EAP networks:
448 1). EAP-TLS (Two-Way Authentication is required in our implementation)
449 2). EAP-TTLS/MSCHAPv2 (One-Way Authentication is required in our implementation)
450 3). PEAPv0/MSCHAPv2 (One-Way Authentication is required in our implementation)
451
452 @param[in] Nic Pointer to the device data of the selected NIC.
453 @param[in] Profile The target network to be connected.
454
455 @retval EFI_SUCCESS The operation is completed.
456 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
457 @retval EFI_UNSUPPORTED The expected EAP method is not supported.
458 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
459 @retval Other Errors Returned errors when setting data to supplicant.
460
461 **/
462 EFI_STATUS
463 WifiMgrConfigEap (
464 IN WIFI_MGR_DEVICE_DATA *Nic,
465 IN WIFI_MGR_NETWORK_PROFILE *Profile
466 )
467 {
468 EFI_STATUS Status;
469 EFI_EAP_CONFIGURATION_PROTOCOL *EapConfig;
470 EFI_EAP_TYPE EapAuthMethod;
471 EFI_EAP_TYPE EapSecondAuthMethod;
472 EFI_EAP_TYPE *AuthMethodList;
473 CHAR8 *Identity;
474 UINTN IdentitySize;
475 CHAR16 *Password;
476 UINTN PasswordSize;
477 UINTN EncryptPasswordLen;
478 CHAR8 *AsciiEncryptPassword;
479 UINTN AuthMethodListSize;
480 UINTN Index;
481
482 if ((Nic == NULL) || (Nic->EapConfig == NULL) || (Profile == NULL)) {
483 return EFI_INVALID_PARAMETER;
484 }
485
486 EapConfig = Nic->EapConfig;
487
488 if (Profile->EapAuthMethod >= EAP_AUTH_METHOD_MAX) {
489 return EFI_INVALID_PARAMETER;
490 }
491
492 EapAuthMethod = mEapAuthMethod[Profile->EapAuthMethod];
493
494 if (EapAuthMethod != EFI_EAP_TYPE_EAPTLS) {
495 if (Profile->EapSecondAuthMethod >= EAP_SEAUTH_METHOD_MAX) {
496 return EFI_INVALID_PARAMETER;
497 }
498
499 EapSecondAuthMethod = mEapSecondAuthMethod[Profile->EapSecondAuthMethod];
500 }
501
502 //
503 // The first time to get Supported Auth Method list, return the size.
504 //
505 AuthMethodListSize = 0;
506 AuthMethodList = NULL;
507 Status = EapConfig->GetData (
508 EapConfig,
509 EFI_EAP_TYPE_ATTRIBUTE,
510 EfiEapConfigEapSupportedAuthMethod,
511 (VOID *)AuthMethodList,
512 &AuthMethodListSize
513 );
514 if (Status == EFI_SUCCESS) {
515 //
516 // No Supported Eap Auth Method
517 //
518 return EFI_UNSUPPORTED;
519 } else if (Status != EFI_BUFFER_TOO_SMALL) {
520 return Status;
521 }
522
523 //
524 // The second time to get Supported Auth Method list, return the list.
525 // In current design, only EAPTLS, TTLS and PEAP are supported
526 //
527 AuthMethodList = (EFI_EAP_TYPE *)AllocateZeroPool (AuthMethodListSize);
528 if (AuthMethodList == NULL) {
529 return EFI_OUT_OF_RESOURCES;
530 }
531
532 Status = EapConfig->GetData (
533 EapConfig,
534 EFI_EAP_TYPE_ATTRIBUTE,
535 EfiEapConfigEapSupportedAuthMethod,
536 (VOID *)AuthMethodList,
537 &AuthMethodListSize
538 );
539 if (EFI_ERROR (Status)) {
540 FreePool (AuthMethodList);
541 return Status;
542 }
543
544 //
545 // Check if EapAuthMethod is in supported Auth Method list, if found, skip the loop.
546 //
547 for (Index = 0; Index < AuthMethodListSize / sizeof (EFI_EAP_TYPE); Index++) {
548 if (EapAuthMethod == AuthMethodList[Index]) {
549 break;
550 }
551 }
552
553 if (Index == AuthMethodListSize / sizeof (EFI_EAP_TYPE)) {
554 FreePool (AuthMethodList);
555 return EFI_UNSUPPORTED;
556 }
557
558 FreePool (AuthMethodList);
559
560 //
561 // Set Identity to Eap peer, Mandatory field for PEAP and TTLS
562 //
563 if (StrLen (Profile->EapIdentity) > 0) {
564 IdentitySize = sizeof (CHAR8) * (StrLen (Profile->EapIdentity) + 1);
565 Identity = AllocateZeroPool (IdentitySize);
566 if (Identity == NULL) {
567 return EFI_OUT_OF_RESOURCES;
568 }
569
570 UnicodeStrToAsciiStrS (Profile->EapIdentity, Identity, IdentitySize);
571 Status = EapConfig->SetData (
572 EapConfig,
573 EFI_EAP_TYPE_IDENTITY,
574 EfiEapConfigIdentityString,
575 (VOID *)Identity,
576 IdentitySize - 1
577 );
578 if (EFI_ERROR (Status)) {
579 FreePool (Identity);
580 return Status;
581 }
582
583 FreePool (Identity);
584 } else {
585 if (EapAuthMethod != EFI_EAP_TYPE_EAPTLS) {
586 return EFI_INVALID_PARAMETER;
587 }
588 }
589
590 //
591 // Set Auth Method to Eap peer, Mandatory field
592 //
593 Status = EapConfig->SetData (
594 EapConfig,
595 EFI_EAP_TYPE_ATTRIBUTE,
596 EfiEapConfigEapAuthMethod,
597 (VOID *)&EapAuthMethod,
598 sizeof (EapAuthMethod)
599 );
600 if (EFI_ERROR (Status)) {
601 return Status;
602 }
603
604 if ((EapAuthMethod == EFI_EAP_TYPE_TTLS) || (EapAuthMethod == EFI_EAP_TYPE_PEAP)) {
605 Status = EapConfig->SetData (
606 EapConfig,
607 EapAuthMethod,
608 EfiEapConfigEap2ndAuthMethod,
609 (VOID *)&EapSecondAuthMethod,
610 sizeof (EapSecondAuthMethod)
611 );
612 if (EFI_ERROR (Status)) {
613 return Status;
614 }
615
616 //
617 // Set Password to Eap peer
618 //
619 if (StrLen (Profile->EapPassword) < PASSWORD_MIN_LEN) {
620 DEBUG ((DEBUG_ERROR, "[WiFi Connection Manager] Error: No Eap Password for Network: %s.\n", Profile->SSId));
621 return EFI_INVALID_PARAMETER;
622 }
623
624 PasswordSize = sizeof (CHAR16) * (StrLen (Profile->EapPassword) + 1);
625 Password = AllocateZeroPool (PasswordSize);
626 if (Password == NULL) {
627 return EFI_OUT_OF_RESOURCES;
628 }
629
630 StrCpyS (Password, PasswordSize, Profile->EapPassword);
631 Status = EapConfig->SetData (
632 EapConfig,
633 EFI_EAP_TYPE_MSCHAPV2,
634 EfiEapConfigEapMSChapV2Password,
635 (VOID *)Password,
636 PasswordSize
637 );
638 ZeroMem (Password, PasswordSize);
639 FreePool (Password);
640 if (EFI_ERROR (Status)) {
641 return Status;
642 }
643
644 //
645 // If CA cert is required, set it to Eap peer
646 //
647 if (Profile->CACertData != NULL) {
648 Status = EapConfig->SetData (
649 EapConfig,
650 EapAuthMethod,
651 EfiEapConfigEapTlsCACert,
652 Profile->CACertData,
653 Profile->CACertSize
654 );
655 if (EFI_ERROR (Status)) {
656 return Status;
657 }
658 } else {
659 return EFI_INVALID_PARAMETER;
660 }
661 } else if (EapAuthMethod == EFI_EAP_TYPE_EAPTLS) {
662 //
663 // Set CA cert to Eap peer
664 //
665 if (Profile->CACertData == NULL) {
666 return EFI_INVALID_PARAMETER;
667 }
668
669 Status = EapConfig->SetData (
670 EapConfig,
671 EFI_EAP_TYPE_EAPTLS,
672 EfiEapConfigEapTlsCACert,
673 Profile->CACertData,
674 Profile->CACertSize
675 );
676 if (EFI_ERROR (Status)) {
677 return Status;
678 }
679
680 //
681 // Set Client cert to Eap peer
682 //
683 if (Profile->ClientCertData == NULL) {
684 return EFI_INVALID_PARAMETER;
685 }
686
687 Status = EapConfig->SetData (
688 EapConfig,
689 EFI_EAP_TYPE_EAPTLS,
690 EfiEapConfigEapTlsClientCert,
691 Profile->ClientCertData,
692 Profile->ClientCertSize
693 );
694 if (EFI_ERROR (Status)) {
695 return Status;
696 }
697
698 //
699 // Set Private key to Eap peer
700 //
701 if (Profile->PrivateKeyData == NULL) {
702 DEBUG ((DEBUG_ERROR, "[WiFi Connection Manager] Error: No Private Key for Network: %s.\n", Profile->SSId));
703 return EFI_INVALID_PARAMETER;
704 }
705
706 Status = EapConfig->SetData (
707 EapConfig,
708 EFI_EAP_TYPE_EAPTLS,
709 EfiEapConfigEapTlsClientPrivateKeyFile,
710 Profile->PrivateKeyData,
711 Profile->PrivateKeyDataSize
712 );
713 if (EFI_ERROR (Status)) {
714 return Status;
715 }
716
717 if (StrLen (Profile->PrivateKeyPassword) > 0) {
718 EncryptPasswordLen = StrLen (Profile->PrivateKeyPassword);
719 AsciiEncryptPassword = AllocateZeroPool (EncryptPasswordLen + 1);
720 if (AsciiEncryptPassword == NULL) {
721 return EFI_OUT_OF_RESOURCES;
722 }
723
724 UnicodeStrToAsciiStrS (Profile->PrivateKeyPassword, AsciiEncryptPassword, EncryptPasswordLen + 1);
725 Status = EapConfig->SetData (
726 EapConfig,
727 EFI_EAP_TYPE_EAPTLS,
728 EfiEapConfigEapTlsClientPrivateKeyFilePassword,
729 (VOID *)AsciiEncryptPassword,
730 EncryptPasswordLen + 1
731 );
732 if (EFI_ERROR (Status)) {
733 ZeroMem (AsciiEncryptPassword, EncryptPasswordLen + 1);
734 FreePool (AsciiEncryptPassword);
735 return Status;
736 }
737
738 ZeroMem (AsciiEncryptPassword, EncryptPasswordLen + 1);
739 FreePool (AsciiEncryptPassword);
740 }
741 } else {
742 return EFI_INVALID_PARAMETER;
743 }
744
745 return EFI_SUCCESS;
746 }
747
748 /**
749 Get current link state from low layer.
750
751 @param[in] Nic Pointer to the device data of the selected NIC.
752 @param[out] LinkState The pointer to buffer to retrieve link state.
753
754 @retval EFI_SUCCESS The operation is completed.
755 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
756 @retval EFI_UNSUPPORTED Adapter information protocol is not supported.
757 @retval Other Errors Returned errors when retrieving link state from low layer.
758
759 **/
760 EFI_STATUS
761 WifiMgrGetLinkState (
762 IN WIFI_MGR_DEVICE_DATA *Nic,
763 OUT EFI_ADAPTER_INFO_MEDIA_STATE *LinkState
764 )
765 {
766 EFI_STATUS Status;
767 EFI_TPL OldTpl;
768 UINTN DataSize;
769 EFI_ADAPTER_INFO_MEDIA_STATE *UndiState;
770 EFI_ADAPTER_INFORMATION_PROTOCOL *Aip;
771
772 if ((Nic == NULL) || (LinkState == NULL)) {
773 return EFI_INVALID_PARAMETER;
774 }
775
776 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
777 Status = gBS->OpenProtocol (
778 Nic->ControllerHandle,
779 &gEfiAdapterInformationProtocolGuid,
780 (VOID **)&Aip,
781 Nic->DriverHandle,
782 Nic->ControllerHandle,
783 EFI_OPEN_PROTOCOL_GET_PROTOCOL
784 );
785 if (EFI_ERROR (Status)) {
786 gBS->RestoreTPL (OldTpl);
787 return EFI_UNSUPPORTED;
788 }
789
790 Status = Aip->GetInformation (
791 Aip,
792 &gEfiAdapterInfoMediaStateGuid,
793 (VOID **)&UndiState,
794 &DataSize
795 );
796 if (EFI_ERROR (Status)) {
797 gBS->RestoreTPL (OldTpl);
798 return Status;
799 }
800
801 gBS->RestoreTPL (OldTpl);
802
803 CopyMem (LinkState, UndiState, sizeof (EFI_ADAPTER_INFO_MEDIA_STATE));
804 FreePool (UndiState);
805 return EFI_SUCCESS;
806 }
807
808 /**
809 Prepare configuration work before connecting to the target network.
810 For WPA2 Personal networks, password should be checked; and for EAP networks, parameters
811 are different for different networks.
812
813 @param[in] Nic Pointer to the device data of the selected NIC.
814 @param[in] Profile The target network to be connected.
815
816 @retval EFI_SUCCESS The operation is completed.
817 @retval EFI_UNSUPPORTED This network is not supported.
818 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
819
820 **/
821 EFI_STATUS
822 WifiMgrPrepareConnection (
823 IN WIFI_MGR_DEVICE_DATA *Nic,
824 IN WIFI_MGR_NETWORK_PROFILE *Profile
825 )
826 {
827 EFI_STATUS Status;
828 UINT8 SecurityType;
829 BOOLEAN AKMSuiteSupported;
830 BOOLEAN CipherSuiteSupported;
831
832 if ((Profile == NULL) || (Nic == NULL)) {
833 return EFI_INVALID_PARAMETER;
834 }
835
836 Status = WifiMgrCheckRSN (
837 Profile->Network.AKMSuite,
838 Profile->Network.CipherSuite,
839 Nic,
840 &SecurityType,
841 &AKMSuiteSupported,
842 &CipherSuiteSupported
843 );
844 if (EFI_ERROR (Status)) {
845 return Status;
846 }
847
848 if (AKMSuiteSupported && CipherSuiteSupported) {
849 switch (SecurityType) {
850 case SECURITY_TYPE_WPA2_PERSONAL:
851 case SECURITY_TYPE_WPA3_PERSONAL:
852
853 Status = WifiMgrConfigPassword (Nic, Profile);
854 if (EFI_ERROR (Status)) {
855 if (Status == EFI_NOT_FOUND) {
856 if (Nic->OneTimeConnectRequest) {
857 WifiMgrUpdateConnectMessage (Nic, FALSE, L"Connect Failed: Invalid Password!");
858 }
859 }
860
861 return Status;
862 }
863
864 break;
865
866 case SECURITY_TYPE_WPA2_ENTERPRISE:
867 case SECURITY_TYPE_WPA3_ENTERPRISE:
868
869 Status = WifiMgrConfigEap (Nic, Profile);
870 if (EFI_ERROR (Status)) {
871 if (Status == EFI_INVALID_PARAMETER) {
872 if (Nic->OneTimeConnectRequest) {
873 WifiMgrUpdateConnectMessage (Nic, FALSE, L"Connect Failed: Invalid Configuration!");
874 }
875 }
876
877 return Status;
878 }
879
880 break;
881
882 case SECURITY_TYPE_NONE:
883 break;
884
885 default:
886 return EFI_UNSUPPORTED;
887 }
888 } else {
889 return EFI_UNSUPPORTED;
890 }
891
892 return EFI_SUCCESS;
893 }
894
895 /**
896 The callback function for connect operation.
897
898 ASSERT when errors occur in config token.
899
900 @param[in] Event The Connect token receive event.
901 @param[in] Context The context of the connect token.
902
903 **/
904 VOID
905 EFIAPI
906 WifiMgrOnConnectFinished (
907 IN EFI_EVENT Event,
908 IN VOID *Context
909 )
910 {
911 EFI_STATUS Status;
912 WIFI_MGR_MAC_CONFIG_TOKEN *ConfigToken;
913 WIFI_MGR_NETWORK_PROFILE *ConnectedProfile;
914 UINT8 SecurityType;
915 UINT8 SSIdLen;
916 CHAR8 *AsciiSSId;
917
918 ASSERT (Context != NULL);
919
920 ConnectedProfile = NULL;
921 ConfigToken = (WIFI_MGR_MAC_CONFIG_TOKEN *)Context;
922 ASSERT (ConfigToken->Nic != NULL);
923
924 ConfigToken->Nic->ConnectState = WifiMgrDisconnected;
925 ASSERT (ConfigToken->Type == TokenTypeConnectNetworkToken);
926
927 ASSERT (ConfigToken->Token.ConnectNetworkToken != NULL);
928 if (ConfigToken->Token.ConnectNetworkToken->Status != EFI_SUCCESS) {
929 if (ConfigToken->Nic->OneTimeConnectRequest) {
930 //
931 // Only update message for user triggered connection
932 //
933 if (ConfigToken->Token.ConnectNetworkToken->Status == EFI_ACCESS_DENIED) {
934 WifiMgrUpdateConnectMessage (ConfigToken->Nic, FALSE, L"Connect Failed: Permission Denied!");
935 } else {
936 WifiMgrUpdateConnectMessage (ConfigToken->Nic, FALSE, L"Connect Failed!");
937 }
938
939 ConfigToken->Nic->OneTimeConnectRequest = FALSE;
940 }
941
942 ConfigToken->Nic->CurrentOperateNetwork = NULL;
943 return;
944 }
945
946 if (ConfigToken->Token.ConnectNetworkToken->ResultCode != ConnectSuccess) {
947 if (ConfigToken->Nic->OneTimeConnectRequest) {
948 if (ConfigToken->Token.ConnectNetworkToken->ResultCode == ConnectFailedReasonUnspecified) {
949 WifiMgrUpdateConnectMessage (ConfigToken->Nic, FALSE, L"Connect Failed: Wrong Password or Unexpected Error!");
950 } else {
951 WifiMgrUpdateConnectMessage (ConfigToken->Nic, FALSE, L"Connect Failed!");
952 }
953 }
954
955 goto Exit;
956 }
957
958 if ((ConfigToken->Token.ConnectNetworkToken->Data == NULL) ||
959 (ConfigToken->Token.ConnectNetworkToken->Data->Network == NULL))
960 {
961 //
962 // An unexpected error occurs, tell low layer to perform a disconnect
963 //
964 ConfigToken->Nic->HasDisconnectPendingNetwork = TRUE;
965 WifiMgrUpdateConnectMessage (ConfigToken->Nic, FALSE, NULL);
966 goto Exit;
967 }
968
969 //
970 // A correct connect token received, terminate the connection process
971 //
972 Status = WifiMgrCheckRSN (
973 ConfigToken->Token.ConnectNetworkToken->Data->Network->AKMSuite,
974 ConfigToken->Token.ConnectNetworkToken->Data->Network->CipherSuite,
975 ConfigToken->Nic,
976 &SecurityType,
977 NULL,
978 NULL
979 );
980 if (EFI_ERROR (Status)) {
981 SecurityType = SECURITY_TYPE_UNKNOWN;
982 }
983
984 SSIdLen = ConfigToken->Token.ConnectNetworkToken->Data->Network->SSId.SSIdLen;
985 AsciiSSId = (CHAR8 *)AllocateZeroPool (sizeof (CHAR8) * (SSIdLen + 1));
986 if (AsciiSSId == NULL) {
987 ConfigToken->Nic->HasDisconnectPendingNetwork = TRUE;
988 WifiMgrUpdateConnectMessage (ConfigToken->Nic, FALSE, NULL);
989 goto Exit;
990 }
991
992 CopyMem (AsciiSSId, ConfigToken->Token.ConnectNetworkToken->Data->Network->SSId.SSId, SSIdLen);
993 *(AsciiSSId + SSIdLen) = '\0';
994
995 ConnectedProfile = WifiMgrGetProfileByAsciiSSId (AsciiSSId, SecurityType, &ConfigToken->Nic->ProfileList);
996 FreePool (AsciiSSId);
997 if (ConnectedProfile == NULL) {
998 ConfigToken->Nic->HasDisconnectPendingNetwork = TRUE;
999 WifiMgrUpdateConnectMessage (ConfigToken->Nic, FALSE, NULL);
1000 goto Exit;
1001 }
1002
1003 ConfigToken->Nic->ConnectState = WifiMgrConnectedToAp;
1004 WifiMgrUpdateConnectMessage (ConfigToken->Nic, TRUE, NULL);
1005
1006 Exit:
1007
1008 if (ConfigToken->Nic->ConnectState == WifiMgrDisconnected) {
1009 ConfigToken->Nic->CurrentOperateNetwork = NULL;
1010 }
1011
1012 ConfigToken->Nic->OneTimeConnectRequest = FALSE;
1013 WifiMgrFreeToken (ConfigToken);
1014 }
1015
1016 /**
1017 Start connect operation, and send out a token to connect to a target network.
1018
1019 @param[in] Nic Pointer to the device data of the selected NIC.
1020 @param[in] Profile The target network to be connected.
1021
1022 @retval EFI_SUCCESS The operation is completed.
1023 @retval EFI_ALREADY_STARTED Already in "connected" state, need to perform a disconnect
1024 operation first.
1025 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
1026 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
1027 @retval Other Errors Return errors when connecting network on low layer.
1028
1029 **/
1030 EFI_STATUS
1031 WifiMgrConnectToNetwork (
1032 IN WIFI_MGR_DEVICE_DATA *Nic,
1033 IN WIFI_MGR_NETWORK_PROFILE *Profile
1034 )
1035 {
1036 EFI_STATUS Status;
1037 EFI_TPL OldTpl;
1038 EFI_ADAPTER_INFO_MEDIA_STATE LinkState;
1039 WIFI_MGR_MAC_CONFIG_TOKEN *ConfigToken;
1040 EFI_80211_CONNECT_NETWORK_TOKEN *ConnectToken;
1041
1042 if ((Nic == NULL) || (Nic->Wmp == NULL) || (Profile == NULL)) {
1043 return EFI_INVALID_PARAMETER;
1044 }
1045
1046 Status = WifiMgrGetLinkState (Nic, &LinkState);
1047 if (EFI_ERROR (Status)) {
1048 return Status;
1049 }
1050
1051 if (LinkState.MediaState == EFI_SUCCESS) {
1052 return EFI_ALREADY_STARTED;
1053 }
1054
1055 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1056 Status = WifiMgrPrepareConnection (Nic, Profile);
1057 if (EFI_ERROR (Status)) {
1058 gBS->RestoreTPL (OldTpl);
1059 return Status;
1060 }
1061
1062 //
1063 // Create a new connect token
1064 //
1065 ConfigToken = AllocateZeroPool (sizeof (WIFI_MGR_MAC_CONFIG_TOKEN));
1066 if (ConfigToken == NULL) {
1067 Status = EFI_OUT_OF_RESOURCES;
1068 goto Exit;
1069 }
1070
1071 ConfigToken->Type = TokenTypeConnectNetworkToken;
1072 ConfigToken->Nic = Nic;
1073 ConfigToken->Token.ConnectNetworkToken = AllocateZeroPool (sizeof (EFI_80211_CONNECT_NETWORK_TOKEN));
1074 if (ConfigToken->Token.ConnectNetworkToken == NULL) {
1075 goto Exit;
1076 }
1077
1078 ConnectToken = ConfigToken->Token.ConnectNetworkToken;
1079 ConnectToken->Data = AllocateZeroPool (sizeof (EFI_80211_CONNECT_NETWORK_DATA));
1080 if (ConnectToken->Data == NULL) {
1081 goto Exit;
1082 }
1083
1084 ConnectToken->Data->Network = AllocateZeroPool (sizeof (EFI_80211_NETWORK));
1085 if (ConnectToken->Data->Network == NULL) {
1086 goto Exit;
1087 }
1088
1089 CopyMem (ConnectToken->Data->Network, &Profile->Network, sizeof (EFI_80211_NETWORK));
1090
1091 //
1092 // Add event handle and start to connect
1093 //
1094 Status = gBS->CreateEvent (
1095 EVT_NOTIFY_SIGNAL,
1096 TPL_CALLBACK,
1097 WifiMgrOnConnectFinished,
1098 ConfigToken,
1099 &ConnectToken->Event
1100 );
1101 if (EFI_ERROR (Status)) {
1102 goto Exit;
1103 }
1104
1105 Nic->ConnectState = WifiMgrConnectingToAp;
1106 Nic->CurrentOperateNetwork = Profile;
1107 WifiMgrUpdateConnectMessage (Nic, FALSE, NULL);
1108
1109 //
1110 // Start Connecting ...
1111 //
1112 Status = Nic->Wmp->ConnectNetwork (Nic->Wmp, ConnectToken);
1113
1114 //
1115 // Erase secrets after connection is triggered
1116 //
1117 WifiMgrCleanProfileSecrets (Profile);
1118
1119 if (EFI_ERROR (Status)) {
1120 if (Status == EFI_ALREADY_STARTED) {
1121 Nic->ConnectState = WifiMgrConnectedToAp;
1122 WifiMgrUpdateConnectMessage (Nic, TRUE, NULL);
1123 } else {
1124 Nic->ConnectState = WifiMgrDisconnected;
1125 Nic->CurrentOperateNetwork = NULL;
1126
1127 if (Nic->OneTimeConnectRequest) {
1128 if (Status == EFI_NOT_FOUND) {
1129 WifiMgrUpdateConnectMessage (Nic, FALSE, L"Connect Failed: Not Available!");
1130 } else {
1131 WifiMgrUpdateConnectMessage (Nic, FALSE, L"Connect Failed: Unexpected Error!");
1132 }
1133 }
1134 }
1135
1136 goto Exit;
1137 }
1138
1139 Exit:
1140
1141 if (EFI_ERROR (Status)) {
1142 WifiMgrFreeToken (ConfigToken);
1143 }
1144
1145 gBS->RestoreTPL (OldTpl);
1146
1147 DEBUG ((DEBUG_INFO, "[WiFi Connection Manager] WifiMgrConnectToNetwork: %r\n", Status));
1148 return Status;
1149 }
1150
1151 /**
1152 The callback function for disconnect operation.
1153
1154 ASSERT when errors occur in config token.
1155
1156 @param[in] Event The Disconnect token receive event.
1157 @param[in] Context The context of the Disconnect token.
1158
1159 **/
1160 VOID
1161 EFIAPI
1162 WifiMgrOnDisconnectFinished (
1163 IN EFI_EVENT Event,
1164 IN VOID *Context
1165 )
1166 {
1167 WIFI_MGR_MAC_CONFIG_TOKEN *ConfigToken;
1168
1169 ASSERT (Context != NULL);
1170
1171 ConfigToken = (WIFI_MGR_MAC_CONFIG_TOKEN *)Context;
1172 ASSERT (ConfigToken->Nic != NULL);
1173 ASSERT (ConfigToken->Type == TokenTypeDisconnectNetworkToken);
1174
1175 ASSERT (ConfigToken->Token.DisconnectNetworkToken != NULL);
1176 if (ConfigToken->Token.DisconnectNetworkToken->Status != EFI_SUCCESS) {
1177 ConfigToken->Nic->ConnectState = WifiMgrConnectedToAp;
1178 WifiMgrUpdateConnectMessage (ConfigToken->Nic, FALSE, NULL);
1179 ConfigToken->Nic->OneTimeDisconnectRequest = FALSE;
1180 goto Exit;
1181 }
1182
1183 ConfigToken->Nic->ConnectState = WifiMgrDisconnected;
1184 ConfigToken->Nic->CurrentOperateNetwork = NULL;
1185 WifiMgrUpdateConnectMessage (ConfigToken->Nic, TRUE, NULL);
1186 ConfigToken->Nic->OneTimeDisconnectRequest = FALSE;
1187
1188 //
1189 // Disconnected network may not be in network list now, trigger a scan again!
1190 //
1191 ConfigToken->Nic->OneTimeScanRequest = TRUE;
1192
1193 Exit:
1194 WifiMgrFreeToken (ConfigToken);
1195 return;
1196 }
1197
1198 /**
1199 Start disconnect operation, and send out a token to disconnect from current connected
1200 network.
1201
1202 @param[in] Nic Pointer to the device data of the selected NIC.
1203
1204 @retval EFI_SUCCESS The operation is completed.
1205 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
1206 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
1207 @retval Other Errors Return errors when disconnecting a network on low layer.
1208
1209 **/
1210 EFI_STATUS
1211 WifiMgrDisconnectToNetwork (
1212 IN WIFI_MGR_DEVICE_DATA *Nic
1213 )
1214 {
1215 EFI_STATUS Status;
1216 EFI_TPL OldTpl;
1217 WIFI_MGR_MAC_CONFIG_TOKEN *ConfigToken;
1218 EFI_80211_DISCONNECT_NETWORK_TOKEN *DisconnectToken;
1219
1220 if (Nic == NULL) {
1221 return EFI_INVALID_PARAMETER;
1222 }
1223
1224 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1225 Status = EFI_SUCCESS;
1226 ConfigToken = AllocateZeroPool (sizeof (WIFI_MGR_MAC_CONFIG_TOKEN));
1227 if (ConfigToken == NULL) {
1228 gBS->RestoreTPL (OldTpl);
1229 return EFI_OUT_OF_RESOURCES;
1230 }
1231
1232 ConfigToken->Type = TokenTypeDisconnectNetworkToken;
1233 ConfigToken->Nic = Nic;
1234 ConfigToken->Token.DisconnectNetworkToken = AllocateZeroPool (sizeof (EFI_80211_DISCONNECT_NETWORK_TOKEN));
1235 if (ConfigToken->Token.DisconnectNetworkToken == NULL) {
1236 WifiMgrFreeToken (ConfigToken);
1237 gBS->RestoreTPL (OldTpl);
1238 return EFI_OUT_OF_RESOURCES;
1239 }
1240
1241 DisconnectToken = ConfigToken->Token.DisconnectNetworkToken;
1242
1243 Status = gBS->CreateEvent (
1244 EVT_NOTIFY_SIGNAL,
1245 TPL_CALLBACK,
1246 WifiMgrOnDisconnectFinished,
1247 ConfigToken,
1248 &DisconnectToken->Event
1249 );
1250 if (EFI_ERROR (Status)) {
1251 WifiMgrFreeToken (ConfigToken);
1252 gBS->RestoreTPL (OldTpl);
1253 return Status;
1254 }
1255
1256 Nic->ConnectState = WifiMgrDisconnectingToAp;
1257 WifiMgrUpdateConnectMessage (ConfigToken->Nic, FALSE, NULL);
1258
1259 Status = Nic->Wmp->DisconnectNetwork (Nic->Wmp, DisconnectToken);
1260 if (EFI_ERROR (Status)) {
1261 if (Status == EFI_NOT_FOUND) {
1262 Nic->ConnectState = WifiMgrDisconnected;
1263 Nic->CurrentOperateNetwork = NULL;
1264
1265 //
1266 // This network is not in network list now, trigger a scan again!
1267 //
1268 Nic->OneTimeScanRequest = TRUE;
1269
1270 //
1271 // State has been changed from Connected to Disconnected
1272 //
1273 WifiMgrUpdateConnectMessage (ConfigToken->Nic, TRUE, NULL);
1274 Status = EFI_SUCCESS;
1275 } else {
1276 if (Nic->OneTimeDisconnectRequest) {
1277 WifiMgrUpdateConnectMessage (ConfigToken->Nic, FALSE, L"Disconnect Failed: Unexpected Error!");
1278 }
1279
1280 Nic->ConnectState = WifiMgrConnectedToAp;
1281 WifiMgrUpdateConnectMessage (ConfigToken->Nic, FALSE, NULL);
1282 }
1283
1284 WifiMgrFreeToken (ConfigToken);
1285 }
1286
1287 gBS->RestoreTPL (OldTpl);
1288 return Status;
1289 }
1290
1291 /**
1292 The state machine of the connection manager, periodically check the state and
1293 perform a corresponding operation.
1294
1295 @param[in] Event The timer event to be triggered.
1296 @param[in] Context The context of the Nic device data.
1297
1298 **/
1299 VOID
1300 EFIAPI
1301 WifiMgrOnTimerTick (
1302 IN EFI_EVENT Event,
1303 IN VOID *Context
1304 )
1305 {
1306 WIFI_MGR_DEVICE_DATA *Nic;
1307 EFI_STATUS Status;
1308 EFI_ADAPTER_INFO_MEDIA_STATE LinkState;
1309 WIFI_MGR_NETWORK_PROFILE *Profile;
1310
1311 if (Context == NULL) {
1312 return;
1313 }
1314
1315 Nic = (WIFI_MGR_DEVICE_DATA *)Context;
1316 NET_CHECK_SIGNATURE (Nic, WIFI_MGR_DEVICE_DATA_SIGNATURE);
1317
1318 Status = WifiMgrGetLinkState (Nic, &LinkState);
1319 if (EFI_ERROR (Status)) {
1320 DEBUG ((DEBUG_INFO, "[WiFi Connection Manager] Error: Failed to get link state!\n"));
1321 return;
1322 }
1323
1324 if (Nic->LastLinkState.MediaState != LinkState.MediaState) {
1325 if ((Nic->LastLinkState.MediaState == EFI_SUCCESS) && (LinkState.MediaState == EFI_NO_MEDIA)) {
1326 Nic->HasDisconnectPendingNetwork = TRUE;
1327 }
1328
1329 Nic->LastLinkState.MediaState = LinkState.MediaState;
1330 }
1331
1332 Nic->ScanTickTime++;
1333 if (((Nic->ScanTickTime > WIFI_SCAN_FREQUENCY) || Nic->OneTimeScanRequest) &&
1334 (Nic->ScanState == WifiMgrScanFinished))
1335 {
1336 Nic->OneTimeScanRequest = FALSE;
1337 Nic->ScanTickTime = 0;
1338
1339 DEBUG ((DEBUG_INFO, "[WiFi Connection Manager] Scan is triggered.\n"));
1340 WifiMgrStartScan (Nic);
1341 }
1342
1343 if ((Nic->AvailableCount > 0) && (Nic->ScanState == WifiMgrScanFinished)) {
1344 switch (Nic->ConnectState) {
1345 case WifiMgrDisconnected:
1346
1347 if (Nic->HasDisconnectPendingNetwork) {
1348 Nic->HasDisconnectPendingNetwork = FALSE;
1349 }
1350
1351 if (Nic->ConnectPendingNetwork != NULL) {
1352 Profile = Nic->ConnectPendingNetwork;
1353 Status = WifiMgrConnectToNetwork (Nic, Profile);
1354 Nic->ConnectPendingNetwork = NULL;
1355 if (EFI_ERROR (Status)) {
1356 //
1357 // Some error happened, don't wait for a return connect token!
1358 //
1359 Nic->OneTimeConnectRequest = FALSE;
1360 }
1361 }
1362
1363 break;
1364
1365 case WifiMgrConnectingToAp:
1366 break;
1367
1368 case WifiMgrDisconnectingToAp:
1369 break;
1370
1371 case WifiMgrConnectedToAp:
1372
1373 if ((Nic->ConnectPendingNetwork != NULL) || Nic->HasDisconnectPendingNetwork) {
1374 Status = WifiMgrDisconnectToNetwork (Nic);
1375 if (EFI_ERROR (Status)) {
1376 //
1377 // Some error happened, don't wait for a return disconnect token!
1378 //
1379 Nic->OneTimeDisconnectRequest = FALSE;
1380 }
1381 }
1382
1383 break;
1384
1385 default:
1386 break;
1387 }
1388 }
1389 }