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