1 /** @file
2   The implementation of EFI IPv4 Configuration II Protocol.
3 
4   Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
5   (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<BR>
6 
7   SPDX-License-Identifier: BSD-2-Clause-Patent
8 
9 **/
10 
11 #include "Ip4Impl.h"
12 
13 LIST_ENTRY  mIp4Config2InstanceList = {&mIp4Config2InstanceList, &mIp4Config2InstanceList};
14 
15 /**
16   The event process routine when the DHCPv4 service binding protocol is installed
17   in the system.
18 
19   @param[in]     Event         Not used.
20   @param[in]     Context       Pointer to the IP4 config2 instance data.
21 
22 **/
23 VOID
24 EFIAPI
25 Ip4Config2OnDhcp4SbInstalled (
26   IN EFI_EVENT  Event,
27   IN VOID       *Context
28   );
29 
30 /**
31   Destroy the Dhcp4 child in IP4_CONFIG2_INSTANCE and release the resources.
32 
33   @param[in, out] Instance    The buffer of IP4 config2 instance to be freed.
34 
35   @retval EFI_SUCCESS         The child was successfully destroyed.
36   @retval Others              Failed to destroy the child.
37 
38 **/
39 EFI_STATUS
40 Ip4Config2DestroyDhcp4 (
41   IN OUT IP4_CONFIG2_INSTANCE  *Instance
42   )
43 {
44   IP4_SERVICE                 *IpSb;
45   EFI_STATUS                  Status;
46   EFI_DHCP4_PROTOCOL          *Dhcp4;
47 
48   Dhcp4 = Instance->Dhcp4;
49   ASSERT (Dhcp4 != NULL);
50 
51   Dhcp4->Stop (Dhcp4);
52   Dhcp4->Configure (Dhcp4, NULL);
53   Instance->Dhcp4 = NULL;
54 
55   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
56 
57   //
58   // Close DHCPv4 protocol and destroy the child.
59   //
60   Status = gBS->CloseProtocol (
61                   Instance->Dhcp4Handle,
62                   &gEfiDhcp4ProtocolGuid,
63                   IpSb->Image,
64                   IpSb->Controller
65                   );
66   if (EFI_ERROR (Status)) {
67     return Status;
68   }
69 
70   Status = NetLibDestroyServiceChild (
71              IpSb->Controller,
72              IpSb->Image,
73              &gEfiDhcp4ServiceBindingProtocolGuid,
74              Instance->Dhcp4Handle
75              );
76 
77   Instance->Dhcp4Handle = NULL;
78 
79   return Status;
80 }
81 
82 /**
83   Update the current policy to NewPolicy. During the transition
84   period, the default router list
85   and address list in all interfaces will be released.
86 
87   @param[in]  IpSb               The IP4 service binding instance.
88   @param[in]  NewPolicy          The new policy to be updated to.
89 
90 **/
91 VOID
92 Ip4Config2OnPolicyChanged (
93   IN IP4_SERVICE            *IpSb,
94   IN EFI_IP4_CONFIG2_POLICY NewPolicy
95   )
96 {
97   IP4_INTERFACE   *IpIf;
98   IP4_ROUTE_TABLE *RouteTable;
99 
100   //
101   // Currently there are only two policies: static and dhcp. Regardless of
102   // what transition is going on, i.e., static -> dhcp and dhcp ->
103   // static, we have to free default router table and all addresses.
104   //
105 
106   if (IpSb->DefaultInterface != NULL) {
107     if (IpSb->DefaultRouteTable != NULL) {
108       Ip4FreeRouteTable (IpSb->DefaultRouteTable);
109       IpSb->DefaultRouteTable = NULL;
110     }
111 
112     Ip4CancelReceive (IpSb->DefaultInterface);
113 
114     Ip4FreeInterface (IpSb->DefaultInterface, NULL);
115     IpSb->DefaultInterface = NULL;
116   }
117 
118   Ip4CleanAssembleTable (&IpSb->Assemble);
119 
120   //
121   // Create new default interface and route table.
122   //
123   IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);
124   if (IpIf == NULL) {
125     return ;
126   }
127 
128   RouteTable = Ip4CreateRouteTable ();
129   if (RouteTable == NULL) {
130     Ip4FreeInterface (IpIf, NULL);
131     return ;
132   }
133 
134   IpSb->DefaultInterface  = IpIf;
135   InsertHeadList (&IpSb->Interfaces, &IpIf->Link);
136   IpSb->DefaultRouteTable = RouteTable;
137   Ip4ReceiveFrame (IpIf, NULL, Ip4AccpetFrame, IpSb);
138 
139   if (IpSb->State == IP4_SERVICE_CONFIGED || IpSb->State == IP4_SERVICE_STARTED) {
140     IpSb->State = IP4_SERVICE_UNSTARTED;
141   }
142 
143   //
144   // Start the dhcp configuration.
145   //
146   if (NewPolicy == Ip4Config2PolicyDhcp) {
147     Ip4StartAutoConfig (&IpSb->Ip4Config2Instance);
148   }
149 
150 }
151 
152 /**
153   Signal the registered event. It is the callback routine for NetMapIterate.
154 
155   @param[in]  Map    Points to the list of registered event.
156   @param[in]  Item   The registered event.
157   @param[in]  Arg    Not used.
158 
159   @retval EFI_SUCCESS           The event was signaled successfully.
160 **/
161 EFI_STATUS
162 EFIAPI
163 Ip4Config2SignalEvent (
164   IN NET_MAP                *Map,
165   IN NET_MAP_ITEM           *Item,
166   IN VOID                   *Arg
167   )
168 {
169   gBS->SignalEvent ((EFI_EVENT) Item->Key);
170 
171   return EFI_SUCCESS;
172 }
173 
174 /**
175   Read the configuration data from variable storage according to the VarName and
176   gEfiIp4Config2ProtocolGuid. It checks the integrity of variable data. If the
177   data is corrupted, it clears the variable data to ZERO. Otherwise, it outputs the
178   configuration data to IP4_CONFIG2_INSTANCE.
179 
180   @param[in]      VarName       The pointer to the variable name
181   @param[in, out] Instance      The pointer to the IP4 config2 instance data.
182 
183   @retval EFI_NOT_FOUND         The variable can not be found or already corrupted.
184   @retval EFI_OUT_OF_RESOURCES  Fail to allocate resource to complete the operation.
185   @retval EFI_SUCCESS           The configuration data was retrieved successfully.
186 
187 **/
188 EFI_STATUS
189 Ip4Config2ReadConfigData (
190   IN     CHAR16               *VarName,
191   IN OUT IP4_CONFIG2_INSTANCE *Instance
192   )
193 {
194   EFI_STATUS              Status;
195   UINTN                   VarSize;
196   IP4_CONFIG2_VARIABLE    *Variable;
197   IP4_CONFIG2_DATA_ITEM   *DataItem;
198   UINTN                   Index;
199   IP4_CONFIG2_DATA_RECORD DataRecord;
200   CHAR8                   *Data;
201 
202   //
203   // Try to read the configuration variable.
204   //
205   VarSize = 0;
206   Status  = gRT->GetVariable (
207                    VarName,
208                    &gEfiIp4Config2ProtocolGuid,
209                    NULL,
210                    &VarSize,
211                    NULL
212                    );
213 
214   if (Status == EFI_BUFFER_TOO_SMALL) {
215     //
216     // Allocate buffer and read the config variable.
217     //
218     Variable = AllocatePool (VarSize);
219     if (Variable == NULL) {
220       return EFI_OUT_OF_RESOURCES;
221     }
222 
223     Status = gRT->GetVariable (
224                     VarName,
225                     &gEfiIp4Config2ProtocolGuid,
226                     NULL,
227                     &VarSize,
228                     Variable
229                     );
230     if (EFI_ERROR (Status) || (UINT16) (~NetblockChecksum ((UINT8 *) Variable, (UINT32) VarSize)) != 0) {
231       //
232       // GetVariable still error or the variable is corrupted.
233       // Fall back to the default value.
234       //
235       FreePool (Variable);
236 
237       //
238       // Remove the problematic variable and return EFI_NOT_FOUND, a new
239       // variable will be set again.
240       //
241       gRT->SetVariable (
242              VarName,
243              &gEfiIp4Config2ProtocolGuid,
244              IP4_CONFIG2_VARIABLE_ATTRIBUTE,
245              0,
246              NULL
247              );
248 
249       return EFI_NOT_FOUND;
250     }
251 
252 
253     for (Index = 0; Index < Variable->DataRecordCount; Index++) {
254 
255       CopyMem (&DataRecord, &Variable->DataRecord[Index], sizeof (DataRecord));
256 
257       DataItem = &Instance->DataItem[DataRecord.DataType];
258       if (DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED) &&
259           (DataItem->DataSize != DataRecord.DataSize)
260           ) {
261         //
262         // Perhaps a corrupted data record...
263         //
264         continue;
265       }
266 
267       if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED)) {
268         //
269         // This data item has variable length data.
270         //
271         DataItem->Data.Ptr = AllocatePool (DataRecord.DataSize);
272         if (DataItem->Data.Ptr == NULL) {
273           //
274           // no memory resource
275           //
276           continue;
277         }
278       }
279 
280       Data = (CHAR8 *) Variable + DataRecord.Offset;
281       CopyMem (DataItem->Data.Ptr, Data, DataRecord.DataSize);
282 
283       DataItem->DataSize = DataRecord.DataSize;
284       DataItem->Status   = EFI_SUCCESS;
285     }
286 
287     FreePool (Variable);
288     return EFI_SUCCESS;
289   }
290 
291   return Status;
292 }
293 
294 /**
295   Write the configuration data from IP4_CONFIG2_INSTANCE to variable storage.
296 
297   @param[in]      VarName       The pointer to the variable name.
298   @param[in]      Instance      The pointer to the IP4 config2 instance data.
299 
300   @retval EFI_OUT_OF_RESOURCES  Fail to allocate resource to complete the operation.
301   @retval EFI_SUCCESS           The configuration data is written successfully.
302 
303 **/
304 EFI_STATUS
305 Ip4Config2WriteConfigData (
306   IN CHAR16               *VarName,
307   IN IP4_CONFIG2_INSTANCE *Instance
308   )
309 {
310   UINTN                   Index;
311   UINTN                   VarSize;
312   IP4_CONFIG2_DATA_ITEM   *DataItem;
313   IP4_CONFIG2_VARIABLE    *Variable;
314   IP4_CONFIG2_DATA_RECORD *DataRecord;
315   CHAR8                   *Heap;
316   EFI_STATUS              Status;
317 
318   VarSize = sizeof (IP4_CONFIG2_VARIABLE) - sizeof (IP4_CONFIG2_DATA_RECORD);
319 
320   for (Index = 0; Index < Ip4Config2DataTypeMaximum; Index++) {
321 
322     DataItem = &Instance->DataItem[Index];
323     if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_VOLATILE) && !EFI_ERROR (DataItem->Status)) {
324 
325       VarSize += sizeof (IP4_CONFIG2_DATA_RECORD) + DataItem->DataSize;
326     }
327   }
328 
329   Variable = AllocatePool (VarSize);
330   if (Variable == NULL) {
331     return EFI_OUT_OF_RESOURCES;
332   }
333 
334   Heap                      = (CHAR8 *) Variable + VarSize;
335   Variable->DataRecordCount = 0;
336 
337   for (Index = 0; Index < Ip4Config2DataTypeMaximum; Index++) {
338 
339     DataItem = &Instance->DataItem[Index];
340     if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_VOLATILE) && !EFI_ERROR (DataItem->Status)) {
341 
342       Heap -= DataItem->DataSize;
343       CopyMem (Heap, DataItem->Data.Ptr, DataItem->DataSize);
344 
345       DataRecord           = &Variable->DataRecord[Variable->DataRecordCount];
346       DataRecord->DataType = (EFI_IP4_CONFIG2_DATA_TYPE) Index;
347       DataRecord->DataSize = (UINT32) DataItem->DataSize;
348       DataRecord->Offset   = (UINT16) (Heap - (CHAR8 *) Variable);
349 
350       Variable->DataRecordCount++;
351     }
352   }
353 
354   Variable->Checksum = 0;
355   Variable->Checksum = (UINT16) ~NetblockChecksum ((UINT8 *) Variable, (UINT32) VarSize);
356 
357   Status = gRT->SetVariable (
358                   VarName,
359                   &gEfiIp4Config2ProtocolGuid,
360                   IP4_CONFIG2_VARIABLE_ATTRIBUTE,
361                   VarSize,
362                   Variable
363                   );
364 
365   FreePool (Variable);
366 
367   return Status;
368 }
369 
370 
371 /**
372   Build a EFI_IP4_ROUTE_TABLE to be returned to the caller of GetModeData.
373   The EFI_IP4_ROUTE_TABLE is clumsy to use in the internal operation of the
374   IP4 driver.
375 
376   @param[in]   IpSb        The IP4 service binding instance.
377   @param[out]  Table       The built IP4 route table.
378 
379   @retval EFI_SUCCESS           The route table is successfully build
380   @retval EFI_NOT_FOUND         Failed to allocate the memory for the route table.
381 
382 **/
383 EFI_STATUS
384 Ip4Config2BuildDefaultRouteTable (
385   IN  IP4_SERVICE               *IpSb,
386   OUT EFI_IP4_ROUTE_TABLE       *Table
387   )
388 {
389   LIST_ENTRY                *Entry;
390   IP4_ROUTE_ENTRY           *RtEntry;
391   UINT32                    Count;
392   INT32                     Index;
393 
394   if (IpSb->DefaultRouteTable == NULL) {
395     return EFI_NOT_FOUND;
396   }
397 
398   Count = IpSb->DefaultRouteTable->TotalNum;
399 
400   if (Count == 0) {
401     return EFI_NOT_FOUND;
402   }
403 
404   //
405   // Copy the route entry to EFI route table. Keep the order of
406   // route entry copied from most specific to default route. That
407   // is, interlevel the route entry from the instance's route area
408   // and those from the default route table's route area.
409   //
410   Count = 0;
411 
412   for (Index = IP4_MASK_MAX; Index >= 0; Index--) {
413 
414     NET_LIST_FOR_EACH (Entry, &(IpSb->DefaultRouteTable->RouteArea[Index])) {
415       RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);
416 
417       EFI_IP4 (Table[Count].SubnetAddress)  = HTONL (RtEntry->Dest & RtEntry->Netmask);
418       EFI_IP4 (Table[Count].SubnetMask)     = HTONL (RtEntry->Netmask);
419       EFI_IP4 (Table[Count].GatewayAddress) = HTONL (RtEntry->NextHop);
420 
421       Count++;
422     }
423 
424   }
425 
426   return EFI_SUCCESS;
427 }
428 
429 /**
430   The event process routine when the DHCPv4 service binding protocol is installed
431   in the system.
432 
433   @param[in]     Event         Not used.
434   @param[in]     Context       The pointer to the IP4 config2 instance data.
435 
436 **/
437 VOID
438 EFIAPI
439 Ip4Config2OnDhcp4SbInstalled (
440   IN EFI_EVENT  Event,
441   IN VOID       *Context
442   )
443 {
444   IP4_CONFIG2_INSTANCE  *Instance;
445 
446   Instance = (IP4_CONFIG2_INSTANCE *) Context;
447 
448   if ((Instance->Dhcp4Handle != NULL) || (Instance->Policy != Ip4Config2PolicyDhcp)) {
449     //
450     // The DHCP4 child is already created or the policy is no longer DHCP.
451     //
452     return ;
453   }
454 
455   Ip4StartAutoConfig (Instance);
456 }
457 
458 /**
459   Set the station address and subnetmask for the default interface.
460 
461   @param[in]  IpSb               The pointer to the IP4 service binding instance.
462   @param[in]  StationAddress     Ip address to be set.
463   @param[in]  SubnetMask         Subnet to be set.
464 
465   @retval EFI_SUCCESS   Set default address successful.
466   @retval Others        Some errors occur in setting.
467 
468 **/
469 EFI_STATUS
470 Ip4Config2SetDefaultAddr (
471   IN IP4_SERVICE            *IpSb,
472   IN IP4_ADDR               StationAddress,
473   IN IP4_ADDR               SubnetMask
474   )
475 {
476   EFI_STATUS                Status;
477   IP4_INTERFACE             *IpIf;
478   IP4_PROTOCOL              *Ip4Instance;
479   EFI_ARP_PROTOCOL          *Arp;
480   LIST_ENTRY                *Entry;
481   IP4_ADDR                  Subnet;
482   IP4_ROUTE_TABLE           *RouteTable;
483 
484   IpIf = IpSb->DefaultInterface;
485   ASSERT (IpIf != NULL);
486 
487   if ((IpIf->Ip == StationAddress) && (IpIf->SubnetMask == SubnetMask)) {
488     IpSb->State = IP4_SERVICE_CONFIGED;
489     return EFI_SUCCESS;
490   }
491 
492   if (IpSb->Reconfig) {
493     //
494     // The default address is changed, free the previous interface first.
495     //
496     if (IpSb->DefaultRouteTable != NULL) {
497       Ip4FreeRouteTable (IpSb->DefaultRouteTable);
498       IpSb->DefaultRouteTable = NULL;
499     }
500 
501     Ip4CancelReceive (IpSb->DefaultInterface);
502     Ip4FreeInterface (IpSb->DefaultInterface, NULL);
503     IpSb->DefaultInterface = NULL;
504     //
505     // Create new default interface and route table.
506     //
507     IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);
508     if (IpIf == NULL) {
509       return EFI_OUT_OF_RESOURCES;
510     }
511 
512     RouteTable = Ip4CreateRouteTable ();
513     if (RouteTable == NULL) {
514       Ip4FreeInterface (IpIf, NULL);
515       return EFI_OUT_OF_RESOURCES;
516     }
517 
518     IpSb->DefaultInterface  = IpIf;
519     InsertHeadList (&IpSb->Interfaces, &IpIf->Link);
520     IpSb->DefaultRouteTable = RouteTable;
521     Ip4ReceiveFrame (IpIf, NULL, Ip4AccpetFrame, IpSb);
522   }
523 
524   if (IpSb->State == IP4_SERVICE_CONFIGED) {
525     IpSb->State = IP4_SERVICE_UNSTARTED;
526   }
527 
528   Status = Ip4SetAddress (IpIf, StationAddress, SubnetMask);
529   if (EFI_ERROR (Status)) {
530     return Status;
531   }
532 
533   if (IpIf->Arp != NULL) {
534     //
535     // A non-NULL IpIf->Arp here means a new ARP child is created when setting default address,
536     // but some IP children may have referenced the default interface before it is configured,
537     // these IP instances also consume this ARP protocol so they need to open it BY_CHILD_CONTROLLER.
538     //
539     Arp = NULL;
540     NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {
541       Ip4Instance = NET_LIST_USER_STRUCT_S (Entry, IP4_PROTOCOL, AddrLink, IP4_PROTOCOL_SIGNATURE);
542       Status = gBS->OpenProtocol (
543                       IpIf->ArpHandle,
544                       &gEfiArpProtocolGuid,
545                       (VOID **) &Arp,
546                       gIp4DriverBinding.DriverBindingHandle,
547                       Ip4Instance->Handle,
548                       EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
549                       );
550       if (EFI_ERROR (Status)) {
551         return Status;
552       }
553     }
554   }
555 
556   //
557   // Add a route for the connected network.
558   //
559   Subnet = StationAddress & SubnetMask;
560 
561   Ip4AddRoute (
562     IpSb->DefaultRouteTable,
563     Subnet,
564     SubnetMask,
565     IP4_ALLZERO_ADDRESS
566     );
567 
568   IpSb->State = IP4_SERVICE_CONFIGED;
569   IpSb->Reconfig = FALSE;
570 
571   return EFI_SUCCESS;
572 }
573 
574 /**
575   Set the station address, subnetmask and gateway address for the default interface.
576 
577   @param[in]  Instance         The pointer to the IP4 config2 instance data.
578   @param[in]  StationAddress   Ip address to be set.
579   @param[in]  SubnetMask       Subnet to be set.
580   @param[in]  GatewayAddress   Gateway to be set.
581 
582   @retval EFI_SUCCESS     Set default If successful.
583   @retval Others          Errors occur as indicated.
584 
585 **/
586 EFI_STATUS
587 Ip4Config2SetDefaultIf (
588   IN IP4_CONFIG2_INSTANCE   *Instance,
589   IN IP4_ADDR               StationAddress,
590   IN IP4_ADDR               SubnetMask,
591   IN IP4_ADDR               GatewayAddress
592   )
593 {
594   EFI_STATUS                Status;
595   IP4_SERVICE               *IpSb;
596 
597   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
598 
599   //
600   // Check whether the StationAddress/SubnetMask pair is valid.
601   //
602   if (!Ip4StationAddressValid (StationAddress, SubnetMask)) {
603     return EFI_INVALID_PARAMETER;
604   }
605 
606   Status = Ip4Config2SetDefaultAddr (IpSb, StationAddress, SubnetMask);
607   if (EFI_ERROR (Status)) {
608     return Status;
609   }
610 
611   //
612   // Create a route if there is a default router.
613   //
614   if (GatewayAddress != IP4_ALLZERO_ADDRESS) {
615     Ip4AddRoute (
616       IpSb->DefaultRouteTable,
617       IP4_ALLZERO_ADDRESS,
618       IP4_ALLZERO_ADDRESS,
619       GatewayAddress
620       );
621   }
622 
623   return EFI_SUCCESS;
624 }
625 
626 
627 /**
628   Release all the DHCP related resources.
629 
630   @param  Instance              The IP4 config2 instance.
631 
632   @return None
633 
634 **/
635 VOID
636 Ip4Config2CleanDhcp4 (
637   IN IP4_CONFIG2_INSTANCE   *Instance
638   )
639 {
640   IP4_SERVICE               *IpSb;
641 
642   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
643 
644   if (Instance->Dhcp4 != NULL) {
645     Instance->Dhcp4->Stop (Instance->Dhcp4);
646 
647     gBS->CloseProtocol (
648           Instance->Dhcp4Handle,
649           &gEfiDhcp4ProtocolGuid,
650           IpSb->Image,
651           IpSb->Controller
652           );
653 
654     Instance->Dhcp4 = NULL;
655   }
656 
657   if (Instance->Dhcp4Handle != NULL) {
658     NetLibDestroyServiceChild (
659       IpSb->Controller,
660       IpSb->Image,
661       &gEfiDhcp4ServiceBindingProtocolGuid,
662       Instance->Dhcp4Handle
663       );
664 
665     Instance->Dhcp4Handle = NULL;
666   }
667 
668   if (Instance->Dhcp4Event != NULL) {
669     gBS->CloseEvent (Instance->Dhcp4Event);
670     Instance->Dhcp4Event = NULL;
671   }
672 }
673 
674 /**
675   This worker function sets the DNS server list for the EFI IPv4 network
676   stack running on the communication device that this EFI_IP4_CONFIG2_PROTOCOL
677   manages. The DNS server addresses must be unicast IPv4 addresses.
678 
679   @param[in]     Instance        The pointer to the IP4 config2 instance data.
680   @param[in]     DataSize        The size of the buffer pointed to by Data in bytes.
681   @param[in]     Data            The data buffer to set, points to an array of
682                                  EFI_IPv4_ADDRESS instances.
683 
684   @retval EFI_BAD_BUFFER_SIZE    The DataSize does not match the size of the type.
685   @retval EFI_INVALID_PARAMETER  One or more fields in Data is invalid.
686   @retval EFI_OUT_OF_RESOURCES   Failed to allocate resources to complete the operation.
687   @retval EFI_ABORTED            The DNS server addresses to be set equal the current
688                                  configuration.
689   @retval EFI_SUCCESS            The specified configuration data for the EFI IPv4
690                                  network stack was set.
691 
692 **/
693 EFI_STATUS
694 Ip4Config2SetDnsServerWorker (
695   IN IP4_CONFIG2_INSTANCE    *Instance,
696   IN UINTN                   DataSize,
697   IN VOID                    *Data
698   )
699 {
700   UINTN                 OldIndex;
701   UINTN                 NewIndex;
702   EFI_IPv4_ADDRESS      *OldDns;
703   EFI_IPv4_ADDRESS      *NewDns;
704   UINTN                 OldDnsCount;
705   UINTN                 NewDnsCount;
706   IP4_CONFIG2_DATA_ITEM *Item;
707   BOOLEAN               OneAdded;
708   VOID                  *Tmp;
709   IP4_ADDR              DnsAddress;
710 
711   if ((DataSize % sizeof (EFI_IPv4_ADDRESS) != 0) || (DataSize == 0)) {
712     return EFI_BAD_BUFFER_SIZE;
713   }
714 
715   Item        = &Instance->DataItem[Ip4Config2DataTypeDnsServer];
716   NewDns      = (EFI_IPv4_ADDRESS *) Data;
717   OldDns      = Item->Data.DnsServers;
718   NewDnsCount = DataSize / sizeof (EFI_IPv4_ADDRESS);
719   OldDnsCount = Item->DataSize / sizeof (EFI_IPv4_ADDRESS);
720   OneAdded    = FALSE;
721 
722   if (NewDnsCount != OldDnsCount) {
723     Tmp = AllocatePool (DataSize);
724     if (Tmp == NULL) {
725       return EFI_OUT_OF_RESOURCES;
726     }
727   } else {
728     Tmp = NULL;
729   }
730 
731   for (NewIndex = 0; NewIndex < NewDnsCount; NewIndex++) {
732     CopyMem (&DnsAddress, NewDns + NewIndex, sizeof (IP4_ADDR));
733     if (IP4_IS_UNSPECIFIED (NTOHL (DnsAddress)) || IP4_IS_LOCAL_BROADCAST (NTOHL (DnsAddress))) {
734       //
735       // The dns server address must be unicast.
736       //
737       if (Tmp != NULL) {
738         FreePool (Tmp);
739       }
740       return EFI_INVALID_PARAMETER;
741     }
742 
743     if (OneAdded) {
744       //
745       // If any address in the new setting is not in the old settings, skip the
746       // comparision below.
747       //
748       continue;
749     }
750 
751     for (OldIndex = 0; OldIndex < OldDnsCount; OldIndex++) {
752       if (EFI_IP4_EQUAL (NewDns + NewIndex, OldDns + OldIndex)) {
753         //
754         // If found break out.
755         //
756         break;
757       }
758     }
759 
760     if (OldIndex == OldDnsCount) {
761       OneAdded = TRUE;
762     }
763   }
764 
765   if (!OneAdded && (DataSize == Item->DataSize)) {
766     //
767     // No new item is added and the size is the same.
768     //
769     Item->Status = EFI_SUCCESS;
770     return EFI_ABORTED;
771   } else {
772     if (Tmp != NULL) {
773       if (Item->Data.Ptr != NULL) {
774         FreePool (Item->Data.Ptr);
775       }
776       Item->Data.Ptr = Tmp;
777     }
778 
779     CopyMem (Item->Data.Ptr, Data, DataSize);
780     Item->DataSize = DataSize;
781     Item->Status   = EFI_SUCCESS;
782     return EFI_SUCCESS;
783   }
784 }
785 
786 
787 
788 /**
789   Callback function when DHCP process finished. It will save the
790   retrieved IP configure parameter from DHCP to the NVRam.
791 
792   @param  Event                  The callback event
793   @param  Context                Opaque context to the callback
794 
795   @return None
796 
797 **/
798 VOID
799 EFIAPI
800 Ip4Config2OnDhcp4Complete (
801   IN EFI_EVENT              Event,
802   IN VOID                   *Context
803   )
804 {
805   IP4_CONFIG2_INSTANCE      *Instance;
806   EFI_DHCP4_MODE_DATA       Dhcp4Mode;
807   EFI_STATUS                Status;
808   IP4_ADDR                  StationAddress;
809   IP4_ADDR                  SubnetMask;
810   IP4_ADDR                  GatewayAddress;
811   UINT32                    Index;
812   UINT32                    OptionCount;
813   EFI_DHCP4_PACKET_OPTION   **OptionList;
814 
815   Instance = (IP4_CONFIG2_INSTANCE *) Context;
816   ASSERT (Instance->Dhcp4 != NULL);
817 
818   //
819   // Get the DHCP retrieved parameters
820   //
821   Status = Instance->Dhcp4->GetModeData (Instance->Dhcp4, &Dhcp4Mode);
822 
823   if (EFI_ERROR (Status)) {
824     goto Exit;
825   }
826 
827   if (Dhcp4Mode.State == Dhcp4Bound) {
828     StationAddress = EFI_NTOHL (Dhcp4Mode.ClientAddress);
829     SubnetMask = EFI_NTOHL (Dhcp4Mode.SubnetMask);
830     GatewayAddress = EFI_NTOHL (Dhcp4Mode.RouterAddress);
831 
832     Status = Ip4Config2SetDefaultIf (Instance, StationAddress, SubnetMask, GatewayAddress);
833     if (EFI_ERROR (Status)) {
834       goto Exit;
835     }
836 
837     //
838     // Parse the ACK to get required DNS server information.
839     //
840     OptionCount = 0;
841     OptionList  = NULL;
842 
843     Status      = Instance->Dhcp4->Parse (Instance->Dhcp4, Dhcp4Mode.ReplyPacket, &OptionCount, OptionList);
844     if (Status != EFI_BUFFER_TOO_SMALL) {
845       goto Exit;
846     }
847 
848     OptionList = AllocateZeroPool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));
849     if (OptionList == NULL) {
850       goto Exit;
851     }
852 
853     Status = Instance->Dhcp4->Parse (Instance->Dhcp4, Dhcp4Mode.ReplyPacket, &OptionCount, OptionList);
854     if (EFI_ERROR (Status)) {
855       FreePool (OptionList);
856       goto Exit;
857     }
858 
859     for (Index = 0; Index < OptionCount; Index++) {
860       //
861       // Look for DNS Server opcode (6).
862       //
863       if (OptionList[Index]->OpCode == DHCP4_TAG_DNS_SERVER) {
864         if (((OptionList[Index]->Length & 0x3) != 0) || (OptionList[Index]->Length == 0)) {
865           break;
866         }
867 
868         Ip4Config2SetDnsServerWorker (Instance, OptionList[Index]->Length, &OptionList[Index]->Data[0]);
869         break;
870       }
871     }
872 
873     FreePool (OptionList);
874 
875     Instance->DhcpSuccess = TRUE;
876   }
877 
878 Exit:
879   Ip4Config2CleanDhcp4 (Instance);
880   DispatchDpc ();
881 }
882 
883 
884 /**
885   Start the DHCP configuration for this IP service instance.
886   It will locates the EFI_IP4_CONFIG2_PROTOCOL, then start the
887   DHCP configuration.
888 
889   @param[in]  Instance           The IP4 config2 instance to configure
890 
891   @retval EFI_SUCCESS            The auto configuration is successfully started
892   @retval Others                 Failed to start auto configuration.
893 
894 **/
895 EFI_STATUS
896 Ip4StartAutoConfig (
897   IN IP4_CONFIG2_INSTANCE   *Instance
898   )
899 {
900   IP4_SERVICE                    *IpSb;
901   EFI_DHCP4_PROTOCOL             *Dhcp4;
902   EFI_DHCP4_MODE_DATA            Dhcp4Mode;
903   EFI_DHCP4_PACKET_OPTION        *OptionList[1];
904   IP4_CONFIG2_DHCP4_OPTION       ParaList;
905   EFI_STATUS                     Status;
906 
907   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
908 
909   if (IpSb->State > IP4_SERVICE_UNSTARTED) {
910     return EFI_SUCCESS;
911   }
912 
913   //
914   // A host must not invoke DHCP configuration if it is already
915   // participating in the DHCP configuration process.
916   //
917   if (Instance->Dhcp4Handle != NULL) {
918     return EFI_SUCCESS;
919   }
920 
921   Status = NetLibCreateServiceChild (
922              IpSb->Controller,
923              IpSb->Image,
924              &gEfiDhcp4ServiceBindingProtocolGuid,
925              &Instance->Dhcp4Handle
926              );
927 
928   if (Status == EFI_UNSUPPORTED) {
929     //
930     // No DHCPv4 Service Binding protocol, register a notify.
931     //
932     if (Instance->Dhcp4SbNotifyEvent == NULL) {
933       Instance->Dhcp4SbNotifyEvent = EfiCreateProtocolNotifyEvent (
934                                        &gEfiDhcp4ServiceBindingProtocolGuid,
935                                        TPL_CALLBACK,
936                                        Ip4Config2OnDhcp4SbInstalled,
937                                        (VOID *) Instance,
938                                        &Instance->Registration
939                                        );
940     }
941   }
942 
943   if (EFI_ERROR (Status)) {
944     return Status;
945   }
946 
947   if (Instance->Dhcp4SbNotifyEvent != NULL) {
948     gBS->CloseEvent (Instance->Dhcp4SbNotifyEvent);
949   }
950 
951   Status = gBS->OpenProtocol (
952                   Instance->Dhcp4Handle,
953                   &gEfiDhcp4ProtocolGuid,
954                   (VOID **) &Instance->Dhcp4,
955                   IpSb->Image,
956                   IpSb->Controller,
957                   EFI_OPEN_PROTOCOL_BY_DRIVER
958                   );
959   if (EFI_ERROR (Status)) {
960     NetLibDestroyServiceChild (
961       IpSb->Controller,
962       IpSb->Image,
963       &gEfiDhcp4ServiceBindingProtocolGuid,
964       Instance->Dhcp4Handle
965       );
966 
967     Instance->Dhcp4Handle = NULL;
968 
969     return Status;
970   }
971 
972   //
973   // Check the current DHCP status, if the DHCP process has
974   // already finished, return now.
975   //
976   Dhcp4  = Instance->Dhcp4;
977   Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4Mode);
978   if (Dhcp4Mode.State == Dhcp4Bound) {
979     Ip4Config2OnDhcp4Complete (NULL, Instance);
980 
981     return EFI_SUCCESS;
982   }
983 
984   //
985   // Try to start the DHCP process. Use most of the current
986   // DHCP configuration to avoid problems if some DHCP client
987   // yields the control of this DHCP service to us.
988   //
989   ParaList.Head.OpCode             = DHCP4_TAG_PARA_LIST;
990   ParaList.Head.Length             = 3;
991   ParaList.Head.Data[0]            = DHCP4_TAG_NETMASK;
992   ParaList.Route                   = DHCP4_TAG_ROUTER;
993   ParaList.Dns                     = DHCP4_TAG_DNS_SERVER;
994   OptionList[0]                    = &ParaList.Head;
995   Dhcp4Mode.ConfigData.OptionCount = 1;
996   Dhcp4Mode.ConfigData.OptionList  = OptionList;
997 
998   Status = Dhcp4->Configure (Dhcp4, &Dhcp4Mode.ConfigData);
999   if (EFI_ERROR (Status)) {
1000     gBS->CloseProtocol (
1001            Instance->Dhcp4Handle,
1002            &gEfiDhcp4ProtocolGuid,
1003            IpSb->Image,
1004            IpSb->Controller
1005            );
1006 
1007     NetLibDestroyServiceChild (
1008       IpSb->Controller,
1009       IpSb->Image,
1010       &gEfiDhcp4ServiceBindingProtocolGuid,
1011       Instance->Dhcp4Handle
1012       );
1013 
1014     Instance->Dhcp4 = NULL;
1015 
1016     Instance->Dhcp4Handle = NULL;
1017 
1018     return Status;
1019   }
1020 
1021   //
1022   // Start the DHCP process
1023   //
1024   Status = gBS->CreateEvent (
1025                   EVT_NOTIFY_SIGNAL,
1026                   TPL_CALLBACK,
1027                   Ip4Config2OnDhcp4Complete,
1028                   Instance,
1029                   &Instance->Dhcp4Event
1030                   );
1031   if (EFI_ERROR (Status)) {
1032     Ip4Config2DestroyDhcp4 (Instance);
1033     return Status;
1034   }
1035 
1036   Status = Dhcp4->Start (Dhcp4, Instance->Dhcp4Event);
1037   if (EFI_ERROR (Status)) {
1038     Ip4Config2DestroyDhcp4 (Instance);
1039     gBS->CloseEvent (Instance->Dhcp4Event);
1040     Instance->Dhcp4Event = NULL;
1041 
1042     return Status;
1043   }
1044 
1045   IpSb->State = IP4_SERVICE_STARTED;
1046   DispatchDpc ();
1047 
1048   return EFI_SUCCESS;
1049 }
1050 
1051 
1052 
1053 /**
1054   The work function is to get the interface information of the communication
1055   device this IP4_CONFIG2_INSTANCE manages.
1056 
1057   @param[in]      Instance Pointer to the IP4 config2 instance data.
1058   @param[in, out] DataSize On input, in bytes, the size of Data. On output, in
1059                            bytes, the size of buffer required to store the specified
1060                            configuration data.
1061   @param[in]      Data     The data buffer in which the configuration data is returned.
1062                            Ignored if DataSize is ZERO.
1063 
1064   @retval EFI_BUFFER_TOO_SMALL The size of Data is too small for the specified
1065                                configuration data, and the required size is
1066                                returned in DataSize.
1067   @retval EFI_SUCCESS          The specified configuration data was obtained.
1068 
1069 **/
1070 EFI_STATUS
1071 Ip4Config2GetIfInfo (
1072   IN IP4_CONFIG2_INSTANCE *Instance,
1073   IN OUT UINTN            *DataSize,
1074   IN VOID                 *Data      OPTIONAL
1075   )
1076 {
1077   IP4_SERVICE                    *IpSb;
1078   UINTN                          Length;
1079   IP4_CONFIG2_DATA_ITEM          *Item;
1080   EFI_IP4_CONFIG2_INTERFACE_INFO *IfInfo;
1081   IP4_ADDR                       Address;
1082 
1083   IpSb   = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
1084   Length = sizeof (EFI_IP4_CONFIG2_INTERFACE_INFO);
1085 
1086   if (IpSb->DefaultRouteTable != NULL) {
1087     Length += IpSb->DefaultRouteTable->TotalNum * sizeof (EFI_IP4_ROUTE_TABLE);
1088   }
1089 
1090   if (*DataSize < Length) {
1091     *DataSize = Length;
1092     return EFI_BUFFER_TOO_SMALL;
1093   }
1094 
1095   //
1096   // Copy the fixed size part of the interface info.
1097   //
1098   Item = &Instance->DataItem[Ip4Config2DataTypeInterfaceInfo];
1099   IfInfo = (EFI_IP4_CONFIG2_INTERFACE_INFO *) Data;
1100   CopyMem (IfInfo, Item->Data.Ptr, sizeof (EFI_IP4_CONFIG2_INTERFACE_INFO));
1101 
1102   //
1103   // Update the address info.
1104   //
1105   if (IpSb->DefaultInterface != NULL) {
1106     Address = HTONL (IpSb->DefaultInterface->Ip);
1107     CopyMem (&IfInfo->StationAddress, &Address, sizeof (EFI_IPv4_ADDRESS));
1108     Address = HTONL (IpSb->DefaultInterface->SubnetMask);
1109     CopyMem (&IfInfo->SubnetMask, &Address, sizeof (EFI_IPv4_ADDRESS));
1110   }
1111 
1112   if (IpSb->DefaultRouteTable != NULL) {
1113     IfInfo->RouteTableSize = IpSb->DefaultRouteTable->TotalNum;
1114     IfInfo->RouteTable   = (EFI_IP4_ROUTE_TABLE *) ((UINT8 *) Data + sizeof (EFI_IP4_CONFIG2_INTERFACE_INFO));
1115 
1116     Ip4Config2BuildDefaultRouteTable (IpSb, IfInfo->RouteTable);
1117   }
1118 
1119   return EFI_SUCCESS;
1120 }
1121 
1122 /**
1123   The work function is to set the general configuration policy for the EFI IPv4 network
1124   stack that is running on the communication device managed by this IP4_CONFIG2_INSTANCE.
1125   The policy will affect other configuration settings.
1126 
1127   @param[in]     Instance Pointer to the IP4 config2 instance data.
1128   @param[in]     DataSize Size of the buffer pointed to by Data in bytes.
1129   @param[in]     Data     The data buffer to set.
1130 
1131   @retval EFI_INVALID_PARAMETER The to be set policy is invalid.
1132   @retval EFI_BAD_BUFFER_SIZE   The DataSize does not match the size of the type.
1133   @retval EFI_ABORTED           The new policy equals the current policy.
1134   @retval EFI_SUCCESS           The specified configuration data for the EFI IPv6
1135                                 network stack was set.
1136 
1137 **/
1138 EFI_STATUS
1139 Ip4Config2SetPolicy (
1140   IN IP4_CONFIG2_INSTANCE *Instance,
1141   IN UINTN                DataSize,
1142   IN VOID                 *Data
1143   )
1144 {
1145   EFI_IP4_CONFIG2_POLICY NewPolicy;
1146   IP4_CONFIG2_DATA_ITEM  *DataItem;
1147   IP4_SERVICE            *IpSb;
1148 
1149   if (DataSize != sizeof (EFI_IP4_CONFIG2_POLICY)) {
1150     return EFI_BAD_BUFFER_SIZE;
1151   }
1152 
1153   NewPolicy = *((EFI_IP4_CONFIG2_POLICY *) Data);
1154 
1155   if (NewPolicy >= Ip4Config2PolicyMax) {
1156     return EFI_INVALID_PARAMETER;
1157   }
1158 
1159   if (NewPolicy == Instance->Policy) {
1160     if (NewPolicy != Ip4Config2PolicyDhcp || Instance->DhcpSuccess) {
1161       return EFI_ABORTED;
1162     }
1163   } else {
1164     //
1165     // The policy is changed. Clean the ManualAddress, Gateway and DnsServers,
1166     // shrink the variable data size, and fire up all the related events.
1167     //
1168     DataItem           = &Instance->DataItem[Ip4Config2DataTypeManualAddress];
1169     if (DataItem->Data.Ptr != NULL) {
1170       FreePool (DataItem->Data.Ptr);
1171     }
1172     DataItem->Data.Ptr = NULL;
1173     DataItem->DataSize = 0;
1174     DataItem->Status   = EFI_NOT_FOUND;
1175     NetMapIterate (&DataItem->EventMap, Ip4Config2SignalEvent, NULL);
1176 
1177     DataItem           = &Instance->DataItem[Ip4Config2DataTypeGateway];
1178     if (DataItem->Data.Ptr != NULL) {
1179       FreePool (DataItem->Data.Ptr);
1180     }
1181     DataItem->Data.Ptr = NULL;
1182     DataItem->DataSize = 0;
1183     DataItem->Status   = EFI_NOT_FOUND;
1184     NetMapIterate (&DataItem->EventMap, Ip4Config2SignalEvent, NULL);
1185 
1186     DataItem           = &Instance->DataItem[Ip4Config2DataTypeDnsServer];
1187     if (DataItem->Data.Ptr != NULL) {
1188       FreePool (DataItem->Data.Ptr);
1189     }
1190     DataItem->Data.Ptr = NULL;
1191     DataItem->DataSize = 0;
1192     DataItem->Status   = EFI_NOT_FOUND;
1193     NetMapIterate (&DataItem->EventMap, Ip4Config2SignalEvent, NULL);
1194 
1195     if (NewPolicy == Ip4Config2PolicyDhcp) {
1196       SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_VOLATILE);
1197     } else {
1198       //
1199       // The policy is changed from dhcp to static. Stop the DHCPv4 process
1200       // and destroy the DHCPv4 child.
1201       //
1202       if (Instance->Dhcp4Handle != NULL) {
1203         Ip4Config2DestroyDhcp4 (Instance);
1204       }
1205 
1206       //
1207       // Close the event.
1208       //
1209       if (Instance->Dhcp4Event != NULL) {
1210         gBS->CloseEvent (Instance->Dhcp4Event);
1211         Instance->Dhcp4Event = NULL;
1212       }
1213     }
1214   }
1215 
1216   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
1217   Ip4Config2OnPolicyChanged (IpSb, NewPolicy);
1218 
1219   Instance->Policy = NewPolicy;
1220 
1221   return EFI_SUCCESS;
1222 }
1223 
1224 /**
1225   The work function is to set the station addresses manually for the EFI IPv4
1226   network stack. It is only configurable when the policy is Ip4Config2PolicyStatic.
1227 
1228   @param[in]     Instance Pointer to the IP4 config2 instance data.
1229   @param[in]     DataSize Size of the buffer pointed to by Data in bytes.
1230   @param[in]     Data     The data buffer to set.
1231 
1232   @retval EFI_BAD_BUFFER_SIZE   The DataSize does not match the size of the type.
1233   @retval EFI_WRITE_PROTECTED   The specified configuration data cannot be set
1234                                 under the current policy.
1235   @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.
1236   @retval EFI_OUT_OF_RESOURCES  Fail to allocate resource to complete the operation.
1237   @retval EFI_NOT_READY         An asynchronous process is invoked to set the specified
1238                                 configuration data, and the process is not finished.
1239   @retval EFI_ABORTED           The manual addresses to be set equal current
1240                                 configuration.
1241   @retval EFI_SUCCESS           The specified configuration data for the EFI IPv6
1242                                 network stack was set.
1243 
1244 **/
1245 EFI_STATUS
1246 Ip4Config2SetManualAddress (
1247   IN IP4_CONFIG2_INSTANCE *Instance,
1248   IN UINTN                DataSize,
1249   IN VOID                 *Data
1250   )
1251 {
1252   EFI_IP4_CONFIG2_MANUAL_ADDRESS NewAddress;
1253   IP4_CONFIG2_DATA_ITEM          *DataItem;
1254   EFI_STATUS                     Status;
1255   IP4_ADDR                       StationAddress;
1256   IP4_ADDR                       SubnetMask;
1257   VOID                           *Ptr;
1258   IP4_SERVICE                    *IpSb;
1259   IP4_INTERFACE                  *IpIf;
1260   IP4_ROUTE_TABLE                *RouteTable;
1261 
1262   DataItem   = NULL;
1263   Status     = EFI_SUCCESS;
1264   Ptr        = NULL;
1265   IpIf       = NULL;
1266   RouteTable = NULL;
1267 
1268   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
1269 
1270   ASSERT (Instance->DataItem[Ip4Config2DataTypeManualAddress].Status != EFI_NOT_READY);
1271 
1272   if ((DataSize != 0) && ((DataSize % sizeof (EFI_IP4_CONFIG2_MANUAL_ADDRESS)) != 0)) {
1273     return EFI_BAD_BUFFER_SIZE;
1274   }
1275 
1276   if (Instance->Policy != Ip4Config2PolicyStatic) {
1277     return EFI_WRITE_PROTECTED;
1278   }
1279 
1280   DataItem = &Instance->DataItem[Ip4Config2DataTypeManualAddress];
1281 
1282   if (Data != NULL && DataSize != 0) {
1283     NewAddress = *((EFI_IP4_CONFIG2_MANUAL_ADDRESS *) Data);
1284 
1285     StationAddress = EFI_NTOHL (NewAddress.Address);
1286     SubnetMask = EFI_NTOHL (NewAddress.SubnetMask);
1287 
1288     //
1289     // Check whether the StationAddress/SubnetMask pair is valid.
1290     //
1291     if (!Ip4StationAddressValid (StationAddress, SubnetMask)) {
1292       return EFI_INVALID_PARAMETER;
1293     }
1294 
1295     //
1296     // Store the new data, and init the DataItem status to EFI_NOT_READY because
1297     // we may have an asynchronous configuration process.
1298     //
1299     Ptr = AllocateCopyPool (DataSize, Data);
1300     if (Ptr == NULL) {
1301       return EFI_OUT_OF_RESOURCES;
1302     }
1303 
1304     if (DataItem->Data.Ptr != NULL) {
1305       FreePool (DataItem->Data.Ptr);
1306     }
1307 
1308     DataItem->Data.Ptr = Ptr;
1309     DataItem->DataSize = DataSize;
1310     DataItem->Status   = EFI_NOT_READY;
1311 
1312     IpSb->Reconfig = TRUE;
1313     Status = Ip4Config2SetDefaultAddr (IpSb, StationAddress, SubnetMask);
1314 
1315     DataItem->Status = Status;
1316 
1317     if (EFI_ERROR (DataItem->Status) && DataItem->Status != EFI_NOT_READY) {
1318       if (Ptr != NULL) {
1319         FreePool (Ptr);
1320       }
1321       DataItem->Data.Ptr = NULL;
1322     }
1323   } else {
1324     //
1325     // DataSize is 0 and Data is NULL, clean up the manual address.
1326     //
1327     if (DataItem->Data.Ptr != NULL) {
1328       FreePool (DataItem->Data.Ptr);
1329     }
1330     DataItem->Data.Ptr = NULL;
1331     DataItem->DataSize = 0;
1332     DataItem->Status   = EFI_NOT_FOUND;
1333 
1334     //
1335     // Free the default router table and Interface, clean up the assemble table.
1336     //
1337     if (IpSb->DefaultInterface != NULL) {
1338       if (IpSb->DefaultRouteTable != NULL) {
1339         Ip4FreeRouteTable (IpSb->DefaultRouteTable);
1340         IpSb->DefaultRouteTable = NULL;
1341       }
1342 
1343       Ip4CancelReceive (IpSb->DefaultInterface);
1344 
1345       Ip4FreeInterface (IpSb->DefaultInterface, NULL);
1346       IpSb->DefaultInterface = NULL;
1347     }
1348 
1349     Ip4CleanAssembleTable (&IpSb->Assemble);
1350 
1351     //
1352     // Create new default interface and route table.
1353     //
1354     IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);
1355     if (IpIf == NULL) {
1356       return EFI_OUT_OF_RESOURCES;
1357     }
1358 
1359     RouteTable = Ip4CreateRouteTable ();
1360     if (RouteTable == NULL) {
1361       Ip4FreeInterface (IpIf, NULL);
1362       return EFI_OUT_OF_RESOURCES;
1363     }
1364 
1365     IpSb->DefaultInterface  = IpIf;
1366     InsertHeadList (&IpSb->Interfaces, &IpIf->Link);
1367     IpSb->DefaultRouteTable = RouteTable;
1368     Ip4ReceiveFrame (IpIf, NULL, Ip4AccpetFrame, IpSb);
1369 
1370     //
1371     // Reset the State to unstarted.
1372     //
1373     if (IpSb->State == IP4_SERVICE_CONFIGED || IpSb->State == IP4_SERVICE_STARTED) {
1374       IpSb->State = IP4_SERVICE_UNSTARTED;
1375     }
1376   }
1377 
1378   return Status;
1379 }
1380 
1381 /**
1382   The work function is to set the gateway addresses manually for the EFI IPv4
1383   network stack that is running on the communication device that this EFI IPv4
1384   Configuration Protocol manages. It is not configurable when the policy is
1385   Ip4Config2PolicyDhcp. The gateway addresses must be unicast IPv4 addresses.
1386 
1387   @param[in]     Instance The pointer to the IP4 config2 instance data.
1388   @param[in]     DataSize The size of the buffer pointed to by Data in bytes.
1389   @param[in]     Data     The data buffer to set. This points to an array of
1390                           EFI_IPv6_ADDRESS instances.
1391 
1392   @retval EFI_BAD_BUFFER_SIZE   The DataSize does not match the size of the type.
1393   @retval EFI_WRITE_PROTECTED   The specified configuration data cannot be set
1394                                 under the current policy.
1395   @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.
1396   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource to complete the operation.
1397   @retval EFI_ABORTED           The manual gateway addresses to be set equal the
1398                                 current configuration.
1399   @retval EFI_SUCCESS           The specified configuration data for the EFI IPv6
1400                                 network stack was set.
1401 
1402 **/
1403 EFI_STATUS
1404 Ip4Config2SetGateway (
1405   IN IP4_CONFIG2_INSTANCE *Instance,
1406   IN UINTN                DataSize,
1407   IN VOID                 *Data
1408   )
1409 {
1410   IP4_SERVICE                    *IpSb;
1411   IP4_CONFIG2_DATA_ITEM          *DataItem;
1412   IP4_ADDR                       Gateway;
1413 
1414   UINTN                 Index1;
1415   UINTN                 Index2;
1416   EFI_IPv4_ADDRESS      *OldGateway;
1417   EFI_IPv4_ADDRESS      *NewGateway;
1418   UINTN                 OldGatewayCount;
1419   UINTN                 NewGatewayCount;
1420   BOOLEAN               OneRemoved;
1421   BOOLEAN               OneAdded;
1422   VOID                  *Tmp;
1423 
1424   OldGateway      = NULL;
1425   NewGateway      = NULL;
1426   OneRemoved      = FALSE;
1427   OneAdded        = FALSE;
1428   Tmp             = NULL;
1429 
1430   if ((DataSize != 0) && (DataSize % sizeof (EFI_IPv4_ADDRESS) != 0)) {
1431     return EFI_BAD_BUFFER_SIZE;
1432   }
1433 
1434   if (Instance->Policy != Ip4Config2PolicyStatic) {
1435     return EFI_WRITE_PROTECTED;
1436   }
1437 
1438   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
1439 
1440   DataItem        = &Instance->DataItem[Ip4Config2DataTypeGateway];
1441   OldGateway      = DataItem->Data.Gateway;
1442   OldGatewayCount = DataItem->DataSize / sizeof (EFI_IPv4_ADDRESS);
1443 
1444   for (Index1 = 0; Index1 < OldGatewayCount; Index1++) {
1445     //
1446     // Remove the old route entry.
1447     //
1448     CopyMem (&Gateway, OldGateway + Index1, sizeof (IP4_ADDR));
1449     Ip4DelRoute (
1450       IpSb->DefaultRouteTable,
1451       IP4_ALLZERO_ADDRESS,
1452       IP4_ALLZERO_ADDRESS,
1453       NTOHL (Gateway)
1454       );
1455     OneRemoved = TRUE;
1456   }
1457 
1458   if (Data != NULL && DataSize != 0) {
1459     NewGateway      = (EFI_IPv4_ADDRESS *) Data;
1460     NewGatewayCount = DataSize / sizeof (EFI_IPv4_ADDRESS);
1461     for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {
1462       CopyMem (&Gateway, NewGateway + Index1, sizeof (IP4_ADDR));
1463 
1464       if ((IpSb->DefaultInterface->SubnetMask != 0) &&
1465           !NetIp4IsUnicast (NTOHL (Gateway), IpSb->DefaultInterface->SubnetMask)) {
1466         return EFI_INVALID_PARAMETER;
1467       }
1468 
1469       for (Index2 = Index1 + 1; Index2 < NewGatewayCount; Index2++) {
1470         if (EFI_IP4_EQUAL (NewGateway + Index1, NewGateway + Index2)) {
1471           return EFI_INVALID_PARAMETER;
1472         }
1473       }
1474     }
1475 
1476     if (NewGatewayCount != OldGatewayCount) {
1477       Tmp = AllocatePool (DataSize);
1478       if (Tmp == NULL) {
1479         return EFI_OUT_OF_RESOURCES;
1480       }
1481     } else {
1482       Tmp = NULL;
1483     }
1484 
1485     for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {
1486       //
1487       // Add the new route entry.
1488       //
1489       CopyMem (&Gateway, NewGateway + Index1, sizeof (IP4_ADDR));
1490       Ip4AddRoute (
1491         IpSb->DefaultRouteTable,
1492         IP4_ALLZERO_ADDRESS,
1493         IP4_ALLZERO_ADDRESS,
1494         NTOHL (Gateway)
1495         );
1496 
1497       OneAdded = TRUE;
1498     }
1499 
1500     if (!OneRemoved && !OneAdded) {
1501       DataItem->Status = EFI_SUCCESS;
1502       return EFI_ABORTED;
1503     } else {
1504       if (Tmp != NULL) {
1505         if (DataItem->Data.Ptr != NULL) {
1506           FreePool (DataItem->Data.Ptr);
1507         }
1508         DataItem->Data.Ptr = Tmp;
1509       }
1510 
1511       CopyMem (DataItem->Data.Ptr, Data, DataSize);
1512       DataItem->DataSize = DataSize;
1513       DataItem->Status   = EFI_SUCCESS;
1514     }
1515   } else {
1516     //
1517     // DataSize is 0 and Data is NULL, clean up the Gateway address.
1518     //
1519     if (DataItem->Data.Ptr != NULL) {
1520       FreePool (DataItem->Data.Ptr);
1521     }
1522     DataItem->Data.Ptr = NULL;
1523     DataItem->DataSize = 0;
1524     DataItem->Status   = EFI_NOT_FOUND;
1525   }
1526 
1527   return EFI_SUCCESS;
1528 }
1529 
1530 /**
1531   The work function is to set the DNS server list for the EFI IPv4 network
1532   stack running on the communication device that this EFI_IP4_CONFIG2_PROTOCOL
1533   manages. It is not configurable when the policy is Ip4Config2PolicyDhcp.
1534   The DNS server addresses must be unicast IPv4 addresses.
1535 
1536   @param[in]     Instance The pointer to the IP4 config2 instance data.
1537   @param[in]     DataSize The size of the buffer pointed to by Data in bytes.
1538   @param[in]     Data     The data buffer to set, points to an array of
1539                           EFI_IPv4_ADDRESS instances.
1540 
1541   @retval EFI_BAD_BUFFER_SIZE   The DataSize does not match the size of the type.
1542   @retval EFI_WRITE_PROTECTED   The specified configuration data cannot be set
1543                                 under the current policy.
1544   @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.
1545   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resources to complete the operation.
1546   @retval EFI_ABORTED           The DNS server addresses to be set equal the current
1547                                 configuration.
1548   @retval EFI_SUCCESS           The specified configuration data for the EFI IPv4
1549                                 network stack was set.
1550 
1551 **/
1552 EFI_STATUS
1553 Ip4Config2SetDnsServer (
1554   IN IP4_CONFIG2_INSTANCE *Instance,
1555   IN UINTN                DataSize,
1556   IN VOID                 *Data
1557   )
1558 {
1559   EFI_STATUS                     Status;
1560   IP4_CONFIG2_DATA_ITEM          *Item;
1561 
1562   Status = EFI_SUCCESS;
1563   Item   = NULL;
1564 
1565   if (Instance->Policy != Ip4Config2PolicyStatic) {
1566     return EFI_WRITE_PROTECTED;
1567   }
1568 
1569   Item = &Instance->DataItem[Ip4Config2DataTypeDnsServer];
1570 
1571   if (DATA_ATTRIB_SET (Item->Attribute, DATA_ATTRIB_VOLATILE)) {
1572     REMOVE_DATA_ATTRIB (Item->Attribute, DATA_ATTRIB_VOLATILE);
1573   }
1574 
1575   if (Data != NULL && DataSize != 0) {
1576     Status = Ip4Config2SetDnsServerWorker (Instance, DataSize, Data);
1577   } else {
1578     //
1579     // DataSize is 0 and Data is NULL, clean up the DnsServer address.
1580     //
1581     if (Item->Data.Ptr != NULL) {
1582       FreePool (Item->Data.Ptr);
1583     }
1584     Item->Data.Ptr = NULL;
1585     Item->DataSize = 0;
1586     Item->Status   = EFI_NOT_FOUND;
1587   }
1588 
1589   return Status;
1590 }
1591 
1592 /**
1593   Generate the operational state of the interface this IP4 config2 instance manages
1594   and output in EFI_IP4_CONFIG2_INTERFACE_INFO.
1595 
1596   @param[in]      IpSb     The pointer to the IP4 service binding instance.
1597   @param[out]     IfInfo   The pointer to the IP4 config2 interface information structure.
1598 
1599 **/
1600 VOID
1601 Ip4Config2InitIfInfo (
1602   IN  IP4_SERVICE                    *IpSb,
1603   OUT EFI_IP4_CONFIG2_INTERFACE_INFO *IfInfo
1604   )
1605 {
1606   UnicodeSPrint (
1607     IfInfo->Name,
1608     EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE,
1609     L"eth%d",
1610     IpSb->Ip4Config2Instance.IfIndex
1611   );
1612 
1613   IfInfo->IfType        = IpSb->SnpMode.IfType;
1614   IfInfo->HwAddressSize = IpSb->SnpMode.HwAddressSize;
1615   CopyMem (&IfInfo->HwAddress, &IpSb->SnpMode.CurrentAddress, IfInfo->HwAddressSize);
1616 }
1617 
1618 
1619 
1620 /**
1621   Set the configuration for the EFI IPv4 network stack running on the communication
1622   device this EFI_IP4_CONFIG2_PROTOCOL instance manages.
1623 
1624   This function is used to set the configuration data of type DataType for the EFI
1625   IPv4 network stack that is running on the communication device that this EFI IPv4
1626   Configuration Protocol instance manages.
1627 
1628   DataSize is used to calculate the count of structure instances in the Data for
1629   a DataType in which multiple structure instances are allowed.
1630 
1631   This function is always non-blocking. When setting some type of configuration data,
1632   an asynchronous process is invoked to check the correctness of the data, such as
1633   performing Duplicate Address Detection on the manually set local IPv4 addresses.
1634   EFI_NOT_READY is returned immediately to indicate that such an asynchronous process
1635   is invoked, and the process is not finished yet. The caller wanting to get the result
1636   of the asynchronous process is required to call RegisterDataNotify() to register an
1637   event on the specified configuration data. Once the event is signaled, the caller
1638   can call GetData() to obtain the configuration data and know the result.
1639   For other types of configuration data that do not require an asynchronous configuration
1640   process, the result of the operation is immediately returned.
1641 
1642   @param[in]     This           The pointer to the EFI_IP4_CONFIG2_PROTOCOL instance.
1643   @param[in]     DataType       The type of data to set.
1644   @param[in]     DataSize       Size of the buffer pointed to by Data in bytes.
1645   @param[in]     Data           The data buffer to set. The type of the data buffer is
1646                                 associated with the DataType.
1647 
1648   @retval EFI_SUCCESS           The specified configuration data for the EFI IPv6
1649                                 network stack was set successfully.
1650   @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
1651                                 - This is NULL.
1652                                 - One or more fields in Data and DataSize do not match the
1653                                   requirement of the data type indicated by DataType.
1654   @retval EFI_WRITE_PROTECTED   The specified configuration data is read-only or the specified
1655                                 configuration data cannot be set under the current policy.
1656   @retval EFI_ACCESS_DENIED     Another set operation on the specified configuration
1657                                 data is already in process.
1658   @retval EFI_NOT_READY         An asynchronous process was invoked to set the specified
1659                                 configuration data, and the process is not finished yet.
1660   @retval EFI_BAD_BUFFER_SIZE   The DataSize does not match the size of the type
1661                                 indicated by DataType.
1662   @retval EFI_UNSUPPORTED       This DataType is not supported.
1663   @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
1664   @retval EFI_DEVICE_ERROR      An unexpected system error or network error occurred.
1665 
1666 **/
1667 EFI_STATUS
1668 EFIAPI
1669 EfiIp4Config2SetData (
1670   IN EFI_IP4_CONFIG2_PROTOCOL   *This,
1671   IN EFI_IP4_CONFIG2_DATA_TYPE  DataType,
1672   IN UINTN                      DataSize,
1673   IN VOID                       *Data
1674   )
1675 {
1676   EFI_TPL              OldTpl;
1677   EFI_STATUS           Status;
1678   IP4_CONFIG2_INSTANCE *Instance;
1679   IP4_SERVICE          *IpSb;
1680 
1681   if ((This == NULL) || (Data == NULL && DataSize != 0) || (Data != NULL && DataSize == 0)) {
1682     return EFI_INVALID_PARAMETER;
1683   }
1684 
1685   if (DataType >= Ip4Config2DataTypeMaximum) {
1686     return EFI_UNSUPPORTED;
1687   }
1688 
1689   Instance = IP4_CONFIG2_INSTANCE_FROM_PROTOCOL (This);
1690   IpSb     = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
1691   NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);
1692 
1693 
1694   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1695 
1696   Status = Instance->DataItem[DataType].Status;
1697   if (Status != EFI_NOT_READY) {
1698 
1699     if (Instance->DataItem[DataType].SetData == NULL) {
1700       //
1701       // This type of data is readonly.
1702       //
1703       Status = EFI_WRITE_PROTECTED;
1704     } else {
1705 
1706       Status = Instance->DataItem[DataType].SetData (Instance, DataSize, Data);
1707       if (!EFI_ERROR (Status)) {
1708         //
1709         // Fire up the events registered with this type of data.
1710         //
1711         NetMapIterate (&Instance->DataItem[DataType].EventMap, Ip4Config2SignalEvent, NULL);
1712         Ip4Config2WriteConfigData (IpSb->MacString, Instance);
1713       } else if (Status == EFI_ABORTED) {
1714         //
1715         // The SetData is aborted because the data to set is the same with
1716         // the one maintained.
1717         //
1718         Status = EFI_SUCCESS;
1719         NetMapIterate (&Instance->DataItem[DataType].EventMap, Ip4Config2SignalEvent, NULL);
1720       }
1721     }
1722   } else {
1723     //
1724     // Another asynchronous process is on the way.
1725     //
1726     Status = EFI_ACCESS_DENIED;
1727   }
1728 
1729   gBS->RestoreTPL (OldTpl);
1730 
1731   return Status;
1732 }
1733 
1734 /**
1735   Get the configuration data for the EFI IPv4 network stack running on the communication
1736   device that this EFI_IP4_CONFIG2_PROTOCOL instance manages.
1737 
1738   This function returns the configuration data of type DataType for the EFI IPv4 network
1739   stack running on the communication device that this EFI IPv4 Configuration Protocol instance
1740   manages.
1741 
1742   The caller is responsible for allocating the buffer used to return the specified
1743   configuration data. The required size will be returned to the caller if the size of
1744   the buffer is too small.
1745 
1746   EFI_NOT_READY is returned if the specified configuration data is not ready due to an
1747   asynchronous configuration process already in progress. The caller can call RegisterDataNotify()
1748   to register an event on the specified configuration data. Once the asynchronous configuration
1749   process is finished, the event will be signaled, and a subsequent GetData() call will return
1750   the specified configuration data.
1751 
1752   @param[in]      This           Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance.
1753   @param[in]      DataType       The type of data to get.
1754   @param[in, out] DataSize       On input, in bytes, the size of Data. On output, in bytes, the
1755                                  size of buffer required to store the specified configuration data.
1756   @param[in]     Data            The data buffer in which the configuration data is returned. The
1757                                  type of the data buffer is associated with the DataType.
1758                                  This is an optional parameter that may be NULL.
1759 
1760   @retval EFI_SUCCESS           The specified configuration data was obtained successfully.
1761   @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE:
1762                                 - This is NULL.
1763                                 - DataSize is NULL.
1764                                 - Data is NULL if *DataSize is not zero.
1765   @retval EFI_BUFFER_TOO_SMALL  The size of Data is too small for the specified configuration data,
1766                                 and the required size is returned in DataSize.
1767   @retval EFI_NOT_READY         The specified configuration data is not ready due to an
1768                                 asynchronous configuration process already in progress.
1769   @retval EFI_NOT_FOUND         The specified configuration data is not found.
1770 
1771 **/
1772 EFI_STATUS
1773 EFIAPI
1774 EfiIp4Config2GetData (
1775   IN EFI_IP4_CONFIG2_PROTOCOL   *This,
1776   IN EFI_IP4_CONFIG2_DATA_TYPE  DataType,
1777   IN OUT UINTN                  *DataSize,
1778   IN VOID                       *Data   OPTIONAL
1779   )
1780 {
1781   EFI_TPL               OldTpl;
1782   EFI_STATUS            Status;
1783   IP4_CONFIG2_INSTANCE  *Instance;
1784   IP4_CONFIG2_DATA_ITEM *DataItem;
1785 
1786   if ((This == NULL) || (DataSize == NULL) || ((*DataSize != 0) && (Data == NULL))) {
1787     return EFI_INVALID_PARAMETER;
1788   }
1789 
1790   if (DataType >= Ip4Config2DataTypeMaximum) {
1791     return EFI_NOT_FOUND;
1792   }
1793 
1794   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1795 
1796   Instance = IP4_CONFIG2_INSTANCE_FROM_PROTOCOL (This);
1797   DataItem = &Instance->DataItem[DataType];
1798 
1799   Status   = Instance->DataItem[DataType].Status;
1800   if (!EFI_ERROR (Status)) {
1801 
1802     if (DataItem->GetData != NULL) {
1803 
1804       Status = DataItem->GetData (Instance, DataSize, Data);
1805     } else if (*DataSize < Instance->DataItem[DataType].DataSize) {
1806       //
1807       // Update the buffer length.
1808       //
1809       *DataSize = Instance->DataItem[DataType].DataSize;
1810       Status    = EFI_BUFFER_TOO_SMALL;
1811     } else {
1812 
1813       *DataSize = Instance->DataItem[DataType].DataSize;
1814       CopyMem (Data, Instance->DataItem[DataType].Data.Ptr, *DataSize);
1815     }
1816   }
1817 
1818   gBS->RestoreTPL (OldTpl);
1819 
1820   return Status;
1821 }
1822 
1823 /**
1824   Register an event that is signaled whenever a configuration process on the specified
1825   configuration data is done.
1826 
1827   This function registers an event that is to be signaled whenever a configuration
1828   process on the specified configuration data is performed. An event can be registered
1829   for a different DataType simultaneously. The caller is responsible for determining
1830   which type of configuration data causes the signaling of the event in such an event.
1831 
1832   @param[in]     This           Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance.
1833   @param[in]     DataType       The type of data to unregister the event for.
1834   @param[in]     Event          The event to register.
1835 
1836   @retval EFI_SUCCESS           The notification event for the specified configuration data is
1837                                 registered.
1838   @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.
1839   @retval EFI_UNSUPPORTED       The configuration data type specified by DataType is not
1840                                 supported.
1841   @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
1842   @retval EFI_ACCESS_DENIED     The Event is already registered for the DataType.
1843 
1844 **/
1845 EFI_STATUS
1846 EFIAPI
1847 EfiIp4Config2RegisterDataNotify (
1848   IN EFI_IP4_CONFIG2_PROTOCOL   *This,
1849   IN EFI_IP4_CONFIG2_DATA_TYPE  DataType,
1850   IN EFI_EVENT                  Event
1851   )
1852 {
1853   EFI_TPL              OldTpl;
1854   EFI_STATUS           Status;
1855   IP4_CONFIG2_INSTANCE *Instance;
1856   NET_MAP              *EventMap;
1857   NET_MAP_ITEM         *Item;
1858 
1859   if ((This == NULL) || (Event == NULL)) {
1860     return EFI_INVALID_PARAMETER;
1861   }
1862 
1863   if (DataType >= Ip4Config2DataTypeMaximum) {
1864     return EFI_UNSUPPORTED;
1865   }
1866 
1867   OldTpl    = gBS->RaiseTPL (TPL_CALLBACK);
1868 
1869   Instance  = IP4_CONFIG2_INSTANCE_FROM_PROTOCOL (This);
1870   EventMap  = &Instance->DataItem[DataType].EventMap;
1871 
1872   //
1873   // Check whether this event is already registered for this DataType.
1874   //
1875   Item = NetMapFindKey (EventMap, Event);
1876   if (Item == NULL) {
1877 
1878     Status = NetMapInsertTail (EventMap, Event, NULL);
1879 
1880     if (EFI_ERROR (Status)) {
1881 
1882       Status = EFI_OUT_OF_RESOURCES;
1883     }
1884 
1885   } else {
1886 
1887     Status = EFI_ACCESS_DENIED;
1888   }
1889 
1890   gBS->RestoreTPL (OldTpl);
1891 
1892   return Status;
1893 }
1894 
1895 /**
1896   Remove a previously registered event for the specified configuration data.
1897 
1898   @param  This                   The pointer to the EFI_IP4_CONFIG2_PROTOCOL instance.
1899   @param  DataType               The type of data to remove from the previously
1900                                  registered event.
1901   @param  Event                  The event to be unregistered.
1902 
1903   @retval EFI_SUCCESS            The event registered for the specified
1904                                  configuration data was removed.
1905   @retval EFI_INVALID_PARAMETER  This is NULL or Event is NULL.
1906   @retval EFI_NOT_FOUND          The Event has not been registered for the
1907                                  specified DataType.
1908 
1909 **/
1910 EFI_STATUS
1911 EFIAPI
1912 EfiIp4Config2UnregisterDataNotify (
1913   IN EFI_IP4_CONFIG2_PROTOCOL   *This,
1914   IN EFI_IP4_CONFIG2_DATA_TYPE  DataType,
1915   IN EFI_EVENT                  Event
1916   )
1917 {
1918   EFI_TPL              OldTpl;
1919   EFI_STATUS           Status;
1920   IP4_CONFIG2_INSTANCE *Instance;
1921   NET_MAP_ITEM         *Item;
1922 
1923   if ((This == NULL) || (Event == NULL)) {
1924     return EFI_INVALID_PARAMETER;
1925   }
1926 
1927   if (DataType >= Ip4Config2DataTypeMaximum) {
1928     return EFI_NOT_FOUND;
1929   }
1930 
1931   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1932 
1933   Instance = IP4_CONFIG2_INSTANCE_FROM_PROTOCOL (This);
1934 
1935   Item = NetMapFindKey (&Instance->DataItem[DataType].EventMap, Event);
1936   if (Item != NULL) {
1937 
1938     NetMapRemoveItem (&Instance->DataItem[DataType].EventMap, Item, NULL);
1939     Status = EFI_SUCCESS;
1940   } else {
1941 
1942     Status = EFI_NOT_FOUND;
1943   }
1944 
1945   gBS->RestoreTPL (OldTpl);
1946 
1947   return Status;
1948 }
1949 
1950 /**
1951   Initialize an IP4_CONFIG2_INSTANCE.
1952 
1953   @param[out]    Instance       The buffer of IP4_CONFIG2_INSTANCE to be initialized.
1954 
1955   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resources to complete the operation.
1956   @retval EFI_SUCCESS           The IP4_CONFIG2_INSTANCE initialized successfully.
1957 
1958 **/
1959 EFI_STATUS
1960 Ip4Config2InitInstance (
1961   OUT IP4_CONFIG2_INSTANCE  *Instance
1962   )
1963 {
1964   IP4_SERVICE           *IpSb;
1965   IP4_CONFIG2_INSTANCE  *TmpInstance;
1966   LIST_ENTRY            *Entry;
1967   EFI_STATUS            Status;
1968   UINTN                 Index;
1969   UINT16                IfIndex;
1970   IP4_CONFIG2_DATA_ITEM *DataItem;
1971 
1972 
1973   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
1974 
1975   Instance->Signature = IP4_CONFIG2_INSTANCE_SIGNATURE;
1976 
1977 
1978   //
1979   // Determine the index of this interface.
1980   //
1981   IfIndex = 0;
1982   NET_LIST_FOR_EACH (Entry, &mIp4Config2InstanceList) {
1983     TmpInstance = NET_LIST_USER_STRUCT_S (Entry, IP4_CONFIG2_INSTANCE, Link, IP4_CONFIG2_INSTANCE_SIGNATURE);
1984 
1985     if (TmpInstance->IfIndex > IfIndex) {
1986       //
1987       // There is a sequence hole because some interface is down.
1988       //
1989       break;
1990     }
1991 
1992     IfIndex++;
1993   }
1994 
1995   Instance->IfIndex = IfIndex;
1996   NetListInsertBefore (Entry, &Instance->Link);
1997 
1998   for (Index = 0; Index < Ip4Config2DataTypeMaximum; Index++) {
1999     //
2000     // Initialize the event map for each data item.
2001     //
2002     NetMapInit (&Instance->DataItem[Index].EventMap);
2003   }
2004 
2005 
2006   //
2007   // Initialize each data type: associate storage and set data size for the
2008   // fixed size data types, hook the SetData function, set the data attribute.
2009   //
2010   DataItem           = &Instance->DataItem[Ip4Config2DataTypeInterfaceInfo];
2011   DataItem->GetData  = Ip4Config2GetIfInfo;
2012   DataItem->Data.Ptr = &Instance->InterfaceInfo;
2013   DataItem->DataSize = sizeof (Instance->InterfaceInfo);
2014   SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED | DATA_ATTRIB_VOLATILE);
2015   Ip4Config2InitIfInfo (IpSb, &Instance->InterfaceInfo);
2016 
2017   DataItem           = &Instance->DataItem[Ip4Config2DataTypePolicy];
2018   DataItem->SetData  = Ip4Config2SetPolicy;
2019   DataItem->Data.Ptr = &Instance->Policy;
2020   DataItem->DataSize = sizeof (Instance->Policy);
2021   Instance->Policy   = Ip4Config2PolicyStatic;
2022   SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED);
2023 
2024   DataItem           = &Instance->DataItem[Ip4Config2DataTypeManualAddress];
2025   DataItem->SetData  = Ip4Config2SetManualAddress;
2026   DataItem->Status   = EFI_NOT_FOUND;
2027 
2028   DataItem           = &Instance->DataItem[Ip4Config2DataTypeGateway];
2029   DataItem->SetData  = Ip4Config2SetGateway;
2030   DataItem->Status   = EFI_NOT_FOUND;
2031 
2032   DataItem           = &Instance->DataItem[Ip4Config2DataTypeDnsServer];
2033   DataItem->SetData  = Ip4Config2SetDnsServer;
2034   DataItem->Status   = EFI_NOT_FOUND;
2035 
2036   Instance->Configured  = TRUE;
2037 
2038   //
2039   // Try to read the config data from NV variable.
2040   // If not found, write initialized config data into NV variable
2041   // as a default config data.
2042   //
2043   Status = Ip4Config2ReadConfigData (IpSb->MacString, Instance);
2044   if (Status == EFI_NOT_FOUND) {
2045     Status = Ip4Config2WriteConfigData (IpSb->MacString, Instance);
2046   }
2047 
2048   if (EFI_ERROR (Status)) {
2049     return Status;
2050   }
2051 
2052   Instance->Ip4Config2.SetData              = EfiIp4Config2SetData;
2053   Instance->Ip4Config2.GetData              = EfiIp4Config2GetData;
2054   Instance->Ip4Config2.RegisterDataNotify   = EfiIp4Config2RegisterDataNotify;
2055   Instance->Ip4Config2.UnregisterDataNotify = EfiIp4Config2UnregisterDataNotify;
2056 
2057   //
2058   // Publish the IP4 configuration form
2059   //
2060   return Ip4Config2FormInit (Instance);
2061 }
2062 
2063 
2064 /**
2065   Release an IP4_CONFIG2_INSTANCE.
2066 
2067   @param[in, out] Instance    The buffer of IP4_CONFIG2_INSTANCE to be freed.
2068 
2069 **/
2070 VOID
2071 Ip4Config2CleanInstance (
2072   IN OUT IP4_CONFIG2_INSTANCE  *Instance
2073   )
2074 {
2075   UINTN                 Index;
2076   IP4_CONFIG2_DATA_ITEM *DataItem;
2077 
2078   if (Instance->DeclineAddress != NULL) {
2079     FreePool (Instance->DeclineAddress);
2080   }
2081 
2082   if (!Instance->Configured) {
2083     return ;
2084   }
2085 
2086   if (Instance->Dhcp4Handle != NULL) {
2087 
2088     Ip4Config2DestroyDhcp4 (Instance);
2089   }
2090 
2091   //
2092   // Close the event.
2093   //
2094   if (Instance->Dhcp4Event != NULL) {
2095     gBS->CloseEvent (Instance->Dhcp4Event);
2096     Instance->Dhcp4Event = NULL;
2097   }
2098 
2099   for (Index = 0; Index < Ip4Config2DataTypeMaximum; Index++) {
2100 
2101     DataItem = &Instance->DataItem[Index];
2102 
2103     if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED)) {
2104       if (DataItem->Data.Ptr != NULL) {
2105         FreePool (DataItem->Data.Ptr);
2106       }
2107       DataItem->Data.Ptr = NULL;
2108       DataItem->DataSize = 0;
2109     }
2110 
2111     NetMapClean (&Instance->DataItem[Index].EventMap);
2112   }
2113 
2114   Ip4Config2FormUnload (Instance);
2115 
2116   RemoveEntryList (&Instance->Link);
2117 }
2118 
2119 /**
2120   The event handle for IP4 auto reconfiguration. The original default
2121   interface and route table will be removed as the default.
2122 
2123   @param[in]  Context                The IP4 service binding instance.
2124 
2125 **/
2126 VOID
2127 EFIAPI
2128 Ip4AutoReconfigCallBackDpc (
2129   IN VOID                   *Context
2130   )
2131 {
2132   IP4_SERVICE               *IpSb;
2133 
2134   IpSb      = (IP4_SERVICE *) Context;
2135   NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);
2136 
2137   if (IpSb->State > IP4_SERVICE_UNSTARTED) {
2138     IpSb->State = IP4_SERVICE_UNSTARTED;
2139   }
2140 
2141   IpSb->Reconfig = TRUE;
2142 
2143   Ip4StartAutoConfig (&IpSb->Ip4Config2Instance);
2144 
2145   return ;
2146 }
2147 
2148 
2149 /**
2150   Request Ip4AutoReconfigCallBackDpc as a DPC at TPL_CALLBACK.
2151 
2152   @param Event     The event that is signalled.
2153   @param Context   The IP4 service binding instance.
2154 
2155 **/
2156 VOID
2157 EFIAPI
2158 Ip4AutoReconfigCallBack (
2159   IN EFI_EVENT              Event,
2160   IN VOID                   *Context
2161   )
2162 {
2163   //
2164   // Request Ip4AutoReconfigCallBackDpc as a DPC at TPL_CALLBACK
2165   //
2166   QueueDpc (TPL_CALLBACK, Ip4AutoReconfigCallBackDpc, Context);
2167 }
2168 
2169