1 /** @file
2 The device manager reference implementation
3 
4 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "DeviceManager.h"
10 
11 DEVICE_MANAGER_CALLBACK_DATA  gDeviceManagerPrivate = {
12   DEVICE_MANAGER_CALLBACK_DATA_SIGNATURE,
13   NULL,
14   NULL,
15   {
16     DeviceManagerExtractConfig,
17     DeviceManagerRouteConfig,
18     DeviceManagerCallback
19   }
20 };
21 
22 #define  MAX_MAC_ADDRESS_NODE_LIST_LEN    10
23 
24 EFI_GUID mDeviceManagerGuid = DEVICE_MANAGER_FORMSET_GUID;
25 
26 //
27 // Which Mac Address string is select
28 // it will decide what menu need to show in the NETWORK_DEVICE_FORM_ID form.
29 //
30 EFI_STRING  mSelectedMacAddrString;
31 
32 //
33 // The Mac Address show in the NETWORK_DEVICE_LIST_FORM_ID
34 //
35 MAC_ADDRESS_NODE_LIST  mMacDeviceList;
36 
37 HII_VENDOR_DEVICE_PATH  mDeviceManagerHiiVendorDevicePath = {
38   {
39     {
40       HARDWARE_DEVICE_PATH,
41       HW_VENDOR_DP,
42       {
43         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
44         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
45       }
46     },
47     //
48     // {102579A0-3686-466e-ACD8-80C087044F4A}
49     //
50     { 0x102579a0, 0x3686, 0x466e, { 0xac, 0xd8, 0x80, 0xc0, 0x87, 0x4, 0x4f, 0x4a } }
51   },
52   {
53     END_DEVICE_PATH_TYPE,
54     END_ENTIRE_DEVICE_PATH_SUBTYPE,
55     {
56       (UINT8) (END_DEVICE_PATH_LENGTH),
57       (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
58     }
59   }
60 };
61 
62 /**
63   Extract device path for given HII handle and class guid.
64 
65   @param Handle          The HII handle.
66 
67   @retval  NULL          Fail to get the device path string.
68   @return  PathString    Get the device path string.
69 
70 **/
71 CHAR16 *
DmExtractDevicePathFromHiiHandle(IN EFI_HII_HANDLE Handle)72 DmExtractDevicePathFromHiiHandle (
73   IN      EFI_HII_HANDLE      Handle
74   )
75 {
76   EFI_STATUS                       Status;
77   EFI_HANDLE                       DriverHandle;
78 
79   ASSERT (Handle != NULL);
80 
81   if (Handle == NULL) {
82     return NULL;
83   }
84 
85   Status = gHiiDatabase->GetPackageListHandle (gHiiDatabase, Handle, &DriverHandle);
86   if (EFI_ERROR (Status)) {
87     return NULL;
88   }
89   //
90   // Get device path string.
91   //
92   return ConvertDevicePathToText(DevicePathFromHandle (DriverHandle), FALSE, FALSE);
93 }
94 
95 /**
96   Get the mac address string from the device path.
97   if the device path has the vlan, get the vanid also.
98 
99   @param MacAddressNode              Device path begin with mac address
100   @param PBuffer                     Output string buffer contain mac address.
101 
102 **/
103 BOOLEAN
GetMacAddressString(IN MAC_ADDR_DEVICE_PATH * MacAddressNode,OUT CHAR16 ** PBuffer)104 GetMacAddressString(
105   IN  MAC_ADDR_DEVICE_PATH   *MacAddressNode,
106   OUT CHAR16                 **PBuffer
107   )
108 {
109   UINTN                 HwAddressSize;
110   UINTN                 Index;
111   UINT8                 *HwAddress;
112   EFI_DEVICE_PATH_PROTOCOL  *Node;
113   UINT16                VlanId;
114   CHAR16                *String;
115   UINTN                 BufferLen;
116 
117   VlanId = 0;
118   String = NULL;
119   ASSERT(MacAddressNode != NULL);
120 
121   HwAddressSize = sizeof (EFI_MAC_ADDRESS);
122   if (MacAddressNode->IfType == 0x01 || MacAddressNode->IfType == 0x00) {
123     HwAddressSize = 6;
124   }
125 
126   //
127   // The output format is MAC:XX:XX:XX:...\XXXX
128   // The size is the Number size + ":" size + Vlan size(\XXXX) + End
129   //
130   BufferLen = (4 + 2 * HwAddressSize + (HwAddressSize - 1) + 5 + 1) * sizeof (CHAR16);
131   String = AllocateZeroPool (BufferLen);
132   if (String == NULL) {
133     return FALSE;
134   }
135 
136   *PBuffer = String;
137   StrCpyS(String, BufferLen / sizeof (CHAR16), L"MAC:");
138   String += 4;
139 
140   //
141   // Convert the MAC address into a unicode string.
142   //
143   HwAddress = &MacAddressNode->MacAddress.Addr[0];
144   for (Index = 0; Index < HwAddressSize; Index++) {
145     UnicodeValueToStringS (
146       String,
147       BufferLen - ((UINTN)String - (UINTN)*PBuffer),
148       PREFIX_ZERO | RADIX_HEX,
149       *(HwAddress++),
150       2
151       );
152     String += StrnLenS (String, (BufferLen - ((UINTN)String - (UINTN)*PBuffer)) / sizeof (CHAR16));
153     if (Index < HwAddressSize - 1) {
154       *String++ = L':';
155     }
156   }
157 
158   //
159   // If VLAN is configured, it will need extra 5 characters like "\0005".
160   // Plus one unicode character for the null-terminator.
161   //
162   Node = (EFI_DEVICE_PATH_PROTOCOL  *)MacAddressNode;
163   while (!IsDevicePathEnd (Node)) {
164     if (Node->Type == MESSAGING_DEVICE_PATH && Node->SubType == MSG_VLAN_DP) {
165       VlanId = ((VLAN_DEVICE_PATH *) Node)->VlanId;
166     }
167     Node = NextDevicePathNode (Node);
168   }
169 
170   if (VlanId != 0) {
171     *String++ = L'\\';
172     UnicodeValueToStringS (
173       String,
174       BufferLen - ((UINTN)String - (UINTN)*PBuffer),
175       PREFIX_ZERO | RADIX_HEX,
176       VlanId,
177       4
178       );
179     String += StrnLenS (String, (BufferLen - ((UINTN)String - (UINTN)*PBuffer)) / sizeof (CHAR16));
180   }
181 
182   //
183   // Null terminate the Unicode string
184   //
185   *String = L'\0';
186 
187   return TRUE;
188 }
189 
190 /**
191   Save question id and prompt id to the mac device list.
192   If the same mac address has saved yet, no need to add more.
193 
194   @param MacAddrString               Mac address string.
195 
196   @retval  EFI_SUCCESS               Add the item is successful.
197   @return  Other values if failed to Add the item.
198 **/
199 BOOLEAN
AddIdToMacDeviceList(IN EFI_STRING MacAddrString)200 AddIdToMacDeviceList (
201   IN  EFI_STRING        MacAddrString
202   )
203 {
204   MENU_INFO_ITEM *TempDeviceList;
205   UINTN          Index;
206   EFI_STRING     StoredString;
207   EFI_STRING_ID  PromptId;
208   EFI_HII_HANDLE HiiHandle;
209 
210   HiiHandle =   gDeviceManagerPrivate.HiiHandle;
211   TempDeviceList = NULL;
212 
213   for (Index = 0; Index < mMacDeviceList.CurListLen; Index ++) {
214     StoredString = HiiGetString (HiiHandle, mMacDeviceList.NodeList[Index].PromptId, NULL);
215     if (StoredString == NULL) {
216       return FALSE;
217     }
218 
219     //
220     // Already has save the same mac address to the list.
221     //
222     if (StrCmp (MacAddrString, StoredString) == 0) {
223       return FALSE;
224     }
225   }
226 
227   PromptId = HiiSetString(HiiHandle, 0, MacAddrString, NULL);
228   //
229   // If not in the list, save it.
230   //
231   if (mMacDeviceList.MaxListLen > mMacDeviceList.CurListLen + 1) {
232     mMacDeviceList.NodeList[mMacDeviceList.CurListLen].PromptId = PromptId;
233     mMacDeviceList.NodeList[mMacDeviceList.CurListLen].QuestionId = (EFI_QUESTION_ID) (mMacDeviceList.CurListLen + NETWORK_DEVICE_LIST_KEY_OFFSET);
234   } else {
235     mMacDeviceList.MaxListLen += MAX_MAC_ADDRESS_NODE_LIST_LEN;
236     if (mMacDeviceList.CurListLen != 0) {
237       TempDeviceList = ReallocatePool (
238                          sizeof (MENU_INFO_ITEM) * mMacDeviceList.CurListLen,
239                          sizeof (MENU_INFO_ITEM) * mMacDeviceList.MaxListLen,
240                          mMacDeviceList.NodeList
241                          );
242     } else {
243       TempDeviceList = (MENU_INFO_ITEM *)AllocatePool (sizeof (MENU_INFO_ITEM) * mMacDeviceList.MaxListLen);
244     }
245 
246     if (TempDeviceList == NULL) {
247       return FALSE;
248     }
249     TempDeviceList[mMacDeviceList.CurListLen].PromptId = PromptId;
250     TempDeviceList[mMacDeviceList.CurListLen].QuestionId = (EFI_QUESTION_ID) (mMacDeviceList.CurListLen + NETWORK_DEVICE_LIST_KEY_OFFSET);
251 
252     mMacDeviceList.NodeList = TempDeviceList;
253   }
254   mMacDeviceList.CurListLen ++;
255 
256   return TRUE;
257 }
258 
259 /**
260   Check the devcie path, try to find whether it has mac address path.
261 
262   In this function, first need to check whether this path has mac address path.
263   second, when the mac address device path has find, also need to deicide whether
264   need to add this mac address relate info to the menu.
265 
266   @param    *Node            Input device which need to be check.
267   @param    NextShowFormId   FormId Which need to be show.
268   @param    *NeedAddItem     Whether need to add the menu in the network device list.
269 
270   @retval  TRUE              Has mac address device path.
271   @retval  FALSE             NOT Has mac address device path.
272 
273 **/
274 BOOLEAN
IsMacAddressDevicePath(IN VOID * Node,IN EFI_FORM_ID NextShowFormId,OUT BOOLEAN * NeedAddItem)275 IsMacAddressDevicePath (
276   IN  VOID          *Node,
277   IN EFI_FORM_ID    NextShowFormId,
278   OUT BOOLEAN       *NeedAddItem
279   )
280 {
281   EFI_DEVICE_PATH_PROTOCOL   *DevicePath;
282   CHAR16                     *Buffer;
283   BOOLEAN                    ReturnVal;
284 
285   ASSERT (Node != NULL);
286   *NeedAddItem = FALSE;
287   ReturnVal    = FALSE;
288   Buffer    = NULL;
289 
290   DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Node;
291 
292   //
293   // find the partition device path node
294   //
295   while (!IsDevicePathEnd (DevicePath)) {
296     if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
297        (DevicePathSubType (DevicePath) == MSG_MAC_ADDR_DP)) {
298       ReturnVal = TRUE;
299 
300       if (DEVICE_MANAGER_FORM_ID == NextShowFormId) {
301         *NeedAddItem = TRUE;
302         break;
303       }
304 
305       if (!GetMacAddressString((MAC_ADDR_DEVICE_PATH*)DevicePath, &Buffer)) {
306         break;
307       }
308 
309       if (NETWORK_DEVICE_FORM_ID == NextShowFormId) {
310         if (StrCmp (Buffer, mSelectedMacAddrString) == 0) {
311           *NeedAddItem = TRUE;
312         }
313         break;
314       }
315 
316       if (NETWORK_DEVICE_LIST_FORM_ID == NextShowFormId) {
317         //
318         // Same handle may has two network child handle, so the questionid
319         // has the offset of SAME_HANDLE_KEY_OFFSET.
320         //
321         if (AddIdToMacDeviceList (Buffer)) {
322           *NeedAddItem = TRUE;
323         }
324         break;
325       }
326     }
327     DevicePath = NextDevicePathNode (DevicePath);
328   }
329 
330   if (Buffer != NULL) {
331     FreePool (Buffer);
332   }
333 
334   return ReturnVal;
335 }
336 
337 /**
338   Check to see if the device path is for the network device.
339 
340   @param Handle          The HII handle which include the mac address device path.
341   @param NextShowFormId  The FormId of the form which will be show next time.
342   @param ItemCount       The new add Mac address item count.
343 
344   @retval  TRUE          Need to add new item in the menu.
345   @return  FALSE         Do not need to add the menu about the network.
346 
347 **/
348 BOOLEAN
IsNeedAddNetworkMenu(IN EFI_HII_HANDLE Handle,IN EFI_FORM_ID NextShowFormId,OUT UINTN * ItemCount)349 IsNeedAddNetworkMenu (
350   IN      EFI_HII_HANDLE      Handle,
351   IN      EFI_FORM_ID         NextShowFormId,
352   OUT     UINTN               *ItemCount
353   )
354 {
355   EFI_STATUS     Status;
356   UINTN          EntryCount;
357   UINTN          Index;
358   EFI_HANDLE     DriverHandle;
359   EFI_HANDLE     ControllerHandle;
360   EFI_DEVICE_PATH_PROTOCOL   *DevicePath;
361   EFI_DEVICE_PATH_PROTOCOL   *TmpDevicePath;
362   EFI_DEVICE_PATH_PROTOCOL   *ChildDevicePath;
363   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY   *OpenInfoBuffer;
364   BOOLEAN        IsNeedAdd;
365 
366   IsNeedAdd  = FALSE;
367   OpenInfoBuffer = NULL;
368   if ((Handle == NULL) || (ItemCount == NULL)) {
369     return FALSE;
370   }
371   *ItemCount = 0;
372 
373   Status = gHiiDatabase->GetPackageListHandle (gHiiDatabase, Handle, &DriverHandle);
374   if (EFI_ERROR (Status)) {
375     return FALSE;
376   }
377   //
378   // Get the device path by the got Driver handle .
379   //
380   Status = gBS->HandleProtocol (DriverHandle, &gEfiDevicePathProtocolGuid, (VOID **) &DevicePath);
381   if (EFI_ERROR (Status)) {
382     return FALSE;
383   }
384   TmpDevicePath = DevicePath;
385 
386   //
387   // Check whether this device path include mac address device path.
388   // If this path has mac address path, get the value whether need
389   // add this info to the menu and return.
390   // Else check more about the child handle devcie path.
391   //
392   if (IsMacAddressDevicePath(TmpDevicePath, NextShowFormId,&IsNeedAdd)) {
393     if ((NETWORK_DEVICE_LIST_FORM_ID == NextShowFormId) && IsNeedAdd) {
394       (*ItemCount) = 1;
395     }
396     return IsNeedAdd;
397   }
398 
399   //
400   // Search whether this path is the controller path, not he child handle path.
401   // And the child handle has the network devcie connected.
402   //
403   TmpDevicePath = DevicePath;
404   Status = gBS->LocateDevicePath(&gEfiDevicePathProtocolGuid, &TmpDevicePath, &ControllerHandle);
405   if (EFI_ERROR (Status)) {
406     return FALSE;
407   }
408 
409   if (!IsDevicePathEnd (TmpDevicePath)) {
410     return FALSE;
411   }
412 
413   //
414   // Retrieve the list of agents that are consuming the specific protocol
415   // on ControllerHandle.
416   // The buffer point by OpenInfoBuffer need be free at this function.
417   //
418   Status = gBS->OpenProtocolInformation (
419                   ControllerHandle,
420                   &gEfiPciIoProtocolGuid,
421                   &OpenInfoBuffer,
422                   &EntryCount
423                   );
424   if (EFI_ERROR (Status)) {
425     return FALSE;
426   }
427 
428   //
429   // Inspect if ChildHandle is one of the agents.
430   //
431   Status = EFI_UNSUPPORTED;
432   for (Index = 0; Index < EntryCount; Index++) {
433     //
434     // Query all the children created by the controller handle's driver
435     //
436     if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
437       Status = gBS->OpenProtocol (
438                       OpenInfoBuffer[Index].ControllerHandle,
439                       &gEfiDevicePathProtocolGuid,
440                       (VOID **) &ChildDevicePath,
441                       NULL,
442                       NULL,
443                       EFI_OPEN_PROTOCOL_GET_PROTOCOL
444                       );
445       if (EFI_ERROR (Status)) {
446         continue;
447       }
448 
449       //
450       // Check whether this device path include mac address device path.
451       //
452       if (!IsMacAddressDevicePath(ChildDevicePath, NextShowFormId,&IsNeedAdd)) {
453         //
454         // If this path not has mac address path, check the other.
455         //
456         continue;
457       } else {
458         //
459         // If need to update the NETWORK_DEVICE_LIST_FORM, try to get more.
460         //
461         if ((NETWORK_DEVICE_LIST_FORM_ID == NextShowFormId)) {
462           if (IsNeedAdd) {
463             (*ItemCount) += 1;
464           }
465           continue;
466         } else {
467           //
468           // If need to update other form, return whether need to add to the menu.
469           //
470           goto Done;
471         }
472       }
473     }
474   }
475 
476 Done:
477   if (OpenInfoBuffer != NULL) {
478     FreePool (OpenInfoBuffer);
479   }
480   return IsNeedAdd;
481 }
482 
483 /**
484   Dynamic create Hii information for Device Manager.
485 
486   @param   NextShowFormId     The FormId which need to be show.
487 
488 **/
489 VOID
CreateDeviceManagerForm(IN EFI_FORM_ID NextShowFormId)490 CreateDeviceManagerForm(
491   IN EFI_FORM_ID      NextShowFormId
492 )
493 {
494   UINTN                       Index;
495   EFI_STRING                  String;
496   EFI_STRING_ID               Token;
497   EFI_STRING_ID               TokenHelp;
498   EFI_HII_HANDLE              *HiiHandles;
499   EFI_HII_HANDLE              HiiHandle;
500   EFI_GUID                    FormSetGuid;
501   VOID                        *StartOpCodeHandle;
502   VOID                        *EndOpCodeHandle;
503   EFI_IFR_GUID_LABEL          *StartLabel;
504   EFI_IFR_GUID_LABEL          *EndLabel;
505   BOOLEAN                     AddNetworkMenu;
506   UINTN                       AddItemCount;
507   UINTN                       NewStringLen;
508   EFI_STRING                  NewStringTitle;
509   CHAR16                      *DevicePathStr;
510   EFI_STRING_ID               DevicePathId;
511   EFI_IFR_FORM_SET            *Buffer;
512   UINTN                       BufferSize;
513   UINT8                       ClassGuidNum;
514   EFI_GUID                    *ClassGuid;
515   UINTN                       TempSize;
516   UINT8                       *Ptr;
517   EFI_STATUS                  Status;
518 
519   TempSize =0;
520   BufferSize = 0;
521   Buffer = NULL;
522 
523   HiiHandle = gDeviceManagerPrivate.HiiHandle;
524   AddNetworkMenu = FALSE;
525   AddItemCount = 0;
526   //
527   // If need show the Network device list form, clear the old save list first.
528   //
529   if ((NextShowFormId == NETWORK_DEVICE_LIST_FORM_ID) && (mMacDeviceList.CurListLen > 0)) {
530     mMacDeviceList.CurListLen = 0;
531   }
532 
533   //
534   // Update the network device form titile.
535   //
536   if (NextShowFormId == NETWORK_DEVICE_FORM_ID) {
537     String = HiiGetString (HiiHandle, STRING_TOKEN (STR_FORM_NETWORK_DEVICE_TITLE_HEAD), NULL);
538     if (String == NULL) {
539       return;
540     }
541     NewStringLen = StrLen (mSelectedMacAddrString) * 2;
542     NewStringLen += (StrLen (String) + 2) * 2;
543     NewStringTitle = AllocatePool (NewStringLen);
544     UnicodeSPrint (NewStringTitle, NewStringLen, L"%s %s", String, mSelectedMacAddrString);
545     HiiSetString (HiiHandle, STRING_TOKEN (STR_FORM_NETWORK_DEVICE_TITLE), NewStringTitle, NULL);
546     FreePool (String);
547     FreePool (NewStringTitle);
548   }
549 
550   //
551   // Allocate space for creation of UpdateData Buffer
552   //
553   StartOpCodeHandle = HiiAllocateOpCodeHandle ();
554   ASSERT (StartOpCodeHandle != NULL);
555 
556   EndOpCodeHandle = HiiAllocateOpCodeHandle ();
557   ASSERT (EndOpCodeHandle != NULL);
558 
559   //
560   // Create Hii Extend Label OpCode as the start opcode
561   //
562   StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
563   StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
564   //
565   // According to the next show Form id(mNextShowFormId) to decide which form need to update.
566   //
567   StartLabel->Number       = (UINT16) (LABEL_FORM_ID_OFFSET + NextShowFormId);
568 
569   //
570   // Create Hii Extend Label OpCode as the end opcode
571   //
572   EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
573   EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
574   EndLabel->Number       = LABEL_END;
575 
576   //
577   // Get all the Hii handles
578   //
579   HiiHandles = HiiGetHiiHandles (NULL);
580   ASSERT (HiiHandles != NULL);
581 
582   //
583   // Search for formset of each class type
584   //
585   for (Index = 0; HiiHandles[Index] != NULL; Index++) {
586     Status = HiiGetFormSetFromHiiHandle(HiiHandles[Index], &Buffer,&BufferSize);
587     if (EFI_ERROR (Status)){
588       continue;
589     }
590     Ptr = (UINT8 *)Buffer;
591     while(TempSize < BufferSize)  {
592       TempSize += ((EFI_IFR_OP_HEADER *) Ptr)->Length;
593       if (((EFI_IFR_OP_HEADER *) Ptr)->Length <= OFFSET_OF (EFI_IFR_FORM_SET, Flags)){
594         Ptr += ((EFI_IFR_OP_HEADER *) Ptr)->Length;
595         continue;
596       }
597 
598       ClassGuidNum = (UINT8) (((EFI_IFR_FORM_SET *)Ptr)->Flags & 0x3);
599       ClassGuid = (EFI_GUID *) (VOID *)(Ptr + sizeof (EFI_IFR_FORM_SET));
600       while (ClassGuidNum-- > 0) {
601         if (CompareGuid (&gEfiHiiPlatformSetupFormsetGuid, ClassGuid)== 0) {
602           ClassGuid ++;
603           continue;
604         }
605 
606         String = HiiGetString (HiiHandles[Index], ((EFI_IFR_FORM_SET *)Ptr)->FormSetTitle, NULL);
607         if (String == NULL) {
608           String = HiiGetString (HiiHandle, STRING_TOKEN (STR_MISSING_STRING), NULL);
609           ASSERT (String != NULL);
610         }
611         Token = HiiSetString (HiiHandle, 0, String, NULL);
612         FreePool (String);
613 
614         String = HiiGetString (HiiHandles[Index], ((EFI_IFR_FORM_SET *)Ptr)->Help, NULL);
615         if (String == NULL) {
616           String = HiiGetString (HiiHandle, STRING_TOKEN (STR_MISSING_STRING), NULL);
617           ASSERT (String != NULL);
618         }
619         TokenHelp = HiiSetString (HiiHandle, 0, String, NULL);
620         FreePool (String);
621 
622         CopyMem (&FormSetGuid, &((EFI_IFR_FORM_SET *) Ptr)->Guid, sizeof (EFI_GUID));
623 
624         //
625         // Network device process
626         //
627         if (IsNeedAddNetworkMenu (HiiHandles[Index], NextShowFormId,&AddItemCount)) {
628           if (NextShowFormId == DEVICE_MANAGER_FORM_ID) {
629             //
630             // Only show one menu item "Network Config" in the device manger form.
631             //
632             if (!AddNetworkMenu) {
633               AddNetworkMenu = TRUE;
634               HiiCreateGotoOpCode (
635                 StartOpCodeHandle,
636                 NETWORK_DEVICE_LIST_FORM_ID,
637                 STRING_TOKEN (STR_FORM_NETWORK_DEVICE_LIST_TITLE),
638                 STRING_TOKEN (STR_FORM_NETWORK_DEVICE_LIST_HELP),
639                 EFI_IFR_FLAG_CALLBACK,
640                 (EFI_QUESTION_ID) QUESTION_NETWORK_DEVICE_ID
641               );
642             }
643           } else if (NextShowFormId == NETWORK_DEVICE_LIST_FORM_ID) {
644             //
645             // In network device list form, same mac address device only show one menu.
646             //
647             while (AddItemCount > 0) {
648               HiiCreateGotoOpCode (
649                 StartOpCodeHandle,
650                 NETWORK_DEVICE_FORM_ID,
651                 mMacDeviceList.NodeList[mMacDeviceList.CurListLen - AddItemCount].PromptId,
652                 STRING_TOKEN (STR_NETWORK_DEVICE_HELP),
653                 EFI_IFR_FLAG_CALLBACK,
654                 mMacDeviceList.NodeList[mMacDeviceList.CurListLen - AddItemCount].QuestionId
655               );
656               AddItemCount -= 1;
657             }
658           } else if (NextShowFormId == NETWORK_DEVICE_FORM_ID) {
659             //
660             // In network device form, only the selected mac address device need to be show.
661             //
662             DevicePathStr = DmExtractDevicePathFromHiiHandle(HiiHandles[Index]);
663             DevicePathId  = 0;
664             if (DevicePathStr != NULL){
665               DevicePathId =  HiiSetString (HiiHandle, 0, DevicePathStr, NULL);
666               FreePool(DevicePathStr);
667             }
668             HiiCreateGotoExOpCode (
669               StartOpCodeHandle,
670               0,
671               Token,
672               TokenHelp,
673               0,
674               (EFI_QUESTION_ID) (Index + DEVICE_KEY_OFFSET),
675               0,
676               &FormSetGuid,
677               DevicePathId
678             );
679           }
680         } else {
681           //
682           // Not network device process, only need to show at device manger form.
683           //
684           if (NextShowFormId == DEVICE_MANAGER_FORM_ID) {
685             DevicePathStr = DmExtractDevicePathFromHiiHandle(HiiHandles[Index]);
686             DevicePathId  = 0;
687             if (DevicePathStr != NULL){
688               DevicePathId =  HiiSetString (HiiHandle, 0, DevicePathStr, NULL);
689               FreePool(DevicePathStr);
690             }
691             HiiCreateGotoExOpCode (
692               StartOpCodeHandle,
693               0,
694               Token,
695               TokenHelp,
696               0,
697               (EFI_QUESTION_ID) (Index + DEVICE_KEY_OFFSET),
698               0,
699               &FormSetGuid,
700               DevicePathId
701             );
702           }
703         }
704         break;
705       }
706 
707       Ptr += ((EFI_IFR_OP_HEADER *) Ptr)->Length;
708     }
709     FreePool(Buffer);
710     Buffer = NULL;
711     TempSize = 0;
712     BufferSize = 0;
713   }
714 
715   HiiUpdateForm (
716     HiiHandle,
717     &mDeviceManagerGuid,
718     NextShowFormId,
719     StartOpCodeHandle,
720     EndOpCodeHandle
721     );
722 
723   HiiFreeOpCodeHandle (StartOpCodeHandle);
724   HiiFreeOpCodeHandle (EndOpCodeHandle);
725   FreePool (HiiHandles);
726 }
727 
728 /**
729   This function allows a caller to extract the current configuration for one
730   or more named elements from the target driver.
731 
732 
733   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
734   @param Request         A null-terminated Unicode string in <ConfigRequest> format.
735   @param Progress        On return, points to a character in the Request string.
736                          Points to the string's null terminator if request was successful.
737                          Points to the most recent '&' before the first failing name/value
738                          pair (or the beginning of the string if the failure is in the
739                          first name/value pair) if the request was not successful.
740   @param Results         A null-terminated Unicode string in <ConfigAltResp> format which
741                          has all values filled in for the names in the Request string.
742                          String to be allocated by the called function.
743 
744   @retval  EFI_SUCCESS            The Results is filled with the requested values.
745   @retval  EFI_OUT_OF_RESOURCES   Not enough memory to store the results.
746   @retval  EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown name.
747   @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.
748 
749 **/
750 EFI_STATUS
751 EFIAPI
DeviceManagerExtractConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Request,OUT EFI_STRING * Progress,OUT EFI_STRING * Results)752 DeviceManagerExtractConfig (
753   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
754   IN  CONST EFI_STRING                       Request,
755   OUT EFI_STRING                             *Progress,
756   OUT EFI_STRING                             *Results
757   )
758 {
759   if (Progress == NULL || Results == NULL) {
760     return EFI_INVALID_PARAMETER;
761   }
762   *Progress = Request;
763   return EFI_NOT_FOUND;
764 }
765 
766 /**
767   This function processes the results of changes in configuration.
768 
769   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
770   @param Configuration   A null-terminated Unicode string in <ConfigResp> format.
771   @param Progress        A pointer to a string filled in with the offset of the most
772                          recent '&' before the first failing name/value pair (or the
773                          beginning of the string if the failure is in the first
774                          name/value pair) or the terminating NULL if all was successful.
775 
776   @retval  EFI_SUCCESS            The Results is processed successfully.
777   @retval  EFI_INVALID_PARAMETER  Configuration is NULL.
778   @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.
779 
780 **/
781 EFI_STATUS
782 EFIAPI
DeviceManagerRouteConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Configuration,OUT EFI_STRING * Progress)783 DeviceManagerRouteConfig (
784   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
785   IN  CONST EFI_STRING                       Configuration,
786   OUT EFI_STRING                             *Progress
787   )
788 {
789   if (Configuration == NULL || Progress == NULL) {
790     return EFI_INVALID_PARAMETER;
791   }
792 
793   *Progress = Configuration;
794 
795   return EFI_NOT_FOUND;
796 }
797 
798 /**
799   This function is invoked if user selected a interactive opcode from Device Manager's
800   Formset. If user set VBIOS, the new value is saved to EFI variable.
801 
802   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
803   @param Action          Specifies the type of action taken by the browser.
804   @param QuestionId      A unique value which is sent to the original exporting driver
805                          so that it can identify the type of data to expect.
806   @param Type            The type of value for the question.
807   @param Value           A pointer to the data being sent to the original exporting driver.
808   @param ActionRequest   On return, points to the action requested by the callback function.
809 
810   @retval  EFI_SUCCESS           The callback successfully handled the action.
811   @retval  EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
812 
813 **/
814 EFI_STATUS
815 EFIAPI
DeviceManagerCallback(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)816 DeviceManagerCallback (
817   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
818   IN  EFI_BROWSER_ACTION                     Action,
819   IN  EFI_QUESTION_ID                        QuestionId,
820   IN  UINT8                                  Type,
821   IN  EFI_IFR_TYPE_VALUE                     *Value,
822   OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
823   )
824 {
825   UINTN CurIndex;
826 
827   if (Action != EFI_BROWSER_ACTION_CHANGING) {
828     //
829     // Do nothing for other UEFI Action. Only do call back when data is changed.
830     //
831     return EFI_UNSUPPORTED;
832   }
833   if ((Value == NULL) || (ActionRequest == NULL)) {
834     return EFI_INVALID_PARAMETER;
835   }
836   if ((QuestionId < MAX_KEY_SECTION_LEN + NETWORK_DEVICE_LIST_KEY_OFFSET) && (QuestionId >= NETWORK_DEVICE_LIST_KEY_OFFSET)) {
837     //
838     // If user select the mac address, need to record mac address string to support next form show.
839     //
840     for (CurIndex = 0; CurIndex < mMacDeviceList.CurListLen; CurIndex ++) {
841       if (mMacDeviceList.NodeList[CurIndex].QuestionId == QuestionId) {
842          mSelectedMacAddrString = HiiGetString (gDeviceManagerPrivate.HiiHandle, mMacDeviceList.NodeList[CurIndex].PromptId, NULL);
843       }
844     }
845     CreateDeviceManagerForm(NETWORK_DEVICE_FORM_ID);
846   } else if(QuestionId == QUESTION_NETWORK_DEVICE_ID){
847     CreateDeviceManagerForm(NETWORK_DEVICE_LIST_FORM_ID);
848   }
849 
850   return EFI_SUCCESS;
851 }
852 
853 /**
854   Install Boot Manager Menu driver.
855 
856   @param ImageHandle     The image handle.
857   @param SystemTable     The system table.
858 
859   @retval  EFI_SUCEESS  Install Boot manager menu success.
860   @retval  Other        Return error status.
861 
862 **/
863 EFI_STATUS
864 EFIAPI
DeviceManagerUiLibConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)865 DeviceManagerUiLibConstructor (
866   IN EFI_HANDLE                            ImageHandle,
867   IN EFI_SYSTEM_TABLE                      *SystemTable
868 )
869 {
870   EFI_STATUS                  Status;
871 
872   gDeviceManagerPrivate.DriverHandle = NULL;
873   Status = gBS->InstallMultipleProtocolInterfaces (
874                   &gDeviceManagerPrivate.DriverHandle,
875                   &gEfiDevicePathProtocolGuid,
876                   &mDeviceManagerHiiVendorDevicePath,
877                   &gEfiHiiConfigAccessProtocolGuid,
878                   &gDeviceManagerPrivate.ConfigAccess,
879                   NULL
880                   );
881   ASSERT_EFI_ERROR (Status);
882 
883   //
884   // Publish our HII data.
885   //
886   gDeviceManagerPrivate.HiiHandle = HiiAddPackages (
887                   &mDeviceManagerGuid,
888                   gDeviceManagerPrivate.DriverHandle,
889                   DeviceManagerVfrBin,
890                   DeviceManagerUiLibStrings,
891                   NULL
892                   );
893   ASSERT (gDeviceManagerPrivate.HiiHandle != NULL);
894 
895   //
896   // The device manager form contains a page listing all the network
897   // controllers in the system. This list can only be populated if all
898   // handles have been connected, so do it here.
899   //
900   EfiBootManagerConnectAll ();
901 
902   //
903   // Update boot manager page
904   //
905   CreateDeviceManagerForm (DEVICE_MANAGER_FORM_ID);
906 
907   return EFI_SUCCESS;
908 }
909 
910 /**
911   Unloads the application and its installed protocol.
912 
913   @param  ImageHandle     Handle that identifies the image to be unloaded.
914   @param  SystemTable     The system table.
915 
916   @retval EFI_SUCCESS           The image has been unloaded.
917 **/
918 EFI_STATUS
919 EFIAPI
DeviceManagerUiLibDestructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)920 DeviceManagerUiLibDestructor(
921   IN EFI_HANDLE                            ImageHandle,
922   IN EFI_SYSTEM_TABLE                      *SystemTable
923 )
924 {
925   EFI_STATUS                  Status;
926 
927   Status = gBS->UninstallMultipleProtocolInterfaces (
928                   gDeviceManagerPrivate.DriverHandle,
929                   &gEfiDevicePathProtocolGuid,
930                   &mDeviceManagerHiiVendorDevicePath,
931                   &gEfiHiiConfigAccessProtocolGuid,
932                   &gDeviceManagerPrivate.ConfigAccess,
933                   NULL
934                   );
935   ASSERT_EFI_ERROR (Status);
936 
937   HiiRemovePackages (gDeviceManagerPrivate.HiiHandle);
938 
939   return EFI_SUCCESS;
940 }
941 
942