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