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