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