1 /** @file
2   HII Config Access protocol implementation of VLAN configuration module.
3 
4 Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions
7 of the BSD License which accompanies this distribution.  The full
8 text of the license may be found at<BR>
9 http://opensource.org/licenses/bsd-license.php
10 
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "VlanConfigImpl.h"
17 
18 CHAR16                          mVlanStorageName[] = L"VlanNvData";
19 EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting = NULL;
20 
21 VLAN_CONFIG_PRIVATE_DATA        mVlanConfigPrivateDateTemplate = {
22   VLAN_CONFIG_PRIVATE_DATA_SIGNATURE,
23   {
24     VlanExtractConfig,
25     VlanRouteConfig,
26     VlanCallback
27   }
28 };
29 
30 VENDOR_DEVICE_PATH              mHiiVendorDevicePathNode = {
31   {
32     HARDWARE_DEVICE_PATH,
33     HW_VENDOR_DP,
34     {
35       (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
36       (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
37     }
38   },
39   VLAN_CONFIG_FORM_SET_GUID
40 };
41 
42 /**
43   This function allows a caller to extract the current configuration for one
44   or more named elements from the target driver.
45 
46   @param[in]  This               Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
47   @param[in]  Request            A null-terminated Unicode string in
48                                  <ConfigRequest> format.
49   @param[out]  Progress          On return, points to a character in the Request
50                                  string. Points to the string's null terminator if
51                                  request was successful. Points to the most recent
52                                  '&' before the first failing name/value pair (or
53                                  the beginning of the string if the failure is in
54                                  the first name/value pair) if the request was not
55                                  successful.
56   @param[out]  Results           A null-terminated Unicode string in
57                                  <ConfigAltResp> format which has all values filled
58                                  in for the names in the Request string. String to
59                                  be allocated by the called function.
60 
61   @retval EFI_SUCCESS            The Results is filled with the requested values.
62   @retval EFI_OUT_OF_RESOURCES   Not enough memory to store the results.
63   @retval EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown name.
64   @retval EFI_NOT_FOUND          Routing data doesn't match any storage in this
65                                  driver.
66 
67 **/
68 EFI_STATUS
69 EFIAPI
VlanExtractConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Request,OUT EFI_STRING * Progress,OUT EFI_STRING * Results)70 VlanExtractConfig (
71   IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL        *This,
72   IN CONST EFI_STRING                            Request,
73        OUT EFI_STRING                            *Progress,
74        OUT EFI_STRING                            *Results
75   )
76 {
77   EFI_STATUS                 Status;
78   UINTN                      BufferSize;
79   VLAN_CONFIGURATION         Configuration;
80   VLAN_CONFIG_PRIVATE_DATA  *PrivateData;
81   EFI_STRING                 ConfigRequestHdr;
82   EFI_STRING                 ConfigRequest;
83   BOOLEAN                    AllocatedRequest;
84   UINTN                      Size;
85 
86   if (Progress == NULL || Results == NULL) {
87     return EFI_INVALID_PARAMETER;
88   }
89 
90   *Progress = Request;
91   if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &gVlanConfigFormSetGuid, mVlanStorageName)) {
92     return EFI_NOT_FOUND;
93   }
94 
95   ConfigRequestHdr = NULL;
96   ConfigRequest    = NULL;
97   AllocatedRequest = FALSE;
98   Size             = 0;
99 
100   //
101   // Retrieve the pointer to the UEFI HII Config Routing Protocol
102   //
103   if (mHiiConfigRouting == NULL) {
104     gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &mHiiConfigRouting);
105   }
106   ASSERT (mHiiConfigRouting != NULL);
107 
108   //
109   // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
110   //
111   PrivateData = VLAN_CONFIG_PRIVATE_DATA_FROM_THIS (This);
112   ZeroMem (&Configuration, sizeof (VLAN_CONFIGURATION));
113   BufferSize = sizeof (Configuration);
114   ConfigRequest = Request;
115   if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
116     //
117     // Request has no request element, construct full request string.
118     // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
119     // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
120     //
121     ConfigRequestHdr = HiiConstructConfigHdr (&gVlanConfigFormSetGuid, mVlanStorageName, PrivateData->DriverHandle);
122     Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
123     ConfigRequest = AllocateZeroPool (Size);
124     ASSERT (ConfigRequest != NULL);
125     AllocatedRequest = TRUE;
126     UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
127     FreePool (ConfigRequestHdr);
128   }
129 
130   Status = mHiiConfigRouting->BlockToConfig (
131                                 mHiiConfigRouting,
132                                 ConfigRequest,
133                                 (UINT8 *) &Configuration,
134                                 BufferSize,
135                                 Results,
136                                 Progress
137                                 );
138   //
139   // Free the allocated config request string.
140   //
141   if (AllocatedRequest) {
142     FreePool (ConfigRequest);
143     ConfigRequest = NULL;
144   }
145   //
146   // Set Progress string to the original request string.
147   //
148   if (Request == NULL) {
149     *Progress = NULL;
150   } else if (StrStr (Request, L"OFFSET") == NULL) {
151     *Progress = Request + StrLen (Request);
152   }
153 
154   return Status;
155 }
156 
157 
158 /**
159   This function processes the results of changes in configuration.
160 
161   @param[in]  This               Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
162   @param[in]  Configuration      A null-terminated Unicode string in <ConfigResp>
163                                  format.
164   @param[out]  Progress          A pointer to a string filled in with the offset of
165                                  the most recent '&' before the first failing
166                                  name/value pair (or the beginning of the string if
167                                  the failure is in the first name/value pair) or
168                                  the terminating NULL if all was successful.
169 
170   @retval EFI_SUCCESS            The Results is processed successfully.
171   @retval EFI_INVALID_PARAMETER  Configuration is NULL.
172   @retval EFI_NOT_FOUND          Routing data doesn't match any storage in this
173                                  driver.
174 
175 **/
176 EFI_STATUS
177 EFIAPI
VlanRouteConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Configuration,OUT EFI_STRING * Progress)178 VlanRouteConfig (
179   IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL      *This,
180   IN CONST EFI_STRING                          Configuration,
181        OUT EFI_STRING                          *Progress
182   )
183 {
184   if (Configuration == NULL || Progress == NULL) {
185     return EFI_INVALID_PARAMETER;
186   }
187 
188   *Progress = Configuration;
189   if (!HiiIsConfigHdrMatch (Configuration, &gVlanConfigFormSetGuid, mVlanStorageName)) {
190     return EFI_NOT_FOUND;
191   }
192 
193   *Progress = Configuration + StrLen (Configuration);
194   return EFI_SUCCESS;
195 }
196 
197 /**
198   This function processes the results of changes in configuration.
199 
200   @param[in]  This               Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
201   @param[in]  Action             Specifies the type of action taken by the browser.
202   @param[in]  QuestionId         A unique value which is sent to the original
203                                  exporting driver so that it can identify the type
204                                  of data to expect.
205   @param[in]  Type               The type of value for the question.
206   @param[in]  Value              A pointer to the data being sent to the original
207                                  exporting driver.
208   @param[out] ActionRequest      On return, points to the action requested by the
209                                  callback function.
210 
211   @retval EFI_SUCCESS            The callback successfully handled the action.
212   @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the
213                                  variable and its data.
214   @retval EFI_DEVICE_ERROR       The variable could not be saved.
215   @retval EFI_UNSUPPORTED        The specified Action is not supported by the
216                                  callback.
217 
218 **/
219 EFI_STATUS
220 EFIAPI
VlanCallback(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN EFI_BROWSER_ACTION Action,IN EFI_QUESTION_ID QuestionId,IN UINT8 Type,IN EFI_IFR_TYPE_VALUE * Value,OUT EFI_BROWSER_ACTION_REQUEST * ActionRequest)221 VlanCallback (
222   IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL      *This,
223   IN     EFI_BROWSER_ACTION                    Action,
224   IN     EFI_QUESTION_ID                       QuestionId,
225   IN     UINT8                                 Type,
226   IN     EFI_IFR_TYPE_VALUE                    *Value,
227      OUT EFI_BROWSER_ACTION_REQUEST            *ActionRequest
228   )
229 {
230   VLAN_CONFIG_PRIVATE_DATA  *PrivateData;
231   VLAN_CONFIGURATION        *Configuration;
232   EFI_VLAN_CONFIG_PROTOCOL  *VlanConfig;
233   UINTN                     Index;
234   EFI_HANDLE                VlanHandle;
235 
236   PrivateData = VLAN_CONFIG_PRIVATE_DATA_FROM_THIS (This);
237 
238   if ((Action == EFI_BROWSER_ACTION_FORM_OPEN) || (Action == EFI_BROWSER_ACTION_FORM_CLOSE)) {
239     return EFI_SUCCESS;
240   }
241 
242   if ((Action != EFI_BROWSER_ACTION_CHANGED) && (Action != EFI_BROWSER_ACTION_CHANGING)) {
243     //
244     // All other action return unsupported.
245     //
246     return EFI_UNSUPPORTED;
247   }
248 
249   //
250   // Get Browser data
251   //
252   Configuration = AllocateZeroPool (sizeof (VLAN_CONFIGURATION));
253   ASSERT (Configuration != NULL);
254   HiiGetBrowserData (&gVlanConfigFormSetGuid, mVlanStorageName, sizeof (VLAN_CONFIGURATION), (UINT8 *) Configuration);
255 
256   VlanConfig = PrivateData->VlanConfig;
257 
258   if (Action == EFI_BROWSER_ACTION_CHANGED) {
259     switch (QuestionId) {
260     case VLAN_ADD_QUESTION_ID:
261       //
262       // Add a VLAN
263       //
264       VlanConfig->Set (VlanConfig, Configuration->VlanId, Configuration->Priority);
265       VlanUpdateForm (PrivateData);
266 
267       //
268       // Connect the newly created VLAN device
269       //
270       VlanHandle = NetLibGetVlanHandle (PrivateData->ControllerHandle, Configuration->VlanId);
271       if (VlanHandle == NULL) {
272         //
273         // There may be no child handle created for VLAN ID 0, connect the parent handle
274         //
275         VlanHandle = PrivateData->ControllerHandle;
276       }
277       gBS->ConnectController (VlanHandle, NULL, NULL, TRUE);
278 
279       //
280       // Clear UI data
281       //
282       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
283       Configuration->VlanId = 0;
284       Configuration->Priority = 0;
285       break;
286 
287     case VLAN_REMOVE_QUESTION_ID:
288       //
289       // Remove VLAN
290       //
291       ASSERT (PrivateData->NumberOfVlan <= MAX_VLAN_NUMBER);
292       for (Index = 0; Index < PrivateData->NumberOfVlan; Index++) {
293         if (Configuration->VlanList[Index] != 0) {
294           //
295           // Checkbox is selected, need remove this VLAN
296           //
297           VlanConfig->Remove (VlanConfig, PrivateData->VlanId[Index]);
298         }
299       }
300 
301       VlanUpdateForm (PrivateData);
302       if (PrivateData->NumberOfVlan == 0) {
303         //
304         // No VLAN device now, connect the physical NIC handle.
305         // Note: PrivateData->NumberOfVlan has been updated by VlanUpdateForm()
306         //
307         gBS->ConnectController (PrivateData->ControllerHandle, NULL, NULL, TRUE);
308       }
309 
310       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
311       ZeroMem (Configuration->VlanList, MAX_VLAN_NUMBER);
312       break;
313 
314     default:
315       break;
316     }
317   } else if (Action == EFI_BROWSER_ACTION_CHANGING) {
318     switch (QuestionId) {
319     case VLAN_UPDATE_QUESTION_ID:
320       //
321       // Update current VLAN list into Form.
322       //
323       VlanUpdateForm (PrivateData);
324       break;
325 
326     default:
327       break;
328     }
329   }
330 
331   HiiSetBrowserData (&gVlanConfigFormSetGuid, mVlanStorageName, sizeof (VLAN_CONFIGURATION), (UINT8 *) Configuration, NULL);
332   FreePool (Configuration);
333   return EFI_SUCCESS;
334 }
335 
336 
337 /**
338   This function update VLAN list in the VLAN configuration Form.
339 
340   @param[in, out]  PrivateData   Points to VLAN configuration private data.
341 
342 **/
343 VOID
VlanUpdateForm(IN OUT VLAN_CONFIG_PRIVATE_DATA * PrivateData)344 VlanUpdateForm (
345   IN OUT VLAN_CONFIG_PRIVATE_DATA    *PrivateData
346   )
347 {
348   EFI_VLAN_CONFIG_PROTOCOL  *VlanConfig;
349   UINT16                    NumberOfVlan;
350   UINTN                     Index;
351   EFI_VLAN_FIND_DATA        *VlanData;
352   VOID                      *StartOpCodeHandle;
353   EFI_IFR_GUID_LABEL        *StartLabel;
354   VOID                      *EndOpCodeHandle;
355   EFI_IFR_GUID_LABEL        *EndLabel;
356   CHAR16                    *String;
357   CHAR16                    VlanStr[30];
358   CHAR16                    VlanIdStr[6];
359   UINTN                     DigitalCount;
360   EFI_STRING_ID             StringId;
361 
362   //
363   // Find current VLAN configuration
364   //
365   VlanData = NULL;
366   NumberOfVlan = 0;
367   VlanConfig = PrivateData->VlanConfig;
368   VlanConfig->Find (VlanConfig, NULL, &NumberOfVlan, &VlanData);
369 
370   //
371   // Update VLAN configuration in PrivateData
372   //
373   if (NumberOfVlan > MAX_VLAN_NUMBER) {
374     NumberOfVlan = MAX_VLAN_NUMBER;
375   }
376   PrivateData->NumberOfVlan = NumberOfVlan;
377 
378   //
379   // Init OpCode Handle
380   //
381   StartOpCodeHandle = HiiAllocateOpCodeHandle ();
382   ASSERT (StartOpCodeHandle != NULL);
383 
384   EndOpCodeHandle = HiiAllocateOpCodeHandle ();
385   ASSERT (EndOpCodeHandle != NULL);
386 
387   //
388   // Create Hii Extend Label OpCode as the start opcode
389   //
390   StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
391                                         StartOpCodeHandle,
392                                         &gEfiIfrTianoGuid,
393                                         NULL,
394                                         sizeof (EFI_IFR_GUID_LABEL)
395                                         );
396   StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
397   StartLabel->Number       = LABEL_VLAN_LIST;
398 
399   //
400   // Create Hii Extend Label OpCode as the end opcode
401   //
402   EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
403                                       EndOpCodeHandle,
404                                       &gEfiIfrTianoGuid,
405                                       NULL,
406                                       sizeof (EFI_IFR_GUID_LABEL)
407                                       );
408   EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
409   EndLabel->Number       = LABEL_END;
410 
411   ZeroMem (PrivateData->VlanId, MAX_VLAN_NUMBER);
412   for (Index = 0; Index < NumberOfVlan; Index++) {
413     String = VlanStr;
414 
415     StrCpyS (String, (sizeof (VlanStr) /sizeof (CHAR16)), L"  VLAN ID:");
416     String += 10;
417     //
418     // Pad VlanId string up to 4 characters with space
419     //
420     DigitalCount = UnicodeValueToString (VlanIdStr, 0, VlanData[Index].VlanId, 5);
421     SetMem16 (String, (4 - DigitalCount) * sizeof (CHAR16), L' ');
422     StrCpyS (String + 4 - DigitalCount, (sizeof (VlanStr) /sizeof (CHAR16)) - 10 - (4 - DigitalCount), VlanIdStr);
423     String += 4;
424 
425     StrCpyS (String,  (sizeof (VlanStr) /sizeof (CHAR16)) - 10 - (4 - DigitalCount) - 4, L", Priority:");
426     String += 11;
427     String += UnicodeValueToString (String, 0, VlanData[Index].Priority, 4);
428     *String = 0;
429 
430     StringId = HiiSetString (PrivateData->HiiHandle, 0, VlanStr, NULL);
431     ASSERT (StringId != 0);
432 
433     HiiCreateCheckBoxOpCode (
434       StartOpCodeHandle,
435       (EFI_QUESTION_ID) (VLAN_LIST_VAR_OFFSET + Index),
436       VLAN_CONFIGURATION_VARSTORE_ID,
437       (UINT16) (VLAN_LIST_VAR_OFFSET + Index),
438       StringId,
439       STRING_TOKEN (STR_VLAN_VLAN_LIST_HELP),
440       0,
441       0,
442       NULL
443       );
444 
445     //
446     // Save VLAN id to private data
447     //
448     PrivateData->VlanId[Index] = VlanData[Index].VlanId;
449   }
450 
451   HiiUpdateForm (
452     PrivateData->HiiHandle,     // HII handle
453     &gVlanConfigFormSetGuid,    // Formset GUID
454     VLAN_CONFIGURATION_FORM_ID, // Form ID
455     StartOpCodeHandle,          // Label for where to insert opcodes
456     EndOpCodeHandle             // Replace data
457     );
458 
459   HiiFreeOpCodeHandle (StartOpCodeHandle);
460   HiiFreeOpCodeHandle (EndOpCodeHandle);
461 
462   if (VlanData != NULL) {
463     FreePool (VlanData);
464   }
465 }
466 
467 
468 /**
469   This function publish the VLAN configuration Form for a network device. The
470   HII Config Access protocol will be installed on a child handle of the network
471   device.
472 
473   @param[in, out]  PrivateData   Points to VLAN configuration private data.
474 
475   @retval EFI_SUCCESS            HII Form is installed for this network device.
476   @retval EFI_OUT_OF_RESOURCES   Not enough resource for HII Form installation.
477   @retval Others                 Other errors as indicated.
478 
479 **/
480 EFI_STATUS
InstallVlanConfigForm(IN OUT VLAN_CONFIG_PRIVATE_DATA * PrivateData)481 InstallVlanConfigForm (
482   IN OUT VLAN_CONFIG_PRIVATE_DATA    *PrivateData
483   )
484 {
485   EFI_STATUS                      Status;
486   EFI_HII_HANDLE                  HiiHandle;
487   EFI_HANDLE                      DriverHandle;
488   CHAR16                          Str[26 + sizeof (EFI_MAC_ADDRESS) * 2 + 1];
489   CHAR16                          *MacString;
490   EFI_DEVICE_PATH_PROTOCOL        *ChildDevicePath;
491   EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;
492   EFI_VLAN_CONFIG_PROTOCOL        *VlanConfig;
493 
494   //
495   // Create child handle and install HII Config Access Protocol
496   //
497   ChildDevicePath = AppendDevicePathNode (
498                       PrivateData->ParentDevicePath,
499                       (CONST EFI_DEVICE_PATH_PROTOCOL *) &mHiiVendorDevicePathNode
500                       );
501   if (ChildDevicePath == NULL) {
502     return EFI_OUT_OF_RESOURCES;
503   }
504   PrivateData->ChildDevicePath = ChildDevicePath;
505 
506   DriverHandle = NULL;
507   ConfigAccess = &PrivateData->ConfigAccess;
508   Status = gBS->InstallMultipleProtocolInterfaces (
509                   &DriverHandle,
510                   &gEfiDevicePathProtocolGuid,
511                   ChildDevicePath,
512                   &gEfiHiiConfigAccessProtocolGuid,
513                   ConfigAccess,
514                   NULL
515                   );
516   if (EFI_ERROR (Status)) {
517     return Status;
518   }
519   PrivateData->DriverHandle = DriverHandle;
520 
521   //
522   // Establish the parent-child relationship between the new created
523   // child handle and the ControllerHandle.
524   //
525   Status = gBS->OpenProtocol (
526                   PrivateData->ControllerHandle,
527                   &gEfiVlanConfigProtocolGuid,
528                   (VOID **)&VlanConfig,
529                   PrivateData->ImageHandle,
530                   PrivateData->DriverHandle,
531                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
532                   );
533   if (EFI_ERROR (Status)) {
534     return Status;
535   }
536 
537   //
538   // Publish the HII package list
539   //
540   HiiHandle = HiiAddPackages (
541                 &gVlanConfigFormSetGuid,
542                 DriverHandle,
543                 VlanConfigDxeStrings,
544                 VlanConfigBin,
545                 NULL
546                 );
547   if (HiiHandle == NULL) {
548     return EFI_OUT_OF_RESOURCES;
549   }
550   PrivateData->HiiHandle = HiiHandle;
551 
552   //
553   // Update formset title help string.
554   //
555   MacString = NULL;
556   Status = NetLibGetMacString (PrivateData->ControllerHandle, PrivateData->ImageHandle, &MacString);
557   if (EFI_ERROR (Status)) {
558     return Status;
559   }
560   PrivateData->MacString = MacString;
561 
562   StrCpyS (Str, sizeof (Str) / sizeof (CHAR16), L"VLAN Configuration (MAC:");
563   StrCatS (Str, sizeof (Str) / sizeof (CHAR16), MacString);
564   StrCatS (Str, sizeof (Str) / sizeof (CHAR16), L")");
565   HiiSetString (
566     HiiHandle,
567     STRING_TOKEN (STR_VLAN_FORM_SET_TITLE_HELP),
568     Str,
569     NULL
570     );
571 
572   //
573   // Update form title help string.
574   //
575   HiiSetString (
576     HiiHandle,
577     STRING_TOKEN (STR_VLAN_FORM_HELP),
578     Str,
579     NULL
580     );
581 
582   return EFI_SUCCESS;
583 }
584 
585 /**
586   This function remove the VLAN configuration Form for a network device. The
587   child handle for HII Config Access protocol will be destroyed.
588 
589   @param[in, out]  PrivateData   Points to VLAN configuration private data.
590 
591   @retval EFI_SUCCESS            HII Form has been uninstalled successfully.
592   @retval Others                 Other errors as indicated.
593 
594 **/
595 EFI_STATUS
UninstallVlanConfigForm(IN OUT VLAN_CONFIG_PRIVATE_DATA * PrivateData)596 UninstallVlanConfigForm (
597   IN OUT VLAN_CONFIG_PRIVATE_DATA    *PrivateData
598   )
599 {
600   EFI_STATUS                   Status;
601   EFI_VLAN_CONFIG_PROTOCOL     *VlanConfig;
602 
603   //
604   // End the parent-child relationship.
605   //
606   Status = gBS->CloseProtocol (
607                   PrivateData->ControllerHandle,
608                   &gEfiVlanConfigProtocolGuid,
609                   PrivateData->ImageHandle,
610                   PrivateData->DriverHandle
611                   );
612   if (EFI_ERROR (Status)) {
613     return Status;
614   }
615 
616   //
617   // Uninstall HII Config Access Protocol
618   //
619   if (PrivateData->DriverHandle != NULL) {
620     Status = gBS->UninstallMultipleProtocolInterfaces (
621                     PrivateData->DriverHandle,
622                     &gEfiDevicePathProtocolGuid,
623                     PrivateData->ChildDevicePath,
624                     &gEfiHiiConfigAccessProtocolGuid,
625                     &PrivateData->ConfigAccess,
626                     NULL
627                     );
628     if (EFI_ERROR (Status)) {
629       gBS->OpenProtocol (
630              PrivateData->ControllerHandle,
631              &gEfiVlanConfigProtocolGuid,
632              (VOID **)&VlanConfig,
633              PrivateData->ImageHandle,
634              PrivateData->DriverHandle,
635              EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
636              );
637       return Status;
638     }
639     PrivateData->DriverHandle = NULL;
640 
641     if (PrivateData->ChildDevicePath != NULL) {
642       FreePool (PrivateData->ChildDevicePath);
643       PrivateData->ChildDevicePath = NULL;
644     }
645   }
646 
647   //
648   // Free MAC string
649   //
650   if (PrivateData->MacString != NULL) {
651     FreePool (PrivateData->MacString);
652     PrivateData->MacString = NULL;
653   }
654 
655   //
656   // Uninstall HII package list
657   //
658   if (PrivateData->HiiHandle != NULL) {
659     HiiRemovePackages (PrivateData->HiiHandle);
660     PrivateData->HiiHandle = NULL;
661   }
662   return EFI_SUCCESS;
663 }
664