Home | History | Annotate | Download | only in VlanConfigDxe
      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
     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
    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
    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
    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
    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
    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