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