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