1 /** @file
2   Helper functions for configuring or obtaining the parameters relating to IP6.
3 
4   Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
5 
6   SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 **/
9 
10 #include "Ip6Impl.h"
11 
12 CHAR16    mIp6ConfigStorageName[]     = L"IP6_CONFIG_IFR_NVDATA";
13 
14 /**
15   The notify function of create event when performing a manual configuration.
16 
17   @param[in]    Event        The pointer of Event.
18   @param[in]    Context      The pointer of Context.
19 
20 **/
21 VOID
22 EFIAPI
Ip6ConfigManualAddressNotify(IN EFI_EVENT Event,IN VOID * Context)23 Ip6ConfigManualAddressNotify (
24   IN EFI_EVENT    Event,
25   IN VOID         *Context
26   )
27 {
28   *((BOOLEAN *) Context) = TRUE;
29 }
30 
31 /**
32   Get the configuration data for the EFI IPv6 network stack running on the
33   communication. It is a help function to the call EfiIp6ConfigGetData().
34 
35   @param[in]      Ip6Config      The pointer to the EFI_IP6_CONFIG_PROTOCOL instance.
36   @param[in]      DataType       The type of data to get.
37   @param[out]     DataSize       The size of buffer required in bytes.
38   @param[out]     Data           The data buffer in which the configuration data is returned. The
39                                  type of the data buffer associated with the DataType.
40                                  It is the caller's responsibility to free the resource.
41 
42   @retval EFI_SUCCESS           The specified configuration data was obtained successfully.
43   @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE:
44                                 - Ip6Config is NULL or invalid.
45                                 - DataSize is NULL.
46                                 - Data is NULL.
47   @retval EFI_OUT_OF_RESOURCES  Fail to perform the operation due to lack of resources.
48   @retval EFI_NOT_READY         The specified configuration data is not ready due to an
49                                 asynchronous configuration process already in progress.
50   @retval EFI_NOT_FOUND         The specified configuration data was not found.
51 
52 **/
53 EFI_STATUS
Ip6ConfigNvGetData(IN EFI_IP6_CONFIG_PROTOCOL * Ip6Config,IN EFI_IP6_CONFIG_DATA_TYPE DataType,OUT UINTN * DataSize,OUT VOID ** Data)54 Ip6ConfigNvGetData (
55   IN  EFI_IP6_CONFIG_PROTOCOL                *Ip6Config,
56   IN  EFI_IP6_CONFIG_DATA_TYPE               DataType,
57   OUT UINTN                                  *DataSize,
58   OUT VOID                                   **Data
59   )
60 {
61   UINTN                   BufferSize;
62   VOID                    *Buffer;
63   EFI_STATUS              Status;
64 
65   if ((Ip6Config == NULL) || (Data == NULL) || (DataSize == NULL)) {
66     return EFI_INVALID_PARAMETER;
67   }
68 
69   BufferSize = 0;
70   Status = Ip6Config->GetData (
71                         Ip6Config,
72                         DataType,
73                         &BufferSize,
74                         NULL
75                         );
76   if (Status != EFI_BUFFER_TOO_SMALL) {
77     return Status;
78   }
79 
80   Buffer = AllocateZeroPool (BufferSize);
81   if (Buffer == NULL) {
82     return EFI_OUT_OF_RESOURCES;
83   }
84 
85   Status = Ip6Config->GetData (
86                         Ip6Config,
87                         DataType,
88                         &BufferSize,
89                         Buffer
90                         );
91   if (EFI_ERROR (Status)) {
92     FreePool (Buffer);
93     return Status;
94   }
95 
96   *DataSize = BufferSize;
97   *Data     = Buffer;
98 
99   return EFI_SUCCESS;
100 }
101 
102 /**
103   Free all nodes in IP6_ADDRESS_INFO_ENTRY in the list array specified
104   with ListHead.
105 
106   @param[in]      ListHead  The head of the list array in IP6_ADDRESS_INFO_ENTRY.
107 
108 **/
109 VOID
Ip6FreeAddressInfoList(IN LIST_ENTRY * ListHead)110 Ip6FreeAddressInfoList (
111   IN LIST_ENTRY                  *ListHead
112   )
113 {
114   IP6_ADDRESS_INFO_ENTRY         *Node;
115   LIST_ENTRY                     *Entry;
116   LIST_ENTRY                     *NextEntry;
117 
118   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, ListHead) {
119     Node = NET_LIST_USER_STRUCT (Entry, IP6_ADDRESS_INFO_ENTRY, Link);
120     RemoveEntryList (&Node->Link);
121     FreePool (Node);
122   }
123 }
124 
125 /**
126   Convert the IPv6 address into a formatted string.
127 
128   @param[in]  Ip6       The IPv6 address.
129   @param[out] Str       The formatted IP string.
130 
131 **/
132 VOID
Ip6ToStr(IN EFI_IPv6_ADDRESS * Ip6,OUT CHAR16 * Str)133 Ip6ToStr (
134   IN  EFI_IPv6_ADDRESS  *Ip6,
135   OUT CHAR16            *Str
136   )
137 {
138   UINTN                 Index;
139   BOOLEAN               Short;
140   UINTN                 Number;
141   CHAR16                FormatString[8];
142 
143   Short = FALSE;
144 
145   for (Index = 0; Index < 15; Index = Index + 2) {
146     if (!Short &&
147         Index % 2 == 0 &&
148         Ip6->Addr[Index] == 0 &&
149         Ip6->Addr[Index + 1] == 0
150         ) {
151       //
152       // Deal with the case of ::.
153       //
154       if (Index == 0) {
155         *Str       = L':';
156         *(Str + 1) = L':';
157         Str        = Str + 2;
158       } else {
159         *Str       = L':';
160         Str        = Str + 1;
161       }
162 
163       while ((Index < 15) && (Ip6->Addr[Index] == 0) && (Ip6->Addr[Index + 1] == 0)) {
164         Index = Index + 2;
165       }
166 
167       Short = TRUE;
168 
169       if (Index == 16) {
170         //
171         // :: is at the end of the address.
172         //
173         *Str = L'\0';
174         break;
175       }
176     }
177 
178     ASSERT (Index < 15);
179 
180     if (Ip6->Addr[Index] == 0) {
181       Number = UnicodeSPrint (Str, 2 * IP6_STR_MAX_SIZE, L"%x:", (UINTN) Ip6->Addr[Index + 1]);
182     } else {
183       if (Ip6->Addr[Index + 1] < 0x10) {
184         CopyMem (FormatString, L"%x0%x:", StrSize (L"%x0%x:"));
185       } else {
186         CopyMem (FormatString, L"%x%x:", StrSize (L"%x%x:"));
187       }
188 
189       Number = UnicodeSPrint (
190                  Str,
191                  2 * IP6_STR_MAX_SIZE,
192                  (CONST CHAR16 *) FormatString,
193                  (UINTN) Ip6->Addr[Index],
194                  (UINTN) Ip6->Addr[Index + 1]
195                  );
196     }
197 
198     Str = Str + Number;
199 
200     if (Index + 2 == 16) {
201       *Str = L'\0';
202       if (*(Str - 1) == L':') {
203         *(Str - 1) = L'\0';
204       }
205     }
206   }
207 }
208 
209 /**
210   Convert EFI_IP6_CONFIG_INTERFACE_ID to string format.
211 
212   @param[out]      String  The buffer to store the converted string.
213   @param[in]       IfId    The pointer of EFI_IP6_CONFIG_INTERFACE_ID.
214 
215   @retval EFI_SUCCESS              The string converted successfully.
216   @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.
217 
218 **/
219 EFI_STATUS
Ip6ConvertInterfaceIdToString(OUT CHAR16 * String,IN EFI_IP6_CONFIG_INTERFACE_ID * IfId)220 Ip6ConvertInterfaceIdToString (
221   OUT CHAR16                         *String,
222   IN  EFI_IP6_CONFIG_INTERFACE_ID    *IfId
223   )
224 {
225   UINT8                          Index;
226   UINTN                          Number;
227 
228   if ((String == NULL) || (IfId == NULL)) {
229     return EFI_INVALID_PARAMETER;
230   }
231 
232   for (Index = 0; Index < 8; Index++) {
233     Number = UnicodeSPrint (
234                String,
235                2 * INTERFACE_ID_STR_STORAGE,
236                L"%x:",
237                (UINTN) IfId->Id[Index]
238                );
239     String = String + Number;
240   }
241 
242   *(String - 1) = '\0';
243 
244   return EFI_SUCCESS;
245 }
246 
247 /**
248   Parse InterfaceId in string format and convert it to EFI_IP6_CONFIG_INTERFACE_ID.
249 
250   @param[in]        String  The buffer of the string to be parsed.
251   @param[out]       IfId    The pointer of EFI_IP6_CONFIG_INTERFACE_ID.
252 
253   @retval EFI_SUCCESS              The operation finished successfully.
254   @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.
255 
256 **/
257 EFI_STATUS
Ip6ParseInterfaceIdFromString(IN CONST CHAR16 * String,OUT EFI_IP6_CONFIG_INTERFACE_ID * IfId)258 Ip6ParseInterfaceIdFromString (
259   IN CONST CHAR16                    *String,
260   OUT EFI_IP6_CONFIG_INTERFACE_ID    *IfId
261   )
262 {
263   UINT8                          Index;
264   CHAR16                         *IfIdStr;
265   CHAR16                         *TempStr;
266   UINTN                          NodeVal;
267 
268   if ((String == NULL) || (IfId == NULL)) {
269     return EFI_INVALID_PARAMETER;
270   }
271 
272   IfIdStr = (CHAR16 *) String;
273 
274   ZeroMem (IfId, sizeof (EFI_IP6_CONFIG_INTERFACE_ID));
275 
276   for (Index = 0; Index < 8; Index++) {
277     TempStr = IfIdStr;
278 
279     while ((*IfIdStr != L'\0') && (*IfIdStr != L':')) {
280       IfIdStr++;
281     }
282 
283     //
284     // The InterfaceId format is X:X:X:X, the number of X should not exceed 8.
285     // If the number of X is less than 8, zero is appended to the InterfaceId.
286     //
287     if ((*IfIdStr == ':') && (Index == 7)) {
288       return EFI_INVALID_PARAMETER;
289     }
290 
291     //
292     // Convert the string to interface id. AsciiStrHexToUintn stops at the
293     // first character that is not a valid hex character, ':' or '\0' here.
294     //
295     NodeVal = StrHexToUintn (TempStr);
296     if (NodeVal > 0xFF) {
297       return EFI_INVALID_PARAMETER;
298     }
299 
300     IfId->Id[Index] = (UINT8) NodeVal;
301 
302     IfIdStr++;
303   }
304 
305   return EFI_SUCCESS;
306 }
307 
308 /**
309   Create Hii Extend Label OpCode as the start opcode and end opcode. It is
310   a help function.
311 
312   @param[in]  StartLabelNumber   The number of start label.
313   @param[out] StartOpCodeHandle  Points to the start opcode handle.
314   @param[out] StartLabel         Points to the created start opcode.
315   @param[out] EndOpCodeHandle    Points to the end opcode handle.
316   @param[out] EndLabel           Points to the created end opcode.
317 
318   @retval EFI_OUT_OF_RESOURCES   Does not have sufficient resources to finish this
319                                  operation.
320   @retval EFI_INVALID_PARAMETER  Any input parameter is invalid.
321   @retval EFI_SUCCESS            The operation completed successfully.
322 
323 **/
324 EFI_STATUS
Ip6CreateOpCode(IN UINT16 StartLabelNumber,OUT VOID ** StartOpCodeHandle,OUT EFI_IFR_GUID_LABEL ** StartLabel,OUT VOID ** EndOpCodeHandle,OUT EFI_IFR_GUID_LABEL ** EndLabel)325 Ip6CreateOpCode (
326   IN  UINT16                        StartLabelNumber,
327   OUT VOID                          **StartOpCodeHandle,
328   OUT EFI_IFR_GUID_LABEL            **StartLabel,
329   OUT VOID                          **EndOpCodeHandle,
330   OUT EFI_IFR_GUID_LABEL            **EndLabel
331   )
332 {
333   EFI_STATUS                        Status;
334   EFI_IFR_GUID_LABEL                *InternalStartLabel;
335   EFI_IFR_GUID_LABEL                *InternalEndLabel;
336 
337   if (StartOpCodeHandle == NULL || StartLabel == NULL || EndOpCodeHandle == NULL || EndLabel == NULL) {
338     return EFI_INVALID_PARAMETER;
339   }
340 
341   *StartOpCodeHandle = NULL;
342   *EndOpCodeHandle   = NULL;
343   Status             = EFI_OUT_OF_RESOURCES;
344 
345   //
346   // Initialize the container for dynamic opcodes.
347   //
348   *StartOpCodeHandle = HiiAllocateOpCodeHandle ();
349   if (*StartOpCodeHandle == NULL) {
350     return Status;
351   }
352 
353   *EndOpCodeHandle = HiiAllocateOpCodeHandle ();
354   if (*EndOpCodeHandle == NULL) {
355     goto Exit;
356   }
357 
358   //
359   // Create Hii Extend Label OpCode as the start opcode.
360   //
361   InternalStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
362                                                 *StartOpCodeHandle,
363                                                 &gEfiIfrTianoGuid,
364                                                 NULL,
365                                                 sizeof (EFI_IFR_GUID_LABEL)
366                                                 );
367   if (InternalStartLabel == NULL) {
368     goto Exit;
369   }
370 
371   InternalStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
372   InternalStartLabel->Number       = StartLabelNumber;
373 
374   //
375   // Create Hii Extend Label OpCode as the end opcode.
376   //
377   InternalEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
378                                               *EndOpCodeHandle,
379                                               &gEfiIfrTianoGuid,
380                                               NULL,
381                                               sizeof (EFI_IFR_GUID_LABEL)
382                                               );
383   if (InternalEndLabel == NULL) {
384     goto Exit;
385   }
386 
387   InternalEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
388   InternalEndLabel->Number       = LABEL_END;
389 
390   *StartLabel = InternalStartLabel;
391   *EndLabel   = InternalEndLabel;
392 
393   return EFI_SUCCESS;
394 
395 Exit:
396 
397   if (*StartOpCodeHandle != NULL) {
398     HiiFreeOpCodeHandle (*StartOpCodeHandle);
399   }
400 
401   if (*EndOpCodeHandle != NULL) {
402     HiiFreeOpCodeHandle (*EndOpCodeHandle);
403   }
404 
405   return Status;
406 }
407 
408 /**
409   This function converts the different format of address list to string format and
410   then generates the corresponding text opcode to illustrate the address info in
411   IP6 configuration page. Currently, the following formats are supported:
412   EFI_IP6_ADDRESS_INFO AddressType: Ip6ConfigNvHostAddress;
413   EFI_IPv6_ADDRESS     AddressType: Ip6ConfigNvGatewayAddress and Ip6ConfigNvDnsAddress;
414   EFI_IP6_ROUTE_TABLE  AddressType: Ip6ConfigNvRouteTable.
415 
416   @param[in, out] String           The pointer to the buffer to store the converted
417                                    string.
418   @param[in]      HiiHandle        A handle that was previously registered in the
419                                    HII Database.
420   @param[in]      AddressType      The address type.
421   @param[in]      AddressInfo      Pointer to the address list.
422   @param[in]      AddressCount     The address count of the address list.
423 
424   @retval EFI_SUCCESS              The operation finished successfully.
425   @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.
426   @retval EFI_UNSUPPORTED          The AddressType is not supported.
427 
428 
429 **/
430 EFI_STATUS
Ip6ConvertAddressListToString(IN OUT CHAR16 * String,IN EFI_HII_HANDLE HiiHandle,IN IP6_CONFIG_NV_ADDRESS_TYPE AddressType,IN VOID * AddressInfo,IN UINTN AddressCount)431 Ip6ConvertAddressListToString (
432   IN OUT CHAR16                         *String,
433   IN     EFI_HII_HANDLE                 HiiHandle,
434   IN     IP6_CONFIG_NV_ADDRESS_TYPE     AddressType,
435   IN     VOID                           *AddressInfo,
436   IN     UINTN                          AddressCount
437   )
438 {
439   UINTN                          Index;
440   UINTN                          Number;
441   CHAR16                         *TempStr;
442   EFI_STATUS                     Status;
443   VOID                           *StartOpCodeHandle;
444   EFI_IFR_GUID_LABEL             *StartLabel;
445   VOID                           *EndOpCodeHandle;
446   EFI_IFR_GUID_LABEL             *EndLabel;
447   UINT16                         StartLabelNumber;
448   EFI_STRING_ID                  TextTwo;
449   UINT8                          *AddressHead;
450   UINT8                          PrefixLength;
451   EFI_IPv6_ADDRESS               *Address;
452 
453   if ((String == NULL) || (HiiHandle == NULL) || (AddressInfo == NULL)) {
454     return EFI_INVALID_PARAMETER;
455   }
456 
457   if (AddressType == Ip6ConfigNvHostAddress) {
458     StartLabelNumber = HOST_ADDRESS_LABEL;
459   } else if (AddressType == Ip6ConfigNvGatewayAddress) {
460     StartLabelNumber = GATEWAY_ADDRESS_LABEL;
461   } else if (AddressType == Ip6ConfigNvDnsAddress) {
462     StartLabelNumber = DNS_ADDRESS_LABEL;
463   } else if (AddressType == Ip6ConfigNvRouteTable) {
464     StartLabelNumber = ROUTE_TABLE_LABEL;
465   } else {
466     ASSERT (FALSE);
467     return EFI_UNSUPPORTED;
468   }
469 
470   Status = Ip6CreateOpCode (
471              StartLabelNumber,
472              &StartOpCodeHandle,
473              &StartLabel,
474              &EndOpCodeHandle,
475              &EndLabel
476              );
477   if (EFI_ERROR (Status)) {
478     return Status;
479   }
480 
481   AddressHead = (UINT8 *) AddressInfo;
482 
483   for (Index = 0; Index < AddressCount; Index++) {
484     if (AddressType == Ip6ConfigNvHostAddress) {
485       AddressInfo = AddressHead + sizeof (EFI_IP6_ADDRESS_INFO) * Index;
486       Address     = &((EFI_IP6_ADDRESS_INFO *) AddressInfo)->Address;
487     } else if (AddressType == Ip6ConfigNvRouteTable) {
488       AddressInfo = AddressHead + sizeof (EFI_IP6_ROUTE_TABLE) * Index;
489       Address     = &((EFI_IP6_ROUTE_TABLE *) AddressInfo)->Destination;
490     } else {
491       AddressInfo = AddressHead + sizeof (EFI_IPv6_ADDRESS) * Index;
492       Address     = AddressInfo;
493     }
494 
495     //
496     // Convert the IP address info to string.
497     //
498     Ip6ToStr (Address, String);
499     TempStr = String + StrLen (String);
500 
501     if ((AddressType == Ip6ConfigNvHostAddress) || (AddressType == Ip6ConfigNvRouteTable)) {
502       if (AddressType == Ip6ConfigNvHostAddress) {
503         PrefixLength = ((EFI_IP6_ADDRESS_INFO *) AddressInfo)->PrefixLength;
504       } else {
505         PrefixLength = ((EFI_IP6_ROUTE_TABLE *) AddressInfo)->PrefixLength;
506       }
507 
508       //
509       // Append the prefix length to the string.
510       //
511       *TempStr = L'/';
512       TempStr++;
513       Number  = UnicodeSPrint (TempStr, 6, L"%d", PrefixLength);
514       TempStr = TempStr + Number;
515     }
516 
517     if (AddressType == Ip6ConfigNvRouteTable) {
518       //
519       // Append " >> " to the string.
520       //
521       Number   = UnicodeSPrint (TempStr, 8, L" >>  ");
522       TempStr  = TempStr + Number;
523 
524       //
525       // Append the gateway address to the string.
526       //
527       Ip6ToStr (&((EFI_IP6_ROUTE_TABLE *) AddressInfo)->Gateway, TempStr);
528       TempStr = TempStr + StrLen (TempStr);
529     }
530 
531     //
532     // Generate a text opcode and update the UI.
533     //
534     TextTwo = HiiSetString (HiiHandle, 0, String, NULL);
535     if (TextTwo == 0) {
536       Status = EFI_INVALID_PARAMETER;
537       goto Exit;
538     }
539 
540     HiiCreateTextOpCode (StartOpCodeHandle, STR_NULL, STR_NULL, TextTwo);
541 
542     String = TempStr;
543     *String = IP6_ADDRESS_DELIMITER;
544     String++;
545   }
546 
547   *(String - 1) = '\0';
548 
549   Status = HiiUpdateForm (
550              HiiHandle,                       // HII handle
551              &gIp6ConfigNvDataGuid,           // Formset GUID
552              FORMID_MAIN_FORM,                // Form ID
553              StartOpCodeHandle,               // Label for where to insert opcodes
554              EndOpCodeHandle                  // Replace data
555              );
556 
557 Exit:
558   HiiFreeOpCodeHandle (StartOpCodeHandle);
559   HiiFreeOpCodeHandle (EndOpCodeHandle);
560 
561   return Status;
562 }
563 
564 /**
565   Parse address list in string format and convert it to a list array of node in
566   IP6_ADDRESS_INFO_ENTRY.
567 
568   @param[in]        String         The buffer to string to be parsed.
569   @param[out]       ListHead       The list head of array.
570   @param[out]       AddressCount   The number of list nodes in the array.
571 
572   @retval EFI_SUCCESS              The operation finished successfully.
573   @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.
574   @retval EFI_OUT_OF_RESOURCES     Failed to perform the operation due to lack of resource.
575 
576 **/
577 EFI_STATUS
Ip6ParseAddressListFromString(IN CONST CHAR16 * String,OUT LIST_ENTRY * ListHead,OUT UINT32 * AddressCount)578 Ip6ParseAddressListFromString (
579   IN CONST CHAR16                    *String,
580   OUT LIST_ENTRY                     *ListHead,
581   OUT UINT32                         *AddressCount
582   )
583 {
584   EFI_STATUS                     Status;
585   CHAR16                         *LocalString;
586   CHAR16                         *Temp;
587   CHAR16                         *TempStr;
588   EFI_IP6_ADDRESS_INFO           AddressInfo;
589   IP6_ADDRESS_INFO_ENTRY         *Node;
590   BOOLEAN                        Last;
591   UINT32                         Count;
592 
593   if ((String == NULL) || (ListHead == NULL) || (AddressCount == NULL)) {
594     return EFI_INVALID_PARAMETER;
595   }
596 
597   ZeroMem (&AddressInfo, sizeof (EFI_IP6_ADDRESS_INFO));
598   LocalString = (CHAR16 *) AllocateCopyPool (StrSize (String), String);
599   if (LocalString == NULL) {
600     return EFI_OUT_OF_RESOURCES;
601   }
602 
603   //
604   // Clean the original address list.
605   //
606   Ip6FreeAddressInfoList (ListHead);
607 
608   Temp  = LocalString;
609   Last  = FALSE;
610   Count = 0;
611 
612   while (*LocalString != L'\0') {
613     TempStr = LocalString;
614     while ((*LocalString != L'\0') && (*LocalString != IP6_ADDRESS_DELIMITER)) {
615       LocalString++;
616     }
617 
618     if (*LocalString == L'\0') {
619       Last = TRUE;
620     }
621 
622     *LocalString = L'\0';
623 
624     Status = NetLibStrToIp6andPrefix (TempStr, &AddressInfo.Address, &AddressInfo.PrefixLength);
625     if (EFI_ERROR (Status)) {
626       goto Error;
627     }
628 
629     if (AddressInfo.PrefixLength == 0xFF) {
630       AddressInfo.PrefixLength = 0;
631     }
632 
633     if (!NetIp6IsValidUnicast (&AddressInfo.Address)) {
634       Status = EFI_INVALID_PARAMETER;
635       goto Error;
636     }
637 
638     Node = AllocatePool (sizeof (IP6_ADDRESS_INFO_ENTRY));
639     if (Node == NULL) {
640       Status = EFI_OUT_OF_RESOURCES;
641       goto Error;
642     }
643 
644     CopyMem (&Node->AddrInfo, &AddressInfo, sizeof (EFI_IP6_ADDRESS_INFO));
645     InsertTailList (ListHead, &Node->Link);
646     Count++;
647 
648     if (Last) {
649       break;
650     }
651 
652     LocalString++;
653   }
654 
655   FreePool (Temp);
656   *AddressCount = Count;
657   return EFI_SUCCESS;
658 
659 Error:
660   Ip6FreeAddressInfoList (ListHead);
661   FreePool (Temp);
662   return Status;
663 }
664 
665 /**
666   This function converts the interface info to string and draws it to the IP6 UI.
667   The interface information includes interface name, interface type, hardware
668   address and route table information.
669 
670   @param[in]       IfInfo          The pointer of EFI_IP6_CONFIG_INTERFACE_INFO.
671   @param[in]       HiiHandle       The handle that was previously registered in the
672                                    HII Database.
673   @param[in, out]  IfrNvData       Points to IP6_CONFIG_IFR_NVDATA.
674 
675   @retval EFI_SUCCESS              The operation finished successfully.
676   @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.
677   @retval EFI_OUT_OF_RESOURCES     The operation failed due to lack of resources.
678 
679 **/
680 EFI_STATUS
Ip6ConvertInterfaceInfoToString(IN EFI_IP6_CONFIG_INTERFACE_INFO * IfInfo,IN EFI_HII_HANDLE HiiHandle,IN OUT IP6_CONFIG_IFR_NVDATA * IfrNvData)681 Ip6ConvertInterfaceInfoToString (
682   IN     EFI_IP6_CONFIG_INTERFACE_INFO  *IfInfo,
683   IN     EFI_HII_HANDLE                 HiiHandle,
684   IN OUT IP6_CONFIG_IFR_NVDATA          *IfrNvData
685   )
686 {
687   UINT32                         Index;
688   UINTN                          Number;
689   CHAR16                         *String;
690   CHAR16                         PortString[ADDRESS_STR_MAX_SIZE];
691   CHAR16                         FormatString[8];
692   EFI_STRING_ID                  StringId;
693 
694   if ((IfInfo == NULL) || (HiiHandle == NULL) || (IfrNvData == NULL)) {
695     return EFI_INVALID_PARAMETER;
696   }
697 
698   //
699   // Print the interface name.
700   //
701   StringId = HiiSetString (
702                HiiHandle,
703                STRING_TOKEN (STR_IP6_INTERFACE_NAME_CONTENT),
704                IfInfo->Name,
705                NULL
706                );
707   if (StringId == 0) {
708     return EFI_OUT_OF_RESOURCES;
709   }
710 
711   //
712   // Print the interface type.
713   //
714   if (IfInfo->IfType == Ip6InterfaceTypeEthernet) {
715     CopyMem (PortString, IP6_ETHERNET, sizeof (IP6_ETHERNET));
716   } else if (IfInfo->IfType == Ip6InterfaceTypeExperimentalEthernet) {
717     CopyMem (PortString, IP6_EXPERIMENTAL_ETHERNET, sizeof (IP6_EXPERIMENTAL_ETHERNET));
718   } else {
719     //
720     // Refer to RFC1700, chapter Number Hardware Type.
721     //
722     UnicodeSPrint (PortString, 6, L"%d", IfInfo->IfType);
723   }
724 
725   StringId = HiiSetString (
726                HiiHandle,
727                STRING_TOKEN (STR_IP6_INTERFACE_TYPE_CONTENT),
728                PortString,
729                NULL
730                );
731   if (StringId == 0) {
732     return EFI_OUT_OF_RESOURCES;
733   }
734 
735   //
736   // Convert the hardware address.
737   //
738   String = PortString;
739   ASSERT (IfInfo->HwAddressSize <= 32);
740 
741   for (Index = 0; Index < IfInfo->HwAddressSize; Index++) {
742 
743     if (IfInfo->HwAddress.Addr[Index] < 0x10) {
744       CopyMem (FormatString, L"0%x-", sizeof (L"0%x-"));
745     } else {
746       CopyMem (FormatString, L"%x-", sizeof (L"%x-"));
747     }
748 
749     Number = UnicodeSPrint (
750                String,
751                8,
752                (CONST CHAR16 *) FormatString,
753                (UINTN) IfInfo->HwAddress.Addr[Index]
754                );
755     String = String + Number;
756   }
757 
758   if (Index != 0) {
759     ASSERT (String > PortString);
760     String--;
761     *String = '\0';
762   }
763 
764   //
765   // Print the hardware address.
766   //
767   StringId = HiiSetString (
768                HiiHandle,
769                STRING_TOKEN (STR_IP6_MAC_ADDRESS_CONTENT),
770                PortString,
771                NULL
772                );
773   if (StringId == 0) {
774     return EFI_OUT_OF_RESOURCES;
775   }
776 
777   return EFI_SUCCESS;
778 }
779 
780 /**
781   Build the address info list from list array of node in IP6_ADDRESS_INFO_ENTRY.
782 
783   @param[in]      Instance         Points to IP6 config instance data.
784   @param[in]      AddressType      The address type.
785   @param[out]     AddressInfo      The pointer to the buffer to store the address list.
786   @param[out]     AddressSize      The address size of the address list.
787 
788   @retval EFI_SUCCESS              The operation finished successfully.
789   @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.
790   @retval EFI_UNSUPPORTED          The AddressType is not supported.
791 
792 **/
793 EFI_STATUS
Ip6BuildNvAddressInfo(IN IP6_CONFIG_INSTANCE * Instance,IN IP6_CONFIG_NV_ADDRESS_TYPE AddressType,OUT VOID ** AddressInfo,OUT UINTN * AddressSize)794 Ip6BuildNvAddressInfo (
795   IN  IP6_CONFIG_INSTANCE            *Instance,
796   IN  IP6_CONFIG_NV_ADDRESS_TYPE     AddressType,
797   OUT VOID                           **AddressInfo,
798   OUT UINTN                          *AddressSize
799   )
800 {
801   IP6_CONFIG_NVDATA                  *Ip6NvData;
802   LIST_ENTRY                         *Entry;
803   LIST_ENTRY                         *ListHead;
804   IP6_ADDRESS_INFO_ENTRY             *Node;
805   VOID                               *AddressList;
806   VOID                               *TmpStr;
807   UINTN                              DataSize;
808   EFI_IPv6_ADDRESS                   *Ip6Address;
809   EFI_IP6_CONFIG_MANUAL_ADDRESS      *ManualAddress;
810 
811   if ((Instance == NULL) || (AddressInfo == NULL) || (AddressSize == NULL)) {
812     return EFI_INVALID_PARAMETER;
813   }
814 
815   NET_CHECK_SIGNATURE (Instance, IP6_CONFIG_INSTANCE_SIGNATURE);
816 
817   Ip6NvData = &Instance->Ip6NvData;
818 
819   if (AddressType == Ip6ConfigNvHostAddress) {
820     ListHead = &Ip6NvData->ManualAddress;
821     DataSize = sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS) * Ip6NvData->ManualAddressCount;
822   } else if (AddressType == Ip6ConfigNvGatewayAddress) {
823     ListHead = &Ip6NvData->GatewayAddress;
824     DataSize = sizeof (EFI_IPv6_ADDRESS) * Ip6NvData->GatewayAddressCount;
825   } else if (AddressType == Ip6ConfigNvDnsAddress) {
826     ListHead = &Ip6NvData->DnsAddress;
827     DataSize = sizeof (EFI_IPv6_ADDRESS) * Ip6NvData->DnsAddressCount;
828   } else {
829     return EFI_UNSUPPORTED;
830   }
831 
832   AddressList = AllocateZeroPool (DataSize);
833   if (AddressList  == NULL) {
834     return EFI_OUT_OF_RESOURCES;
835   }
836 
837   TmpStr = AddressList;
838 
839   NET_LIST_FOR_EACH (Entry, ListHead) {
840     Node = NET_LIST_USER_STRUCT (Entry, IP6_ADDRESS_INFO_ENTRY, Link);
841     if (AddressType == Ip6ConfigNvHostAddress) {
842       ManualAddress = (EFI_IP6_CONFIG_MANUAL_ADDRESS *) AddressList;
843       IP6_COPY_ADDRESS (&ManualAddress->Address, &Node->AddrInfo.Address);
844       ManualAddress->PrefixLength = Node->AddrInfo.PrefixLength;
845       AddressList = (UINT8 *) AddressList + sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS);
846     } else {
847       Ip6Address = (EFI_IPv6_ADDRESS *) AddressList;
848       IP6_COPY_ADDRESS (Ip6Address, &Node->AddrInfo.Address);
849       AddressList = (UINT8 *) AddressList + sizeof (EFI_IPv6_ADDRESS);
850     }
851   }
852 
853   *AddressInfo = TmpStr;
854   *AddressSize = DataSize;
855   return EFI_SUCCESS;
856 }
857 
858 /**
859   Convert the IP6 configuration data into the IFR data.
860 
861   @param[in, out]  IfrNvData       The IFR NV data.
862   @param[in]       Instance        The IP6 config instance data.
863 
864   @retval EFI_SUCCESS              The operation finished successfully.
865   @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.
866   @retval EFI_UNSUPPORTED          The policy is not supported in the current implementation.
867   @retval Others                   Other errors as indicated.
868 
869 **/
870 EFI_STATUS
Ip6ConvertConfigNvDataToIfrNvData(IN OUT IP6_CONFIG_IFR_NVDATA * IfrNvData,IN IP6_CONFIG_INSTANCE * Instance)871 Ip6ConvertConfigNvDataToIfrNvData (
872   IN OUT IP6_CONFIG_IFR_NVDATA       *IfrNvData,
873   IN     IP6_CONFIG_INSTANCE         *Instance
874   )
875 {
876   IP6_CONFIG_NVDATA                          *Ip6NvData;
877   EFI_IP6_CONFIG_PROTOCOL                    *Ip6Config;
878   UINTN                                      DataSize;
879   VOID                                       *Data;
880   EFI_STATUS                                 Status;
881   EFI_IP6_CONFIG_POLICY                      Policy;
882   EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS   DadXmits;
883   EFI_HII_HANDLE                             HiiHandle;
884 
885   if ((IfrNvData == NULL) || (Instance == NULL)) {
886     return EFI_INVALID_PARAMETER;
887   }
888 
889   NET_CHECK_SIGNATURE (Instance, IP6_CONFIG_INSTANCE_SIGNATURE);
890 
891   Ip6Config = &Instance->Ip6Config;
892   Ip6NvData = &Instance->Ip6NvData;
893   Data      = NULL;
894   DataSize  = 0;
895   HiiHandle = Instance->CallbackInfo.RegisteredHandle;
896 
897   //
898   // Get the current interface info.
899   //
900   Status = Ip6ConfigNvGetData (
901              Ip6Config,
902              Ip6ConfigDataTypeInterfaceInfo,
903              &DataSize,
904              (VOID **) &Data
905              );
906   if (EFI_ERROR (Status)) {
907     goto Exit;
908   }
909 
910   //
911   // Convert the interface info to string and print.
912   //
913   Status = Ip6ConvertInterfaceInfoToString (
914              (EFI_IP6_CONFIG_INTERFACE_INFO *) Data,
915              HiiHandle,
916              IfrNvData
917              );
918   if (EFI_ERROR (Status)) {
919     goto Exit;
920   }
921 
922   //
923   // Get the interface id.
924   //
925   DataSize = sizeof (EFI_IP6_CONFIG_INTERFACE_ID);
926   ZeroMem (&Ip6NvData->InterfaceId, DataSize);
927   Status = Ip6Config->GetData (
928                         Ip6Config,
929                         Ip6ConfigDataTypeAltInterfaceId,
930                         &DataSize,
931                         &Ip6NvData->InterfaceId
932                         );
933   if (EFI_ERROR (Status)) {
934     goto Exit;
935   }
936 
937   Ip6ConvertInterfaceIdToString (IfrNvData->InterfaceId, &Ip6NvData->InterfaceId);
938 
939   //
940   // Get current policy.
941   //
942   DataSize = sizeof (EFI_IP6_CONFIG_POLICY);
943   Status   = Ip6Config->GetData (
944                           Ip6Config,
945                           Ip6ConfigDataTypePolicy,
946                           &DataSize,
947                           &Policy
948                           );
949 
950   if (EFI_ERROR (Status)) {
951     goto Exit;
952   }
953 
954   if (Policy == Ip6ConfigPolicyManual) {
955     IfrNvData->Policy = IP6_POLICY_MANUAL;
956   } else if (Policy == Ip6ConfigPolicyAutomatic) {
957     IfrNvData->Policy = IP6_POLICY_AUTO;
958   } else {
959     ASSERT (FALSE);
960     Status = EFI_UNSUPPORTED;
961     goto Exit;
962   }
963 
964   //
965   // Get Duplicate Address Detection Transmits count.
966   //
967   DataSize = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS);
968   Status   = Ip6Config->GetData (
969                           Ip6Config,
970                           Ip6ConfigDataTypeDupAddrDetectTransmits,
971                           &DataSize,
972                           &DadXmits
973                           );
974 
975   if (EFI_ERROR (Status)) {
976     goto Exit;
977   }
978 
979   IfrNvData->DadTransmitCount = DadXmits.DupAddrDetectTransmits;
980 
981 Exit:
982   if (Data != NULL) {
983      FreePool (Data);
984   }
985 
986   return Status;
987 }
988 
989 /**
990   Convert IFR data into IP6 configuration data. The policy, alternative interface
991   ID, and DAD transmit counts, and will be saved.
992 
993   @param[in]       IfrNvData       The IFR NV data.
994   @param[in, out]  Instance        The IP6 config instance data.
995 
996   @retval EFI_SUCCESS              The operation finished successfully.
997   @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.
998   @retval Others                   Other errors as indicated.
999 
1000 **/
1001 EFI_STATUS
Ip6ConvertIfrNvDataToConfigNvDataGeneral(IN IP6_CONFIG_IFR_NVDATA * IfrNvData,IN OUT IP6_CONFIG_INSTANCE * Instance)1002 Ip6ConvertIfrNvDataToConfigNvDataGeneral (
1003   IN     IP6_CONFIG_IFR_NVDATA       *IfrNvData,
1004   IN OUT IP6_CONFIG_INSTANCE         *Instance
1005   )
1006 {
1007   IP6_CONFIG_NVDATA                  *Ip6NvData;
1008   EFI_IP6_CONFIG_PROTOCOL            *Ip6Config;
1009   EFI_STATUS                         Status;
1010 
1011   if ((IfrNvData == NULL) || (Instance == NULL)) {
1012     return EFI_INVALID_PARAMETER;
1013   }
1014 
1015   NET_CHECK_SIGNATURE (Instance, IP6_CONFIG_INSTANCE_SIGNATURE);
1016   Ip6NvData = &Instance->Ip6NvData;
1017   Ip6Config = &Instance->Ip6Config;
1018 
1019   //
1020   // Update those fields which don't have INTERACTIVE attribute.
1021   //
1022   if (IfrNvData->Policy == IP6_POLICY_AUTO) {
1023     Ip6NvData->Policy = Ip6ConfigPolicyAutomatic;
1024   } else if (IfrNvData->Policy == IP6_POLICY_MANUAL) {
1025     Ip6NvData->Policy = Ip6ConfigPolicyManual;
1026   }
1027 
1028   Ip6NvData->DadTransmitCount.DupAddrDetectTransmits = IfrNvData->DadTransmitCount;
1029 
1030   //
1031   // Set the configured policy.
1032   //
1033   Status = Ip6Config->SetData (
1034                         Ip6Config,
1035                         Ip6ConfigDataTypePolicy,
1036                         sizeof (EFI_IP6_CONFIG_POLICY),
1037                         &Ip6NvData->Policy
1038                         );
1039   if (EFI_ERROR (Status)) {
1040     return Status;
1041   }
1042 
1043   //
1044   // Set the duplicate address detection transmits count.
1045   //
1046   Status = Ip6Config->SetData (
1047                         Ip6Config,
1048                         Ip6ConfigDataTypeDupAddrDetectTransmits,
1049                         sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS),
1050                         &Ip6NvData->DadTransmitCount
1051                         );
1052   if (EFI_ERROR (Status)) {
1053     return Status;
1054   }
1055 
1056   //
1057   // Set the alternative interface ID
1058   //
1059   Status = Ip6Config->SetData (
1060                         Ip6Config,
1061                         Ip6ConfigDataTypeAltInterfaceId,
1062                         sizeof (EFI_IP6_CONFIG_INTERFACE_ID),
1063                         &Ip6NvData->InterfaceId
1064                         );
1065   if (EFI_ERROR (Status)) {
1066     return Status;
1067   }
1068 
1069   return EFI_SUCCESS;
1070 }
1071 
1072 /**
1073   Convert IFR data into IP6 configuration data. The policy, configured
1074   manual address, gateway address, and DNS server address will be saved.
1075 
1076   @param[in]       IfrNvData       The IFR NV data.
1077   @param[in, out]  Instance        The IP6 config instance data.
1078 
1079   @retval EFI_SUCCESS              The operation finished successfully.
1080   @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.
1081   @retval Others                   Other errors as indicated.
1082 
1083 **/
1084 EFI_STATUS
Ip6ConvertIfrNvDataToConfigNvDataAdvanced(IN IP6_CONFIG_IFR_NVDATA * IfrNvData,IN OUT IP6_CONFIG_INSTANCE * Instance)1085 Ip6ConvertIfrNvDataToConfigNvDataAdvanced (
1086   IN     IP6_CONFIG_IFR_NVDATA       *IfrNvData,
1087   IN OUT IP6_CONFIG_INSTANCE         *Instance
1088   )
1089 {
1090   IP6_CONFIG_NVDATA                  *Ip6NvData;
1091   EFI_IP6_CONFIG_PROTOCOL            *Ip6Config;
1092   EFI_STATUS                         Status;
1093   EFI_IP6_CONFIG_MANUAL_ADDRESS      *ManualAddress;
1094   EFI_IPv6_ADDRESS                   *Address;
1095   BOOLEAN                            IsAddressOk;
1096   EFI_EVENT                          SetAddressEvent;
1097   EFI_EVENT                          TimeoutEvent;
1098   UINTN                              DataSize;
1099 
1100   if ((IfrNvData == NULL) || (Instance == NULL)) {
1101     return EFI_INVALID_PARAMETER;
1102   }
1103 
1104   if (IfrNvData->Policy == IP6_POLICY_AUTO) {
1105     return EFI_SUCCESS;
1106   }
1107 
1108   NET_CHECK_SIGNATURE (Instance, IP6_CONFIG_INSTANCE_SIGNATURE);
1109   Ip6NvData = &Instance->Ip6NvData;
1110   Ip6Config = &Instance->Ip6Config;
1111 
1112   //
1113   // Update those fields which don't have INTERACTIVE attribute.
1114   //
1115   Ip6NvData->Policy = Ip6ConfigPolicyManual;
1116 
1117   //
1118   // Set the configured policy.
1119   //
1120   Status = Ip6Config->SetData (
1121                         Ip6Config,
1122                         Ip6ConfigDataTypePolicy,
1123                         sizeof (EFI_IP6_CONFIG_POLICY),
1124                         &Ip6NvData->Policy
1125                         );
1126   if (EFI_ERROR (Status)) {
1127     return Status;
1128   }
1129 
1130   //
1131   // Create events & timers for asynchronous settings.
1132   //
1133   SetAddressEvent = NULL;
1134   TimeoutEvent    = NULL;
1135   ManualAddress   = NULL;
1136   Address         = NULL;
1137 
1138   Status = gBS->CreateEvent (
1139                   EVT_NOTIFY_SIGNAL,
1140                   TPL_NOTIFY,
1141                   Ip6ConfigManualAddressNotify,
1142                   &IsAddressOk,
1143                   &SetAddressEvent
1144                   );
1145   if (EFI_ERROR (Status)) {
1146     goto Exit;
1147   }
1148 
1149   Status = gBS->CreateEvent (
1150                   EVT_TIMER,
1151                   TPL_CALLBACK,
1152                   NULL,
1153                   NULL,
1154                   &TimeoutEvent
1155                   );
1156   if (EFI_ERROR (Status)) {
1157     goto Exit;
1158   }
1159 
1160   //
1161   // Set the manual address list. This is an asynchronous process.
1162   //
1163   if (!IsListEmpty (&Ip6NvData->ManualAddress) && (Ip6NvData->ManualAddressCount != 0)) {
1164     Status = Ip6BuildNvAddressInfo (
1165                Instance,
1166                Ip6ConfigNvHostAddress,
1167                (VOID **) &ManualAddress,
1168                &DataSize
1169                );
1170     if (EFI_ERROR (Status)) {
1171       goto Exit;
1172     }
1173 
1174     IsAddressOk = FALSE;
1175 
1176     Status = Ip6Config->RegisterDataNotify (
1177                           Ip6Config,
1178                           Ip6ConfigDataTypeManualAddress,
1179                           SetAddressEvent
1180                           );
1181     if (EFI_ERROR (Status)) {
1182       goto Exit;
1183     }
1184 
1185     Status = Ip6Config->SetData (
1186                           Ip6Config,
1187                           Ip6ConfigDataTypeManualAddress,
1188                           DataSize,
1189                           (VOID *) ManualAddress
1190                           );
1191     if (Status == EFI_NOT_READY) {
1192       gBS->SetTimer (TimeoutEvent, TimerRelative, 50000000);
1193       while (EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
1194         if (IsAddressOk) {
1195           Status = EFI_SUCCESS;
1196         }
1197         break;
1198       }
1199     }
1200 
1201     Status = Ip6Config->UnregisterDataNotify (
1202                           Ip6Config,
1203                           Ip6ConfigDataTypeManualAddress,
1204                           SetAddressEvent
1205                           );
1206     if (EFI_ERROR (Status)) {
1207       goto Exit;
1208     }
1209   }
1210 
1211   //
1212   // Set gateway address list.
1213   //
1214   if (!IsListEmpty (&Ip6NvData->GatewayAddress) && (Ip6NvData->GatewayAddressCount != 0)) {
1215     Status = Ip6BuildNvAddressInfo (
1216                Instance,
1217                Ip6ConfigNvGatewayAddress,
1218                (VOID **) &Address,
1219                &DataSize
1220                );
1221     if (EFI_ERROR (Status)) {
1222       goto Exit;
1223     }
1224 
1225     Status = Ip6Config->SetData (
1226                           Ip6Config,
1227                           Ip6ConfigDataTypeGateway,
1228                           DataSize,
1229                           (VOID *) Address
1230                           );
1231     if (EFI_ERROR (Status)) {
1232       goto Exit;
1233     }
1234 
1235     FreePool (Address);
1236     Address = NULL;
1237   }
1238 
1239   //
1240   // Set DNS server address list.
1241   //
1242   if (!IsListEmpty (&Ip6NvData->DnsAddress) && (Ip6NvData->DnsAddressCount != 0)) {
1243     Status = Ip6BuildNvAddressInfo (
1244                Instance,
1245                Ip6ConfigNvDnsAddress,
1246                (VOID **) &Address,
1247                &DataSize
1248                );
1249     if (EFI_ERROR (Status)) {
1250       goto Exit;
1251     }
1252 
1253     Status = Ip6Config->SetData (
1254                           Ip6Config,
1255                           Ip6ConfigDataTypeDnsServer,
1256                           DataSize,
1257                           (VOID *) Address
1258                           );
1259     if (EFI_ERROR (Status)) {
1260       goto Exit;
1261     }
1262   }
1263 
1264   Status = EFI_SUCCESS;
1265 
1266 Exit:
1267   if (SetAddressEvent != NULL) {
1268     gBS->CloseEvent (SetAddressEvent);
1269   }
1270 
1271   if (TimeoutEvent != NULL) {
1272     gBS->CloseEvent (TimeoutEvent);
1273   }
1274 
1275   if (ManualAddress != NULL) {
1276     FreePool (ManualAddress);
1277   }
1278 
1279   if (Address != NULL) {
1280     FreePool (Address);
1281   }
1282 
1283   return Status;
1284 }
1285 
1286 
1287 /**
1288   This function allows the caller to request the current
1289   configuration for one or more named elements. The resulting
1290   string is in <ConfigAltResp> format. Any and all alternative
1291   configuration strings shall also be appended to the end of the
1292   current configuration string. If they are, they must appear
1293   after the current configuration. They must contain the same
1294   routing (GUID, NAME, PATH) as the current configuration string.
1295   They must have an additional description indicating the type of
1296   alternative configuration the string represents,
1297   "ALTCFG=<StringToken>". That <StringToken> (when
1298   converted from Hex UNICODE to binary) is a reference to a
1299   string in the associated string pack.
1300 
1301   @param[in] This       Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
1302   @param[in] Request    A null-terminated Unicode string in
1303                         <ConfigRequest> format. Note that this
1304                         includes the routing information as well as
1305                         the configurable name / value pairs. It is
1306                         invalid for this string to be in
1307                         <MultiConfigRequest> format.
1308   @param[out] Progress  On return, points to a character in the
1309                         Request string. Points to the string's null
1310                         terminator if request was successful. Points
1311                         to the most recent "&" before the first
1312                         failing name / value pair (or the beginning
1313                         of the string if the failure is in the first
1314                         name / value pair) if the request was not
1315                         successful.
1316   @param[out] Results   A null-terminated Unicode string in
1317                         <ConfigAltResp> format which has all values
1318                         filled in for the names in the Request string.
1319                         String to be allocated by the called function.
1320 
1321   @retval EFI_SUCCESS             The Results string is filled with the
1322                                   values corresponding to all requested
1323                                   names.
1324   @retval EFI_OUT_OF_RESOURCES    Not enough memory to store the
1325                                   parts of the results that must be
1326                                   stored awaiting possible future
1327                                   protocols.
1328   @retval EFI_INVALID_PARAMETER   For example, passing in a NULL
1329                                   for the Request parameter
1330                                   would result in this type of
1331                                   error. In this case, the
1332                                   Progress parameter would be
1333                                   set to NULL.
1334   @retval EFI_NOT_FOUND           Routing data doesn't match any
1335                                   known driver. Progress set to the
1336                                   first character in the routing header.
1337                                   Note: There is no requirement that the
1338                                   driver validate the routing data. It
1339                                   must skip the <ConfigHdr> in order to
1340                                   process the names.
1341   @retval EFI_INVALID_PARAMETER   Illegal syntax. Progress set
1342                                   to most recent & before the
1343                                   error or the beginning of the
1344                                   string.
1345   @retval EFI_INVALID_PARAMETER   Unknown name. Progress points
1346                                   to the & before the name in
1347                                   question. Currently not implemented.
1348 **/
1349 EFI_STATUS
1350 EFIAPI
Ip6FormExtractConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Request,OUT EFI_STRING * Progress,OUT EFI_STRING * Results)1351 Ip6FormExtractConfig (
1352   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
1353   IN  CONST EFI_STRING                       Request,
1354   OUT EFI_STRING                             *Progress,
1355   OUT EFI_STRING                             *Results
1356   )
1357 {
1358 
1359   EFI_STATUS                                 Status;
1360   IP6_FORM_CALLBACK_INFO                     *Private;
1361   IP6_CONFIG_INSTANCE                        *Ip6ConfigInstance;
1362   IP6_CONFIG_IFR_NVDATA                      *IfrNvData;
1363   EFI_STRING                                 ConfigRequestHdr;
1364   EFI_STRING                                 ConfigRequest;
1365   BOOLEAN                                    AllocatedRequest;
1366   UINTN                                      Size;
1367   UINTN                                      BufferSize;
1368 
1369   if (This == NULL || Progress == NULL || Results == NULL) {
1370     return EFI_INVALID_PARAMETER;
1371   }
1372 
1373   *Progress = Request;
1374   if ((Request != NULL) &&
1375       !HiiIsConfigHdrMatch (Request, &gIp6ConfigNvDataGuid, mIp6ConfigStorageName)) {
1376     return EFI_NOT_FOUND;
1377   }
1378 
1379   ConfigRequestHdr = NULL;
1380   ConfigRequest    = NULL;
1381   AllocatedRequest = FALSE;
1382   Size             = 0;
1383 
1384   Private = IP6_FORM_CALLBACK_INFO_FROM_CONFIG_ACCESS (This);
1385   Ip6ConfigInstance = IP6_CONFIG_INSTANCE_FROM_FORM_CALLBACK (Private);
1386   BufferSize = sizeof (IP6_CONFIG_IFR_NVDATA);
1387 
1388   IfrNvData = (IP6_CONFIG_IFR_NVDATA *) AllocateZeroPool (BufferSize);
1389   if (IfrNvData == NULL) {
1390     return EFI_OUT_OF_RESOURCES;
1391   }
1392 
1393   Status = Ip6ConvertConfigNvDataToIfrNvData (IfrNvData, Ip6ConfigInstance);
1394   if (EFI_ERROR (Status)) {
1395     goto Exit;
1396   }
1397 
1398   ConfigRequest = Request;
1399   if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
1400     //
1401     // Request has no request element, construct full request string.
1402     // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
1403     // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator.
1404     //
1405     ConfigRequestHdr = HiiConstructConfigHdr (
1406                          &gIp6ConfigNvDataGuid,
1407                          mIp6ConfigStorageName,
1408                          Private->ChildHandle
1409                          );
1410     Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
1411     ConfigRequest = AllocateZeroPool (Size);
1412     ASSERT (ConfigRequest != NULL);
1413     AllocatedRequest = TRUE;
1414     UnicodeSPrint (
1415       ConfigRequest,
1416       Size,
1417       L"%s&OFFSET=0&WIDTH=%016LX",
1418       ConfigRequestHdr,
1419       (UINT64) BufferSize
1420       );
1421     FreePool (ConfigRequestHdr);
1422   }
1423 
1424   //
1425   // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
1426   //
1427   Status = gHiiConfigRouting->BlockToConfig (
1428                                 gHiiConfigRouting,
1429                                 ConfigRequest,
1430                                 (UINT8 *) IfrNvData,
1431                                 BufferSize,
1432                                 Results,
1433                                 Progress
1434                                 );
1435 
1436 Exit:
1437   FreePool (IfrNvData);
1438   //
1439   // Free the allocated config request string.
1440   //
1441   if (AllocatedRequest) {
1442     FreePool (ConfigRequest);
1443     ConfigRequest = NULL;
1444   }
1445   //
1446   // Set Progress string to the original request string.
1447   //
1448   if (Request == NULL) {
1449     *Progress = NULL;
1450   } else if (StrStr (Request, L"OFFSET") == NULL) {
1451     *Progress = Request + StrLen (Request);
1452   }
1453 
1454   return Status;
1455 }
1456 
1457 /**
1458   This function applies changes in a driver's configuration.
1459   Input is a Configuration, which has the routing data for this
1460   driver followed by name / value configuration pairs. The driver
1461   must apply those pairs to its configurable storage. If the
1462   driver's configuration is stored in a linear block of data
1463   and the driver's name / value pairs are in <BlockConfig>
1464   format, it may use the ConfigToBlock helper function (above) to
1465   simplify the job. Currently not implemented.
1466 
1467   @param[in]  This           Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
1468   @param[in]  Configuration  A null-terminated Unicode string in
1469                              <ConfigString> format.
1470   @param[out] Progress       A pointer to a string filled in with the
1471                              offset of the most recent '&' before the
1472                              first failing name / value pair (or the
1473                              beginning of the string if the failure
1474                              is in the first name / value pair) or
1475                              the terminating NULL if all was
1476                              successful.
1477 
1478   @retval EFI_SUCCESS             The results have been distributed or are
1479                                   awaiting distribution.
1480   @retval EFI_OUT_OF_MEMORY       Not enough memory to store the
1481                                   parts of the results that must be
1482                                   stored awaiting possible future
1483                                   protocols.
1484   @retval EFI_INVALID_PARAMETERS  Passing in a NULL for the
1485                                   Results parameter would result
1486                                   in this type of error.
1487   @retval EFI_NOT_FOUND           Target for the specified routing data
1488                                   was not found.
1489 **/
1490 EFI_STATUS
1491 EFIAPI
Ip6FormRouteConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Configuration,OUT EFI_STRING * Progress)1492 Ip6FormRouteConfig (
1493   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
1494   IN  CONST EFI_STRING                       Configuration,
1495   OUT EFI_STRING                             *Progress
1496   )
1497 {
1498   if (This == NULL || Configuration == NULL || Progress == NULL) {
1499     return EFI_INVALID_PARAMETER;
1500   }
1501 
1502   //
1503   // Check routing data in <ConfigHdr>.
1504   // Note: if only one Storage is used, then this checking could be skipped.
1505   //
1506   if (!HiiIsConfigHdrMatch (Configuration, &gIp6ConfigNvDataGuid, mIp6ConfigStorageName)) {
1507     *Progress = Configuration;
1508     return EFI_NOT_FOUND;
1509   }
1510 
1511   *Progress = Configuration + StrLen (Configuration);
1512 
1513   return EFI_SUCCESS;
1514 }
1515 
1516 /**
1517   Display host addresses, route table, DNS addresses and gateway addresses in
1518   "IPv6 Current Setting" page.
1519 
1520   @param[in]       Instance        The IP6 config instance data.
1521 
1522   @retval EFI_SUCCESS              The operation finished successfully.
1523   @retval Others                   Other errors as indicated.
1524 
1525 **/
1526 EFI_STATUS
Ip6GetCurrentSetting(IN IP6_CONFIG_INSTANCE * Instance)1527 Ip6GetCurrentSetting (
1528   IN IP6_CONFIG_INSTANCE        *Instance
1529   )
1530 {
1531   EFI_IP6_CONFIG_PROTOCOL       *Ip6Config;
1532   EFI_HII_HANDLE                HiiHandle;
1533   EFI_IP6_CONFIG_INTERFACE_INFO *Data;
1534   UINTN                         DataSize;
1535   EFI_STATUS                    Status;
1536   CHAR16                        PortString[ADDRESS_STR_MAX_SIZE];
1537   EFI_IP6_CONFIG_INTERFACE_INFO *IfInfo;
1538 
1539 
1540   Ip6Config = &Instance->Ip6Config;
1541   HiiHandle = Instance->CallbackInfo.RegisteredHandle;
1542   Data      = NULL;
1543 
1544   //
1545   // Get current interface info.
1546   //
1547   Status = Ip6ConfigNvGetData (
1548              Ip6Config,
1549              Ip6ConfigDataTypeInterfaceInfo,
1550              &DataSize,
1551              (VOID **) &Data
1552              );
1553   if (EFI_ERROR (Status)) {
1554     return Status;
1555   }
1556 
1557   //
1558   // Generate dynamic text opcode for host address and draw it.
1559   //
1560   IfInfo = (EFI_IP6_CONFIG_INTERFACE_INFO *) Data;
1561   Status = Ip6ConvertAddressListToString (
1562              PortString,
1563              HiiHandle,
1564              Ip6ConfigNvHostAddress,
1565              IfInfo->AddressInfo,
1566              IfInfo->AddressInfoCount
1567              );
1568   if (EFI_ERROR (Status)) {
1569     FreePool (Data);
1570     return Status;
1571   }
1572 
1573   //
1574   // Generate the dynamic text opcode for route table and draw it.
1575   //
1576   Status = Ip6ConvertAddressListToString (
1577              PortString,
1578              HiiHandle,
1579              Ip6ConfigNvRouteTable,
1580              IfInfo->RouteTable,
1581              IfInfo->RouteCount
1582              );
1583   if (EFI_ERROR (Status)) {
1584     FreePool (Data);
1585     return Status;
1586   }
1587 
1588   //
1589   // Get DNS server list.
1590   //
1591   FreePool (Data);
1592   DataSize = 0;
1593   Data = NULL;
1594   Status = Ip6ConfigNvGetData (
1595              Ip6Config,
1596              Ip6ConfigDataTypeDnsServer,
1597              &DataSize,
1598              (VOID **) &Data
1599              );
1600   if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
1601     if (Data != NULL) {
1602       FreePool (Data);
1603     }
1604     return Status;
1605   }
1606 
1607   if (DataSize > 0) {
1608     //
1609     // Generate the dynamic text opcode for DNS server and draw it.
1610     //
1611     Status = Ip6ConvertAddressListToString (
1612                PortString,
1613                HiiHandle,
1614                Ip6ConfigNvDnsAddress,
1615                Data,
1616                DataSize / sizeof (EFI_IPv6_ADDRESS)
1617                );
1618     if (EFI_ERROR (Status)) {
1619       FreePool (Data);
1620       return Status;
1621     }
1622   }
1623 
1624   //
1625   // Get gateway address list.
1626   //
1627   if (Data != NULL) {
1628     FreePool (Data);
1629   }
1630 
1631   DataSize = 0;
1632   Data = NULL;
1633   Status = Ip6ConfigNvGetData (
1634              Ip6Config,
1635              Ip6ConfigDataTypeGateway,
1636              &DataSize,
1637              (VOID **) &Data
1638              );
1639   if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
1640     if (Data != NULL) {
1641       FreePool (Data);
1642     }
1643     return Status;
1644   }
1645 
1646   if (DataSize > 0) {
1647     //
1648     // Generate the dynamic text opcode for gateway and draw it.
1649     //
1650     Status = Ip6ConvertAddressListToString (
1651                PortString,
1652                HiiHandle,
1653                Ip6ConfigNvGatewayAddress,
1654                Data,
1655                DataSize / sizeof (EFI_IPv6_ADDRESS)
1656                );
1657     if (EFI_ERROR (Status)) {
1658       FreePool (Data);
1659       return Status;
1660     }
1661   }
1662 
1663   if (Data != NULL) {
1664     FreePool (Data);
1665   }
1666 
1667   return EFI_SUCCESS;
1668 }
1669 
1670 /**
1671   This function is called to provide results data to the driver.
1672   This data consists of a unique key that is used to identify
1673   which data is either being passed back or being asked for.
1674 
1675   @param[in]  This               Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
1676   @param[in]  Action             Specifies the type of action taken by the browser.
1677   @param[in]  QuestionId         A unique value which is sent to the original
1678                                  exporting driver so that it can identify the type
1679                                  of data to expect. The format of the data tends to
1680                                  vary based on the opcode that generated the callback.
1681   @param[in]  Type               The type of value for the question.
1682   @param[in]  Value              A pointer to the data being sent to the original
1683                                  exporting driver.
1684   @param[out]  ActionRequest     On return, points to the action requested by the
1685                                  callback function.
1686 
1687   @retval EFI_SUCCESS            The callback successfully handled the action.
1688   @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the
1689                                  variable and its data.
1690   @retval EFI_DEVICE_ERROR       The variable could not be saved.
1691   @retval EFI_UNSUPPORTED        The specified Action is not supported by the
1692                                  callback. Currently not implemented.
1693   @retval EFI_INVALID_PARAMETER  Passed in the wrong parameter.
1694   @retval Others                 Other errors as indicated.
1695 
1696 **/
1697 EFI_STATUS
1698 EFIAPI
Ip6FormCallback(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)1699 Ip6FormCallback (
1700   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
1701   IN  EFI_BROWSER_ACTION                     Action,
1702   IN  EFI_QUESTION_ID                        QuestionId,
1703   IN  UINT8                                  Type,
1704   IN  EFI_IFR_TYPE_VALUE                     *Value,
1705   OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
1706   )
1707 {
1708   IP6_FORM_CALLBACK_INFO        *Private;
1709   UINTN                         BufferSize;
1710   IP6_CONFIG_IFR_NVDATA         *IfrNvData;
1711   EFI_STATUS                    Status;
1712   EFI_INPUT_KEY                 Key;
1713   IP6_CONFIG_INSTANCE           *Instance;
1714   IP6_CONFIG_NVDATA             *Ip6NvData;
1715 
1716   if (This == NULL) {
1717     return EFI_INVALID_PARAMETER;
1718   }
1719 
1720   Private   = IP6_FORM_CALLBACK_INFO_FROM_CONFIG_ACCESS (This);
1721   Instance  = IP6_CONFIG_INSTANCE_FROM_FORM_CALLBACK (Private);
1722   Ip6NvData = &Instance->Ip6NvData;
1723 
1724   if ((Action == EFI_BROWSER_ACTION_FORM_OPEN) || (Action == EFI_BROWSER_ACTION_FORM_CLOSE)){
1725     return EFI_SUCCESS;
1726   }
1727 
1728   if (Action != EFI_BROWSER_ACTION_CHANGING && Action != EFI_BROWSER_ACTION_CHANGED) {
1729     return EFI_UNSUPPORTED;
1730   }
1731 
1732   if ((Value == NULL) || (ActionRequest == NULL)) {
1733     return EFI_INVALID_PARAMETER;
1734   }
1735 
1736   //
1737   // Retrieve uncommitted data from Browser
1738   //
1739 
1740   BufferSize = sizeof (IP6_CONFIG_IFR_NVDATA);
1741   IfrNvData = AllocateZeroPool (BufferSize);
1742   if (IfrNvData == NULL) {
1743     return EFI_OUT_OF_RESOURCES;
1744   }
1745 
1746   Status = EFI_SUCCESS;
1747 
1748   HiiGetBrowserData (NULL, NULL, BufferSize, (UINT8 *) IfrNvData);
1749 
1750   if (Action == EFI_BROWSER_ACTION_CHANGING) {
1751     switch (QuestionId) {
1752     case KEY_GET_CURRENT_SETTING:
1753       Status = Ip6GetCurrentSetting (Instance);
1754       break;
1755 
1756     default:
1757       break;
1758     }
1759   } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
1760     switch (QuestionId) {
1761     case KEY_SAVE_CONFIG_CHANGES:
1762       Status = Ip6ConvertIfrNvDataToConfigNvDataAdvanced (IfrNvData, Instance);
1763       if (EFI_ERROR (Status)) {
1764         break;
1765       }
1766 
1767       Status = Ip6GetCurrentSetting (Instance);
1768 
1769       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
1770       break;
1771 
1772     case KEY_IGNORE_CONFIG_CHANGES:
1773       Ip6FreeAddressInfoList (&Ip6NvData->ManualAddress);
1774       Ip6FreeAddressInfoList (&Ip6NvData->GatewayAddress);
1775       Ip6FreeAddressInfoList (&Ip6NvData->DnsAddress);
1776 
1777       Ip6NvData->ManualAddressCount  = 0;
1778       Ip6NvData->GatewayAddressCount = 0;
1779       Ip6NvData->DnsAddressCount     = 0;
1780 
1781       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
1782       break;
1783 
1784     case KEY_SAVE_CHANGES:
1785       Status = Ip6ConvertIfrNvDataToConfigNvDataGeneral (IfrNvData, Instance);
1786       if (EFI_ERROR (Status)) {
1787         break;
1788       }
1789       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
1790       break;
1791 
1792     case KEY_INTERFACE_ID:
1793       Status = Ip6ParseInterfaceIdFromString (IfrNvData->InterfaceId, &Ip6NvData->InterfaceId);
1794       if (EFI_ERROR (Status)) {
1795         CreatePopUp (
1796           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1797           &Key,
1798           L"Invalid Interface ID!",
1799           NULL
1800           );
1801       }
1802 
1803       break;
1804 
1805     case KEY_MANUAL_ADDRESS:
1806       Status = Ip6ParseAddressListFromString (
1807                  IfrNvData->ManualAddress,
1808                  &Ip6NvData->ManualAddress,
1809                  &Ip6NvData->ManualAddressCount
1810                  );
1811       if (EFI_ERROR (Status)) {
1812         CreatePopUp (
1813           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1814           &Key,
1815           L"Invalid Host Addresses!",
1816           NULL
1817           );
1818       }
1819 
1820       break;
1821 
1822     case KEY_GATEWAY_ADDRESS:
1823       Status = Ip6ParseAddressListFromString (
1824                  IfrNvData->GatewayAddress,
1825                  &Ip6NvData->GatewayAddress,
1826                  &Ip6NvData->GatewayAddressCount
1827                  );
1828       if (EFI_ERROR (Status)) {
1829         CreatePopUp (
1830           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1831           &Key,
1832           L"Invalid Gateway Addresses!",
1833           NULL
1834           );
1835       }
1836 
1837       break;
1838 
1839     case KEY_DNS_ADDRESS:
1840       Status = Ip6ParseAddressListFromString (
1841                  IfrNvData->DnsAddress,
1842                  &Ip6NvData->DnsAddress,
1843                  &Ip6NvData->DnsAddressCount
1844                  );
1845       if (EFI_ERROR (Status)) {
1846         CreatePopUp (
1847           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
1848           &Key,
1849           L"Invalid DNS Addresses!",
1850           NULL
1851           );
1852       }
1853 
1854       break;
1855 
1856     default:
1857       break;
1858     }
1859   }
1860 
1861   if (!EFI_ERROR (Status)) {
1862     //
1863     // Pass changed uncommitted data back to Form Browser.
1864     //
1865     BufferSize = sizeof (IP6_CONFIG_IFR_NVDATA);
1866     HiiSetBrowserData (NULL, NULL, BufferSize, (UINT8 *) IfrNvData, NULL);
1867   }
1868 
1869   FreePool (IfrNvData);
1870   return Status;
1871 }
1872 
1873 /**
1874   Install HII Config Access protocol for network device and allocate resources.
1875 
1876   @param[in, out]  Instance      The IP6_CONFIG_INSTANCE to create a form.
1877 
1878   @retval EFI_SUCCESS            The HII Config Access protocol is installed.
1879   @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory.
1880   @retval Others                 Other errors as indicated.
1881 
1882 **/
1883 EFI_STATUS
Ip6ConfigFormInit(IN OUT IP6_CONFIG_INSTANCE * Instance)1884 Ip6ConfigFormInit (
1885   IN OUT IP6_CONFIG_INSTANCE     *Instance
1886   )
1887 {
1888   EFI_STATUS                     Status;
1889   IP6_SERVICE                    *IpSb;
1890   IP6_FORM_CALLBACK_INFO         *CallbackInfo;
1891   EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
1892   VENDOR_DEVICE_PATH             VendorDeviceNode;
1893   EFI_SERVICE_BINDING_PROTOCOL   *MnpSb;
1894   CHAR16                         *MacString;
1895   CHAR16                         MenuString[128];
1896   CHAR16                         PortString[128];
1897   CHAR16                         *OldMenuString;
1898   EFI_DEVICE_PATH_PROTOCOL       *ParentDevicePath;
1899 
1900   IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
1901   ASSERT (IpSb != NULL);
1902 
1903   Status = gBS->HandleProtocol (
1904                   IpSb->Controller,
1905                   &gEfiDevicePathProtocolGuid,
1906                   (VOID **) &ParentDevicePath
1907                   );
1908   if (EFI_ERROR (Status)) {
1909     return Status;
1910   }
1911 
1912   CallbackInfo = &Instance->CallbackInfo;
1913   CallbackInfo->Signature = IP6_FORM_CALLBACK_INFO_SIGNATURE;
1914 
1915   //
1916   // Construct device path node for EFI HII Config Access protocol,
1917   // which consists of controller physical device path and one hardware
1918   // vendor guid node.
1919   //
1920   ZeroMem (&VendorDeviceNode, sizeof (VENDOR_DEVICE_PATH));
1921   VendorDeviceNode.Header.Type    = HARDWARE_DEVICE_PATH;
1922   VendorDeviceNode.Header.SubType = HW_VENDOR_DP;
1923 
1924   CopyGuid (&VendorDeviceNode.Guid, &gEfiCallerIdGuid);
1925 
1926   SetDevicePathNodeLength (&VendorDeviceNode.Header, sizeof (VENDOR_DEVICE_PATH));
1927   CallbackInfo->HiiVendorDevicePath = AppendDevicePathNode (
1928                                         ParentDevicePath,
1929                                         (EFI_DEVICE_PATH_PROTOCOL *) &VendorDeviceNode
1930                                         );
1931   if (CallbackInfo->HiiVendorDevicePath == NULL) {
1932     Status = EFI_OUT_OF_RESOURCES;
1933     goto Error;
1934   }
1935 
1936   ConfigAccess                = &CallbackInfo->HiiConfigAccess;
1937   ConfigAccess->ExtractConfig = Ip6FormExtractConfig;
1938   ConfigAccess->RouteConfig   = Ip6FormRouteConfig;
1939   ConfigAccess->Callback      = Ip6FormCallback;
1940 
1941   //
1942   // Install Device Path Protocol and Config Access protocol on new handle
1943   //
1944   Status = gBS->InstallMultipleProtocolInterfaces (
1945                   &CallbackInfo->ChildHandle,
1946                   &gEfiDevicePathProtocolGuid,
1947                   CallbackInfo->HiiVendorDevicePath,
1948                   &gEfiHiiConfigAccessProtocolGuid,
1949                   ConfigAccess,
1950                   NULL
1951                   );
1952   if (!EFI_ERROR (Status)) {
1953     //
1954     // Open the Parent Handle for the child
1955     //
1956     Status = gBS->OpenProtocol (
1957                     IpSb->Controller,
1958                     &gEfiManagedNetworkServiceBindingProtocolGuid,
1959                     (VOID **) &MnpSb,
1960                     IpSb->Image,
1961                     CallbackInfo->ChildHandle,
1962                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1963                     );
1964   }
1965 
1966   if (EFI_ERROR (Status)) {
1967     goto Error;
1968   }
1969 
1970   //
1971   // Publish our HII data
1972   //
1973   CallbackInfo->RegisteredHandle = HiiAddPackages (
1974                                      &gIp6ConfigNvDataGuid,
1975                                      CallbackInfo->ChildHandle,
1976                                      Ip6DxeStrings,
1977                                      Ip6ConfigBin,
1978                                      NULL
1979                                      );
1980   if (CallbackInfo->RegisteredHandle == NULL) {
1981     Status = EFI_OUT_OF_RESOURCES;
1982     goto Error;
1983   }
1984 
1985   //
1986   // Append MAC string in the menu help string and tile help string
1987   //
1988   Status = NetLibGetMacString (IpSb->Controller, IpSb->Image, &MacString);
1989   if (!EFI_ERROR (Status)) {
1990     OldMenuString = HiiGetString (
1991                       CallbackInfo->RegisteredHandle,
1992                       STRING_TOKEN (STR_IP6_CONFIG_FORM_HELP),
1993                       NULL)
1994                       ;
1995     UnicodeSPrint (MenuString, 128, L"%s (MAC:%s)", OldMenuString, MacString);
1996     HiiSetString (
1997       CallbackInfo->RegisteredHandle,
1998       STRING_TOKEN (STR_IP6_CONFIG_FORM_HELP),
1999       MenuString,
2000       NULL
2001       );
2002     UnicodeSPrint (PortString, 128, L"MAC:%s", MacString);
2003     HiiSetString (
2004       CallbackInfo->RegisteredHandle,
2005       STRING_TOKEN (STR_IP6_DEVICE_FORM_HELP),
2006       PortString,
2007       NULL
2008       );
2009 
2010     FreePool (MacString);
2011     FreePool (OldMenuString);
2012 
2013     InitializeListHead (&Instance->Ip6NvData.ManualAddress);
2014     InitializeListHead (&Instance->Ip6NvData.GatewayAddress);
2015     InitializeListHead (&Instance->Ip6NvData.DnsAddress);
2016 
2017     return EFI_SUCCESS;
2018   }
2019 
2020 Error:
2021   Ip6ConfigFormUnload (Instance);
2022   return Status;
2023 }
2024 
2025 /**
2026   Uninstall the HII Config Access protocol for network devices and free up the resources.
2027 
2028   @param[in, out]  Instance      The IP6_CONFIG_INSTANCE to unload a form.
2029 
2030 **/
2031 VOID
Ip6ConfigFormUnload(IN OUT IP6_CONFIG_INSTANCE * Instance)2032 Ip6ConfigFormUnload (
2033   IN OUT IP6_CONFIG_INSTANCE     *Instance
2034   )
2035 {
2036   IP6_SERVICE                    *IpSb;
2037   IP6_FORM_CALLBACK_INFO         *CallbackInfo;
2038   IP6_CONFIG_NVDATA              *Ip6NvData;
2039 
2040   IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
2041   ASSERT (IpSb != NULL);
2042 
2043   CallbackInfo = &Instance->CallbackInfo;
2044 
2045   if (CallbackInfo->ChildHandle != NULL) {
2046 
2047     //
2048     // Close the child handle
2049     //
2050     gBS->CloseProtocol (
2051            IpSb->Controller,
2052            &gEfiManagedNetworkServiceBindingProtocolGuid,
2053            IpSb->Image,
2054            CallbackInfo->ChildHandle
2055            );
2056     //
2057     // Uninstall EFI_HII_CONFIG_ACCESS_PROTOCOL
2058     //
2059     gBS->UninstallMultipleProtocolInterfaces (
2060            CallbackInfo->ChildHandle,
2061            &gEfiDevicePathProtocolGuid,
2062            CallbackInfo->HiiVendorDevicePath,
2063            &gEfiHiiConfigAccessProtocolGuid,
2064            &CallbackInfo->HiiConfigAccess,
2065            NULL
2066            );
2067   }
2068 
2069   if (CallbackInfo->HiiVendorDevicePath != NULL) {
2070     FreePool (CallbackInfo->HiiVendorDevicePath);
2071   }
2072 
2073   if (CallbackInfo->RegisteredHandle != NULL) {
2074     //
2075     // Remove HII package list
2076     //
2077     HiiRemovePackages (CallbackInfo->RegisteredHandle);
2078   }
2079 
2080   Ip6NvData = &Instance->Ip6NvData;
2081 
2082   Ip6FreeAddressInfoList (&Ip6NvData->ManualAddress);
2083   Ip6FreeAddressInfoList (&Ip6NvData->GatewayAddress);
2084   Ip6FreeAddressInfoList (&Ip6NvData->DnsAddress);
2085 
2086   Ip6NvData->ManualAddressCount  = 0;
2087   Ip6NvData->GatewayAddressCount = 0;
2088   Ip6NvData->DnsAddressCount     = 0;
2089 }
2090