]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/Ip6Dxe/Ip6ConfigImpl.c
ArmVirtPkg: clear PcdPerformanceLibraryPropertyMask PCD
[mirror_edk2.git] / NetworkPkg / Ip6Dxe / Ip6ConfigImpl.c
1 /** @file
2 The implementation of EFI IPv6 Configuration Protocol.
3
4 Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>
5
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "Ip6Impl.h"
17
18 LIST_ENTRY mIp6ConfigInstanceList = {&mIp6ConfigInstanceList, &mIp6ConfigInstanceList};
19
20 /**
21 The event process routine when the DHCPv6 service binding protocol is installed
22 in the system.
23
24 @param[in] Event Not used.
25 @param[in] Context Pointer to the IP6 config instance data.
26
27 **/
28 VOID
29 EFIAPI
30 Ip6ConfigOnDhcp6SbInstalled (
31 IN EFI_EVENT Event,
32 IN VOID *Context
33 );
34
35 /**
36 Update the current policy to NewPolicy. During the transition
37 period, the default router list, on-link prefix list, autonomous prefix list
38 and address list in all interfaces will be released.
39
40 @param[in] IpSb The IP6 service binding instance.
41 @param[in] NewPolicy The new policy to be updated to.
42
43 **/
44 VOID
45 Ip6ConfigOnPolicyChanged (
46 IN IP6_SERVICE *IpSb,
47 IN EFI_IP6_CONFIG_POLICY NewPolicy
48 )
49 {
50 LIST_ENTRY *Entry;
51 LIST_ENTRY *Entry2;
52 LIST_ENTRY *Next;
53 IP6_INTERFACE *IpIf;
54 IP6_DAD_ENTRY *DadEntry;
55 IP6_DELAY_JOIN_LIST *DelayNode;
56
57 //
58 // Currently there are only two policies: Manual and Automatic. Regardless of
59 // what transition is going on, i.e., Manual -> Automatic and Automatic ->
60 // Manual, we have to free default router list, on-link prefix list, autonomous
61 // prefix list, address list in all the interfaces and destroy any IPv6 child
62 // instance whose local IP is neither 0 nor the link-local address.
63 //
64 Ip6CleanDefaultRouterList (IpSb);
65 Ip6CleanPrefixListTable (IpSb, &IpSb->OnlinkPrefix);
66 Ip6CleanPrefixListTable (IpSb, &IpSb->AutonomousPrefix);
67
68 //
69 // It's tricky... If the LinkLocal address is O.K., add back the link-local
70 // prefix to the on-link prefix table.
71 //
72 if (IpSb->LinkLocalOk) {
73 Ip6CreatePrefixListEntry (
74 IpSb,
75 TRUE,
76 (UINT32) IP6_INFINIT_LIFETIME,
77 (UINT32) IP6_INFINIT_LIFETIME,
78 IP6_LINK_LOCAL_PREFIX_LENGTH,
79 &IpSb->LinkLocalAddr
80 );
81 }
82
83 //
84 // All IPv6 children that use global unicast address as it's source address
85 // should be destryoed now. The survivers are those use the link-local address
86 // or the unspecified address as the source address.
87 // TODO: Conduct a check here.
88 Ip6RemoveAddr (
89 IpSb,
90 &IpSb->DefaultInterface->AddressList,
91 &IpSb->DefaultInterface->AddressCount,
92 NULL,
93 0
94 );
95
96 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
97 //
98 // remove all pending delay node and DAD entries for the global addresses.
99 //
100 IpIf = NET_LIST_USER_STRUCT_S (Entry, IP6_INTERFACE, Link, IP6_INTERFACE_SIGNATURE);
101
102 NET_LIST_FOR_EACH_SAFE (Entry2, Next, &IpIf->DelayJoinList) {
103 DelayNode = NET_LIST_USER_STRUCT (Entry2, IP6_DELAY_JOIN_LIST, Link);
104 if (!NetIp6IsLinkLocalAddr (&DelayNode->AddressInfo->Address)) {
105 RemoveEntryList (&DelayNode->Link);
106 FreePool (DelayNode);
107 }
108 }
109
110 NET_LIST_FOR_EACH_SAFE (Entry2, Next, &IpIf->DupAddrDetectList) {
111 DadEntry = NET_LIST_USER_STRUCT_S (Entry2, IP6_DAD_ENTRY, Link, IP6_DAD_ENTRY_SIGNATURE);
112
113 if (!NetIp6IsLinkLocalAddr (&DadEntry->AddressInfo->Address)) {
114 //
115 // Fail this DAD entry if the address is not link-local.
116 //
117 Ip6OnDADFinished (FALSE, IpIf, DadEntry);
118 }
119 }
120 }
121
122 if (NewPolicy == Ip6ConfigPolicyAutomatic) {
123 //
124 // Set parameters to trigger router solicitation sending in timer handler.
125 //
126 IpSb->RouterAdvertiseReceived = FALSE;
127 IpSb->SolicitTimer = IP6_MAX_RTR_SOLICITATIONS;
128 //
129 // delay 1 second
130 //
131 IpSb->Ticks = (UINT32) IP6_GET_TICKS (IP6_ONE_SECOND_IN_MS);
132 }
133
134 }
135
136 /**
137 The work function to trigger the DHCPv6 process to perform a stateful autoconfiguration.
138
139 @param[in] Instance Pointer to the IP6 config instance data.
140 @param[in] OtherInfoOnly If FALSE, get stateful address and other information
141 via DHCPv6. Otherwise, only get the other information.
142
143 @retval EFI_SUCCESS The operation finished successfully.
144 @retval EFI_UNSUPPORTED The DHCP6 driver is not available.
145
146 **/
147 EFI_STATUS
148 Ip6ConfigStartStatefulAutoConfig (
149 IN IP6_CONFIG_INSTANCE *Instance,
150 IN BOOLEAN OtherInfoOnly
151 )
152 {
153 EFI_STATUS Status;
154 IP6_SERVICE *IpSb;
155 EFI_DHCP6_CONFIG_DATA Dhcp6CfgData;
156 EFI_DHCP6_PROTOCOL *Dhcp6;
157 EFI_DHCP6_PACKET_OPTION *OptList[1];
158 UINT16 OptBuf[4];
159 EFI_DHCP6_PACKET_OPTION *Oro;
160 EFI_DHCP6_RETRANSMISSION InfoReqReXmit;
161
162 //
163 // A host must not invoke stateful address configuration if it is already
164 // participating in the statuful protocol as a result of an earlier advertisement.
165 //
166 if (Instance->Dhcp6Handle != NULL) {
167 return EFI_SUCCESS;
168 }
169
170 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
171
172 Instance->OtherInfoOnly = OtherInfoOnly;
173
174 Status = NetLibCreateServiceChild (
175 IpSb->Controller,
176 IpSb->Image,
177 &gEfiDhcp6ServiceBindingProtocolGuid,
178 &Instance->Dhcp6Handle
179 );
180
181 if (Status == EFI_UNSUPPORTED) {
182 //
183 // No DHCPv6 Service Binding protocol, register a notify.
184 //
185 if (Instance->Dhcp6SbNotifyEvent == NULL) {
186 Instance->Dhcp6SbNotifyEvent = EfiCreateProtocolNotifyEvent (
187 &gEfiDhcp6ServiceBindingProtocolGuid,
188 TPL_CALLBACK,
189 Ip6ConfigOnDhcp6SbInstalled,
190 (VOID *) Instance,
191 &Instance->Registration
192 );
193 }
194 }
195
196 if (EFI_ERROR (Status)) {
197 return Status;
198 }
199
200 if (Instance->Dhcp6SbNotifyEvent != NULL) {
201 gBS->CloseEvent (Instance->Dhcp6SbNotifyEvent);
202 }
203
204 Status = gBS->OpenProtocol (
205 Instance->Dhcp6Handle,
206 &gEfiDhcp6ProtocolGuid,
207 (VOID **) &Instance->Dhcp6,
208 IpSb->Image,
209 IpSb->Controller,
210 EFI_OPEN_PROTOCOL_BY_DRIVER
211 );
212 ASSERT_EFI_ERROR (Status);
213
214 Dhcp6 = Instance->Dhcp6;
215 Dhcp6->Configure (Dhcp6, NULL);
216
217 //
218 // Set the exta options to send. Here we only want the option request option
219 // with DNS SERVERS.
220 //
221 Oro = (EFI_DHCP6_PACKET_OPTION *) OptBuf;
222 Oro->OpCode = HTONS (DHCP6_OPT_ORO);
223 Oro->OpLen = HTONS (2);
224 *((UINT16 *) &Oro->Data[0]) = HTONS (DHCP6_OPT_DNS_SERVERS);
225 OptList[0] = Oro;
226
227 Status = EFI_SUCCESS;
228
229 if (!OtherInfoOnly) {
230 //
231 // Get stateful address and other information via DHCPv6.
232 //
233 Dhcp6CfgData.Dhcp6Callback = NULL;
234 Dhcp6CfgData.CallbackContext = NULL;
235 Dhcp6CfgData.OptionCount = 1;
236 Dhcp6CfgData.OptionList = &OptList[0];
237 Dhcp6CfgData.IaDescriptor.Type = EFI_DHCP6_IA_TYPE_NA;
238 Dhcp6CfgData.IaDescriptor.IaId = Instance->IaId;
239 Dhcp6CfgData.IaInfoEvent = Instance->Dhcp6Event;
240 Dhcp6CfgData.ReconfigureAccept = FALSE;
241 Dhcp6CfgData.RapidCommit = FALSE;
242 Dhcp6CfgData.SolicitRetransmission = NULL;
243
244 Status = Dhcp6->Configure (Dhcp6, &Dhcp6CfgData);
245
246 if (!EFI_ERROR (Status)) {
247
248 if (IpSb->LinkLocalOk) {
249 Status = Dhcp6->Start (Dhcp6);
250 } else {
251 IpSb->Dhcp6NeedStart = TRUE;
252 }
253
254 }
255 } else {
256 //
257 // Only get other information via DHCPv6, this doesn't require a config
258 // action.
259 //
260 InfoReqReXmit.Irt = 4;
261 InfoReqReXmit.Mrc = 64;
262 InfoReqReXmit.Mrt = 60;
263 InfoReqReXmit.Mrd = 0;
264
265 if (IpSb->LinkLocalOk) {
266 Status = Dhcp6->InfoRequest (
267 Dhcp6,
268 TRUE,
269 Oro,
270 0,
271 NULL,
272 &InfoReqReXmit,
273 Instance->Dhcp6Event,
274 Ip6ConfigOnDhcp6Reply,
275 Instance
276 );
277 } else {
278 IpSb->Dhcp6NeedInfoRequest = TRUE;
279 }
280
281 }
282
283 return Status;
284 }
285
286 /**
287 Signal the registered event. It is the callback routine for NetMapIterate.
288
289 @param[in] Map Points to the list of registered event.
290 @param[in] Item The registered event.
291 @param[in] Arg Not used.
292
293 **/
294 EFI_STATUS
295 EFIAPI
296 Ip6ConfigSignalEvent (
297 IN NET_MAP *Map,
298 IN NET_MAP_ITEM *Item,
299 IN VOID *Arg
300 )
301 {
302 gBS->SignalEvent ((EFI_EVENT) Item->Key);
303
304 return EFI_SUCCESS;
305 }
306
307 /**
308 Read the configuration data from variable storage according to the VarName and
309 gEfiIp6ConfigProtocolGuid. It checks the integrity of variable data. If the
310 data is corrupted, it clears the variable data to ZERO. Othewise, it outputs the
311 configuration data to IP6_CONFIG_INSTANCE.
312
313 @param[in] VarName The pointer to the variable name
314 @param[in, out] Instance The pointer to the IP6 config instance data.
315
316 @retval EFI_NOT_FOUND The variable can not be found or already corrupted.
317 @retval EFI_OUT_OF_RESOURCES Fail to allocate resource to complete the operation.
318 @retval EFI_SUCCESS The configuration data was retrieved successfully.
319
320 **/
321 EFI_STATUS
322 Ip6ConfigReadConfigData (
323 IN CHAR16 *VarName,
324 IN OUT IP6_CONFIG_INSTANCE *Instance
325 )
326 {
327 EFI_STATUS Status;
328 UINTN VarSize;
329 IP6_CONFIG_VARIABLE *Variable;
330 IP6_CONFIG_DATA_ITEM *DataItem;
331 UINTN Index;
332 IP6_CONFIG_DATA_RECORD DataRecord;
333 CHAR8 *Data;
334
335 //
336 // Try to read the configuration variable.
337 //
338 VarSize = 0;
339 Status = gRT->GetVariable (
340 VarName,
341 &gEfiIp6ConfigProtocolGuid,
342 NULL,
343 &VarSize,
344 NULL
345 );
346
347 if (Status == EFI_BUFFER_TOO_SMALL) {
348 //
349 // Allocate buffer and read the config variable.
350 //
351 Variable = AllocatePool (VarSize);
352 if (Variable == NULL) {
353 return EFI_OUT_OF_RESOURCES;
354 }
355
356 Status = gRT->GetVariable (
357 VarName,
358 &gEfiIp6ConfigProtocolGuid,
359 NULL,
360 &VarSize,
361 Variable
362 );
363 if (EFI_ERROR (Status) || (UINT16) (~NetblockChecksum ((UINT8 *) Variable, (UINT32) VarSize)) != 0) {
364 //
365 // GetVariable still error or the variable is corrupted.
366 // Fall back to the default value.
367 //
368 FreePool (Variable);
369
370 //
371 // Remove the problematic variable and return EFI_NOT_FOUND, a new
372 // variable will be set again.
373 //
374 gRT->SetVariable (
375 VarName,
376 &gEfiIp6ConfigProtocolGuid,
377 IP6_CONFIG_VARIABLE_ATTRIBUTE,
378 0,
379 NULL
380 );
381
382 return EFI_NOT_FOUND;
383 }
384
385 //
386 // Get the IAID we use.
387 //
388 Instance->IaId = Variable->IaId;
389
390 for (Index = 0; Index < Variable->DataRecordCount; Index++) {
391
392 CopyMem (&DataRecord, &Variable->DataRecord[Index], sizeof (DataRecord));
393
394 DataItem = &Instance->DataItem[DataRecord.DataType];
395 if (DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED) &&
396 (DataItem->DataSize != DataRecord.DataSize)
397 ) {
398 //
399 // Perhaps a corrupted data record...
400 //
401 continue;
402 }
403
404 if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED)) {
405 //
406 // This data item has variable length data.
407 //
408 DataItem->Data.Ptr = AllocatePool (DataRecord.DataSize);
409 if (DataItem->Data.Ptr == NULL) {
410 //
411 // no memory resource
412 //
413 continue;
414 }
415 }
416
417 Data = (CHAR8 *) Variable + DataRecord.Offset;
418 CopyMem (DataItem->Data.Ptr, Data, DataRecord.DataSize);
419
420 DataItem->DataSize = DataRecord.DataSize;
421 DataItem->Status = EFI_SUCCESS;
422 }
423
424 FreePool (Variable);
425 return EFI_SUCCESS;
426 }
427
428 return Status;
429 }
430
431 /**
432 Write the configuration data from IP6_CONFIG_INSTANCE to variable storage.
433
434 @param[in] VarName The pointer to the variable name.
435 @param[in] Instance The pointer to the IP6 configuration instance data.
436
437 @retval EFI_OUT_OF_RESOURCES Fail to allocate resource to complete the operation.
438 @retval EFI_SUCCESS The configuration data is written successfully.
439
440 **/
441 EFI_STATUS
442 Ip6ConfigWriteConfigData (
443 IN CHAR16 *VarName,
444 IN IP6_CONFIG_INSTANCE *Instance
445 )
446 {
447 UINTN Index;
448 UINTN VarSize;
449 IP6_CONFIG_DATA_ITEM *DataItem;
450 IP6_CONFIG_VARIABLE *Variable;
451 IP6_CONFIG_DATA_RECORD *DataRecord;
452 CHAR8 *Heap;
453 EFI_STATUS Status;
454
455 VarSize = sizeof (IP6_CONFIG_VARIABLE) - sizeof (IP6_CONFIG_DATA_RECORD);
456
457 for (Index = 0; Index < Ip6ConfigDataTypeMaximum; Index++) {
458
459 DataItem = &Instance->DataItem[Index];
460 if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_VOLATILE) && !EFI_ERROR (DataItem->Status)) {
461
462 VarSize += sizeof (IP6_CONFIG_DATA_RECORD) + DataItem->DataSize;
463 }
464 }
465
466 Variable = AllocatePool (VarSize);
467 if (Variable == NULL) {
468 return EFI_OUT_OF_RESOURCES;
469 }
470
471 Variable->IaId = Instance->IaId;
472 Heap = (CHAR8 *) Variable + VarSize;
473 Variable->DataRecordCount = 0;
474
475 for (Index = 0; Index < Ip6ConfigDataTypeMaximum; Index++) {
476
477 DataItem = &Instance->DataItem[Index];
478 if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_VOLATILE) && !EFI_ERROR (DataItem->Status)) {
479
480 Heap -= DataItem->DataSize;
481 CopyMem (Heap, DataItem->Data.Ptr, DataItem->DataSize);
482
483 DataRecord = &Variable->DataRecord[Variable->DataRecordCount];
484 DataRecord->DataType = (EFI_IP6_CONFIG_DATA_TYPE) Index;
485 DataRecord->DataSize = (UINT32) DataItem->DataSize;
486 DataRecord->Offset = (UINT16) (Heap - (CHAR8 *) Variable);
487
488 Variable->DataRecordCount++;
489 }
490 }
491
492 Variable->Checksum = 0;
493 Variable->Checksum = (UINT16) ~NetblockChecksum ((UINT8 *) Variable, (UINT32) VarSize);
494
495 Status = gRT->SetVariable (
496 VarName,
497 &gEfiIp6ConfigProtocolGuid,
498 IP6_CONFIG_VARIABLE_ATTRIBUTE,
499 VarSize,
500 Variable
501 );
502
503 FreePool (Variable);
504
505 return Status;
506 }
507
508 /**
509 The work function for EfiIp6ConfigGetData() to get the interface information
510 of the communication device this IP6Config instance manages.
511
512 @param[in] Instance Pointer to the IP6 config instance data.
513 @param[in, out] DataSize On input, in bytes, the size of Data. On output, in
514 bytes, the size of buffer required to store the specified
515 configuration data.
516 @param[in] Data The data buffer in which the configuration data is returned.
517 Ignored if DataSize is ZERO.
518
519 @retval EFI_BUFFER_TOO_SMALL The size of Data is too small for the specified
520 configuration data, and the required size is
521 returned in DataSize.
522 @retval EFI_SUCCESS The specified configuration data was obtained.
523
524 **/
525 EFI_STATUS
526 Ip6ConfigGetIfInfo (
527 IN IP6_CONFIG_INSTANCE *Instance,
528 IN OUT UINTN *DataSize,
529 IN VOID *Data OPTIONAL
530 )
531 {
532 IP6_SERVICE *IpSb;
533 UINTN Length;
534 IP6_CONFIG_DATA_ITEM *Item;
535 EFI_IP6_CONFIG_INTERFACE_INFO *IfInfo;
536 UINT32 AddressCount;
537 UINT32 RouteCount;
538
539 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
540 Length = sizeof (EFI_IP6_CONFIG_INTERFACE_INFO);
541
542 //
543 // Calculate the required length, add the buffer size for AddressInfo and
544 // RouteTable
545 //
546 Ip6BuildEfiAddressList (IpSb, &AddressCount, NULL);
547 Ip6BuildEfiRouteTable (IpSb->RouteTable, &RouteCount, NULL);
548
549 Length += AddressCount * sizeof (EFI_IP6_ADDRESS_INFO) + RouteCount * sizeof (EFI_IP6_ROUTE_TABLE);
550
551 if (*DataSize < Length) {
552 *DataSize = Length;
553 return EFI_BUFFER_TOO_SMALL;
554 }
555
556 //
557 // Copy the fixed size part of the interface info.
558 //
559 Item = &Instance->DataItem[Ip6ConfigDataTypeInterfaceInfo];
560 IfInfo = (EFI_IP6_CONFIG_INTERFACE_INFO *) Data;
561 CopyMem (IfInfo, Item->Data.Ptr, sizeof (EFI_IP6_CONFIG_INTERFACE_INFO));
562
563 //
564 // AddressInfo
565 //
566 IfInfo->AddressInfo = (EFI_IP6_ADDRESS_INFO *) (IfInfo + 1);
567 Ip6BuildEfiAddressList (IpSb, &IfInfo->AddressInfoCount, &IfInfo->AddressInfo);
568
569 //
570 // RouteTable
571 //
572 IfInfo->RouteTable = (EFI_IP6_ROUTE_TABLE *) (IfInfo->AddressInfo + IfInfo->AddressInfoCount);
573 Ip6BuildEfiRouteTable (IpSb->RouteTable, &IfInfo->RouteCount, &IfInfo->RouteTable);
574
575 if (IfInfo->AddressInfoCount == 0) {
576 IfInfo->AddressInfo = NULL;
577 }
578
579 if (IfInfo->RouteCount == 0) {
580 IfInfo->RouteTable = NULL;
581 }
582
583 return EFI_SUCCESS;
584 }
585
586 /**
587 The work function for EfiIp6ConfigSetData() to set the alternative inteface ID
588 for the communication device managed by this IP6Config instance, if the link local
589 IPv6 addresses generated from the interface ID based on the default source the
590 EFI IPv6 Protocol uses is a duplicate address.
591
592 @param[in] Instance Pointer to the IP6 configuration instance data.
593 @param[in] DataSize Size of the buffer pointed to by Data in bytes.
594 @param[in] Data The data buffer to set.
595
596 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type,
597 8 bytes.
598 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6
599 network stack was set.
600
601 **/
602 EFI_STATUS
603 Ip6ConfigSetAltIfId (
604 IN IP6_CONFIG_INSTANCE *Instance,
605 IN UINTN DataSize,
606 IN VOID *Data
607 )
608 {
609 EFI_IP6_CONFIG_INTERFACE_ID *OldIfId;
610 EFI_IP6_CONFIG_INTERFACE_ID *NewIfId;
611 IP6_CONFIG_DATA_ITEM *DataItem;
612
613 if (DataSize != sizeof (EFI_IP6_CONFIG_INTERFACE_ID)) {
614 return EFI_BAD_BUFFER_SIZE;
615 }
616
617 DataItem = &Instance->DataItem[Ip6ConfigDataTypeAltInterfaceId];
618 OldIfId = DataItem->Data.AltIfId;
619 NewIfId = (EFI_IP6_CONFIG_INTERFACE_ID *) Data;
620
621 CopyMem (OldIfId, NewIfId, DataSize);
622 DataItem->Status = EFI_SUCCESS;
623
624 return EFI_SUCCESS;
625 }
626
627 /**
628 The work function for EfiIp6ConfigSetData() to set the general configuration
629 policy for the EFI IPv6 network stack that is running on the communication device
630 managed by this IP6Config instance. The policy will affect other configuration settings.
631
632 @param[in] Instance Pointer to the IP6 config instance data.
633 @param[in] DataSize Size of the buffer pointed to by Data in bytes.
634 @param[in] Data The data buffer to set.
635
636 @retval EFI_INVALID_PARAMETER The to be set policy is invalid.
637 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.
638 @retval EFI_ABORTED The new policy equals the current policy.
639 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6
640 network stack was set.
641
642 **/
643 EFI_STATUS
644 Ip6ConfigSetPolicy (
645 IN IP6_CONFIG_INSTANCE *Instance,
646 IN UINTN DataSize,
647 IN VOID *Data
648 )
649 {
650 EFI_IP6_CONFIG_POLICY NewPolicy;
651 IP6_CONFIG_DATA_ITEM *DataItem;
652 IP6_SERVICE *IpSb;
653
654 if (DataSize != sizeof (EFI_IP6_CONFIG_POLICY)) {
655 return EFI_BAD_BUFFER_SIZE;
656 }
657
658 NewPolicy = *((EFI_IP6_CONFIG_POLICY *) Data);
659
660 if (NewPolicy > Ip6ConfigPolicyAutomatic) {
661 return EFI_INVALID_PARAMETER;
662 }
663
664 if (NewPolicy == Instance->Policy) {
665
666 return EFI_ABORTED;
667 } else {
668 //
669 // Clean the ManualAddress, Gateway and DnsServers, shrink the variable
670 // data size, and fire up all the related events.
671 //
672 DataItem = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];
673 if (DataItem->Data.Ptr != NULL) {
674 FreePool (DataItem->Data.Ptr);
675 }
676 DataItem->Data.Ptr = NULL;
677 DataItem->DataSize = 0;
678 DataItem->Status = EFI_NOT_FOUND;
679 NetMapIterate (&DataItem->EventMap, Ip6ConfigSignalEvent, NULL);
680
681 DataItem = &Instance->DataItem[Ip6ConfigDataTypeGateway];
682 if (DataItem->Data.Ptr != NULL) {
683 FreePool (DataItem->Data.Ptr);
684 }
685 DataItem->Data.Ptr = NULL;
686 DataItem->DataSize = 0;
687 DataItem->Status = EFI_NOT_FOUND;
688 NetMapIterate (&DataItem->EventMap, Ip6ConfigSignalEvent, NULL);
689
690 DataItem = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];
691 DataItem->Data.Ptr = NULL;
692 DataItem->DataSize = 0;
693 DataItem->Status = EFI_NOT_FOUND;
694 NetMapIterate (&DataItem->EventMap, Ip6ConfigSignalEvent, NULL);
695
696 if (NewPolicy == Ip6ConfigPolicyManual) {
697 //
698 // The policy is changed from automatic to manual. Stop the DHCPv6 process
699 // and destroy the DHCPv6 child.
700 //
701 if (Instance->Dhcp6Handle != NULL) {
702 Ip6ConfigDestroyDhcp6 (Instance);
703 }
704 }
705
706 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
707 Ip6ConfigOnPolicyChanged (IpSb, NewPolicy);
708
709 Instance->Policy = NewPolicy;
710
711 return EFI_SUCCESS;
712 }
713 }
714
715 /**
716 The work function for EfiIp6ConfigSetData() to set the number of consecutive
717 Neighbor Solicitation messages sent while performing Duplicate Address Detection
718 on a tentative address. A value of ZERO indicates that Duplicate Address Detection
719 will not be performed on a tentative address.
720
721 @param[in] Instance The Instance Pointer to the IP6 config instance data.
722 @param[in] DataSize Size of the buffer pointed to by Data in bytes.
723 @param[in] Data The data buffer to set.
724
725 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.
726 @retval EFI_ABORTED The new transmit count equals the current configuration.
727 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6
728 network stack was set.
729
730 **/
731 EFI_STATUS
732 Ip6ConfigSetDadXmits (
733 IN IP6_CONFIG_INSTANCE *Instance,
734 IN UINTN DataSize,
735 IN VOID *Data
736 )
737 {
738 EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS *OldDadXmits;
739
740 if (DataSize != sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS)) {
741 return EFI_BAD_BUFFER_SIZE;
742 }
743
744 OldDadXmits = Instance->DataItem[Ip6ConfigDataTypeDupAddrDetectTransmits].Data.DadXmits;
745
746 if ((*(UINT32 *) Data) == OldDadXmits->DupAddrDetectTransmits) {
747
748 return EFI_ABORTED;
749 } else {
750
751 OldDadXmits->DupAddrDetectTransmits = *((UINT32 *) Data);
752 return EFI_SUCCESS;
753 }
754 }
755
756 /**
757 The callback function for Ip6SetAddr. The prototype is defined
758 as IP6_DAD_CALLBACK. It is called after Duplicate Address Detection is performed
759 for the manual address set by Ip6ConfigSetMaunualAddress.
760
761 @param[in] IsDadPassed If TRUE, Duplicate Address Detection passed.
762 @param[in] TargetAddress The tentative IPv6 address to be checked.
763 @param[in] Context Pointer to the IP6 configuration instance data.
764
765 **/
766 VOID
767 Ip6ManualAddrDadCallback (
768 IN BOOLEAN IsDadPassed,
769 IN EFI_IPv6_ADDRESS *TargetAddress,
770 IN VOID *Context
771 )
772 {
773 IP6_CONFIG_INSTANCE *Instance;
774 UINTN Index;
775 IP6_CONFIG_DATA_ITEM *Item;
776 EFI_IP6_CONFIG_MANUAL_ADDRESS *ManualAddr;
777 EFI_IP6_CONFIG_MANUAL_ADDRESS *PassedAddr;
778 UINTN DadPassCount;
779 UINTN DadFailCount;
780 IP6_SERVICE *IpSb;
781
782 Instance = (IP6_CONFIG_INSTANCE *) Context;
783 NET_CHECK_SIGNATURE (Instance, IP6_CONFIG_INSTANCE_SIGNATURE);
784 Item = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];
785 ManualAddr = NULL;
786
787 for (Index = 0; Index < Item->DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS); Index++) {
788 //
789 // Find the original tag used to place into the NET_MAP.
790 //
791 ManualAddr = Item->Data.ManualAddress + Index;
792 if (EFI_IP6_EQUAL (TargetAddress, &ManualAddr->Address)) {
793 break;
794 }
795 }
796
797 ASSERT (Index != Item->DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS));
798
799 if (IsDadPassed) {
800 NetMapInsertTail (&Instance->DadPassedMap, ManualAddr, NULL);
801 } else {
802 NetMapInsertTail (&Instance->DadFailedMap, ManualAddr, NULL);
803 }
804
805 DadPassCount = NetMapGetCount (&Instance->DadPassedMap);
806 DadFailCount = NetMapGetCount (&Instance->DadFailedMap);
807
808 if ((DadPassCount + DadFailCount) == (Item->DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS))) {
809 //
810 // All addresses have finished the configuration process.
811 //
812 if (DadFailCount != 0) {
813 //
814 // There is at least one duplicate address.
815 //
816 FreePool (Item->Data.Ptr);
817
818 Item->DataSize = DadPassCount * sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS);
819 if (Item->DataSize == 0) {
820 //
821 // All failed, bad luck.
822 //
823 Item->Data.Ptr = NULL;
824 Item->Status = EFI_NOT_FOUND;
825 } else {
826 //
827 // Part of addresses are detected to be duplicates, so update the
828 // data with those passed.
829 //
830 PassedAddr = (EFI_IP6_CONFIG_MANUAL_ADDRESS *) AllocatePool (Item->DataSize);
831 ASSERT (PassedAddr != NULL);
832
833 Item->Data.Ptr = PassedAddr;
834 Item->Status = EFI_SUCCESS;
835
836 while (!NetMapIsEmpty (&Instance->DadPassedMap)) {
837 ManualAddr = (EFI_IP6_CONFIG_MANUAL_ADDRESS *) NetMapRemoveHead (&Instance->DadPassedMap, NULL);
838 CopyMem (PassedAddr, ManualAddr, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS));
839
840 PassedAddr++;
841 }
842
843 ASSERT ((UINTN) PassedAddr - (UINTN) Item->Data.Ptr == Item->DataSize);
844 }
845 } else {
846 //
847 // All addresses are valid.
848 //
849 Item->Status = EFI_SUCCESS;
850 }
851
852 //
853 // Remove the tags we put in the NET_MAPs.
854 //
855 while (!NetMapIsEmpty (&Instance->DadFailedMap)) {
856 NetMapRemoveHead (&Instance->DadFailedMap, NULL);
857 }
858
859 while (!NetMapIsEmpty (&Instance->DadPassedMap)) {
860 NetMapRemoveHead (&Instance->DadPassedMap, NULL);
861 }
862
863 //
864 // Signal the waiting events.
865 //
866 NetMapIterate (&Item->EventMap, Ip6ConfigSignalEvent, NULL);
867 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
868 Ip6ConfigWriteConfigData (IpSb->MacString, Instance);
869 }
870 }
871
872 /**
873 The work function for EfiIp6ConfigSetData() to set the station addresses manually
874 for the EFI IPv6 network stack. It is only configurable when the policy is
875 Ip6ConfigPolicyManual.
876
877 @param[in] Instance Pointer to the IP6 configuration instance data.
878 @param[in] DataSize Size of the buffer pointed to by Data in bytes.
879 @param[in] Data The data buffer to set.
880
881 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.
882 @retval EFI_WRITE_PROTECTED The specified configuration data cannot be set
883 under the current policy.
884 @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.
885 @retval EFI_OUT_OF_RESOURCES Fail to allocate resource to complete the operation.
886 @retval EFI_NOT_READY An asynchrous process is invoked to set the specified
887 configuration data, and the process is not finished.
888 @retval EFI_ABORTED The manual addresses to be set equal current
889 configuration.
890 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6
891 network stack was set.
892
893 **/
894 EFI_STATUS
895 Ip6ConfigSetMaunualAddress (
896 IN IP6_CONFIG_INSTANCE *Instance,
897 IN UINTN DataSize,
898 IN VOID *Data
899 )
900 {
901 EFI_IP6_CONFIG_MANUAL_ADDRESS *NewAddress;
902 EFI_IP6_CONFIG_MANUAL_ADDRESS *TmpAddress;
903 IP6_CONFIG_DATA_ITEM *DataItem;
904 UINTN NewAddressCount;
905 UINTN Index1;
906 UINTN Index2;
907 IP6_SERVICE *IpSb;
908 IP6_ADDRESS_INFO *CurrentAddrInfo;
909 IP6_ADDRESS_INFO *Copy;
910 LIST_ENTRY CurrentSourceList;
911 UINT32 CurrentSourceCount;
912 LIST_ENTRY *Entry;
913 LIST_ENTRY *Entry2;
914 IP6_INTERFACE *IpIf;
915 IP6_PREFIX_LIST_ENTRY *PrefixEntry;
916 EFI_STATUS Status;
917 BOOLEAN IsUpdated;
918
919 ASSERT (Instance->DataItem[Ip6ConfigDataTypeManualAddress].Status != EFI_NOT_READY);
920
921 if (((DataSize % sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS)) != 0) || (DataSize == 0)) {
922 return EFI_BAD_BUFFER_SIZE;
923 }
924
925 if (Instance->Policy != Ip6ConfigPolicyManual) {
926 return EFI_WRITE_PROTECTED;
927 }
928
929 NewAddressCount = DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS);
930 NewAddress = (EFI_IP6_CONFIG_MANUAL_ADDRESS *) Data;
931
932 for (Index1 = 0; Index1 < NewAddressCount; Index1++, NewAddress++) {
933
934 if (NetIp6IsLinkLocalAddr (&NewAddress->Address) ||
935 !NetIp6IsValidUnicast (&NewAddress->Address) ||
936 (NewAddress->PrefixLength > 128)
937 ) {
938 //
939 // make sure the IPv6 address is unicast and not link-local address &&
940 // the prefix length is valid.
941 //
942 return EFI_INVALID_PARAMETER;
943 }
944
945 TmpAddress = NewAddress + 1;
946 for (Index2 = Index1 + 1; Index2 < NewAddressCount; Index2++, TmpAddress++) {
947 //
948 // Any two addresses in the array can't be equal.
949 //
950 if (EFI_IP6_EQUAL (&TmpAddress->Address, &NewAddress->Address)) {
951
952 return EFI_INVALID_PARAMETER;
953 }
954 }
955 }
956
957 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
958
959 //
960 // Build the current source address list.
961 //
962 InitializeListHead (&CurrentSourceList);
963 CurrentSourceCount = 0;
964
965 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
966 IpIf = NET_LIST_USER_STRUCT_S (Entry, IP6_INTERFACE, Link, IP6_INTERFACE_SIGNATURE);
967
968 NET_LIST_FOR_EACH (Entry2, &IpIf->AddressList) {
969 CurrentAddrInfo = NET_LIST_USER_STRUCT_S (Entry2, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);
970
971 Copy = AllocateCopyPool (sizeof (IP6_ADDRESS_INFO), CurrentAddrInfo);
972 if (Copy == NULL) {
973 break;
974 }
975
976 InsertTailList (&CurrentSourceList, &Copy->Link);
977 CurrentSourceCount++;
978 }
979 }
980
981 //
982 // Update the value... a long journey starts
983 //
984 NewAddress = AllocateCopyPool (DataSize, Data);
985 if (NewAddress == NULL) {
986 Ip6RemoveAddr (NULL, &CurrentSourceList, &CurrentSourceCount, NULL, 0);
987
988 return EFI_OUT_OF_RESOURCES;
989 }
990
991 //
992 // Store the new data, and init the DataItem status to EFI_NOT_READY because
993 // we may have an asynchronous configuration process.
994 //
995 DataItem = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];
996 if (DataItem->Data.Ptr != NULL) {
997 FreePool (DataItem->Data.Ptr);
998 }
999 DataItem->Data.Ptr = NewAddress;
1000 DataItem->DataSize = DataSize;
1001 DataItem->Status = EFI_NOT_READY;
1002
1003 //
1004 // Trigger DAD, it's an asynchronous process.
1005 //
1006 IsUpdated = FALSE;
1007
1008 for (Index1 = 0; Index1 < NewAddressCount; Index1++, NewAddress++) {
1009 if (Ip6IsOneOfSetAddress (IpSb, &NewAddress->Address, NULL, &CurrentAddrInfo)) {
1010 ASSERT (CurrentAddrInfo != NULL);
1011 //
1012 // Remove this already existing source address from the CurrentSourceList
1013 // built before.
1014 //
1015 Ip6RemoveAddr (
1016 NULL,
1017 &CurrentSourceList,
1018 &CurrentSourceCount,
1019 &CurrentAddrInfo->Address,
1020 128
1021 );
1022
1023 //
1024 // If the new address's prefix length is not specified, just use the previous configured
1025 // prefix length for this address.
1026 //
1027 if (NewAddress->PrefixLength == 0) {
1028 NewAddress->PrefixLength = CurrentAddrInfo->PrefixLength;
1029 }
1030
1031 //
1032 // This manual address is already in use, see whether prefix length is changed.
1033 //
1034 if (NewAddress->PrefixLength != CurrentAddrInfo->PrefixLength) {
1035 //
1036 // Remove the on-link prefix table, the route entry will be removed
1037 // implicitly.
1038 //
1039 PrefixEntry = Ip6FindPrefixListEntry (
1040 IpSb,
1041 TRUE,
1042 CurrentAddrInfo->PrefixLength,
1043 &CurrentAddrInfo->Address
1044 );
1045 if (PrefixEntry != NULL) {
1046 Ip6DestroyPrefixListEntry (IpSb, PrefixEntry, TRUE, FALSE);
1047 }
1048
1049 //
1050 // Save the prefix length.
1051 //
1052 CurrentAddrInfo->PrefixLength = NewAddress->PrefixLength;
1053 IsUpdated = TRUE;
1054 }
1055
1056 //
1057 // create a new on-link prefix entry.
1058 //
1059 PrefixEntry = Ip6FindPrefixListEntry (
1060 IpSb,
1061 TRUE,
1062 NewAddress->PrefixLength,
1063 &NewAddress->Address
1064 );
1065 if (PrefixEntry == NULL) {
1066 Ip6CreatePrefixListEntry (
1067 IpSb,
1068 TRUE,
1069 (UINT32) IP6_INFINIT_LIFETIME,
1070 (UINT32) IP6_INFINIT_LIFETIME,
1071 NewAddress->PrefixLength,
1072 &NewAddress->Address
1073 );
1074 }
1075
1076 CurrentAddrInfo->IsAnycast = NewAddress->IsAnycast;
1077 //
1078 // Artificially mark this address passed DAD be'coz it is already in use.
1079 //
1080 Ip6ManualAddrDadCallback (TRUE, &NewAddress->Address, Instance);
1081 } else {
1082 //
1083 // A new address.
1084 //
1085 IsUpdated = TRUE;
1086
1087 //
1088 // Set the new address, this will trigger DAD and activate the address if
1089 // DAD succeeds.
1090 //
1091 Ip6SetAddress (
1092 IpSb->DefaultInterface,
1093 &NewAddress->Address,
1094 NewAddress->IsAnycast,
1095 NewAddress->PrefixLength,
1096 (UINT32) IP6_INFINIT_LIFETIME,
1097 (UINT32) IP6_INFINIT_LIFETIME,
1098 Ip6ManualAddrDadCallback,
1099 Instance
1100 );
1101 }
1102 }
1103
1104 //
1105 // Check the CurrentSourceList, it now contains those addresses currently in
1106 // use and will be removed.
1107 //
1108 IpIf = IpSb->DefaultInterface;
1109
1110 while (!IsListEmpty (&CurrentSourceList)) {
1111 IsUpdated = TRUE;
1112
1113 CurrentAddrInfo = NET_LIST_HEAD (&CurrentSourceList, IP6_ADDRESS_INFO, Link);
1114
1115 //
1116 // This local address is going to be removed, the IP instances that are
1117 // currently using it will be destroyed.
1118 //
1119 Ip6RemoveAddr (
1120 IpSb,
1121 &IpIf->AddressList,
1122 &IpIf->AddressCount,
1123 &CurrentAddrInfo->Address,
1124 128
1125 );
1126
1127 //
1128 // Remove the on-link prefix table, the route entry will be removed
1129 // implicitly.
1130 //
1131 PrefixEntry = Ip6FindPrefixListEntry (
1132 IpSb,
1133 TRUE,
1134 CurrentAddrInfo->PrefixLength,
1135 &CurrentAddrInfo->Address
1136 );
1137 if (PrefixEntry != NULL) {
1138 Ip6DestroyPrefixListEntry (IpSb, PrefixEntry, TRUE, FALSE);
1139 }
1140
1141 RemoveEntryList (&CurrentAddrInfo->Link);
1142 FreePool (CurrentAddrInfo);
1143 }
1144
1145 if (IsUpdated) {
1146 if (DataItem->Status == EFI_NOT_READY) {
1147 //
1148 // If DAD is disabled on this interface, the configuration process is
1149 // actually synchronous, and the data item's status will be changed to
1150 // the final status before we reach here, just check it.
1151 //
1152 Status = EFI_NOT_READY;
1153 } else {
1154 Status = EFI_SUCCESS;
1155 }
1156 } else {
1157 //
1158 // No update is taken, reset the status to success and return EFI_ABORTED.
1159 //
1160 DataItem->Status = EFI_SUCCESS;
1161 Status = EFI_ABORTED;
1162 }
1163
1164 return Status;
1165 }
1166
1167 /**
1168 The work function for EfiIp6ConfigSetData() to set the gateway addresses manually
1169 for the EFI IPv6 network stack that is running on the communication device that
1170 this EFI IPv6 Configuration Protocol manages. It is not configurable when the policy is
1171 Ip6ConfigPolicyAutomatic. The gateway addresses must be unicast IPv6 addresses.
1172
1173 @param[in] Instance The pointer to the IP6 config instance data.
1174 @param[in] DataSize The size of the buffer pointed to by Data in bytes.
1175 @param[in] Data The data buffer to set. This points to an array of
1176 EFI_IPv6_ADDRESS instances.
1177
1178 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.
1179 @retval EFI_WRITE_PROTECTED The specified configuration data cannot be set
1180 under the current policy.
1181 @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.
1182 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to complete the operation.
1183 @retval EFI_ABORTED The manual gateway addresses to be set equal the
1184 current configuration.
1185 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6
1186 network stack was set.
1187
1188 **/
1189 EFI_STATUS
1190 Ip6ConfigSetGateway (
1191 IN IP6_CONFIG_INSTANCE *Instance,
1192 IN UINTN DataSize,
1193 IN VOID *Data
1194 )
1195 {
1196 UINTN Index1;
1197 UINTN Index2;
1198 EFI_IPv6_ADDRESS *OldGateway;
1199 EFI_IPv6_ADDRESS *NewGateway;
1200 UINTN OldGatewayCount;
1201 UINTN NewGatewayCount;
1202 IP6_CONFIG_DATA_ITEM *Item;
1203 BOOLEAN OneRemoved;
1204 BOOLEAN OneAdded;
1205 IP6_SERVICE *IpSb;
1206 IP6_DEFAULT_ROUTER *DefaultRouter;
1207 VOID *Tmp;
1208
1209 if ((DataSize % sizeof (EFI_IPv6_ADDRESS) != 0) || (DataSize == 0)) {
1210 return EFI_BAD_BUFFER_SIZE;
1211 }
1212
1213 if (Instance->Policy != Ip6ConfigPolicyManual) {
1214 return EFI_WRITE_PROTECTED;
1215 }
1216
1217 NewGateway = (EFI_IPv6_ADDRESS *) Data;
1218 NewGatewayCount = DataSize / sizeof (EFI_IPv6_ADDRESS);
1219 for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {
1220
1221 if (!NetIp6IsValidUnicast (NewGateway + Index1)) {
1222
1223 return EFI_INVALID_PARAMETER;
1224 }
1225
1226 for (Index2 = Index1 + 1; Index2 < NewGatewayCount; Index2++) {
1227 if (EFI_IP6_EQUAL (NewGateway + Index1, NewGateway + Index2)) {
1228 return EFI_INVALID_PARAMETER;
1229 }
1230 }
1231 }
1232
1233 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
1234 Item = &Instance->DataItem[Ip6ConfigDataTypeGateway];
1235 OldGateway = Item->Data.Gateway;
1236 OldGatewayCount = Item->DataSize / sizeof (EFI_IPv6_ADDRESS);
1237 OneRemoved = FALSE;
1238 OneAdded = FALSE;
1239
1240 if (NewGatewayCount != OldGatewayCount) {
1241 Tmp = AllocatePool (DataSize);
1242 if (Tmp == NULL) {
1243 return EFI_OUT_OF_RESOURCES;
1244 }
1245 } else {
1246 Tmp = NULL;
1247 }
1248
1249 for (Index1 = 0; Index1 < OldGatewayCount; Index1++) {
1250 //
1251 // Find the gateways that are no long in the new setting and remove them.
1252 //
1253 for (Index2 = 0; Index2 < NewGatewayCount; Index2++) {
1254 if (EFI_IP6_EQUAL (OldGateway + Index1, NewGateway + Index2)) {
1255 OneRemoved = TRUE;
1256 break;
1257 }
1258 }
1259
1260 if (Index2 == NewGatewayCount) {
1261 //
1262 // Remove this default router.
1263 //
1264 DefaultRouter = Ip6FindDefaultRouter (IpSb, OldGateway + Index1);
1265 if (DefaultRouter != NULL) {
1266 Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
1267 }
1268 }
1269 }
1270
1271 for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {
1272
1273 DefaultRouter = Ip6FindDefaultRouter (IpSb, NewGateway + Index1);
1274 if (DefaultRouter == NULL) {
1275 Ip6CreateDefaultRouter (IpSb, NewGateway + Index1, IP6_INF_ROUTER_LIFETIME);
1276 OneAdded = TRUE;
1277 }
1278 }
1279
1280 if (!OneRemoved && !OneAdded) {
1281 Item->Status = EFI_SUCCESS;
1282 return EFI_ABORTED;
1283 } else {
1284
1285 if (Tmp != NULL) {
1286 if (Item->Data.Ptr != NULL) {
1287 FreePool (Item->Data.Ptr);
1288 }
1289 Item->Data.Ptr = Tmp;
1290 }
1291
1292 CopyMem (Item->Data.Ptr, Data, DataSize);
1293 Item->DataSize = DataSize;
1294 Item->Status = EFI_SUCCESS;
1295 return EFI_SUCCESS;
1296 }
1297 }
1298
1299 /**
1300 The work function for EfiIp6ConfigSetData() to set the DNS server list for the
1301 EFI IPv6 network stack running on the communication device that this EFI IPv6
1302 Configuration Protocol manages. It is not configurable when the policy is
1303 Ip6ConfigPolicyAutomatic. The DNS server addresses must be unicast IPv6 addresses.
1304
1305 @param[in] Instance The pointer to the IP6 config instance data.
1306 @param[in] DataSize The size of the buffer pointed to by Data in bytes.
1307 @param[in] Data The data buffer to set, points to an array of
1308 EFI_IPv6_ADDRESS instances.
1309
1310 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.
1311 @retval EFI_WRITE_PROTECTED The specified configuration data cannot be set
1312 under the current policy.
1313 @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.
1314 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to complete the operation.
1315 @retval EFI_ABORTED The DNS server addresses to be set equal the current
1316 configuration.
1317 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6
1318 network stack was set.
1319
1320 **/
1321 EFI_STATUS
1322 Ip6ConfigSetDnsServer (
1323 IN IP6_CONFIG_INSTANCE *Instance,
1324 IN UINTN DataSize,
1325 IN VOID *Data
1326 )
1327 {
1328 UINTN OldIndex;
1329 UINTN NewIndex;
1330 EFI_IPv6_ADDRESS *OldDns;
1331 EFI_IPv6_ADDRESS *NewDns;
1332 UINTN OldDnsCount;
1333 UINTN NewDnsCount;
1334 IP6_CONFIG_DATA_ITEM *Item;
1335 BOOLEAN OneAdded;
1336 VOID *Tmp;
1337
1338 if ((DataSize % sizeof (EFI_IPv6_ADDRESS) != 0) || (DataSize == 0)) {
1339 return EFI_BAD_BUFFER_SIZE;
1340 }
1341
1342 if (Instance->Policy != Ip6ConfigPolicyManual) {
1343 return EFI_WRITE_PROTECTED;
1344 }
1345
1346 Item = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];
1347 NewDns = (EFI_IPv6_ADDRESS *) Data;
1348 OldDns = Item->Data.DnsServers;
1349 NewDnsCount = DataSize / sizeof (EFI_IPv6_ADDRESS);
1350 OldDnsCount = Item->DataSize / sizeof (EFI_IPv6_ADDRESS);
1351 OneAdded = FALSE;
1352
1353 if (NewDnsCount != OldDnsCount) {
1354 Tmp = AllocatePool (DataSize);
1355 if (Tmp == NULL) {
1356 return EFI_OUT_OF_RESOURCES;
1357 }
1358 } else {
1359 Tmp = NULL;
1360 }
1361
1362 for (NewIndex = 0; NewIndex < NewDnsCount; NewIndex++) {
1363
1364 if (!NetIp6IsValidUnicast (NewDns + NewIndex)) {
1365 //
1366 // The dns server address must be unicast.
1367 //
1368 if (Tmp != NULL) {
1369 FreePool (Tmp);
1370 }
1371 return EFI_INVALID_PARAMETER;
1372 }
1373
1374 if (OneAdded) {
1375 //
1376 // If any address in the new setting is not in the old settings, skip the
1377 // comparision below.
1378 //
1379 continue;
1380 }
1381
1382 for (OldIndex = 0; OldIndex < OldDnsCount; OldIndex++) {
1383 if (EFI_IP6_EQUAL (NewDns + NewIndex, OldDns + OldIndex)) {
1384 //
1385 // If found break out.
1386 //
1387 break;
1388 }
1389 }
1390
1391 if (OldIndex == OldDnsCount) {
1392 OneAdded = TRUE;
1393 }
1394 }
1395
1396 if (!OneAdded && (DataSize == Item->DataSize)) {
1397 //
1398 // No new item is added and the size is the same.
1399 //
1400 Item->Status = EFI_SUCCESS;
1401 return EFI_ABORTED;
1402 } else {
1403 if (Tmp != NULL) {
1404 if (Item->Data.Ptr != NULL) {
1405 FreePool (Item->Data.Ptr);
1406 }
1407 Item->Data.Ptr = Tmp;
1408 }
1409
1410 CopyMem (Item->Data.Ptr, Data, DataSize);
1411 Item->DataSize = DataSize;
1412 Item->Status = EFI_SUCCESS;
1413 return EFI_SUCCESS;
1414 }
1415 }
1416
1417 /**
1418 Generate the operational state of the interface this IP6 config instance manages
1419 and output in EFI_IP6_CONFIG_INTERFACE_INFO.
1420
1421 @param[in] IpSb The pointer to the IP6 service binding instance.
1422 @param[out] IfInfo The pointer to the IP6 configuration interface information structure.
1423
1424 **/
1425 VOID
1426 Ip6ConfigInitIfInfo (
1427 IN IP6_SERVICE *IpSb,
1428 OUT EFI_IP6_CONFIG_INTERFACE_INFO *IfInfo
1429 )
1430 {
1431 UnicodeSPrint (
1432 IfInfo->Name,
1433 sizeof (IfInfo->Name),
1434 L"eth%d",
1435 IpSb->Ip6ConfigInstance.IfIndex
1436 );
1437
1438 IfInfo->IfType = IpSb->SnpMode.IfType;
1439 IfInfo->HwAddressSize = IpSb->SnpMode.HwAddressSize;
1440 CopyMem (&IfInfo->HwAddress, &IpSb->SnpMode.CurrentAddress, IfInfo->HwAddressSize);
1441 }
1442
1443 /**
1444 Parse DHCPv6 reply packet to get the DNS server list.
1445 It is the work function for Ip6ConfigOnDhcp6Reply and Ip6ConfigOnDhcp6Event.
1446
1447 @param[in] Dhcp6 The pointer to the EFI_DHCP6_PROTOCOL instance.
1448 @param[in, out] Instance The pointer to the IP6 configuration instance data.
1449 @param[in] Reply The pointer to the DHCPv6 reply packet.
1450
1451 @retval EFI_SUCCESS The DNS server address was retrieved from the reply packet.
1452 @retval EFI_NOT_READY The reply packet does not contain the DNS server option, or
1453 the DNS server address is not valid.
1454
1455 **/
1456 EFI_STATUS
1457 Ip6ConfigParseDhcpReply (
1458 IN EFI_DHCP6_PROTOCOL *Dhcp6,
1459 IN OUT IP6_CONFIG_INSTANCE *Instance,
1460 IN EFI_DHCP6_PACKET *Reply
1461 )
1462 {
1463 EFI_STATUS Status;
1464 UINT32 OptCount;
1465 EFI_DHCP6_PACKET_OPTION **OptList;
1466 UINT16 OpCode;
1467 UINT16 Length;
1468 UINTN Index;
1469 UINTN Index2;
1470 EFI_IPv6_ADDRESS *DnsServer;
1471 IP6_CONFIG_DATA_ITEM *Item;
1472
1473 //
1474 // A DHCPv6 reply packet is received as the response to our InfoRequest
1475 // packet.
1476 //
1477 OptCount = 0;
1478 Status = Dhcp6->Parse (Dhcp6, Reply, &OptCount, NULL);
1479 if (Status != EFI_BUFFER_TOO_SMALL) {
1480 return EFI_NOT_READY;
1481 }
1482
1483 OptList = AllocatePool (OptCount * sizeof (EFI_DHCP6_PACKET_OPTION *));
1484 if (OptList == NULL) {
1485 return EFI_NOT_READY;
1486 }
1487
1488 Status = Dhcp6->Parse (Dhcp6, Reply, &OptCount, OptList);
1489 if (EFI_ERROR (Status)) {
1490 Status = EFI_NOT_READY;
1491 goto ON_EXIT;
1492 }
1493
1494 Status = EFI_SUCCESS;
1495
1496 for (Index = 0; Index < OptCount; Index++) {
1497 //
1498 // Go through all the options to check the ones we are interested in.
1499 // The OpCode and Length are in network byte-order and may not be naturally
1500 // aligned.
1501 //
1502 CopyMem (&OpCode, &OptList[Index]->OpCode, sizeof (OpCode));
1503 OpCode = NTOHS (OpCode);
1504
1505 if (OpCode == DHCP6_OPT_DNS_SERVERS) {
1506 CopyMem (&Length, &OptList[Index]->OpLen, sizeof (Length));
1507 Length = NTOHS (Length);
1508
1509 if ((Length == 0) || ((Length % sizeof (EFI_IPv6_ADDRESS)) != 0)) {
1510 //
1511 // The length should be a multiple of 16 bytes.
1512 //
1513 Status = EFI_NOT_READY;
1514 break;
1515 }
1516
1517 //
1518 // Validate the DnsServers: whether they are unicast addresses.
1519 //
1520 DnsServer = (EFI_IPv6_ADDRESS *) OptList[Index]->Data;
1521 for (Index2 = 0; Index2 < Length / sizeof (EFI_IPv6_ADDRESS); Index2++) {
1522 if (!NetIp6IsValidUnicast (DnsServer)) {
1523 Status = EFI_NOT_READY;
1524 goto ON_EXIT;
1525 }
1526
1527 DnsServer++;
1528 }
1529
1530 Item = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];
1531
1532 if (Item->DataSize != Length) {
1533 if (Item->Data.Ptr != NULL) {
1534 FreePool (Item->Data.Ptr);
1535 }
1536
1537 Item->Data.Ptr = AllocatePool (Length);
1538 ASSERT (Item->Data.Ptr != NULL);
1539 }
1540
1541 CopyMem (Item->Data.Ptr, OptList[Index]->Data, Length);
1542 Item->DataSize = Length;
1543 Item->Status = EFI_SUCCESS;
1544
1545 //
1546 // Signal the waiting events.
1547 //
1548 NetMapIterate (&Item->EventMap, Ip6ConfigSignalEvent, NULL);
1549
1550 break;
1551 }
1552 }
1553
1554 ON_EXIT:
1555
1556 FreePool (OptList);
1557 return Status;
1558 }
1559
1560 /**
1561 The callback function for Ip6SetAddr. The prototype is defined
1562 as IP6_DAD_CALLBACK. It is called after Duplicate Address Detection is performed
1563 on the tentative address by DHCPv6 in Ip6ConfigOnDhcp6Event().
1564
1565 @param[in] IsDadPassed If TRUE, Duplicate Address Detection passes.
1566 @param[in] TargetAddress The tentative IPv6 address to be checked.
1567 @param[in] Context Pointer to the IP6 configuration instance data.
1568
1569 **/
1570 VOID
1571 Ip6ConfigSetStatefulAddrCallback (
1572 IN BOOLEAN IsDadPassed,
1573 IN EFI_IPv6_ADDRESS *TargetAddress,
1574 IN VOID *Context
1575 )
1576 {
1577 IP6_CONFIG_INSTANCE *Instance;
1578
1579 Instance = (IP6_CONFIG_INSTANCE *) Context;
1580 NET_CHECK_SIGNATURE (Instance, IP6_CONFIG_INSTANCE_SIGNATURE);
1581
1582 //
1583 // We should record the addresses that fail the DAD, and DECLINE them.
1584 //
1585 if (IsDadPassed) {
1586 //
1587 // Decrease the count, no interests in those passed DAD.
1588 //
1589 if (Instance->FailedIaAddressCount > 0 ) {
1590 Instance->FailedIaAddressCount--;
1591 }
1592 } else {
1593 //
1594 // Record it.
1595 //
1596 IP6_COPY_ADDRESS (Instance->DeclineAddress + Instance->DeclineAddressCount, TargetAddress);
1597 Instance->DeclineAddressCount++;
1598 }
1599
1600 if (Instance->FailedIaAddressCount == Instance->DeclineAddressCount) {
1601 //
1602 // The checking on all addresses are finished.
1603 //
1604 if (Instance->DeclineAddressCount != 0) {
1605 //
1606 // Decline those duplicates.
1607 //
1608 if (Instance->Dhcp6 != NULL) {
1609 Instance->Dhcp6->Decline (
1610 Instance->Dhcp6,
1611 Instance->DeclineAddressCount,
1612 Instance->DeclineAddress
1613 );
1614 }
1615 }
1616
1617 if (Instance->DeclineAddress != NULL) {
1618 FreePool (Instance->DeclineAddress);
1619 }
1620 Instance->DeclineAddress = NULL;
1621 Instance->DeclineAddressCount = 0;
1622 }
1623 }
1624
1625 /**
1626 The event handle routine when DHCPv6 process is finished or is updated.
1627
1628 @param[in] Event Not used.
1629 @param[in] Context The pointer to the IP6 configuration instance data.
1630
1631 **/
1632 VOID
1633 EFIAPI
1634 Ip6ConfigOnDhcp6Event (
1635 IN EFI_EVENT Event,
1636 IN VOID *Context
1637 )
1638 {
1639 IP6_CONFIG_INSTANCE *Instance;
1640 EFI_DHCP6_PROTOCOL *Dhcp6;
1641 EFI_STATUS Status;
1642 EFI_DHCP6_MODE_DATA Dhcp6ModeData;
1643 EFI_DHCP6_IA *Ia;
1644 EFI_DHCP6_IA_ADDRESS *IaAddr;
1645 UINT32 Index;
1646 IP6_SERVICE *IpSb;
1647 IP6_ADDRESS_INFO *AddrInfo;
1648 IP6_INTERFACE *IpIf;
1649
1650 Instance = (IP6_CONFIG_INSTANCE *) Context;
1651
1652 if ((Instance->Policy != Ip6ConfigPolicyAutomatic) || Instance->OtherInfoOnly) {
1653 //
1654 // IPv6 is not operating in the automatic policy now or
1655 // the DHCPv6 information request message exchange is aborted.
1656 //
1657 return ;
1658 }
1659
1660 //
1661 // The stateful address autoconfiguration is done or updated.
1662 //
1663 Dhcp6 = Instance->Dhcp6;
1664
1665 Status = Dhcp6->GetModeData (Dhcp6, &Dhcp6ModeData, NULL);
1666 if (EFI_ERROR (Status)) {
1667 return ;
1668 }
1669
1670 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
1671 IpIf = IpSb->DefaultInterface;
1672 Ia = Dhcp6ModeData.Ia;
1673 IaAddr = Ia->IaAddress;
1674
1675 if (Instance->DeclineAddress != NULL) {
1676 FreePool (Instance->DeclineAddress);
1677 }
1678
1679 Instance->DeclineAddress = (EFI_IPv6_ADDRESS *) AllocatePool (Ia->IaAddressCount * sizeof (EFI_IPv6_ADDRESS));
1680 if (Instance->DeclineAddress == NULL) {
1681 goto ON_EXIT;
1682 }
1683
1684 Instance->FailedIaAddressCount = Ia->IaAddressCount;
1685 Instance->DeclineAddressCount = 0;
1686
1687 for (Index = 0; Index < Ia->IaAddressCount; Index++, IaAddr++) {
1688 if (Ia->IaAddress[Index].ValidLifetime != 0 && Ia->State == Dhcp6Bound) {
1689 //
1690 // Set this address, either it's a new address or with updated lifetimes.
1691 // An appropriate prefix length will be set.
1692 //
1693 Ip6SetAddress (
1694 IpIf,
1695 &IaAddr->IpAddress,
1696 FALSE,
1697 0,
1698 IaAddr->ValidLifetime,
1699 IaAddr->PreferredLifetime,
1700 Ip6ConfigSetStatefulAddrCallback,
1701 Instance
1702 );
1703 } else {
1704 //
1705 // discard this address, artificially decrease the count as if this address
1706 // passed DAD.
1707 //
1708 if (Ip6IsOneOfSetAddress (IpSb, &IaAddr->IpAddress, NULL, &AddrInfo)) {
1709 ASSERT (AddrInfo != NULL);
1710 Ip6RemoveAddr (
1711 IpSb,
1712 &IpIf->AddressList,
1713 &IpIf->AddressCount,
1714 &AddrInfo->Address,
1715 AddrInfo->PrefixLength
1716 );
1717 }
1718
1719 if (Instance->FailedIaAddressCount > 0) {
1720 Instance->FailedIaAddressCount--;
1721 }
1722 }
1723 }
1724
1725 //
1726 // Parse the Reply packet to get the options we need.
1727 //
1728 if (Dhcp6ModeData.Ia->ReplyPacket != NULL) {
1729 Ip6ConfigParseDhcpReply (Dhcp6, Instance, Dhcp6ModeData.Ia->ReplyPacket);
1730 }
1731
1732 ON_EXIT:
1733
1734 FreePool (Dhcp6ModeData.ClientId);
1735 FreePool (Dhcp6ModeData.Ia);
1736 }
1737
1738 /**
1739 The event process routine when the DHCPv6 server is answered with a reply packet
1740 for an information request.
1741
1742 @param[in] This Points to the EFI_DHCP6_PROTOCOL.
1743 @param[in] Context The pointer to the IP6 configuration instance data.
1744 @param[in] Packet The DHCPv6 reply packet.
1745
1746 @retval EFI_SUCCESS The DNS server address was retrieved from the reply packet.
1747 @retval EFI_NOT_READY The reply packet does not contain the DNS server option, or
1748 the DNS server address is not valid.
1749
1750 **/
1751 EFI_STATUS
1752 EFIAPI
1753 Ip6ConfigOnDhcp6Reply (
1754 IN EFI_DHCP6_PROTOCOL *This,
1755 IN VOID *Context,
1756 IN EFI_DHCP6_PACKET *Packet
1757 )
1758 {
1759 return Ip6ConfigParseDhcpReply (This, (IP6_CONFIG_INSTANCE *) Context, Packet);
1760 }
1761
1762 /**
1763 The event process routine when the DHCPv6 service binding protocol is installed
1764 in the system.
1765
1766 @param[in] Event Not used.
1767 @param[in] Context The pointer to the IP6 config instance data.
1768
1769 **/
1770 VOID
1771 EFIAPI
1772 Ip6ConfigOnDhcp6SbInstalled (
1773 IN EFI_EVENT Event,
1774 IN VOID *Context
1775 )
1776 {
1777 IP6_CONFIG_INSTANCE *Instance;
1778
1779 Instance = (IP6_CONFIG_INSTANCE *) Context;
1780
1781 if ((Instance->Dhcp6Handle != NULL) || (Instance->Policy != Ip6ConfigPolicyAutomatic)) {
1782 //
1783 // The DHCP6 child is already created or the policy is no longer AUTOMATIC.
1784 //
1785 return ;
1786 }
1787
1788 Ip6ConfigStartStatefulAutoConfig (Instance, Instance->OtherInfoOnly);
1789 }
1790
1791 /**
1792 Set the configuration for the EFI IPv6 network stack running on the communication
1793 device this EFI IPv6 Configuration Protocol instance manages.
1794
1795 This function is used to set the configuration data of type DataType for the EFI
1796 IPv6 network stack that is running on the communication device that this EFI IPv6
1797 Configuration Protocol instance manages.
1798
1799 DataSize is used to calculate the count of structure instances in the Data for
1800 a DataType in which multiple structure instances are allowed.
1801
1802 This function is always non-blocking. When setting some type of configuration data,
1803 an asynchronous process is invoked to check the correctness of the data, such as
1804 performing Duplicate Address Detection on the manually set local IPv6 addresses.
1805 EFI_NOT_READY is returned immediately to indicate that such an asynchronous process
1806 is invoked, and the process is not finished yet. The caller wanting to get the result
1807 of the asynchronous process is required to call RegisterDataNotify() to register an
1808 event on the specified configuration data. Once the event is signaled, the caller
1809 can call GetData() to obtain the configuration data and know the result.
1810 For other types of configuration data that do not require an asynchronous configuration
1811 process, the result of the operation is immediately returned.
1812
1813 @param[in] This The pointer to the EFI_IP6_CONFIG_PROTOCOL instance.
1814 @param[in] DataType The type of data to set.
1815 @param[in] DataSize Size of the buffer pointed to by Data in bytes.
1816 @param[in] Data The data buffer to set. The type of the data buffer is
1817 associated with the DataType.
1818
1819 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6
1820 network stack was set successfully.
1821 @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
1822 - This is NULL.
1823 - Data is NULL.
1824 - One or more fields in Data do not match the requirement of the
1825 data type indicated by DataType.
1826 @retval EFI_WRITE_PROTECTED The specified configuration data is read-only or the specified
1827 configuration data cannot be set under the current policy.
1828 @retval EFI_ACCESS_DENIED Another set operation on the specified configuration
1829 data is already in process.
1830 @retval EFI_NOT_READY An asynchronous process was invoked to set the specified
1831 configuration data, and the process is not finished yet.
1832 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type
1833 indicated by DataType.
1834 @retval EFI_UNSUPPORTED This DataType is not supported.
1835 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1836 @retval EFI_DEVICE_ERROR An unexpected system error or network error occurred.
1837
1838 **/
1839 EFI_STATUS
1840 EFIAPI
1841 EfiIp6ConfigSetData (
1842 IN EFI_IP6_CONFIG_PROTOCOL *This,
1843 IN EFI_IP6_CONFIG_DATA_TYPE DataType,
1844 IN UINTN DataSize,
1845 IN VOID *Data
1846 )
1847 {
1848 EFI_TPL OldTpl;
1849 EFI_STATUS Status;
1850 IP6_CONFIG_INSTANCE *Instance;
1851 IP6_SERVICE *IpSb;
1852
1853 if ((This == NULL) || (Data == NULL)) {
1854 return EFI_INVALID_PARAMETER;
1855 }
1856
1857 if (DataType >= Ip6ConfigDataTypeMaximum) {
1858 return EFI_UNSUPPORTED;
1859 }
1860
1861 Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);
1862 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
1863 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
1864
1865 if (IpSb->LinkLocalDadFail) {
1866 return EFI_DEVICE_ERROR;
1867 }
1868
1869 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1870
1871 Status = Instance->DataItem[DataType].Status;
1872 if (Status != EFI_NOT_READY) {
1873
1874 if (Instance->DataItem[DataType].SetData == NULL) {
1875 //
1876 // This type of data is readonly.
1877 //
1878 Status = EFI_WRITE_PROTECTED;
1879 } else {
1880
1881 Status = Instance->DataItem[DataType].SetData (Instance, DataSize, Data);
1882 if (!EFI_ERROR (Status)) {
1883 //
1884 // Fire up the events registered with this type of data.
1885 //
1886 NetMapIterate (&Instance->DataItem[DataType].EventMap, Ip6ConfigSignalEvent, NULL);
1887 Ip6ConfigWriteConfigData (IpSb->MacString, Instance);
1888 } else if (Status == EFI_ABORTED) {
1889 //
1890 // The SetData is aborted because the data to set is the same with
1891 // the one maintained.
1892 //
1893 Status = EFI_SUCCESS;
1894 NetMapIterate (&Instance->DataItem[DataType].EventMap, Ip6ConfigSignalEvent, NULL);
1895 }
1896 }
1897 } else {
1898 //
1899 // Another asynchornous process is on the way.
1900 //
1901 Status = EFI_ACCESS_DENIED;
1902 }
1903
1904 gBS->RestoreTPL (OldTpl);
1905
1906 return Status;
1907 }
1908
1909 /**
1910 Get the configuration data for the EFI IPv6 network stack running on the communication
1911 device that this EFI IPv6 Configuration Protocol instance manages.
1912
1913 This function returns the configuration data of type DataType for the EFI IPv6 network
1914 stack running on the communication device that this EFI IPv6 Configuration Protocol instance
1915 manages.
1916
1917 The caller is responsible for allocating the buffer used to return the specified
1918 configuration data. The required size will be returned to the caller if the size of
1919 the buffer is too small.
1920
1921 EFI_NOT_READY is returned if the specified configuration data is not ready due to an
1922 asynchronous configuration process already in progress. The caller can call RegisterDataNotify()
1923 to register an event on the specified configuration data. Once the asynchronous configuration
1924 process is finished, the event will be signaled, and a subsequent GetData() call will return
1925 the specified configuration data.
1926
1927 @param[in] This Pointer to the EFI_IP6_CONFIG_PROTOCOL instance.
1928 @param[in] DataType The type of data to get.
1929 @param[in, out] DataSize On input, in bytes, the size of Data. On output, in bytes, the
1930 size of buffer required to store the specified configuration data.
1931 @param[in] Data The data buffer in which the configuration data is returned. The
1932 type of the data buffer is associated with the DataType.
1933 This is an optional parameter that may be NULL.
1934
1935 @retval EFI_SUCCESS The specified configuration data was obtained successfully.
1936 @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE:
1937 - This is NULL.
1938 - DataSize is NULL.
1939 - Data is NULL if *DataSize is not zero.
1940 @retval EFI_BUFFER_TOO_SMALL The size of Data is too small for the specified configuration data,
1941 and the required size is returned in DataSize.
1942 @retval EFI_NOT_READY The specified configuration data is not ready due to an
1943 asynchronous configuration process already in progress.
1944 @retval EFI_NOT_FOUND The specified configuration data is not found.
1945
1946 **/
1947 EFI_STATUS
1948 EFIAPI
1949 EfiIp6ConfigGetData (
1950 IN EFI_IP6_CONFIG_PROTOCOL *This,
1951 IN EFI_IP6_CONFIG_DATA_TYPE DataType,
1952 IN OUT UINTN *DataSize,
1953 IN VOID *Data OPTIONAL
1954 )
1955 {
1956 EFI_TPL OldTpl;
1957 EFI_STATUS Status;
1958 IP6_CONFIG_INSTANCE *Instance;
1959 IP6_CONFIG_DATA_ITEM *DataItem;
1960
1961 if ((This == NULL) || (DataSize == NULL) || ((*DataSize != 0) && (Data == NULL))) {
1962 return EFI_INVALID_PARAMETER;
1963 }
1964
1965 if (DataType >= Ip6ConfigDataTypeMaximum) {
1966 return EFI_NOT_FOUND;
1967 }
1968
1969 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1970
1971 Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);
1972 DataItem = &Instance->DataItem[DataType];
1973
1974 Status = Instance->DataItem[DataType].Status;
1975 if (!EFI_ERROR (Status)) {
1976
1977 if (DataItem->GetData != NULL) {
1978
1979 Status = DataItem->GetData (Instance, DataSize, Data);
1980 } else if (*DataSize < Instance->DataItem[DataType].DataSize) {
1981 //
1982 // Update the buffer length.
1983 //
1984 *DataSize = Instance->DataItem[DataType].DataSize;
1985 Status = EFI_BUFFER_TOO_SMALL;
1986 } else {
1987
1988 *DataSize = Instance->DataItem[DataType].DataSize;
1989 CopyMem (Data, Instance->DataItem[DataType].Data.Ptr, *DataSize);
1990 }
1991 }
1992
1993 gBS->RestoreTPL (OldTpl);
1994
1995 return Status;
1996 }
1997
1998 /**
1999 Register an event that is signaled whenever a configuration process on the specified
2000 configuration data is done.
2001
2002 This function registers an event that is to be signaled whenever a configuration
2003 process on the specified configuration data is performed. An event can be registered
2004 for a different DataType simultaneously. The caller is responsible for determining
2005 which type of configuration data causes the signaling of the event in such an event.
2006
2007 @param[in] This Pointer to the EFI_IP6_CONFIG_PROTOCOL instance.
2008 @param[in] DataType The type of data to unregister the event for.
2009 @param[in] Event The event to register.
2010
2011 @retval EFI_SUCCESS The notification event for the specified configuration data is
2012 registered.
2013 @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.
2014 @retval EFI_UNSUPPORTED The configuration data type specified by DataType is not
2015 supported.
2016 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
2017 @retval EFI_ACCESS_DENIED The Event is already registered for the DataType.
2018
2019 **/
2020 EFI_STATUS
2021 EFIAPI
2022 EfiIp6ConfigRegisterDataNotify (
2023 IN EFI_IP6_CONFIG_PROTOCOL *This,
2024 IN EFI_IP6_CONFIG_DATA_TYPE DataType,
2025 IN EFI_EVENT Event
2026 )
2027 {
2028 EFI_TPL OldTpl;
2029 EFI_STATUS Status;
2030 IP6_CONFIG_INSTANCE *Instance;
2031 NET_MAP *EventMap;
2032 NET_MAP_ITEM *Item;
2033
2034 if ((This == NULL) || (Event == NULL)) {
2035 return EFI_INVALID_PARAMETER;
2036 }
2037
2038 if (DataType >= Ip6ConfigDataTypeMaximum) {
2039 return EFI_UNSUPPORTED;
2040 }
2041
2042 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
2043
2044 Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);
2045 EventMap = &Instance->DataItem[DataType].EventMap;
2046
2047 //
2048 // Check whether this event is already registered for this DataType.
2049 //
2050 Item = NetMapFindKey (EventMap, Event);
2051 if (Item == NULL) {
2052
2053 Status = NetMapInsertTail (EventMap, Event, NULL);
2054
2055 if (EFI_ERROR (Status)) {
2056
2057 Status = EFI_OUT_OF_RESOURCES;
2058 }
2059
2060 } else {
2061
2062 Status = EFI_ACCESS_DENIED;
2063 }
2064
2065 gBS->RestoreTPL (OldTpl);
2066
2067 return Status;
2068 }
2069
2070 /**
2071 Remove a previously registered event for the specified configuration data.
2072
2073 @param This The pointer to the EFI_IP6_CONFIG_PROTOCOL instance.
2074 @param DataType The type of data to remove from the previously
2075 registered event.
2076 @param Event The event to be unregistered.
2077
2078 @retval EFI_SUCCESS The event registered for the specified
2079 configuration data was removed.
2080 @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.
2081 @retval EFI_NOT_FOUND The Event has not been registered for the
2082 specified DataType.
2083
2084 **/
2085 EFI_STATUS
2086 EFIAPI
2087 EfiIp6ConfigUnregisterDataNotify (
2088 IN EFI_IP6_CONFIG_PROTOCOL *This,
2089 IN EFI_IP6_CONFIG_DATA_TYPE DataType,
2090 IN EFI_EVENT Event
2091 )
2092 {
2093 EFI_TPL OldTpl;
2094 EFI_STATUS Status;
2095 IP6_CONFIG_INSTANCE *Instance;
2096 NET_MAP_ITEM *Item;
2097
2098 if ((This == NULL) || (Event == NULL)) {
2099 return EFI_INVALID_PARAMETER;
2100 }
2101
2102 if (DataType >= Ip6ConfigDataTypeMaximum) {
2103 return EFI_NOT_FOUND;
2104 }
2105
2106 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
2107
2108 Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);
2109
2110 Item = NetMapFindKey (&Instance->DataItem[DataType].EventMap, Event);
2111 if (Item != NULL) {
2112
2113 NetMapRemoveItem (&Instance->DataItem[DataType].EventMap, Item, NULL);
2114 Status = EFI_SUCCESS;
2115 } else {
2116
2117 Status = EFI_NOT_FOUND;
2118 }
2119
2120 gBS->RestoreTPL (OldTpl);
2121
2122 return Status;
2123 }
2124
2125 /**
2126 Initialize an IP6_CONFIG_INSTANCE.
2127
2128 @param[out] Instance The buffer of IP6_CONFIG_INSTANCE to be initialized.
2129
2130 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to complete the operation.
2131 @retval EFI_SUCCESS The IP6_CONFIG_INSTANCE initialized successfully.
2132
2133 **/
2134 EFI_STATUS
2135 Ip6ConfigInitInstance (
2136 OUT IP6_CONFIG_INSTANCE *Instance
2137 )
2138 {
2139 IP6_SERVICE *IpSb;
2140 IP6_CONFIG_INSTANCE *TmpInstance;
2141 LIST_ENTRY *Entry;
2142 EFI_STATUS Status;
2143 UINTN Index;
2144 UINT16 IfIndex;
2145 IP6_CONFIG_DATA_ITEM *DataItem;
2146
2147 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
2148
2149 Instance->Signature = IP6_CONFIG_INSTANCE_SIGNATURE;
2150
2151 //
2152 // Determine the index of this interface.
2153 //
2154 IfIndex = 0;
2155 NET_LIST_FOR_EACH (Entry, &mIp6ConfigInstanceList) {
2156 TmpInstance = NET_LIST_USER_STRUCT_S (Entry, IP6_CONFIG_INSTANCE, Link, IP6_CONFIG_INSTANCE_SIGNATURE);
2157
2158 if (TmpInstance->IfIndex > IfIndex) {
2159 //
2160 // There is a sequence hole because some interface is down.
2161 //
2162 break;
2163 }
2164
2165 IfIndex++;
2166 }
2167
2168 Instance->IfIndex = IfIndex;
2169 NetListInsertBefore (Entry, &Instance->Link);
2170
2171 for (Index = 0; Index < Ip6ConfigDataTypeMaximum; Index++) {
2172 //
2173 // Initialize the event map for each data item.
2174 //
2175 NetMapInit (&Instance->DataItem[Index].EventMap);
2176 }
2177
2178 //
2179 // Initialize the NET_MAPs used for DAD on manually configured source addresses.
2180 //
2181 NetMapInit (&Instance->DadFailedMap);
2182 NetMapInit (&Instance->DadPassedMap);
2183
2184 //
2185 // Initialize each data type: associate storage and set data size for the
2186 // fixed size data types, hook the SetData function, set the data attribute.
2187 //
2188 DataItem = &Instance->DataItem[Ip6ConfigDataTypeInterfaceInfo];
2189 DataItem->GetData = Ip6ConfigGetIfInfo;
2190 DataItem->Data.Ptr = &Instance->InterfaceInfo;
2191 DataItem->DataSize = sizeof (Instance->InterfaceInfo);
2192 SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED | DATA_ATTRIB_VOLATILE);
2193 Ip6ConfigInitIfInfo (IpSb, &Instance->InterfaceInfo);
2194
2195 DataItem = &Instance->DataItem[Ip6ConfigDataTypeAltInterfaceId];
2196 DataItem->SetData = Ip6ConfigSetAltIfId;
2197 DataItem->Data.Ptr = &Instance->AltIfId;
2198 DataItem->DataSize = sizeof (Instance->AltIfId);
2199 DataItem->Status = EFI_NOT_FOUND;
2200 SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED);
2201
2202 DataItem = &Instance->DataItem[Ip6ConfigDataTypePolicy];
2203 DataItem->SetData = Ip6ConfigSetPolicy;
2204 DataItem->Data.Ptr = &Instance->Policy;
2205 DataItem->DataSize = sizeof (Instance->Policy);
2206 Instance->Policy = Ip6ConfigPolicyManual;
2207 SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED);
2208
2209 DataItem = &Instance->DataItem[Ip6ConfigDataTypeDupAddrDetectTransmits];
2210 DataItem->SetData = Ip6ConfigSetDadXmits;
2211 DataItem->Data.Ptr = &Instance->DadXmits;
2212 DataItem->DataSize = sizeof (Instance->DadXmits);
2213 Instance->DadXmits.DupAddrDetectTransmits = IP6_CONFIG_DEFAULT_DAD_XMITS;
2214 SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED);
2215
2216 DataItem = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];
2217 DataItem->SetData = Ip6ConfigSetMaunualAddress;
2218 DataItem->Status = EFI_NOT_FOUND;
2219
2220 DataItem = &Instance->DataItem[Ip6ConfigDataTypeGateway];
2221 DataItem->SetData = Ip6ConfigSetGateway;
2222 DataItem->Status = EFI_NOT_FOUND;
2223
2224 DataItem = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];
2225 DataItem->SetData = Ip6ConfigSetDnsServer;
2226 DataItem->Status = EFI_NOT_FOUND;
2227
2228 //
2229 // Create the event used for DHCP.
2230 //
2231 Status = gBS->CreateEvent (
2232 EVT_NOTIFY_SIGNAL,
2233 TPL_CALLBACK,
2234 Ip6ConfigOnDhcp6Event,
2235 Instance,
2236 &Instance->Dhcp6Event
2237 );
2238 ASSERT_EFI_ERROR (Status);
2239
2240 Instance->Configured = TRUE;
2241
2242 //
2243 // Try to read the config data from NV variable.
2244 //
2245 Status = Ip6ConfigReadConfigData (IpSb->MacString, Instance);
2246 if (Status == EFI_NOT_FOUND) {
2247 //
2248 // The NV variable is not set, so generate a random IAID, and write down the
2249 // fresh new configuration as the NV variable now.
2250 //
2251 Instance->IaId = NET_RANDOM (NetRandomInitSeed ());
2252
2253 for (Index = 0; Index < IpSb->SnpMode.HwAddressSize; Index++) {
2254 Instance->IaId |= (IpSb->SnpMode.CurrentAddress.Addr[Index] << ((Index << 3) & 31));
2255 }
2256
2257 Ip6ConfigWriteConfigData (IpSb->MacString, Instance);
2258 } else if (EFI_ERROR (Status)) {
2259 return Status;
2260 }
2261
2262 Instance->Ip6Config.SetData = EfiIp6ConfigSetData;
2263 Instance->Ip6Config.GetData = EfiIp6ConfigGetData;
2264 Instance->Ip6Config.RegisterDataNotify = EfiIp6ConfigRegisterDataNotify;
2265 Instance->Ip6Config.UnregisterDataNotify = EfiIp6ConfigUnregisterDataNotify;
2266
2267
2268 //
2269 // Publish the IP6 configuration form
2270 //
2271 return Ip6ConfigFormInit (Instance);
2272 }
2273
2274 /**
2275 Release an IP6_CONFIG_INSTANCE.
2276
2277 @param[in, out] Instance The buffer of IP6_CONFIG_INSTANCE to be freed.
2278
2279 **/
2280 VOID
2281 Ip6ConfigCleanInstance (
2282 IN OUT IP6_CONFIG_INSTANCE *Instance
2283 )
2284 {
2285 UINTN Index;
2286 IP6_CONFIG_DATA_ITEM *DataItem;
2287
2288 if (Instance->DeclineAddress != NULL) {
2289 FreePool (Instance->DeclineAddress);
2290 }
2291
2292 if (!Instance->Configured) {
2293 return ;
2294 }
2295
2296 if (Instance->Dhcp6Handle != NULL) {
2297
2298 Ip6ConfigDestroyDhcp6 (Instance);
2299 }
2300
2301 //
2302 // Close the event.
2303 //
2304 if (Instance->Dhcp6Event != NULL) {
2305 gBS->CloseEvent (Instance->Dhcp6Event);
2306 }
2307
2308 NetMapClean (&Instance->DadPassedMap);
2309 NetMapClean (&Instance->DadFailedMap);
2310
2311 for (Index = 0; Index < Ip6ConfigDataTypeMaximum; Index++) {
2312
2313 DataItem = &Instance->DataItem[Index];
2314
2315 if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED)) {
2316 if (DataItem->Data.Ptr != NULL) {
2317 FreePool (DataItem->Data.Ptr);
2318 }
2319 DataItem->Data.Ptr = NULL;
2320 DataItem->DataSize = 0;
2321 }
2322
2323 NetMapClean (&Instance->DataItem[Index].EventMap);
2324 }
2325
2326 Ip6ConfigFormUnload (Instance);
2327
2328 RemoveEntryList (&Instance->Link);
2329 }
2330
2331 /**
2332 Destroy the Dhcp6 child in IP6_CONFIG_INSTANCE and release the resources.
2333
2334 @param[in, out] Instance The buffer of IP6_CONFIG_INSTANCE to be freed.
2335
2336 @retval EFI_SUCCESS The child was successfully destroyed.
2337 @retval Others Failed to destroy the child.
2338
2339 **/
2340 EFI_STATUS
2341 Ip6ConfigDestroyDhcp6 (
2342 IN OUT IP6_CONFIG_INSTANCE *Instance
2343 )
2344 {
2345 IP6_SERVICE *IpSb;
2346 EFI_STATUS Status;
2347 EFI_DHCP6_PROTOCOL *Dhcp6;
2348
2349 Dhcp6 = Instance->Dhcp6;
2350 ASSERT (Dhcp6 != NULL);
2351
2352 Dhcp6->Stop (Dhcp6);
2353 Dhcp6->Configure (Dhcp6, NULL);
2354 Instance->Dhcp6 = NULL;
2355
2356 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
2357
2358 //
2359 // Close DHCPv6 protocol and destroy the child.
2360 //
2361 Status = gBS->CloseProtocol (
2362 Instance->Dhcp6Handle,
2363 &gEfiDhcp6ProtocolGuid,
2364 IpSb->Image,
2365 IpSb->Controller
2366 );
2367 if (EFI_ERROR (Status)) {
2368 return Status;
2369 }
2370
2371 Status = NetLibDestroyServiceChild (
2372 IpSb->Controller,
2373 IpSb->Image,
2374 &gEfiDhcp6ServiceBindingProtocolGuid,
2375 Instance->Dhcp6Handle
2376 );
2377
2378 Instance->Dhcp6Handle = NULL;
2379
2380 return Status;
2381 }
2382