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