• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Helper functions for configuring or getting the parameters relating to Ip4.
3 
4 Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution.  The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9 
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include "Ip4Impl.h"
16 
17 CHAR16    mIp4Config2StorageName[]     = L"IP4_CONFIG2_IFR_NVDATA";
18 
19 /**
20   Calculate the prefix length of the IPv4 subnet mask.
21 
22   @param[in]  SubnetMask The IPv4 subnet mask.
23 
24   @return The prefix length of the subnet mask.
25   @retval 0 Other errors as indicated.
26 
27 **/
28 UINT8
GetSubnetMaskPrefixLength(IN EFI_IPv4_ADDRESS * SubnetMask)29 GetSubnetMaskPrefixLength (
30   IN EFI_IPv4_ADDRESS  *SubnetMask
31   )
32 {
33   UINT8   Len;
34   UINT32  ReverseMask;
35 
36   //
37   // The SubnetMask is in network byte order.
38   //
39   ReverseMask = SwapBytes32 (*(UINT32 *)&SubnetMask[0]);
40 
41   //
42   // Reverse it.
43   //
44   ReverseMask = ~ReverseMask;
45 
46   if ((ReverseMask & (ReverseMask + 1)) != 0) {
47     return 0;
48   }
49 
50   Len = 0;
51 
52   while (ReverseMask != 0) {
53     ReverseMask = ReverseMask >> 1;
54     Len++;
55   }
56 
57   return (UINT8) (32 - Len);
58 }
59 
60 /**
61   Convert the decimal dotted IPv4 address into the binary IPv4 address.
62 
63   @param[in]   Str             The UNICODE string.
64   @param[out]  Ip              The storage to return the IPv4 address.
65 
66   @retval EFI_SUCCESS           The binary IP address is returned in Ip.
67   @retval EFI_INVALID_PARAMETER The IP string is malformatted.
68 
69 **/
70 EFI_STATUS
Ip4Config2StrToIp(IN CHAR16 * Str,OUT EFI_IPv4_ADDRESS * Ip)71 Ip4Config2StrToIp (
72   IN  CHAR16            *Str,
73   OUT EFI_IPv4_ADDRESS  *Ip
74   )
75 {
76   UINTN Index;
77   UINTN Number;
78 
79   Index = 0;
80 
81   while (*Str != L'\0') {
82 
83     if (Index > 3) {
84       return EFI_INVALID_PARAMETER;
85     }
86 
87     Number = 0;
88     while ((*Str >= L'0') && (*Str <= L'9')) {
89       Number = Number * 10 + (*Str - L'0');
90       Str++;
91     }
92 
93     if (Number > 0xFF) {
94       return EFI_INVALID_PARAMETER;
95     }
96 
97     Ip->Addr[Index] = (UINT8) Number;
98 
99     if ((*Str != L'\0') && (*Str != L'.')) {
100       //
101       // The current character should be either the NULL terminator or
102       // the dot delimiter.
103       //
104       return EFI_INVALID_PARAMETER;
105     }
106 
107     if (*Str == L'.') {
108       //
109       // Skip the delimiter.
110       //
111       Str++;
112     }
113 
114     Index++;
115   }
116 
117   if (Index != 4) {
118     return EFI_INVALID_PARAMETER;
119   }
120 
121   return EFI_SUCCESS;
122 }
123 
124 /**
125   Convert the decimal dotted IPv4 addresses separated by space into the binary IPv4 address list.
126 
127   @param[in]   Str             The UNICODE string contains IPv4 addresses.
128   @param[out]  PtrIpList       The storage to return the IPv4 address list.
129   @param[out]  IpCount         The size of the IPv4 address list.
130 
131   @retval EFI_SUCCESS           The binary IP address list is returned in PtrIpList.
132   @retval EFI_OUT_OF_RESOURCES  Error occurs in allocating memory.
133   @retval EFI_INVALID_PARAMETER The IP string is malformatted.
134 
135 **/
136 EFI_STATUS
Ip4Config2StrToIpList(IN CHAR16 * Str,OUT EFI_IPv4_ADDRESS ** PtrIpList,OUT UINTN * IpCount)137 Ip4Config2StrToIpList (
138   IN  CHAR16            *Str,
139   OUT EFI_IPv4_ADDRESS  **PtrIpList,
140   OUT UINTN             *IpCount
141   )
142 {
143   UINTN              BeginIndex;
144   UINTN              EndIndex;
145   UINTN              Index;
146   UINTN              IpIndex;
147   CHAR16             *StrTemp;
148   BOOLEAN            SpaceTag;
149 
150   BeginIndex = 0;
151   EndIndex   = BeginIndex;
152   Index      = 0;
153   IpIndex    = 0;
154   StrTemp    = NULL;
155   SpaceTag   = TRUE;
156 
157   *PtrIpList = NULL;
158   *IpCount   = 0;
159 
160   if (Str == NULL) {
161     return EFI_SUCCESS;
162   }
163 
164   //
165   // Get the number of Ip.
166   //
167   while (*(Str + Index) != L'\0') {
168     if (*(Str + Index) == L' ') {
169       SpaceTag = TRUE;
170     } else {
171       if (SpaceTag) {
172         (*IpCount)++;
173         SpaceTag = FALSE;
174       }
175     }
176 
177     Index++;
178   }
179 
180   if (*IpCount == 0) {
181     return EFI_SUCCESS;
182   }
183 
184   //
185   // Allocate buffer for IpList.
186   //
187   *PtrIpList = AllocateZeroPool(*IpCount * sizeof(EFI_IPv4_ADDRESS));
188   if (*PtrIpList == NULL) {
189     return EFI_OUT_OF_RESOURCES;
190   }
191 
192   //
193   // Get IpList from Str.
194   //
195   Index = 0;
196   while (*(Str + Index) != L'\0') {
197     if (*(Str + Index) == L' ') {
198       if(!SpaceTag) {
199         StrTemp = AllocateZeroPool((EndIndex - BeginIndex + 1) * sizeof(CHAR16));
200         if (StrTemp == NULL) {
201           FreePool(*PtrIpList);
202           *PtrIpList = NULL;
203           *IpCount = 0;
204           return EFI_OUT_OF_RESOURCES;
205         }
206 
207         CopyMem (StrTemp, Str + BeginIndex, (EndIndex - BeginIndex) * sizeof(CHAR16));
208         *(StrTemp + (EndIndex - BeginIndex)) = L'\0';
209 
210         if (Ip4Config2StrToIp (StrTemp, &((*PtrIpList)[IpIndex])) != EFI_SUCCESS) {
211           FreePool(StrTemp);
212           FreePool(*PtrIpList);
213           *PtrIpList = NULL;
214           *IpCount = 0;
215           return EFI_INVALID_PARAMETER;
216         }
217 
218         BeginIndex = EndIndex;
219         IpIndex++;
220 
221         FreePool(StrTemp);
222       }
223 
224       BeginIndex++;
225       EndIndex++;
226       SpaceTag = TRUE;
227     } else {
228       EndIndex++;
229       SpaceTag = FALSE;
230     }
231 
232     Index++;
233 
234     if (*(Str + Index) == L'\0') {
235       if (!SpaceTag) {
236         StrTemp = AllocateZeroPool((EndIndex - BeginIndex + 1) * sizeof(CHAR16));
237         if (StrTemp == NULL) {
238           FreePool(*PtrIpList);
239           *PtrIpList = NULL;
240           *IpCount = 0;
241           return EFI_OUT_OF_RESOURCES;
242         }
243 
244         CopyMem (StrTemp, Str + BeginIndex, (EndIndex - BeginIndex) * sizeof(CHAR16));
245         *(StrTemp + (EndIndex - BeginIndex)) = L'\0';
246 
247         if (Ip4Config2StrToIp (StrTemp, &((*PtrIpList)[IpIndex])) != EFI_SUCCESS) {
248           FreePool(StrTemp);
249           FreePool(*PtrIpList);
250           *PtrIpList = NULL;
251           *IpCount = 0;
252           return EFI_INVALID_PARAMETER;
253         }
254 
255         FreePool(StrTemp);
256       }
257     }
258   }
259 
260   return EFI_SUCCESS;
261 }
262 
263 /**
264   Convert the IPv4 address into a dotted string.
265 
266   @param[in]   Ip   The IPv4 address.
267   @param[out]  Str  The dotted IP string.
268 
269 **/
270 VOID
Ip4Config2IpToStr(IN EFI_IPv4_ADDRESS * Ip,OUT CHAR16 * Str)271 Ip4Config2IpToStr (
272   IN  EFI_IPv4_ADDRESS  *Ip,
273   OUT CHAR16            *Str
274   )
275 {
276   UnicodeSPrint (
277     Str,
278     2 * IP4_STR_MAX_SIZE,
279     L"%d.%d.%d.%d",
280     Ip->Addr[0],
281     Ip->Addr[1],
282     Ip->Addr[2],
283     Ip->Addr[3]
284     );
285 }
286 
287 
288 /**
289   Convert the IPv4 address list into string consists of several decimal
290   dotted IPv4 addresses separated by space.
291 
292   @param[in]   Ip        The IPv4 address list.
293   @param[in]   IpCount   The size of IPv4 address list.
294   @param[out]  Str       The string contains several decimal dotted
295                          IPv4 addresses separated by space.
296 **/
297 VOID
Ip4Config2IpListToStr(IN EFI_IPv4_ADDRESS * Ip,IN UINTN IpCount,OUT CHAR16 * Str)298 Ip4Config2IpListToStr (
299   IN  EFI_IPv4_ADDRESS  *Ip,
300   IN  UINTN             IpCount,
301   OUT CHAR16            *Str
302   )
303 {
304   UINTN            Index;
305   UINTN            TemIndex;
306   UINTN            StrIndex;
307   CHAR16           *TempStr;
308   EFI_IPv4_ADDRESS *TempIp;
309 
310   Index    = 0;
311   TemIndex = 0;
312   StrIndex = 0;
313   TempStr  = NULL;
314   TempIp   = NULL;
315 
316   for (Index = 0; Index < IpCount; Index ++) {
317     TempIp = Ip + Index;
318     if (TempStr == NULL) {
319       TempStr = AllocateZeroPool(2 * IP4_STR_MAX_SIZE);
320       ASSERT(TempStr != NULL);
321     }
322 
323     UnicodeSPrint (
324       TempStr,
325       2 * IP4_STR_MAX_SIZE,
326       L"%d.%d.%d.%d",
327       TempIp->Addr[0],
328       TempIp->Addr[1],
329       TempIp->Addr[2],
330       TempIp->Addr[3]
331       );
332 
333     for (TemIndex = 0; TemIndex < IP4_STR_MAX_SIZE; TemIndex ++) {
334       if (*(TempStr + TemIndex) == L'\0') {
335         if (Index == IpCount - 1) {
336           Str[StrIndex++] = L'\0';
337         } else {
338           Str[StrIndex++] = L' ';
339         }
340         break;
341       } else {
342         Str[StrIndex++] = *(TempStr + TemIndex);
343       }
344     }
345   }
346 
347   if (TempStr != NULL) {
348     FreePool(TempStr);
349   }
350 }
351 
352 /**
353   The notify function of create event when performing a manual configuration.
354 
355   @param[in]    Event        The pointer of Event.
356   @param[in]    Context      The pointer of Context.
357 
358 **/
359 VOID
360 EFIAPI
Ip4Config2ManualAddressNotify(IN EFI_EVENT Event,IN VOID * Context)361 Ip4Config2ManualAddressNotify (
362   IN EFI_EVENT    Event,
363   IN VOID         *Context
364   )
365 {
366   *((BOOLEAN *) Context) = TRUE;
367 }
368 
369 /**
370   Convert the network configuration data into the IFR data.
371 
372   @param[in]       Instance          The IP4 config2 instance.
373   @param[in, out]  IfrNvData         The IFR nv data.
374 
375   @retval EFI_SUCCESS            The configure parameter to IFR data was
376                                  set successfully.
377   @retval EFI_INVALID_PARAMETER  Source instance or target IFR data is not available.
378   @retval Others                 Other errors as indicated.
379 
380 **/
381 EFI_STATUS
Ip4Config2ConvertConfigNvDataToIfrNvData(IN IP4_CONFIG2_INSTANCE * Instance,IN OUT IP4_CONFIG2_IFR_NVDATA * IfrNvData)382 Ip4Config2ConvertConfigNvDataToIfrNvData (
383   IN     IP4_CONFIG2_INSTANCE       *Instance,
384   IN OUT IP4_CONFIG2_IFR_NVDATA     *IfrNvData
385   )
386 {
387   IP4_SERVICE                                *IpSb;
388   EFI_IP4_CONFIG2_PROTOCOL                   *Ip4Config2;
389   EFI_IP4_CONFIG2_INTERFACE_INFO             *Ip4Info;
390   EFI_IP4_CONFIG2_POLICY                     Policy;
391   UINTN                                      DataSize;
392   UINTN                                      GatewaySize;
393   EFI_IPv4_ADDRESS                           GatewayAddress;
394   EFI_STATUS                                 Status;
395   UINTN                                      DnsSize;
396   UINTN                                      DnsCount;
397   EFI_IPv4_ADDRESS                           *DnsAddress;
398 
399   Status      = EFI_SUCCESS;
400   Ip4Config2  = &Instance->Ip4Config2;
401   Ip4Info     = NULL;
402   DnsAddress  = NULL;
403   GatewaySize = sizeof (EFI_IPv4_ADDRESS);
404 
405   if ((IfrNvData == NULL) || (Instance == NULL)) {
406     return EFI_INVALID_PARAMETER;
407   }
408 
409   NET_CHECK_SIGNATURE (Instance, IP4_CONFIG2_INSTANCE_SIGNATURE);
410 
411   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
412 
413   if (IpSb->DefaultInterface->Configured) {
414     IfrNvData->Configure = 1;
415   } else {
416     IfrNvData->Configure = 0;
417     goto Exit;
418   }
419 
420   //
421   // Get the Policy info.
422   //
423   DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);
424   Status   = Ip4Config2->GetData (
425                            Ip4Config2,
426                            Ip4Config2DataTypePolicy,
427                            &DataSize,
428                            &Policy
429                            );
430   if (EFI_ERROR (Status)) {
431     goto Exit;
432   }
433 
434   if (Policy == Ip4Config2PolicyStatic) {
435     IfrNvData->DhcpEnable = FALSE;
436   } else if (Policy == Ip4Config2PolicyDhcp) {
437     IfrNvData->DhcpEnable = TRUE;
438     goto Exit;
439   }
440 
441   //
442   // Get the interface info.
443   //
444   DataSize    = 0;
445   Status = Ip4Config2->GetData (
446                          Ip4Config2,
447                          Ip4Config2DataTypeInterfaceInfo,
448                          &DataSize,
449                          NULL
450                          );
451   if (Status != EFI_BUFFER_TOO_SMALL) {
452     return Status;
453   }
454 
455   Ip4Info = AllocateZeroPool (DataSize);
456   if (Ip4Info == NULL) {
457     Status = EFI_OUT_OF_RESOURCES;
458     return Status;
459   }
460 
461   Status = Ip4Config2->GetData (
462                          Ip4Config2,
463                          Ip4Config2DataTypeInterfaceInfo,
464                          &DataSize,
465                          Ip4Info
466                          );
467   if (EFI_ERROR (Status)) {
468     goto Exit;
469   }
470 
471   //
472   // Get the Gateway info.
473   //
474   Status = Ip4Config2->GetData (
475                          Ip4Config2,
476                          Ip4Config2DataTypeGateway,
477                          &GatewaySize,
478                          &GatewayAddress
479                          );
480   if (EFI_ERROR (Status)) {
481     goto Exit;
482   }
483 
484   //
485   // Get the Dns info.
486   //
487   DnsSize = 0;
488   Status = Ip4Config2->GetData (
489                          Ip4Config2,
490                          Ip4Config2DataTypeDnsServer,
491                          &DnsSize,
492                          NULL
493                          );
494   if ((Status != EFI_BUFFER_TOO_SMALL) && (Status != EFI_NOT_FOUND)) {
495     goto Exit;
496   }
497 
498   DnsCount = (UINT32) (DnsSize / sizeof (EFI_IPv4_ADDRESS));
499 
500   if (DnsSize > 0) {
501     DnsAddress = AllocateZeroPool(DnsSize);
502     if (DnsAddress == NULL) {
503       Status = EFI_OUT_OF_RESOURCES;
504       goto Exit;
505     }
506 
507     Status = Ip4Config2->GetData (
508                            Ip4Config2,
509                            Ip4Config2DataTypeDnsServer,
510                            &DnsSize,
511                            DnsAddress
512                            );
513     if (EFI_ERROR (Status)) {
514       goto Exit;
515     }
516   }
517 
518   Ip4Config2IpToStr (&Ip4Info->StationAddress, IfrNvData->StationAddress);
519   Ip4Config2IpToStr (&Ip4Info->SubnetMask, IfrNvData->SubnetMask);
520   Ip4Config2IpToStr (&GatewayAddress, IfrNvData->GatewayAddress);
521   Ip4Config2IpListToStr (DnsAddress, DnsCount, IfrNvData->DnsAddress);
522 
523 Exit:
524 
525   if (DnsAddress != NULL) {
526     FreePool(DnsAddress);
527   }
528 
529   if (Ip4Info != NULL) {
530     FreePool(Ip4Info);
531   }
532 
533   return Status;
534 }
535 
536 /**
537   Convert the IFR data into the network configuration data and set the IP
538   configure parameters for the NIC.
539 
540   @param[in]       IfrFormNvData     The IFR NV data.
541   @param[in, out]  Instance          The IP4 config2 instance.
542 
543   @retval EFI_SUCCESS            The configure parameter for this NIC was
544                                  set successfully.
545   @retval EFI_INVALID_PARAMETER  The address information for setting is invalid.
546   @retval Others                 Other errors as indicated.
547 
548 **/
549 EFI_STATUS
Ip4Config2ConvertIfrNvDataToConfigNvData(IN IP4_CONFIG2_IFR_NVDATA * IfrFormNvData,IN OUT IP4_CONFIG2_INSTANCE * Instance)550 Ip4Config2ConvertIfrNvDataToConfigNvData (
551   IN     IP4_CONFIG2_IFR_NVDATA     *IfrFormNvData,
552   IN OUT IP4_CONFIG2_INSTANCE       *Instance
553   )
554 {
555   EFI_STATUS                       Status;
556   EFI_IP4_CONFIG2_PROTOCOL         *Ip4Cfg2;
557   IP4_CONFIG2_NVDATA               *Ip4NvData;
558 
559   EFI_IP_ADDRESS                   StationAddress;
560   EFI_IP_ADDRESS                   SubnetMask;
561   EFI_IP_ADDRESS                   Gateway;
562   IP4_ADDR                         Ip;
563   EFI_IPv4_ADDRESS                 *DnsAddress;
564   UINTN                            DnsCount;
565   UINTN                            Index;
566 
567   EFI_EVENT                        TimeoutEvent;
568   EFI_EVENT                        SetAddressEvent;
569   BOOLEAN                          IsAddressOk;
570   UINTN                            DataSize;
571   EFI_INPUT_KEY                    Key;
572 
573   Status          = EFI_SUCCESS;
574   Ip4Cfg2         = &Instance->Ip4Config2;
575   Ip4NvData       = &Instance->Ip4NvData;
576 
577   DnsCount        = 0;
578   DnsAddress      = NULL;
579 
580   TimeoutEvent    = NULL;
581   SetAddressEvent = NULL;
582 
583 
584 
585   if (Instance == NULL || IfrFormNvData == NULL) {
586     return EFI_INVALID_PARAMETER;
587   }
588 
589   if (IfrFormNvData->Configure != TRUE) {
590     return EFI_SUCCESS;
591   }
592 
593   if (IfrFormNvData->DhcpEnable == TRUE) {
594     Ip4NvData->Policy = Ip4Config2PolicyDhcp;
595 
596     Status = Ip4Cfg2->SetData (
597                         Ip4Cfg2,
598                         Ip4Config2DataTypePolicy,
599                         sizeof (EFI_IP4_CONFIG2_POLICY),
600                         &Ip4NvData->Policy
601                         );
602     if (EFI_ERROR(Status)) {
603       return Status;
604     }
605   } else {
606     //
607     // Get Ip4NvData from IfrFormNvData if it is valid.
608     //
609     Ip4NvData->Policy = Ip4Config2PolicyStatic;
610 
611     Status = Ip4Config2StrToIp (IfrFormNvData->SubnetMask, &SubnetMask.v4);
612     if (EFI_ERROR (Status) || ((SubnetMask.Addr[0] != 0) && (GetSubnetMaskPrefixLength (&SubnetMask.v4) == 0))) {
613       CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Subnet Mask!", NULL);
614       return EFI_INVALID_PARAMETER;
615     }
616 
617     Status = Ip4Config2StrToIp (IfrFormNvData->StationAddress, &StationAddress.v4);
618     if (EFI_ERROR (Status) || !NetIp4IsUnicast (NTOHL (StationAddress.Addr[0]), NTOHL (SubnetMask.Addr[0]))) {
619       CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid IP address!", NULL);
620       return EFI_INVALID_PARAMETER;
621     }
622 
623     Status = Ip4Config2StrToIp (IfrFormNvData->GatewayAddress, &Gateway.v4);
624     if (EFI_ERROR (Status) || ((Gateway.Addr[0] != 0) && !NetIp4IsUnicast (NTOHL (Gateway.Addr[0]), NTOHL (SubnetMask.Addr[0])))) {
625       CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Gateway!", NULL);
626       return EFI_INVALID_PARAMETER;
627     }
628 
629     Status = Ip4Config2StrToIpList (IfrFormNvData->DnsAddress, &DnsAddress, &DnsCount);
630     if (!EFI_ERROR (Status) && DnsCount > 0) {
631       for (Index = 0; Index < DnsCount; Index ++) {
632         CopyMem (&Ip, &DnsAddress[Index], sizeof (IP4_ADDR));
633         if (IP4_IS_UNSPECIFIED (NTOHL (Ip)) || IP4_IS_LOCAL_BROADCAST (NTOHL (Ip))) {
634           CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Dns Server!", NULL);
635           FreePool(DnsAddress);
636           return EFI_INVALID_PARAMETER;
637         }
638       }
639     } else {
640       if (EFI_ERROR (Status)) {
641         CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Dns Server!", NULL);
642       }
643     }
644 
645     if (Ip4NvData->ManualAddress != NULL) {
646       FreePool(Ip4NvData->ManualAddress);
647     }
648     Ip4NvData->ManualAddressCount = 1;
649     Ip4NvData->ManualAddress = AllocateZeroPool(sizeof(EFI_IP4_CONFIG2_MANUAL_ADDRESS));
650     if (Ip4NvData->ManualAddress == NULL) {
651       if (DnsAddress != NULL) {
652         FreePool(DnsAddress);
653       }
654 
655       return EFI_OUT_OF_RESOURCES;
656     }
657     CopyMem(&Ip4NvData->ManualAddress->Address, &StationAddress.v4, sizeof(EFI_IPv4_ADDRESS));
658     CopyMem(&Ip4NvData->ManualAddress->SubnetMask, &SubnetMask.v4, sizeof(EFI_IPv4_ADDRESS));
659 
660     if (Ip4NvData->GatewayAddress != NULL) {
661       FreePool(Ip4NvData->GatewayAddress);
662     }
663     Ip4NvData->GatewayAddressCount = 1;
664     Ip4NvData->GatewayAddress = AllocateZeroPool(sizeof(EFI_IPv4_ADDRESS));
665     if (Ip4NvData->GatewayAddress == NULL) {
666       if (DnsAddress != NULL) {
667         FreePool(DnsAddress);
668       }
669       return EFI_OUT_OF_RESOURCES;
670     }
671     CopyMem(Ip4NvData->GatewayAddress, &Gateway.v4, sizeof(EFI_IPv4_ADDRESS));
672 
673     if (Ip4NvData->DnsAddress != NULL) {
674       FreePool(Ip4NvData->DnsAddress);
675     }
676     Ip4NvData->DnsAddressCount = (UINT32) DnsCount;
677     Ip4NvData->DnsAddress      = DnsAddress;
678 
679     //
680     // Setting Ip4NvData.
681     //
682     Status = Ip4Cfg2->SetData (
683                         Ip4Cfg2,
684                         Ip4Config2DataTypePolicy,
685                         sizeof (EFI_IP4_CONFIG2_POLICY),
686                         &Ip4NvData->Policy
687                         );
688     if (EFI_ERROR(Status)) {
689       return Status;
690     }
691 
692     //
693     // Create events & timers for asynchronous settings.
694     //
695     Status = gBS->CreateEvent (
696                     EVT_TIMER,
697                     TPL_CALLBACK,
698                     NULL,
699                     NULL,
700                     &TimeoutEvent
701                     );
702     if (EFI_ERROR (Status)) {
703       return EFI_OUT_OF_RESOURCES;
704     }
705 
706     Status = gBS->CreateEvent (
707                     EVT_NOTIFY_SIGNAL,
708                     TPL_NOTIFY,
709                     Ip4Config2ManualAddressNotify,
710                     &IsAddressOk,
711                     &SetAddressEvent
712                     );
713     if (EFI_ERROR (Status)) {
714       goto Exit;
715     }
716 
717     IsAddressOk = FALSE;
718 
719     Status = Ip4Cfg2->RegisterDataNotify (
720                         Ip4Cfg2,
721                         Ip4Config2DataTypeManualAddress,
722                         SetAddressEvent
723                         );
724     if (EFI_ERROR (Status)) {
725       goto Exit;
726     }
727 
728     //
729     // Set ManualAddress.
730     //
731     DataSize = Ip4NvData->ManualAddressCount * sizeof (EFI_IP4_CONFIG2_MANUAL_ADDRESS);
732     Status = Ip4Cfg2->SetData (
733                         Ip4Cfg2,
734                         Ip4Config2DataTypeManualAddress,
735                         DataSize,
736                         (VOID *) Ip4NvData->ManualAddress
737                         );
738 
739     if (Status == EFI_NOT_READY) {
740       gBS->SetTimer (TimeoutEvent, TimerRelative, 50000000);
741       while (EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
742         if (IsAddressOk) {
743           Status = EFI_SUCCESS;
744           break;
745         }
746       }
747     }
748 
749     Ip4Cfg2->UnregisterDataNotify (
750                Ip4Cfg2,
751                Ip4Config2DataTypeManualAddress,
752                SetAddressEvent
753                );
754     if (EFI_ERROR (Status)) {
755       goto Exit;
756     }
757 
758     //
759     // Set gateway.
760     //
761     DataSize = Ip4NvData->GatewayAddressCount * sizeof (EFI_IPv4_ADDRESS);
762     Status = Ip4Cfg2->SetData (
763                         Ip4Cfg2,
764                         Ip4Config2DataTypeGateway,
765                         DataSize,
766                         Ip4NvData->GatewayAddress
767                         );
768     if (EFI_ERROR (Status)) {
769       goto Exit;
770     }
771 
772     //
773     // Set DNS addresses.
774     //
775     if (Ip4NvData->DnsAddressCount > 0 && Ip4NvData->DnsAddress != NULL) {
776       DataSize = Ip4NvData->DnsAddressCount * sizeof (EFI_IPv4_ADDRESS);
777       Status = Ip4Cfg2->SetData (
778                           Ip4Cfg2,
779                           Ip4Config2DataTypeDnsServer,
780                           DataSize,
781                           Ip4NvData->DnsAddress
782                           );
783 
784       if (EFI_ERROR (Status)) {
785         goto Exit;
786       }
787     }
788   }
789 
790 Exit:
791   if (SetAddressEvent != NULL) {
792     gBS->CloseEvent (SetAddressEvent);
793   }
794 
795   if (TimeoutEvent != NULL) {
796     gBS->CloseEvent (TimeoutEvent);
797   }
798 
799   return Status;
800 }
801 
802 /**
803   This function allows the caller to request the current
804   configuration for one or more named elements. The resulting
805   string is in <ConfigAltResp> format. Any and all alternative
806   configuration strings shall also be appended to the end of the
807   current configuration string. If they are, they must appear
808   after the current configuration. They must contain the same
809   routing (GUID, NAME, PATH) as the current configuration string.
810   They must have an additional description indicating the type of
811   alternative configuration the string represents,
812   "ALTCFG=<StringToken>". That <StringToken> (when
813   converted from Hex UNICODE to binary) is a reference to a
814   string in the associated string pack.
815 
816   @param[in] This       Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
817   @param[in] Request    A null-terminated Unicode string in
818                         <ConfigRequest> format. Note that this
819                         includes the routing information as well as
820                         the configurable name / value pairs. It is
821                         invalid for this string to be in
822                         <MultiConfigRequest> format.
823   @param[out] Progress  On return, points to a character in the
824                         Request string. Points to the string's null
825                         terminator if request was successful. Points
826                         to the most recent "&" before the first
827                         failing name / value pair (or the beginning
828                         of the string if the failure is in the first
829                         name / value pair) if the request was not
830                         successful.
831   @param[out] Results   A null-terminated Unicode string in
832                         <ConfigAltResp> format which has all values
833                         filled in for the names in the Request string.
834                         String to be allocated by the called function.
835 
836   @retval EFI_SUCCESS             The Results string is filled with the
837                                   values corresponding to all requested
838                                   names.
839   @retval EFI_OUT_OF_RESOURCES    Not enough memory to store the
840                                   parts of the results that must be
841                                   stored awaiting possible future
842                                   protocols.
843   @retval EFI_NOT_FOUND           Routing data doesn't match any
844                                   known driver. Progress set to the
845                                   first character in the routing header.
846                                   Note: There is no requirement that the
847                                   driver validate the routing data. It
848                                   must skip the <ConfigHdr> in order to
849                                   process the names.
850   @retval EFI_INVALID_PARAMETER   Illegal syntax. Progress set
851                                   to most recent & before the
852                                   error or the beginning of the
853                                   string.
854   @retval EFI_INVALID_PARAMETER   Unknown name. Progress points
855                                   to the & before the name in
856                                   question.Currently not implemented.
857 **/
858 EFI_STATUS
859 EFIAPI
Ip4FormExtractConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Request,OUT EFI_STRING * Progress,OUT EFI_STRING * Results)860 Ip4FormExtractConfig (
861   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
862   IN  CONST EFI_STRING                       Request,
863   OUT EFI_STRING                             *Progress,
864   OUT EFI_STRING                             *Results
865   )
866 {
867   EFI_STATUS                       Status;
868   IP4_CONFIG2_INSTANCE             *Ip4Config2Instance;
869   IP4_FORM_CALLBACK_INFO           *Private;
870   IP4_CONFIG2_IFR_NVDATA           *IfrFormNvData;
871   EFI_STRING                       ConfigRequestHdr;
872   EFI_STRING                       ConfigRequest;
873   BOOLEAN                          AllocatedRequest;
874   EFI_STRING                       FormResult;
875   UINTN                            Size;
876   UINTN                            BufferSize;
877 
878   if (Progress == NULL || Results == NULL) {
879     return EFI_INVALID_PARAMETER;
880   }
881 
882   Status             = EFI_SUCCESS;
883   IfrFormNvData      = NULL;
884   ConfigRequest      = NULL;
885   FormResult         = NULL;
886   Size               = 0;
887   AllocatedRequest   = FALSE;
888   ConfigRequest      = Request;
889   Private            = IP4_FORM_CALLBACK_INFO_FROM_CONFIG_ACCESS(This);
890   Ip4Config2Instance = IP4_CONFIG2_INSTANCE_FROM_FORM_CALLBACK(Private);
891   BufferSize         = sizeof (IP4_CONFIG2_IFR_NVDATA);
892   *Progress          = Request;
893 
894   //
895   // Check Request data in <ConfigHdr>.
896   //
897   if ((Request == NULL) || HiiIsConfigHdrMatch (Request, &gIp4Config2NvDataGuid, mIp4Config2StorageName)) {
898     IfrFormNvData = AllocateZeroPool (sizeof (IP4_CONFIG2_IFR_NVDATA));
899     if (IfrFormNvData == NULL) {
900       return EFI_OUT_OF_RESOURCES;
901     }
902 
903     Ip4Config2ConvertConfigNvDataToIfrNvData (Ip4Config2Instance, IfrFormNvData);
904 
905     if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
906       //
907       // Request has no request element, construct full request string.
908       // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
909       // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
910       //
911       ConfigRequestHdr = HiiConstructConfigHdr (&gIp4Config2NvDataGuid, mIp4Config2StorageName, Private->ChildHandle);
912       Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
913       ConfigRequest = AllocateZeroPool (Size);
914       ASSERT (ConfigRequest != NULL);
915       AllocatedRequest = TRUE;
916 
917       UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
918       FreePool (ConfigRequestHdr);
919     }
920 
921     //
922     // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
923     //
924     Status = gHiiConfigRouting->BlockToConfig (
925                                   gHiiConfigRouting,
926                                   ConfigRequest,
927                                   (UINT8 *) IfrFormNvData,
928                                   BufferSize,
929                                   &FormResult,
930                                   Progress
931                                   );
932 
933     FreePool (IfrFormNvData);
934 
935     //
936     // Free the allocated config request string.
937     //
938     if (AllocatedRequest) {
939       FreePool (ConfigRequest);
940       ConfigRequest = NULL;
941     }
942 
943     if (EFI_ERROR (Status)) {
944       goto Failure;
945     }
946   }
947 
948   if (Request == NULL || HiiIsConfigHdrMatch (Request, &gIp4Config2NvDataGuid, mIp4Config2StorageName)) {
949     *Results = FormResult;
950   } else {
951     return EFI_NOT_FOUND;
952   }
953 
954 Failure:
955   //
956   // Set Progress string to the original request string.
957   //
958   if (Request == NULL) {
959     *Progress = NULL;
960   } else if (StrStr (Request, L"OFFSET") == NULL) {
961     *Progress = Request + StrLen (Request);
962   }
963 
964   return Status;
965 }
966 
967 /**
968   This function applies changes in a driver's configuration.
969   Input is a Configuration, which has the routing data for this
970   driver followed by name / value configuration pairs. The driver
971   must apply those pairs to its configurable storage. If the
972   driver's configuration is stored in a linear block of data
973   and the driver's name / value pairs are in <BlockConfig>
974   format, it may use the ConfigToBlock helper function (above) to
975   simplify the job. Currently not implemented.
976 
977   @param[in]  This           Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
978   @param[in]  Configuration  A null-terminated Unicode string in
979                              <ConfigString> format.
980   @param[out] Progress       A pointer to a string filled in with the
981                              offset of the most recent '&' before the
982                              first failing name / value pair (or the
983                              beginn ing of the string if the failure
984                              is in the first name / value pair) or
985                              the terminating NULL if all was
986                              successful.
987 
988   @retval EFI_SUCCESS             The results have been distributed or are
989                                   awaiting distribution.
990   @retval EFI_OUT_OF_MEMORY       Not enough memory to store the
991                                   parts of the results that must be
992                                   stored awaiting possible future
993                                   protocols.
994   @retval EFI_INVALID_PARAMETERS  Passing in a NULL for the
995                                   Results parameter would result
996                                   in this type of error.
997   @retval EFI_NOT_FOUND           Target for the specified routing data
998                                   was not found.
999 **/
1000 EFI_STATUS
1001 EFIAPI
Ip4FormRouteConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Configuration,OUT EFI_STRING * Progress)1002 Ip4FormRouteConfig (
1003   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
1004   IN  CONST EFI_STRING                       Configuration,
1005   OUT EFI_STRING                             *Progress
1006   )
1007 {
1008   EFI_STATUS                       Status;
1009   UINTN                            BufferSize;
1010   IP4_CONFIG2_IFR_NVDATA           *IfrFormNvData;
1011   IP4_CONFIG2_INSTANCE             *Ip4Config2Instance;
1012   IP4_FORM_CALLBACK_INFO           *Private;
1013 
1014   Status        = EFI_SUCCESS;
1015   IfrFormNvData = NULL;
1016 
1017   if (Configuration == NULL || Progress == NULL) {
1018     return EFI_INVALID_PARAMETER;
1019   }
1020 
1021   *Progress = Configuration;
1022 
1023   Private            = IP4_FORM_CALLBACK_INFO_FROM_CONFIG_ACCESS(This);
1024   Ip4Config2Instance = IP4_CONFIG2_INSTANCE_FROM_FORM_CALLBACK(Private);
1025 
1026   //
1027   // Check Routing data in <ConfigHdr>.
1028   //
1029   if (HiiIsConfigHdrMatch (Configuration, &gIp4Config2NvDataGuid, mIp4Config2StorageName)) {
1030     //
1031     // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
1032     //
1033     IfrFormNvData = AllocateZeroPool (sizeof (IP4_CONFIG2_IFR_NVDATA));
1034     if (IfrFormNvData == NULL) {
1035       return EFI_OUT_OF_RESOURCES;
1036     }
1037 
1038     BufferSize = 0;
1039 
1040     Status = gHiiConfigRouting->ConfigToBlock (
1041                                   gHiiConfigRouting,
1042                                   Configuration,
1043                                   (UINT8 *) IfrFormNvData,
1044                                   &BufferSize,
1045                                   Progress
1046                                   );
1047     if (Status != EFI_BUFFER_TOO_SMALL) {
1048       return Status;
1049     }
1050 
1051     Status = gHiiConfigRouting->ConfigToBlock (
1052                                   gHiiConfigRouting,
1053                                   Configuration,
1054                                   (UINT8 *) IfrFormNvData,
1055                                   &BufferSize,
1056                                   Progress
1057                                   );
1058     if (!EFI_ERROR (Status)) {
1059       Status = Ip4Config2ConvertIfrNvDataToConfigNvData (IfrFormNvData, Ip4Config2Instance);
1060     }
1061 
1062     FreePool (IfrFormNvData);
1063   } else {
1064     return EFI_NOT_FOUND;
1065   }
1066 
1067   return Status;
1068 
1069 }
1070 
1071 /**
1072   This function is called to provide results data to the driver.
1073   This data consists of a unique key that is used to identify
1074   which data is either being passed back or being asked for.
1075 
1076   @param[in]  This               Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
1077   @param[in]  Action             Specifies the type of action taken by the browser.
1078   @param[in]  QuestionId         A unique value which is sent to the original
1079                                  exporting driver so that it can identify the type
1080                                  of data to expect. The format of the data tends to
1081                                  vary based on the opcode that enerated the callback.
1082   @param[in]  Type               The type of value for the question.
1083   @param[in]  Value              A pointer to the data being sent to the original
1084                                  exporting driver.
1085   @param[out] ActionRequest      On return, points to the action requested by the
1086                                  callback function.
1087 
1088   @retval EFI_SUCCESS            The callback successfully handled the action.
1089   @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the
1090                                  variable and its data.
1091   @retval EFI_DEVICE_ERROR       The variable could not be saved.
1092   @retval EFI_UNSUPPORTED        The specified Action is not supported by the
1093                                  callback.Currently not implemented.
1094   @retval EFI_INVALID_PARAMETERS Passing in wrong parameter.
1095   @retval Others                 Other errors as indicated.
1096 
1097 **/
1098 EFI_STATUS
1099 EFIAPI
Ip4FormCallback(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)1100 Ip4FormCallback (
1101   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
1102   IN  EFI_BROWSER_ACTION                     Action,
1103   IN  EFI_QUESTION_ID                        QuestionId,
1104   IN  UINT8                                  Type,
1105   IN  EFI_IFR_TYPE_VALUE                     *Value,
1106   OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
1107   )
1108 {
1109   EFI_STATUS                Status;
1110   IP4_CONFIG2_INSTANCE      *Instance;
1111   IP4_CONFIG2_IFR_NVDATA    *IfrFormNvData;
1112   IP4_FORM_CALLBACK_INFO    *Private;
1113 
1114   EFI_IP_ADDRESS            StationAddress;
1115   EFI_IP_ADDRESS            SubnetMask;
1116   EFI_IP_ADDRESS            Gateway;
1117   IP4_ADDR                  Ip;
1118   EFI_IPv4_ADDRESS          *DnsAddress;
1119   UINTN                     DnsCount;
1120   UINTN                     Index;
1121   EFI_INPUT_KEY             Key;
1122 
1123   IfrFormNvData = NULL;
1124   DnsCount      = 0;
1125   DnsAddress    = NULL;
1126 
1127   if (Action == EFI_BROWSER_ACTION_CHANGED) {
1128     Private = IP4_FORM_CALLBACK_INFO_FROM_CONFIG_ACCESS(This);
1129     Instance = IP4_CONFIG2_INSTANCE_FROM_FORM_CALLBACK(Private);
1130 
1131     IfrFormNvData = AllocateZeroPool (sizeof (IP4_CONFIG2_IFR_NVDATA));
1132     if (IfrFormNvData == NULL) {
1133       return EFI_OUT_OF_RESOURCES;
1134     }
1135 
1136     //
1137     // Retrieve uncommitted data from Browser
1138     //
1139     if (!HiiGetBrowserData (&gIp4Config2NvDataGuid, mIp4Config2StorageName, sizeof (IP4_CONFIG2_IFR_NVDATA), (UINT8 *) IfrFormNvData)) {
1140       FreePool (IfrFormNvData);
1141       return EFI_NOT_FOUND;
1142     }
1143 
1144     Status = EFI_SUCCESS;
1145 
1146     switch (QuestionId) {
1147     case KEY_LOCAL_IP:
1148       Status = Ip4Config2StrToIp (IfrFormNvData->StationAddress, &StationAddress.v4);
1149       if (EFI_ERROR (Status) || IP4_IS_UNSPECIFIED (NTOHL (StationAddress.Addr[0])) || IP4_IS_LOCAL_BROADCAST (NTOHL (StationAddress.Addr[0]))) {
1150         CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid IP address!", NULL);
1151         Status = EFI_INVALID_PARAMETER;
1152       }
1153       break;
1154 
1155     case KEY_SUBNET_MASK:
1156       Status = Ip4Config2StrToIp (IfrFormNvData->SubnetMask, &SubnetMask.v4);
1157       if (EFI_ERROR (Status) || ((SubnetMask.Addr[0] != 0) && (GetSubnetMaskPrefixLength (&SubnetMask.v4) == 0))) {
1158         CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Subnet Mask!", NULL);
1159         Status = EFI_INVALID_PARAMETER;
1160       }
1161       break;
1162 
1163     case KEY_GATE_WAY:
1164       Status = Ip4Config2StrToIp (IfrFormNvData->GatewayAddress, &Gateway.v4);
1165       if (EFI_ERROR (Status) || IP4_IS_LOCAL_BROADCAST(NTOHL(Gateway.Addr[0]))) {
1166         CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Gateway!", NULL);
1167         Status = EFI_INVALID_PARAMETER;
1168       }
1169       break;
1170 
1171     case KEY_DNS:
1172       Status = Ip4Config2StrToIpList (IfrFormNvData->DnsAddress, &DnsAddress, &DnsCount);
1173       if (!EFI_ERROR (Status) && DnsCount > 0) {
1174         for (Index = 0; Index < DnsCount; Index ++) {
1175           CopyMem (&Ip, &DnsAddress[Index], sizeof (IP4_ADDR));
1176           if (IP4_IS_UNSPECIFIED (NTOHL (Ip)) || IP4_IS_LOCAL_BROADCAST (NTOHL (Ip))) {
1177             CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Dns Server!", NULL);
1178             Status = EFI_INVALID_PARAMETER;
1179             break;
1180           }
1181         }
1182       } else {
1183         if (EFI_ERROR (Status)) {
1184           CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Dns Server!", NULL);
1185         }
1186       }
1187 
1188       if(DnsAddress != NULL) {
1189         FreePool(DnsAddress);
1190       }
1191       break;
1192 
1193     case KEY_SAVE_CHANGES:
1194       Status = Ip4Config2ConvertIfrNvDataToConfigNvData (IfrFormNvData, Instance);
1195       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
1196       break;
1197 
1198     default:
1199       break;
1200     }
1201 
1202     FreePool (IfrFormNvData);
1203 
1204     return Status;
1205   }
1206 
1207   //
1208   // All other action return unsupported.
1209   //
1210   return EFI_UNSUPPORTED;
1211 }
1212 
1213 /**
1214   Install HII Config Access protocol for network device and allocate resource.
1215 
1216   @param[in, out]  Instance        The IP4 config2 Instance.
1217 
1218   @retval EFI_SUCCESS              The HII Config Access protocol is installed.
1219   @retval EFI_OUT_OF_RESOURCES     Failed to allocate memory.
1220   @retval Others                   Other errors as indicated.
1221 
1222 **/
1223 EFI_STATUS
Ip4Config2FormInit(IN OUT IP4_CONFIG2_INSTANCE * Instance)1224 Ip4Config2FormInit (
1225   IN OUT IP4_CONFIG2_INSTANCE     *Instance
1226   )
1227 {
1228   EFI_STATUS                     Status;
1229   IP4_SERVICE                    *IpSb;
1230   IP4_FORM_CALLBACK_INFO         *CallbackInfo;
1231   EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
1232   VENDOR_DEVICE_PATH             VendorDeviceNode;
1233   EFI_SERVICE_BINDING_PROTOCOL   *MnpSb;
1234   CHAR16                         *MacString;
1235   CHAR16                         MenuString[128];
1236   CHAR16                         PortString[128];
1237   CHAR16                         *OldMenuString;
1238   EFI_DEVICE_PATH_PROTOCOL       *ParentDevicePath;
1239 
1240   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
1241   ASSERT (IpSb != NULL);
1242 
1243   CallbackInfo = &Instance->CallbackInfo;
1244 
1245   CallbackInfo->Signature = IP4_FORM_CALLBACK_INFO_SIGNATURE;
1246 
1247   Status = gBS->HandleProtocol (
1248                   IpSb->Controller,
1249                   &gEfiDevicePathProtocolGuid,
1250                   (VOID **) &ParentDevicePath
1251                   );
1252   if (EFI_ERROR (Status)) {
1253     return Status;
1254   }
1255 
1256   //
1257   // Construct device path node for EFI HII Config Access protocol,
1258   // which consists of controller physical device path and one hardware
1259   // vendor guid node.
1260   //
1261   ZeroMem (&VendorDeviceNode, sizeof (VENDOR_DEVICE_PATH));
1262   VendorDeviceNode.Header.Type    = HARDWARE_DEVICE_PATH;
1263   VendorDeviceNode.Header.SubType = HW_VENDOR_DP;
1264 
1265   CopyGuid (&VendorDeviceNode.Guid, &gEfiCallerIdGuid);
1266 
1267   SetDevicePathNodeLength (&VendorDeviceNode.Header, sizeof (VENDOR_DEVICE_PATH));
1268   CallbackInfo->HiiVendorDevicePath = AppendDevicePathNode (
1269                                         ParentDevicePath,
1270                                         (EFI_DEVICE_PATH_PROTOCOL *) &VendorDeviceNode
1271                                         );
1272   if (CallbackInfo->HiiVendorDevicePath == NULL) {
1273     Status = EFI_OUT_OF_RESOURCES;
1274     goto Error;
1275   }
1276 
1277   ConfigAccess                = &CallbackInfo->HiiConfigAccessProtocol;
1278   ConfigAccess->ExtractConfig = Ip4FormExtractConfig;
1279   ConfigAccess->RouteConfig   = Ip4FormRouteConfig;
1280   ConfigAccess->Callback      = Ip4FormCallback;
1281 
1282   //
1283   // Install Device Path Protocol and Config Access protocol on new handle
1284   //
1285   Status = gBS->InstallMultipleProtocolInterfaces (
1286                   &CallbackInfo->ChildHandle,
1287                   &gEfiDevicePathProtocolGuid,
1288                   CallbackInfo->HiiVendorDevicePath,
1289                   &gEfiHiiConfigAccessProtocolGuid,
1290                   ConfigAccess,
1291                   NULL
1292                   );
1293 
1294   if (!EFI_ERROR (Status)) {
1295     //
1296     // Open the Parent Handle for the child
1297     //
1298     Status = gBS->OpenProtocol (
1299                     IpSb->Controller,
1300                     &gEfiManagedNetworkServiceBindingProtocolGuid,
1301                     (VOID **) &MnpSb,
1302                     IpSb->Image,
1303                     CallbackInfo->ChildHandle,
1304                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1305                     );
1306   }
1307 
1308   if (EFI_ERROR (Status)) {
1309     goto Error;
1310   }
1311 
1312   //
1313   // Publish our HII data
1314   //
1315   CallbackInfo->RegisteredHandle = HiiAddPackages (
1316                                      &gIp4Config2NvDataGuid,
1317                                      CallbackInfo->ChildHandle,
1318                                      Ip4DxeStrings,
1319                                      Ip4Config2Bin,
1320                                      NULL
1321                                      );
1322   if (CallbackInfo->RegisteredHandle == NULL) {
1323     Status = EFI_OUT_OF_RESOURCES;
1324     goto Error;
1325   }
1326 
1327   //
1328   // Append MAC string in the menu help string and tile help string
1329   //
1330   Status = NetLibGetMacString (IpSb->Controller, IpSb->Image, &MacString);
1331   if (!EFI_ERROR (Status)) {
1332     OldMenuString = HiiGetString (
1333                       CallbackInfo->RegisteredHandle,
1334                       STRING_TOKEN (STR_IP4_CONFIG2_FORM_HELP),
1335                       NULL
1336                       );
1337     UnicodeSPrint (MenuString, 128, L"%s (MAC:%s)", OldMenuString, MacString);
1338     HiiSetString (
1339       CallbackInfo->RegisteredHandle,
1340       STRING_TOKEN (STR_IP4_CONFIG2_FORM_HELP),
1341       MenuString,
1342       NULL
1343       );
1344 
1345     UnicodeSPrint (PortString, 128, L"MAC:%s", MacString);
1346     HiiSetString (
1347       CallbackInfo->RegisteredHandle,
1348       STRING_TOKEN (STR_IP4_DEVICE_FORM_HELP),
1349       PortString,
1350       NULL
1351       );
1352 
1353     FreePool (MacString);
1354     FreePool (OldMenuString);
1355 
1356     return EFI_SUCCESS;
1357   }
1358 
1359 Error:
1360   Ip4Config2FormUnload (Instance);
1361   return Status;
1362 }
1363 
1364 /**
1365   Uninstall the HII Config Access protocol for network devices and free up the resources.
1366 
1367   @param[in, out]  Instance      The IP4 config2 instance to unload a form.
1368 
1369 **/
1370 VOID
Ip4Config2FormUnload(IN OUT IP4_CONFIG2_INSTANCE * Instance)1371 Ip4Config2FormUnload (
1372   IN OUT IP4_CONFIG2_INSTANCE     *Instance
1373   )
1374 {
1375   IP4_SERVICE                    *IpSb;
1376   IP4_FORM_CALLBACK_INFO         *CallbackInfo;
1377   IP4_CONFIG2_NVDATA             *Ip4NvData;
1378 
1379   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
1380   ASSERT (IpSb != NULL);
1381 
1382   CallbackInfo = &Instance->CallbackInfo;
1383 
1384   if (CallbackInfo->ChildHandle != NULL) {
1385     //
1386     // Close the child handle
1387     //
1388     gBS->CloseProtocol (
1389            IpSb->Controller,
1390            &gEfiManagedNetworkServiceBindingProtocolGuid,
1391            IpSb->Image,
1392            CallbackInfo->ChildHandle
1393            );
1394 
1395     //
1396     // Uninstall EFI_HII_CONFIG_ACCESS_PROTOCOL
1397     //
1398     gBS->UninstallMultipleProtocolInterfaces (
1399            CallbackInfo->ChildHandle,
1400            &gEfiDevicePathProtocolGuid,
1401            CallbackInfo->HiiVendorDevicePath,
1402            &gEfiHiiConfigAccessProtocolGuid,
1403            &CallbackInfo->HiiConfigAccessProtocol,
1404            NULL
1405            );
1406   }
1407 
1408   if (CallbackInfo->HiiVendorDevicePath != NULL) {
1409     FreePool (CallbackInfo->HiiVendorDevicePath);
1410   }
1411 
1412   if (CallbackInfo->RegisteredHandle != NULL) {
1413     //
1414     // Remove HII package list
1415     //
1416     HiiRemovePackages (CallbackInfo->RegisteredHandle);
1417   }
1418 
1419   Ip4NvData = &Instance->Ip4NvData;
1420 
1421   if(Ip4NvData->ManualAddress != NULL) {
1422     FreePool(Ip4NvData->ManualAddress);
1423   }
1424 
1425   if(Ip4NvData->GatewayAddress != NULL) {
1426     FreePool(Ip4NvData->GatewayAddress);
1427   }
1428 
1429   if(Ip4NvData->DnsAddress != NULL) {
1430     FreePool(Ip4NvData->DnsAddress);
1431   }
1432 
1433   Ip4NvData->ManualAddressCount  = 0;
1434   Ip4NvData->GatewayAddressCount = 0;
1435   Ip4NvData->DnsAddressCount     = 0;
1436 }
1437