MdeModulePkg: Fix IPv4 double free
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Ip4Dxe / Ip4Config2Impl.c
1 /** @file
2 The implementation of EFI IPv4 Configuration II Protocol.
3
4 Copyright (c) 2015 - 2016, 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 if (NewPolicy != Ip4Config2PolicyDhcp || Instance->DhcpSuccess) {
1148 return EFI_ABORTED;
1149 }
1150 } else {
1151 if (NewPolicy == Ip4Config2PolicyDhcp) {
1152 //
1153 // The policy is changed from static to dhcp:
1154 // Clean the ManualAddress, Gateway and DnsServers, shrink the variable
1155 // data size, and fire up all the related events.
1156 //
1157 DataItem = &Instance->DataItem[Ip4Config2DataTypeManualAddress];
1158 if (DataItem->Data.Ptr != NULL) {
1159 FreePool (DataItem->Data.Ptr);
1160 }
1161 DataItem->Data.Ptr = NULL;
1162 DataItem->DataSize = 0;
1163 DataItem->Status = EFI_NOT_FOUND;
1164 NetMapIterate (&DataItem->EventMap, Ip4Config2SignalEvent, NULL);
1165
1166 DataItem = &Instance->DataItem[Ip4Config2DataTypeGateway];
1167 if (DataItem->Data.Ptr != NULL) {
1168 FreePool (DataItem->Data.Ptr);
1169 }
1170 DataItem->Data.Ptr = NULL;
1171 DataItem->DataSize = 0;
1172 DataItem->Status = EFI_NOT_FOUND;
1173 NetMapIterate (&DataItem->EventMap, Ip4Config2SignalEvent, NULL);
1174
1175 DataItem = &Instance->DataItem[Ip4Config2DataTypeDnsServer];
1176 if (DataItem->Data.Ptr != NULL) {
1177 FreePool (DataItem->Data.Ptr);
1178 }
1179 DataItem->Data.Ptr = NULL;
1180 DataItem->DataSize = 0;
1181 DataItem->Status = EFI_NOT_FOUND;
1182 NetMapIterate (&DataItem->EventMap, Ip4Config2SignalEvent, NULL);
1183 } else {
1184 //
1185 // The policy is changed from dhcp to static. Stop the DHCPv4 process
1186 // and destroy the DHCPv4 child.
1187 //
1188 if (Instance->Dhcp4Handle != NULL) {
1189 Ip4Config2DestroyDhcp4 (Instance);
1190 }
1191
1192 //
1193 // Close the event.
1194 //
1195 if (Instance->Dhcp4Event != NULL) {
1196 gBS->CloseEvent (Instance->Dhcp4Event);
1197 Instance->Dhcp4Event = NULL;
1198 }
1199 }
1200 }
1201
1202 IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
1203 Ip4Config2OnPolicyChanged (IpSb, NewPolicy);
1204
1205 Instance->Policy = NewPolicy;
1206
1207 return EFI_SUCCESS;
1208 }
1209
1210 /**
1211 The work function is to set the station addresses manually for the EFI IPv4
1212 network stack. It is only configurable when the policy is Ip4Config2PolicyStatic.
1213
1214 @param[in] Instance Pointer to the IP4 config2 instance data.
1215 @param[in] DataSize Size of the buffer pointed to by Data in bytes.
1216 @param[in] Data The data buffer to set.
1217
1218 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.
1219 @retval EFI_WRITE_PROTECTED The specified configuration data cannot be set
1220 under the current policy.
1221 @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.
1222 @retval EFI_OUT_OF_RESOURCES Fail to allocate resource to complete the operation.
1223 @retval EFI_NOT_READY An asynchrous process is invoked to set the specified
1224 configuration data, and the process is not finished.
1225 @retval EFI_ABORTED The manual addresses to be set equal current
1226 configuration.
1227 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6
1228 network stack was set.
1229
1230 **/
1231 EFI_STATUS
1232 Ip4Config2SetMaunualAddress (
1233 IN IP4_CONFIG2_INSTANCE *Instance,
1234 IN UINTN DataSize,
1235 IN VOID *Data
1236 )
1237 {
1238 EFI_IP4_CONFIG2_MANUAL_ADDRESS NewAddress;
1239 IP4_CONFIG2_DATA_ITEM *DataItem;
1240 EFI_STATUS Status;
1241 IP4_ADDR StationAddress;
1242 IP4_ADDR SubnetMask;
1243 VOID *Ptr;
1244 IP4_SERVICE *IpSb;
1245
1246 IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
1247
1248 ASSERT (Instance->DataItem[Ip4Config2DataTypeManualAddress].Status != EFI_NOT_READY);
1249
1250 if (((DataSize % sizeof (EFI_IP4_CONFIG2_MANUAL_ADDRESS)) != 0) || (DataSize == 0)) {
1251 return EFI_BAD_BUFFER_SIZE;
1252 }
1253
1254 if (Instance->Policy != Ip4Config2PolicyStatic) {
1255 return EFI_WRITE_PROTECTED;
1256 }
1257
1258 NewAddress = *((EFI_IP4_CONFIG2_MANUAL_ADDRESS *) Data);
1259
1260 //
1261 // Store the new data, and init the DataItem status to EFI_NOT_READY because
1262 // we may have an asynchronous configuration process.
1263 //
1264 Ptr = AllocateCopyPool (DataSize, Data);
1265 if (Ptr == NULL) {
1266 return EFI_OUT_OF_RESOURCES;
1267 }
1268
1269 DataItem = &Instance->DataItem[Ip4Config2DataTypeManualAddress];
1270 if (DataItem->Data.Ptr != NULL) {
1271 FreePool (DataItem->Data.Ptr);
1272 }
1273
1274 DataItem->Data.Ptr = Ptr;
1275 DataItem->DataSize = DataSize;
1276 DataItem->Status = EFI_NOT_READY;
1277
1278 StationAddress = EFI_NTOHL (NewAddress.Address);
1279 SubnetMask = EFI_NTOHL (NewAddress.SubnetMask);
1280
1281 IpSb->Reconfig = TRUE;
1282 Status = Ip4Config2SetDefaultAddr (IpSb, StationAddress, SubnetMask);
1283 if (EFI_ERROR (Status)) {
1284 goto ON_EXIT;
1285 }
1286
1287 DataItem->Status = EFI_SUCCESS;
1288
1289 ON_EXIT:
1290 if (EFI_ERROR (DataItem->Status)) {
1291 if (Ptr != NULL) {
1292 FreePool (Ptr);
1293 }
1294 DataItem->Data.Ptr = NULL;
1295 }
1296
1297 return EFI_SUCCESS;
1298 }
1299
1300 /**
1301 The work function is to set the gateway addresses manually for the EFI IPv4
1302 network stack that is running on the communication device that this EFI IPv4
1303 Configuration Protocol manages. It is not configurable when the policy is
1304 Ip4Config2PolicyDhcp. The gateway addresses must be unicast IPv4 addresses.
1305
1306 @param[in] Instance The pointer to the IP4 config2 instance data.
1307 @param[in] DataSize The size of the buffer pointed to by Data in bytes.
1308 @param[in] Data The data buffer to set. This points to an array of
1309 EFI_IPv6_ADDRESS instances.
1310
1311 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.
1312 @retval EFI_WRITE_PROTECTED The specified configuration data cannot be set
1313 under the current policy.
1314 @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.
1315 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to complete the operation.
1316 @retval EFI_ABORTED The manual gateway addresses to be set equal the
1317 current configuration.
1318 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6
1319 network stack was set.
1320
1321 **/
1322 EFI_STATUS
1323 Ip4Config2SetGateway (
1324 IN IP4_CONFIG2_INSTANCE *Instance,
1325 IN UINTN DataSize,
1326 IN VOID *Data
1327 )
1328 {
1329 IP4_SERVICE *IpSb;
1330 IP4_CONFIG2_DATA_ITEM *DataItem;
1331 IP4_ADDR Gateway;
1332
1333 UINTN Index1;
1334 UINTN Index2;
1335 EFI_IPv4_ADDRESS *OldGateway;
1336 EFI_IPv4_ADDRESS *NewGateway;
1337 UINTN OldGatewayCount;
1338 UINTN NewGatewayCount;
1339 BOOLEAN OneRemoved;
1340 BOOLEAN OneAdded;
1341 VOID *Tmp;
1342
1343 if ((DataSize % sizeof (EFI_IPv4_ADDRESS) != 0) || (DataSize == 0)) {
1344 return EFI_BAD_BUFFER_SIZE;
1345 }
1346
1347 if (Instance->Policy != Ip4Config2PolicyStatic) {
1348 return EFI_WRITE_PROTECTED;
1349 }
1350
1351
1352 NewGateway = (EFI_IPv4_ADDRESS *) Data;
1353 NewGatewayCount = DataSize / sizeof (EFI_IPv4_ADDRESS);
1354 for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {
1355 CopyMem (&Gateway, NewGateway + Index1, sizeof (IP4_ADDR));
1356
1357 if (!NetIp4IsUnicast (NTOHL (Gateway), 0)) {
1358
1359 return EFI_INVALID_PARAMETER;
1360 }
1361
1362 for (Index2 = Index1 + 1; Index2 < NewGatewayCount; Index2++) {
1363 if (EFI_IP4_EQUAL (NewGateway + Index1, NewGateway + Index2)) {
1364 return EFI_INVALID_PARAMETER;
1365 }
1366 }
1367 }
1368
1369 IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
1370 DataItem = &Instance->DataItem[Ip4Config2DataTypeGateway];
1371 OldGateway = DataItem->Data.Gateway;
1372 OldGatewayCount = DataItem->DataSize / sizeof (EFI_IPv4_ADDRESS);
1373 OneRemoved = FALSE;
1374 OneAdded = FALSE;
1375
1376 if (NewGatewayCount != OldGatewayCount) {
1377 Tmp = AllocatePool (DataSize);
1378 if (Tmp == NULL) {
1379 return EFI_OUT_OF_RESOURCES;
1380 }
1381 } else {
1382 Tmp = NULL;
1383 }
1384
1385 for (Index1 = 0; Index1 < OldGatewayCount; Index1++) {
1386 //
1387 // Remove this route entry.
1388 //
1389 CopyMem (&Gateway, OldGateway + Index1, sizeof (IP4_ADDR));
1390 Ip4DelRoute (
1391 IpSb->DefaultRouteTable,
1392 IP4_ALLZERO_ADDRESS,
1393 IP4_ALLZERO_ADDRESS,
1394 NTOHL (Gateway)
1395 );
1396 OneRemoved = TRUE;
1397
1398 }
1399
1400 for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {
1401 CopyMem (&Gateway, NewGateway + Index1, sizeof (IP4_ADDR));
1402 Ip4AddRoute (
1403 IpSb->DefaultRouteTable,
1404 IP4_ALLZERO_ADDRESS,
1405 IP4_ALLZERO_ADDRESS,
1406 NTOHL (Gateway)
1407 );
1408
1409 OneAdded = TRUE;
1410 }
1411
1412
1413 if (!OneRemoved && !OneAdded) {
1414 DataItem->Status = EFI_SUCCESS;
1415 return EFI_ABORTED;
1416 } else {
1417
1418 if (Tmp != NULL) {
1419 if (DataItem->Data.Ptr != NULL) {
1420 FreePool (DataItem->Data.Ptr);
1421 }
1422 DataItem->Data.Ptr = Tmp;
1423 }
1424
1425 CopyMem (DataItem->Data.Ptr, Data, DataSize);
1426 DataItem->DataSize = DataSize;
1427 DataItem->Status = EFI_SUCCESS;
1428 return EFI_SUCCESS;
1429 }
1430
1431 }
1432
1433 /**
1434 The work function is to set the DNS server list for the EFI IPv4 network
1435 stack running on the communication device that this EFI_IP4_CONFIG2_PROTOCOL
1436 manages. It is not configurable when the policy is Ip4Config2PolicyDhcp.
1437 The DNS server addresses must be unicast IPv4 addresses.
1438
1439 @param[in] Instance The pointer to the IP4 config2 instance data.
1440 @param[in] DataSize The size of the buffer pointed to by Data in bytes.
1441 @param[in] Data The data buffer to set, points to an array of
1442 EFI_IPv4_ADDRESS instances.
1443
1444 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.
1445 @retval EFI_WRITE_PROTECTED The specified configuration data cannot be set
1446 under the current policy.
1447 @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.
1448 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to complete the operation.
1449 @retval EFI_ABORTED The DNS server addresses to be set equal the current
1450 configuration.
1451 @retval EFI_SUCCESS The specified configuration data for the EFI IPv4
1452 network stack was set.
1453
1454 **/
1455 EFI_STATUS
1456 Ip4Config2SetDnsServer (
1457 IN IP4_CONFIG2_INSTANCE *Instance,
1458 IN UINTN DataSize,
1459 IN VOID *Data
1460 )
1461 {
1462 if (Instance->Policy != Ip4Config2PolicyStatic) {
1463 return EFI_WRITE_PROTECTED;
1464 }
1465
1466 return Ip4Config2SetDnsServerWorker (Instance, DataSize, Data);
1467 }
1468
1469 /**
1470 Generate the operational state of the interface this IP4 config2 instance manages
1471 and output in EFI_IP4_CONFIG2_INTERFACE_INFO.
1472
1473 @param[in] IpSb The pointer to the IP4 service binding instance.
1474 @param[out] IfInfo The pointer to the IP4 config2 interface information structure.
1475
1476 **/
1477 VOID
1478 Ip4Config2InitIfInfo (
1479 IN IP4_SERVICE *IpSb,
1480 OUT EFI_IP4_CONFIG2_INTERFACE_INFO *IfInfo
1481 )
1482 {
1483 IfInfo->Name[0] = L'e';
1484 IfInfo->Name[1] = L't';
1485 IfInfo->Name[2] = L'h';
1486 IfInfo->Name[3] = (CHAR16) (L'0' + IpSb->Ip4Config2Instance.IfIndex);
1487 IfInfo->Name[4] = 0;
1488
1489 IfInfo->IfType = IpSb->SnpMode.IfType;
1490 IfInfo->HwAddressSize = IpSb->SnpMode.HwAddressSize;
1491 CopyMem (&IfInfo->HwAddress, &IpSb->SnpMode.CurrentAddress, IfInfo->HwAddressSize);
1492 }
1493
1494 /**
1495 The event handle routine when DHCPv4 process is finished or is updated.
1496
1497 @param[in] Event Not used.
1498 @param[in] Context The pointer to the IP4 configuration instance data.
1499
1500 **/
1501 VOID
1502 EFIAPI
1503 Ip4Config2OnDhcp4Event (
1504 IN EFI_EVENT Event,
1505 IN VOID *Context
1506 )
1507 {
1508 return ;
1509 }
1510
1511
1512 /**
1513 Set the configuration for the EFI IPv4 network stack running on the communication
1514 device this EFI_IP4_CONFIG2_PROTOCOL instance manages.
1515
1516 This function is used to set the configuration data of type DataType for the EFI
1517 IPv4 network stack that is running on the communication device that this EFI IPv4
1518 Configuration Protocol instance manages.
1519
1520 DataSize is used to calculate the count of structure instances in the Data for
1521 a DataType in which multiple structure instances are allowed.
1522
1523 This function is always non-blocking. When setting some type of configuration data,
1524 an asynchronous process is invoked to check the correctness of the data, such as
1525 performing Duplicate Address Detection on the manually set local IPv4 addresses.
1526 EFI_NOT_READY is returned immediately to indicate that such an asynchronous process
1527 is invoked, and the process is not finished yet. The caller wanting to get the result
1528 of the asynchronous process is required to call RegisterDataNotify() to register an
1529 event on the specified configuration data. Once the event is signaled, the caller
1530 can call GetData() to obtain the configuration data and know the result.
1531 For other types of configuration data that do not require an asynchronous configuration
1532 process, the result of the operation is immediately returned.
1533
1534 @param[in] This The pointer to the EFI_IP4_CONFIG2_PROTOCOL instance.
1535 @param[in] DataType The type of data to set.
1536 @param[in] DataSize Size of the buffer pointed to by Data in bytes.
1537 @param[in] Data The data buffer to set. The type of the data buffer is
1538 associated with the DataType.
1539
1540 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6
1541 network stack was set successfully.
1542 @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
1543 - This is NULL.
1544 - Data is NULL.
1545 - One or more fields in Data do not match the requirement of the
1546 data type indicated by DataType.
1547 @retval EFI_WRITE_PROTECTED The specified configuration data is read-only or the specified
1548 configuration data cannot be set under the current policy.
1549 @retval EFI_ACCESS_DENIED Another set operation on the specified configuration
1550 data is already in process.
1551 @retval EFI_NOT_READY An asynchronous process was invoked to set the specified
1552 configuration data, and the process is not finished yet.
1553 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type
1554 indicated by DataType.
1555 @retval EFI_UNSUPPORTED This DataType is not supported.
1556 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1557 @retval EFI_DEVICE_ERROR An unexpected system error or network error occurred.
1558
1559 **/
1560 EFI_STATUS
1561 EFIAPI
1562 EfiIp4Config2SetData (
1563 IN EFI_IP4_CONFIG2_PROTOCOL *This,
1564 IN EFI_IP4_CONFIG2_DATA_TYPE DataType,
1565 IN UINTN DataSize,
1566 IN VOID *Data
1567 )
1568 {
1569 EFI_TPL OldTpl;
1570 EFI_STATUS Status;
1571 IP4_CONFIG2_INSTANCE *Instance;
1572 IP4_SERVICE *IpSb;
1573
1574 if ((This == NULL) || (Data == NULL)) {
1575 return EFI_INVALID_PARAMETER;
1576 }
1577
1578 if (DataType >= Ip4Config2DataTypeMaximum) {
1579 return EFI_UNSUPPORTED;
1580 }
1581
1582 Instance = IP4_CONFIG2_INSTANCE_FROM_PROTOCOL (This);
1583 IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
1584 NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);
1585
1586
1587 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1588
1589 Status = Instance->DataItem[DataType].Status;
1590 if (Status != EFI_NOT_READY) {
1591
1592 if (Instance->DataItem[DataType].SetData == NULL) {
1593 //
1594 // This type of data is readonly.
1595 //
1596 Status = EFI_WRITE_PROTECTED;
1597 } else {
1598
1599 Status = Instance->DataItem[DataType].SetData (Instance, DataSize, Data);
1600 if (!EFI_ERROR (Status)) {
1601 //
1602 // Fire up the events registered with this type of data.
1603 //
1604 NetMapIterate (&Instance->DataItem[DataType].EventMap, Ip4Config2SignalEvent, NULL);
1605 Ip4Config2WriteConfigData (IpSb->MacString, Instance);
1606 } else if (Status == EFI_ABORTED) {
1607 //
1608 // The SetData is aborted because the data to set is the same with
1609 // the one maintained.
1610 //
1611 Status = EFI_SUCCESS;
1612 NetMapIterate (&Instance->DataItem[DataType].EventMap, Ip4Config2SignalEvent, NULL);
1613 }
1614 }
1615 } else {
1616 //
1617 // Another asynchornous process is on the way.
1618 //
1619 Status = EFI_ACCESS_DENIED;
1620 }
1621
1622 gBS->RestoreTPL (OldTpl);
1623
1624 return Status;
1625 }
1626
1627 /**
1628 Get the configuration data for the EFI IPv4 network stack running on the communication
1629 device that this EFI_IP4_CONFIG2_PROTOCOL instance manages.
1630
1631 This function returns the configuration data of type DataType for the EFI IPv4 network
1632 stack running on the communication device that this EFI IPv4 Configuration Protocol instance
1633 manages.
1634
1635 The caller is responsible for allocating the buffer used to return the specified
1636 configuration data. The required size will be returned to the caller if the size of
1637 the buffer is too small.
1638
1639 EFI_NOT_READY is returned if the specified configuration data is not ready due to an
1640 asynchronous configuration process already in progress. The caller can call RegisterDataNotify()
1641 to register an event on the specified configuration data. Once the asynchronous configuration
1642 process is finished, the event will be signaled, and a subsequent GetData() call will return
1643 the specified configuration data.
1644
1645 @param[in] This Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance.
1646 @param[in] DataType The type of data to get.
1647 @param[in, out] DataSize On input, in bytes, the size of Data. On output, in bytes, the
1648 size of buffer required to store the specified configuration data.
1649 @param[in] Data The data buffer in which the configuration data is returned. The
1650 type of the data buffer is associated with the DataType.
1651 This is an optional parameter that may be NULL.
1652
1653 @retval EFI_SUCCESS The specified configuration data was obtained successfully.
1654 @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE:
1655 - This is NULL.
1656 - DataSize is NULL.
1657 - Data is NULL if *DataSize is not zero.
1658 @retval EFI_BUFFER_TOO_SMALL The size of Data is too small for the specified configuration data,
1659 and the required size is returned in DataSize.
1660 @retval EFI_NOT_READY The specified configuration data is not ready due to an
1661 asynchronous configuration process already in progress.
1662 @retval EFI_NOT_FOUND The specified configuration data is not found.
1663
1664 **/
1665 EFI_STATUS
1666 EFIAPI
1667 EfiIp4Config2GetData (
1668 IN EFI_IP4_CONFIG2_PROTOCOL *This,
1669 IN EFI_IP4_CONFIG2_DATA_TYPE DataType,
1670 IN OUT UINTN *DataSize,
1671 IN VOID *Data OPTIONAL
1672 )
1673 {
1674 EFI_TPL OldTpl;
1675 EFI_STATUS Status;
1676 IP4_CONFIG2_INSTANCE *Instance;
1677 IP4_CONFIG2_DATA_ITEM *DataItem;
1678
1679 if ((This == NULL) || (DataSize == NULL) || ((*DataSize != 0) && (Data == NULL))) {
1680 return EFI_INVALID_PARAMETER;
1681 }
1682
1683 if (DataType >= Ip4Config2DataTypeMaximum) {
1684 return EFI_NOT_FOUND;
1685 }
1686
1687 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1688
1689 Instance = IP4_CONFIG2_INSTANCE_FROM_PROTOCOL (This);
1690 DataItem = &Instance->DataItem[DataType];
1691
1692 Status = Instance->DataItem[DataType].Status;
1693 if (!EFI_ERROR (Status)) {
1694
1695 if (DataItem->GetData != NULL) {
1696
1697 Status = DataItem->GetData (Instance, DataSize, Data);
1698 } else if (*DataSize < Instance->DataItem[DataType].DataSize) {
1699 //
1700 // Update the buffer length.
1701 //
1702 *DataSize = Instance->DataItem[DataType].DataSize;
1703 Status = EFI_BUFFER_TOO_SMALL;
1704 } else {
1705
1706 *DataSize = Instance->DataItem[DataType].DataSize;
1707 CopyMem (Data, Instance->DataItem[DataType].Data.Ptr, *DataSize);
1708 }
1709 }
1710
1711 gBS->RestoreTPL (OldTpl);
1712
1713 return Status;
1714 }
1715
1716 /**
1717 Register an event that is signaled whenever a configuration process on the specified
1718 configuration data is done.
1719
1720 This function registers an event that is to be signaled whenever a configuration
1721 process on the specified configuration data is performed. An event can be registered
1722 for a different DataType simultaneously. The caller is responsible for determining
1723 which type of configuration data causes the signaling of the event in such an event.
1724
1725 @param[in] This Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance.
1726 @param[in] DataType The type of data to unregister the event for.
1727 @param[in] Event The event to register.
1728
1729 @retval EFI_SUCCESS The notification event for the specified configuration data is
1730 registered.
1731 @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.
1732 @retval EFI_UNSUPPORTED The configuration data type specified by DataType is not
1733 supported.
1734 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1735 @retval EFI_ACCESS_DENIED The Event is already registered for the DataType.
1736
1737 **/
1738 EFI_STATUS
1739 EFIAPI
1740 EfiIp4Config2RegisterDataNotify (
1741 IN EFI_IP4_CONFIG2_PROTOCOL *This,
1742 IN EFI_IP4_CONFIG2_DATA_TYPE DataType,
1743 IN EFI_EVENT Event
1744 )
1745 {
1746 EFI_TPL OldTpl;
1747 EFI_STATUS Status;
1748 IP4_CONFIG2_INSTANCE *Instance;
1749 NET_MAP *EventMap;
1750 NET_MAP_ITEM *Item;
1751
1752 if ((This == NULL) || (Event == NULL)) {
1753 return EFI_INVALID_PARAMETER;
1754 }
1755
1756 if (DataType >= Ip4Config2DataTypeMaximum) {
1757 return EFI_UNSUPPORTED;
1758 }
1759
1760 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1761
1762 Instance = IP4_CONFIG2_INSTANCE_FROM_PROTOCOL (This);
1763 EventMap = &Instance->DataItem[DataType].EventMap;
1764
1765 //
1766 // Check whether this event is already registered for this DataType.
1767 //
1768 Item = NetMapFindKey (EventMap, Event);
1769 if (Item == NULL) {
1770
1771 Status = NetMapInsertTail (EventMap, Event, NULL);
1772
1773 if (EFI_ERROR (Status)) {
1774
1775 Status = EFI_OUT_OF_RESOURCES;
1776 }
1777
1778 } else {
1779
1780 Status = EFI_ACCESS_DENIED;
1781 }
1782
1783 gBS->RestoreTPL (OldTpl);
1784
1785 return Status;
1786 }
1787
1788 /**
1789 Remove a previously registered event for the specified configuration data.
1790
1791 @param This The pointer to the EFI_IP4_CONFIG2_PROTOCOL instance.
1792 @param DataType The type of data to remove from the previously
1793 registered event.
1794 @param Event The event to be unregistered.
1795
1796 @retval EFI_SUCCESS The event registered for the specified
1797 configuration data was removed.
1798 @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.
1799 @retval EFI_NOT_FOUND The Event has not been registered for the
1800 specified DataType.
1801
1802 **/
1803 EFI_STATUS
1804 EFIAPI
1805 EfiIp4Config2UnregisterDataNotify (
1806 IN EFI_IP4_CONFIG2_PROTOCOL *This,
1807 IN EFI_IP4_CONFIG2_DATA_TYPE DataType,
1808 IN EFI_EVENT Event
1809 )
1810 {
1811 EFI_TPL OldTpl;
1812 EFI_STATUS Status;
1813 IP4_CONFIG2_INSTANCE *Instance;
1814 NET_MAP_ITEM *Item;
1815
1816 if ((This == NULL) || (Event == NULL)) {
1817 return EFI_INVALID_PARAMETER;
1818 }
1819
1820 if (DataType >= Ip4Config2DataTypeMaximum) {
1821 return EFI_NOT_FOUND;
1822 }
1823
1824 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1825
1826 Instance = IP4_CONFIG2_INSTANCE_FROM_PROTOCOL (This);
1827
1828 Item = NetMapFindKey (&Instance->DataItem[DataType].EventMap, Event);
1829 if (Item != NULL) {
1830
1831 NetMapRemoveItem (&Instance->DataItem[DataType].EventMap, Item, NULL);
1832 Status = EFI_SUCCESS;
1833 } else {
1834
1835 Status = EFI_NOT_FOUND;
1836 }
1837
1838 gBS->RestoreTPL (OldTpl);
1839
1840 return Status;
1841 }
1842
1843 /**
1844 Initialize an IP4_CONFIG2_INSTANCE.
1845
1846 @param[out] Instance The buffer of IP4_CONFIG2_INSTANCE to be initialized.
1847
1848 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to complete the operation.
1849 @retval EFI_SUCCESS The IP4_CONFIG2_INSTANCE initialized successfully.
1850
1851 **/
1852 EFI_STATUS
1853 Ip4Config2InitInstance (
1854 OUT IP4_CONFIG2_INSTANCE *Instance
1855 )
1856 {
1857 IP4_SERVICE *IpSb;
1858 IP4_CONFIG2_INSTANCE *TmpInstance;
1859 LIST_ENTRY *Entry;
1860 EFI_STATUS Status;
1861 UINTN Index;
1862 UINT16 IfIndex;
1863 IP4_CONFIG2_DATA_ITEM *DataItem;
1864
1865
1866 IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
1867
1868 Instance->Signature = IP4_CONFIG2_INSTANCE_SIGNATURE;
1869
1870
1871 //
1872 // Determine the index of this interface.
1873 //
1874 IfIndex = 0;
1875 NET_LIST_FOR_EACH (Entry, &mIp4Config2InstanceList) {
1876 TmpInstance = NET_LIST_USER_STRUCT_S (Entry, IP4_CONFIG2_INSTANCE, Link, IP4_CONFIG2_INSTANCE_SIGNATURE);
1877
1878 if (TmpInstance->IfIndex > IfIndex) {
1879 //
1880 // There is a sequence hole because some interface is down.
1881 //
1882 break;
1883 }
1884
1885 IfIndex++;
1886 }
1887
1888 Instance->IfIndex = IfIndex;
1889 NetListInsertBefore (Entry, &Instance->Link);
1890
1891 for (Index = 0; Index < Ip4Config2DataTypeMaximum; Index++) {
1892 //
1893 // Initialize the event map for each data item.
1894 //
1895 NetMapInit (&Instance->DataItem[Index].EventMap);
1896 }
1897
1898
1899 //
1900 // Initialize each data type: associate storage and set data size for the
1901 // fixed size data types, hook the SetData function, set the data attribute.
1902 //
1903 DataItem = &Instance->DataItem[Ip4Config2DataTypeInterfaceInfo];
1904 DataItem->GetData = Ip4Config2GetIfInfo;
1905 DataItem->Data.Ptr = &Instance->InterfaceInfo;
1906 DataItem->DataSize = sizeof (Instance->InterfaceInfo);
1907 SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED | DATA_ATTRIB_VOLATILE);
1908 Ip4Config2InitIfInfo (IpSb, &Instance->InterfaceInfo);
1909
1910 DataItem = &Instance->DataItem[Ip4Config2DataTypePolicy];
1911 DataItem->SetData = Ip4Config2SetPolicy;
1912 DataItem->Data.Ptr = &Instance->Policy;
1913 DataItem->DataSize = sizeof (Instance->Policy);
1914 Instance->Policy = Ip4Config2PolicyStatic;
1915 SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED);
1916
1917 DataItem = &Instance->DataItem[Ip4Config2DataTypeManualAddress];
1918 DataItem->SetData = Ip4Config2SetMaunualAddress;
1919 DataItem->Status = EFI_NOT_FOUND;
1920
1921 DataItem = &Instance->DataItem[Ip4Config2DataTypeGateway];
1922 DataItem->SetData = Ip4Config2SetGateway;
1923 DataItem->Status = EFI_NOT_FOUND;
1924
1925 DataItem = &Instance->DataItem[Ip4Config2DataTypeDnsServer];
1926 DataItem->SetData = Ip4Config2SetDnsServer;
1927 DataItem->Status = EFI_NOT_FOUND;
1928
1929 //
1930 // Create the event used for DHCP.
1931 //
1932 Status = gBS->CreateEvent (
1933 EVT_NOTIFY_SIGNAL,
1934 TPL_CALLBACK,
1935 Ip4Config2OnDhcp4Event,
1936 Instance,
1937 &Instance->Dhcp4Event
1938 );
1939 ASSERT_EFI_ERROR (Status);
1940
1941 Instance->Configured = TRUE;
1942
1943 //
1944 // Try to read the config data from NV variable.
1945 // If not found, write initialized config data into NV variable
1946 // as a default config data.
1947 //
1948 Status = Ip4Config2ReadConfigData (IpSb->MacString, Instance);
1949 if (Status == EFI_NOT_FOUND) {
1950 Status = Ip4Config2WriteConfigData (IpSb->MacString, Instance);
1951 }
1952
1953 if (EFI_ERROR (Status)) {
1954 return Status;
1955 }
1956
1957 Instance->Ip4Config2.SetData = EfiIp4Config2SetData;
1958 Instance->Ip4Config2.GetData = EfiIp4Config2GetData;
1959 Instance->Ip4Config2.RegisterDataNotify = EfiIp4Config2RegisterDataNotify;
1960 Instance->Ip4Config2.UnregisterDataNotify = EfiIp4Config2UnregisterDataNotify;
1961
1962 //
1963 // Publish the IP4 configuration form
1964 //
1965 return Ip4Config2FormInit (Instance);
1966 }
1967
1968
1969 /**
1970 Release an IP4_CONFIG2_INSTANCE.
1971
1972 @param[in, out] Instance The buffer of IP4_CONFIG2_INSTANCE to be freed.
1973
1974 **/
1975 VOID
1976 Ip4Config2CleanInstance (
1977 IN OUT IP4_CONFIG2_INSTANCE *Instance
1978 )
1979 {
1980 UINTN Index;
1981 IP4_CONFIG2_DATA_ITEM *DataItem;
1982
1983 if (Instance->DeclineAddress != NULL) {
1984 FreePool (Instance->DeclineAddress);
1985 }
1986
1987 if (!Instance->Configured) {
1988 return ;
1989 }
1990
1991 if (Instance->Dhcp4Handle != NULL) {
1992
1993 Ip4Config2DestroyDhcp4 (Instance);
1994 }
1995
1996 //
1997 // Close the event.
1998 //
1999 if (Instance->Dhcp4Event != NULL) {
2000 gBS->CloseEvent (Instance->Dhcp4Event);
2001 Instance->Dhcp4Event = NULL;
2002 }
2003
2004 for (Index = 0; Index < Ip4Config2DataTypeMaximum; Index++) {
2005
2006 DataItem = &Instance->DataItem[Index];
2007
2008 if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED)) {
2009 if (DataItem->Data.Ptr != NULL) {
2010 FreePool (DataItem->Data.Ptr);
2011 }
2012 DataItem->Data.Ptr = NULL;
2013 DataItem->DataSize = 0;
2014 }
2015
2016 NetMapClean (&Instance->DataItem[Index].EventMap);
2017 }
2018
2019 Ip4Config2FormUnload (Instance);
2020
2021 RemoveEntryList (&Instance->Link);
2022 }
2023
2024 /**
2025 The event handle for IP4 auto reconfiguration. The original default
2026 interface and route table will be removed as the default.
2027
2028 @param[in] Context The IP4 service binding instance.
2029
2030 **/
2031 VOID
2032 EFIAPI
2033 Ip4AutoReconfigCallBackDpc (
2034 IN VOID *Context
2035 )
2036 {
2037 IP4_SERVICE *IpSb;
2038
2039 IpSb = (IP4_SERVICE *) Context;
2040 NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);
2041
2042 if (IpSb->State > IP4_SERVICE_UNSTARTED) {
2043 IpSb->State = IP4_SERVICE_UNSTARTED;
2044 }
2045
2046 IpSb->Reconfig = TRUE;
2047
2048 Ip4StartAutoConfig (&IpSb->Ip4Config2Instance);
2049
2050 return ;
2051 }
2052
2053
2054 /**
2055 Request Ip4AutoReconfigCallBackDpc as a DPC at TPL_CALLBACK.
2056
2057 @param Event The event that is signalled.
2058 @param Context The IP4 service binding instance.
2059
2060 **/
2061 VOID
2062 EFIAPI
2063 Ip4AutoReconfigCallBack (
2064 IN EFI_EVENT Event,
2065 IN VOID *Context
2066 )
2067 {
2068 //
2069 // Request Ip4AutoReconfigCallBackDpc as a DPC at TPL_CALLBACK
2070 //
2071 QueueDpc (TPL_CALLBACK, Ip4AutoReconfigCallBackDpc, Context);
2072 }
2073