]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/Ip6Dxe/Ip6ConfigImpl.c
7575b7947d9989d724ff590abe117b0ce73eb596
[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 if (Item->DataSize == 0) {
788 return;
789 }
790
791 for (Index = 0; Index < Item->DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS); Index++) {
792 //
793 // Find the original tag used to place into the NET_MAP.
794 //
795 ManualAddr = Item->Data.ManualAddress + Index;
796 if (EFI_IP6_EQUAL (TargetAddress, &ManualAddr->Address)) {
797 break;
798 }
799 }
800
801 ASSERT (Index != Item->DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS));
802
803 if (IsDadPassed) {
804 NetMapInsertTail (&Instance->DadPassedMap, ManualAddr, NULL);
805 } else {
806 NetMapInsertTail (&Instance->DadFailedMap, ManualAddr, NULL);
807 }
808
809 DadPassCount = NetMapGetCount (&Instance->DadPassedMap);
810 DadFailCount = NetMapGetCount (&Instance->DadFailedMap);
811
812 if ((DadPassCount + DadFailCount) == (Item->DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS))) {
813 //
814 // All addresses have finished the configuration process.
815 //
816 if (DadFailCount != 0) {
817 //
818 // There is at least one duplicate address.
819 //
820 FreePool (Item->Data.Ptr);
821
822 Item->DataSize = DadPassCount * sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS);
823 if (Item->DataSize == 0) {
824 //
825 // All failed, bad luck.
826 //
827 Item->Data.Ptr = NULL;
828 Item->Status = EFI_NOT_FOUND;
829 } else {
830 //
831 // Part of addresses are detected to be duplicates, so update the
832 // data with those passed.
833 //
834 PassedAddr = (EFI_IP6_CONFIG_MANUAL_ADDRESS *) AllocatePool (Item->DataSize);
835 ASSERT (PassedAddr != NULL);
836
837 Item->Data.Ptr = PassedAddr;
838 Item->Status = EFI_SUCCESS;
839
840 while (!NetMapIsEmpty (&Instance->DadPassedMap)) {
841 ManualAddr = (EFI_IP6_CONFIG_MANUAL_ADDRESS *) NetMapRemoveHead (&Instance->DadPassedMap, NULL);
842 CopyMem (PassedAddr, ManualAddr, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS));
843
844 PassedAddr++;
845 }
846
847 ASSERT ((UINTN) PassedAddr - (UINTN) Item->Data.Ptr == Item->DataSize);
848 }
849 } else {
850 //
851 // All addresses are valid.
852 //
853 Item->Status = EFI_SUCCESS;
854 }
855
856 //
857 // Remove the tags we put in the NET_MAPs.
858 //
859 while (!NetMapIsEmpty (&Instance->DadFailedMap)) {
860 NetMapRemoveHead (&Instance->DadFailedMap, NULL);
861 }
862
863 while (!NetMapIsEmpty (&Instance->DadPassedMap)) {
864 NetMapRemoveHead (&Instance->DadPassedMap, NULL);
865 }
866
867 //
868 // Signal the waiting events.
869 //
870 NetMapIterate (&Item->EventMap, Ip6ConfigSignalEvent, NULL);
871 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
872 Ip6ConfigWriteConfigData (IpSb->MacString, Instance);
873 }
874 }
875
876 /**
877 The work function for EfiIp6ConfigSetData() to set the station addresses manually
878 for the EFI IPv6 network stack. It is only configurable when the policy is
879 Ip6ConfigPolicyManual.
880
881 @param[in] Instance Pointer to the IP6 configuration instance data.
882 @param[in] DataSize Size of the buffer pointed to by Data in bytes.
883 @param[in] Data The data buffer to set.
884
885 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.
886 @retval EFI_WRITE_PROTECTED The specified configuration data cannot be set
887 under the current policy.
888 @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.
889 @retval EFI_OUT_OF_RESOURCES Fail to allocate resource to complete the operation.
890 @retval EFI_NOT_READY An asynchrous process is invoked to set the specified
891 configuration data, and the process is not finished.
892 @retval EFI_ABORTED The manual addresses to be set equal current
893 configuration.
894 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6
895 network stack was set.
896
897 **/
898 EFI_STATUS
899 Ip6ConfigSetMaunualAddress (
900 IN IP6_CONFIG_INSTANCE *Instance,
901 IN UINTN DataSize,
902 IN VOID *Data
903 )
904 {
905 EFI_IP6_CONFIG_MANUAL_ADDRESS *NewAddress;
906 EFI_IP6_CONFIG_MANUAL_ADDRESS *TmpAddress;
907 IP6_CONFIG_DATA_ITEM *DataItem;
908 UINTN NewAddressCount;
909 UINTN Index1;
910 UINTN Index2;
911 IP6_SERVICE *IpSb;
912 IP6_ADDRESS_INFO *CurrentAddrInfo;
913 IP6_ADDRESS_INFO *Copy;
914 LIST_ENTRY CurrentSourceList;
915 UINT32 CurrentSourceCount;
916 LIST_ENTRY *Entry;
917 LIST_ENTRY *Entry2;
918 IP6_INTERFACE *IpIf;
919 IP6_PREFIX_LIST_ENTRY *PrefixEntry;
920 EFI_STATUS Status;
921 BOOLEAN IsUpdated;
922
923 ASSERT (Instance->DataItem[Ip6ConfigDataTypeManualAddress].Status != EFI_NOT_READY);
924
925 if (((DataSize % sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS)) != 0) || (DataSize == 0)) {
926 return EFI_BAD_BUFFER_SIZE;
927 }
928
929 if (Instance->Policy != Ip6ConfigPolicyManual) {
930 return EFI_WRITE_PROTECTED;
931 }
932
933 NewAddressCount = DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS);
934 NewAddress = (EFI_IP6_CONFIG_MANUAL_ADDRESS *) Data;
935
936 for (Index1 = 0; Index1 < NewAddressCount; Index1++, NewAddress++) {
937
938 if (NetIp6IsLinkLocalAddr (&NewAddress->Address) ||
939 !NetIp6IsValidUnicast (&NewAddress->Address) ||
940 (NewAddress->PrefixLength > 128)
941 ) {
942 //
943 // make sure the IPv6 address is unicast and not link-local address &&
944 // the prefix length is valid.
945 //
946 return EFI_INVALID_PARAMETER;
947 }
948
949 TmpAddress = NewAddress + 1;
950 for (Index2 = Index1 + 1; Index2 < NewAddressCount; Index2++, TmpAddress++) {
951 //
952 // Any two addresses in the array can't be equal.
953 //
954 if (EFI_IP6_EQUAL (&TmpAddress->Address, &NewAddress->Address)) {
955
956 return EFI_INVALID_PARAMETER;
957 }
958 }
959 }
960
961 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
962
963 //
964 // Build the current source address list.
965 //
966 InitializeListHead (&CurrentSourceList);
967 CurrentSourceCount = 0;
968
969 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
970 IpIf = NET_LIST_USER_STRUCT_S (Entry, IP6_INTERFACE, Link, IP6_INTERFACE_SIGNATURE);
971
972 NET_LIST_FOR_EACH (Entry2, &IpIf->AddressList) {
973 CurrentAddrInfo = NET_LIST_USER_STRUCT_S (Entry2, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);
974
975 Copy = AllocateCopyPool (sizeof (IP6_ADDRESS_INFO), CurrentAddrInfo);
976 if (Copy == NULL) {
977 break;
978 }
979
980 InsertTailList (&CurrentSourceList, &Copy->Link);
981 CurrentSourceCount++;
982 }
983 }
984
985 //
986 // Update the value... a long journey starts
987 //
988 NewAddress = AllocateCopyPool (DataSize, Data);
989 if (NewAddress == NULL) {
990 Ip6RemoveAddr (NULL, &CurrentSourceList, &CurrentSourceCount, NULL, 0);
991
992 return EFI_OUT_OF_RESOURCES;
993 }
994
995 //
996 // Store the new data, and init the DataItem status to EFI_NOT_READY because
997 // we may have an asynchronous configuration process.
998 //
999 DataItem = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];
1000 if (DataItem->Data.Ptr != NULL) {
1001 FreePool (DataItem->Data.Ptr);
1002 }
1003 DataItem->Data.Ptr = NewAddress;
1004 DataItem->DataSize = DataSize;
1005 DataItem->Status = EFI_NOT_READY;
1006
1007 //
1008 // Trigger DAD, it's an asynchronous process.
1009 //
1010 IsUpdated = FALSE;
1011
1012 for (Index1 = 0; Index1 < NewAddressCount; Index1++, NewAddress++) {
1013 if (Ip6IsOneOfSetAddress (IpSb, &NewAddress->Address, NULL, &CurrentAddrInfo)) {
1014 ASSERT (CurrentAddrInfo != NULL);
1015 //
1016 // Remove this already existing source address from the CurrentSourceList
1017 // built before.
1018 //
1019 Ip6RemoveAddr (
1020 NULL,
1021 &CurrentSourceList,
1022 &CurrentSourceCount,
1023 &CurrentAddrInfo->Address,
1024 128
1025 );
1026
1027 //
1028 // If the new address's prefix length is not specified, just use the previous configured
1029 // prefix length for this address.
1030 //
1031 if (NewAddress->PrefixLength == 0) {
1032 NewAddress->PrefixLength = CurrentAddrInfo->PrefixLength;
1033 }
1034
1035 //
1036 // This manual address is already in use, see whether prefix length is changed.
1037 //
1038 if (NewAddress->PrefixLength != CurrentAddrInfo->PrefixLength) {
1039 //
1040 // Remove the on-link prefix table, the route entry will be removed
1041 // implicitly.
1042 //
1043 PrefixEntry = Ip6FindPrefixListEntry (
1044 IpSb,
1045 TRUE,
1046 CurrentAddrInfo->PrefixLength,
1047 &CurrentAddrInfo->Address
1048 );
1049 if (PrefixEntry != NULL) {
1050 Ip6DestroyPrefixListEntry (IpSb, PrefixEntry, TRUE, FALSE);
1051 }
1052
1053 //
1054 // Save the prefix length.
1055 //
1056 CurrentAddrInfo->PrefixLength = NewAddress->PrefixLength;
1057 IsUpdated = TRUE;
1058 }
1059
1060 //
1061 // create a new on-link prefix entry.
1062 //
1063 PrefixEntry = Ip6FindPrefixListEntry (
1064 IpSb,
1065 TRUE,
1066 NewAddress->PrefixLength,
1067 &NewAddress->Address
1068 );
1069 if (PrefixEntry == NULL) {
1070 Ip6CreatePrefixListEntry (
1071 IpSb,
1072 TRUE,
1073 (UINT32) IP6_INFINIT_LIFETIME,
1074 (UINT32) IP6_INFINIT_LIFETIME,
1075 NewAddress->PrefixLength,
1076 &NewAddress->Address
1077 );
1078 }
1079
1080 CurrentAddrInfo->IsAnycast = NewAddress->IsAnycast;
1081 //
1082 // Artificially mark this address passed DAD be'coz it is already in use.
1083 //
1084 Ip6ManualAddrDadCallback (TRUE, &NewAddress->Address, Instance);
1085 } else {
1086 //
1087 // A new address.
1088 //
1089 IsUpdated = TRUE;
1090
1091 //
1092 // Set the new address, this will trigger DAD and activate the address if
1093 // DAD succeeds.
1094 //
1095 Ip6SetAddress (
1096 IpSb->DefaultInterface,
1097 &NewAddress->Address,
1098 NewAddress->IsAnycast,
1099 NewAddress->PrefixLength,
1100 (UINT32) IP6_INFINIT_LIFETIME,
1101 (UINT32) IP6_INFINIT_LIFETIME,
1102 Ip6ManualAddrDadCallback,
1103 Instance
1104 );
1105 }
1106 }
1107
1108 //
1109 // Check the CurrentSourceList, it now contains those addresses currently in
1110 // use and will be removed.
1111 //
1112 IpIf = IpSb->DefaultInterface;
1113
1114 while (!IsListEmpty (&CurrentSourceList)) {
1115 IsUpdated = TRUE;
1116
1117 CurrentAddrInfo = NET_LIST_HEAD (&CurrentSourceList, IP6_ADDRESS_INFO, Link);
1118
1119 //
1120 // This local address is going to be removed, the IP instances that are
1121 // currently using it will be destroyed.
1122 //
1123 Ip6RemoveAddr (
1124 IpSb,
1125 &IpIf->AddressList,
1126 &IpIf->AddressCount,
1127 &CurrentAddrInfo->Address,
1128 128
1129 );
1130
1131 //
1132 // Remove the on-link prefix table, the route entry will be removed
1133 // implicitly.
1134 //
1135 PrefixEntry = Ip6FindPrefixListEntry (
1136 IpSb,
1137 TRUE,
1138 CurrentAddrInfo->PrefixLength,
1139 &CurrentAddrInfo->Address
1140 );
1141 if (PrefixEntry != NULL) {
1142 Ip6DestroyPrefixListEntry (IpSb, PrefixEntry, TRUE, FALSE);
1143 }
1144
1145 RemoveEntryList (&CurrentAddrInfo->Link);
1146 FreePool (CurrentAddrInfo);
1147 }
1148
1149 if (IsUpdated) {
1150 if (DataItem->Status == EFI_NOT_READY) {
1151 //
1152 // If DAD is disabled on this interface, the configuration process is
1153 // actually synchronous, and the data item's status will be changed to
1154 // the final status before we reach here, just check it.
1155 //
1156 Status = EFI_NOT_READY;
1157 } else {
1158 Status = EFI_SUCCESS;
1159 }
1160 } else {
1161 //
1162 // No update is taken, reset the status to success and return EFI_ABORTED.
1163 //
1164 DataItem->Status = EFI_SUCCESS;
1165 Status = EFI_ABORTED;
1166 }
1167
1168 return Status;
1169 }
1170
1171 /**
1172 The work function for EfiIp6ConfigSetData() to set the gateway addresses manually
1173 for the EFI IPv6 network stack that is running on the communication device that
1174 this EFI IPv6 Configuration Protocol manages. It is not configurable when the policy is
1175 Ip6ConfigPolicyAutomatic. The gateway addresses must be unicast IPv6 addresses.
1176
1177 @param[in] Instance The pointer to the IP6 config instance data.
1178 @param[in] DataSize The size of the buffer pointed to by Data in bytes.
1179 @param[in] Data The data buffer to set. This points to an array of
1180 EFI_IPv6_ADDRESS instances.
1181
1182 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.
1183 @retval EFI_WRITE_PROTECTED The specified configuration data cannot be set
1184 under the current policy.
1185 @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.
1186 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to complete the operation.
1187 @retval EFI_ABORTED The manual gateway addresses to be set equal the
1188 current configuration.
1189 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6
1190 network stack was set.
1191
1192 **/
1193 EFI_STATUS
1194 Ip6ConfigSetGateway (
1195 IN IP6_CONFIG_INSTANCE *Instance,
1196 IN UINTN DataSize,
1197 IN VOID *Data
1198 )
1199 {
1200 UINTN Index1;
1201 UINTN Index2;
1202 EFI_IPv6_ADDRESS *OldGateway;
1203 EFI_IPv6_ADDRESS *NewGateway;
1204 UINTN OldGatewayCount;
1205 UINTN NewGatewayCount;
1206 IP6_CONFIG_DATA_ITEM *Item;
1207 BOOLEAN OneRemoved;
1208 BOOLEAN OneAdded;
1209 IP6_SERVICE *IpSb;
1210 IP6_DEFAULT_ROUTER *DefaultRouter;
1211 VOID *Tmp;
1212
1213 if ((DataSize % sizeof (EFI_IPv6_ADDRESS) != 0) || (DataSize == 0)) {
1214 return EFI_BAD_BUFFER_SIZE;
1215 }
1216
1217 if (Instance->Policy != Ip6ConfigPolicyManual) {
1218 return EFI_WRITE_PROTECTED;
1219 }
1220
1221 NewGateway = (EFI_IPv6_ADDRESS *) Data;
1222 NewGatewayCount = DataSize / sizeof (EFI_IPv6_ADDRESS);
1223 for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {
1224
1225 if (!NetIp6IsValidUnicast (NewGateway + Index1)) {
1226
1227 return EFI_INVALID_PARAMETER;
1228 }
1229
1230 for (Index2 = Index1 + 1; Index2 < NewGatewayCount; Index2++) {
1231 if (EFI_IP6_EQUAL (NewGateway + Index1, NewGateway + Index2)) {
1232 return EFI_INVALID_PARAMETER;
1233 }
1234 }
1235 }
1236
1237 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
1238 Item = &Instance->DataItem[Ip6ConfigDataTypeGateway];
1239 OldGateway = Item->Data.Gateway;
1240 OldGatewayCount = Item->DataSize / sizeof (EFI_IPv6_ADDRESS);
1241 OneRemoved = FALSE;
1242 OneAdded = FALSE;
1243
1244 if (NewGatewayCount != OldGatewayCount) {
1245 Tmp = AllocatePool (DataSize);
1246 if (Tmp == NULL) {
1247 return EFI_OUT_OF_RESOURCES;
1248 }
1249 } else {
1250 Tmp = NULL;
1251 }
1252
1253 for (Index1 = 0; Index1 < OldGatewayCount; Index1++) {
1254 //
1255 // Find the gateways that are no long in the new setting and remove them.
1256 //
1257 for (Index2 = 0; Index2 < NewGatewayCount; Index2++) {
1258 if (EFI_IP6_EQUAL (OldGateway + Index1, NewGateway + Index2)) {
1259 OneRemoved = TRUE;
1260 break;
1261 }
1262 }
1263
1264 if (Index2 == NewGatewayCount) {
1265 //
1266 // Remove this default router.
1267 //
1268 DefaultRouter = Ip6FindDefaultRouter (IpSb, OldGateway + Index1);
1269 if (DefaultRouter != NULL) {
1270 Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
1271 }
1272 }
1273 }
1274
1275 for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {
1276
1277 DefaultRouter = Ip6FindDefaultRouter (IpSb, NewGateway + Index1);
1278 if (DefaultRouter == NULL) {
1279 Ip6CreateDefaultRouter (IpSb, NewGateway + Index1, IP6_INF_ROUTER_LIFETIME);
1280 OneAdded = TRUE;
1281 }
1282 }
1283
1284 if (!OneRemoved && !OneAdded) {
1285 Item->Status = EFI_SUCCESS;
1286 return EFI_ABORTED;
1287 } else {
1288
1289 if (Tmp != NULL) {
1290 if (Item->Data.Ptr != NULL) {
1291 FreePool (Item->Data.Ptr);
1292 }
1293 Item->Data.Ptr = Tmp;
1294 }
1295
1296 CopyMem (Item->Data.Ptr, Data, DataSize);
1297 Item->DataSize = DataSize;
1298 Item->Status = EFI_SUCCESS;
1299 return EFI_SUCCESS;
1300 }
1301 }
1302
1303 /**
1304 The work function for EfiIp6ConfigSetData() to set the DNS server list for the
1305 EFI IPv6 network stack running on the communication device that this EFI IPv6
1306 Configuration Protocol manages. It is not configurable when the policy is
1307 Ip6ConfigPolicyAutomatic. The DNS server addresses must be unicast IPv6 addresses.
1308
1309 @param[in] Instance The pointer to the IP6 config instance data.
1310 @param[in] DataSize The size of the buffer pointed to by Data in bytes.
1311 @param[in] Data The data buffer to set, points to an array of
1312 EFI_IPv6_ADDRESS instances.
1313
1314 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.
1315 @retval EFI_WRITE_PROTECTED The specified configuration data cannot be set
1316 under the current policy.
1317 @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.
1318 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to complete the operation.
1319 @retval EFI_ABORTED The DNS server addresses to be set equal the current
1320 configuration.
1321 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6
1322 network stack was set.
1323
1324 **/
1325 EFI_STATUS
1326 Ip6ConfigSetDnsServer (
1327 IN IP6_CONFIG_INSTANCE *Instance,
1328 IN UINTN DataSize,
1329 IN VOID *Data
1330 )
1331 {
1332 UINTN OldIndex;
1333 UINTN NewIndex;
1334 EFI_IPv6_ADDRESS *OldDns;
1335 EFI_IPv6_ADDRESS *NewDns;
1336 UINTN OldDnsCount;
1337 UINTN NewDnsCount;
1338 IP6_CONFIG_DATA_ITEM *Item;
1339 BOOLEAN OneAdded;
1340 VOID *Tmp;
1341
1342 if ((DataSize % sizeof (EFI_IPv6_ADDRESS) != 0) || (DataSize == 0)) {
1343 return EFI_BAD_BUFFER_SIZE;
1344 }
1345
1346 if (Instance->Policy != Ip6ConfigPolicyManual) {
1347 return EFI_WRITE_PROTECTED;
1348 }
1349
1350 Item = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];
1351 NewDns = (EFI_IPv6_ADDRESS *) Data;
1352 OldDns = Item->Data.DnsServers;
1353 NewDnsCount = DataSize / sizeof (EFI_IPv6_ADDRESS);
1354 OldDnsCount = Item->DataSize / sizeof (EFI_IPv6_ADDRESS);
1355 OneAdded = FALSE;
1356
1357 if (NewDnsCount != OldDnsCount) {
1358 Tmp = AllocatePool (DataSize);
1359 if (Tmp == NULL) {
1360 return EFI_OUT_OF_RESOURCES;
1361 }
1362 } else {
1363 Tmp = NULL;
1364 }
1365
1366 for (NewIndex = 0; NewIndex < NewDnsCount; NewIndex++) {
1367
1368 if (!NetIp6IsValidUnicast (NewDns + NewIndex)) {
1369 //
1370 // The dns server address must be unicast.
1371 //
1372 if (Tmp != NULL) {
1373 FreePool (Tmp);
1374 }
1375 return EFI_INVALID_PARAMETER;
1376 }
1377
1378 if (OneAdded) {
1379 //
1380 // If any address in the new setting is not in the old settings, skip the
1381 // comparision below.
1382 //
1383 continue;
1384 }
1385
1386 for (OldIndex = 0; OldIndex < OldDnsCount; OldIndex++) {
1387 if (EFI_IP6_EQUAL (NewDns + NewIndex, OldDns + OldIndex)) {
1388 //
1389 // If found break out.
1390 //
1391 break;
1392 }
1393 }
1394
1395 if (OldIndex == OldDnsCount) {
1396 OneAdded = TRUE;
1397 }
1398 }
1399
1400 if (!OneAdded && (DataSize == Item->DataSize)) {
1401 //
1402 // No new item is added and the size is the same.
1403 //
1404 Item->Status = EFI_SUCCESS;
1405 return EFI_ABORTED;
1406 } else {
1407 if (Tmp != NULL) {
1408 if (Item->Data.Ptr != NULL) {
1409 FreePool (Item->Data.Ptr);
1410 }
1411 Item->Data.Ptr = Tmp;
1412 }
1413
1414 CopyMem (Item->Data.Ptr, Data, DataSize);
1415 Item->DataSize = DataSize;
1416 Item->Status = EFI_SUCCESS;
1417 return EFI_SUCCESS;
1418 }
1419 }
1420
1421 /**
1422 Generate the operational state of the interface this IP6 config instance manages
1423 and output in EFI_IP6_CONFIG_INTERFACE_INFO.
1424
1425 @param[in] IpSb The pointer to the IP6 service binding instance.
1426 @param[out] IfInfo The pointer to the IP6 configuration interface information structure.
1427
1428 **/
1429 VOID
1430 Ip6ConfigInitIfInfo (
1431 IN IP6_SERVICE *IpSb,
1432 OUT EFI_IP6_CONFIG_INTERFACE_INFO *IfInfo
1433 )
1434 {
1435 UnicodeSPrint (
1436 IfInfo->Name,
1437 sizeof (IfInfo->Name),
1438 L"eth%d",
1439 IpSb->Ip6ConfigInstance.IfIndex
1440 );
1441
1442 IfInfo->IfType = IpSb->SnpMode.IfType;
1443 IfInfo->HwAddressSize = IpSb->SnpMode.HwAddressSize;
1444 CopyMem (&IfInfo->HwAddress, &IpSb->SnpMode.CurrentAddress, IfInfo->HwAddressSize);
1445 }
1446
1447 /**
1448 Parse DHCPv6 reply packet to get the DNS server list.
1449 It is the work function for Ip6ConfigOnDhcp6Reply and Ip6ConfigOnDhcp6Event.
1450
1451 @param[in] Dhcp6 The pointer to the EFI_DHCP6_PROTOCOL instance.
1452 @param[in, out] Instance The pointer to the IP6 configuration instance data.
1453 @param[in] Reply The pointer to the DHCPv6 reply packet.
1454
1455 @retval EFI_SUCCESS The DNS server address was retrieved from the reply packet.
1456 @retval EFI_NOT_READY The reply packet does not contain the DNS server option, or
1457 the DNS server address is not valid.
1458
1459 **/
1460 EFI_STATUS
1461 Ip6ConfigParseDhcpReply (
1462 IN EFI_DHCP6_PROTOCOL *Dhcp6,
1463 IN OUT IP6_CONFIG_INSTANCE *Instance,
1464 IN EFI_DHCP6_PACKET *Reply
1465 )
1466 {
1467 EFI_STATUS Status;
1468 UINT32 OptCount;
1469 EFI_DHCP6_PACKET_OPTION **OptList;
1470 UINT16 OpCode;
1471 UINT16 Length;
1472 UINTN Index;
1473 UINTN Index2;
1474 EFI_IPv6_ADDRESS *DnsServer;
1475 IP6_CONFIG_DATA_ITEM *Item;
1476
1477 //
1478 // A DHCPv6 reply packet is received as the response to our InfoRequest
1479 // packet.
1480 //
1481 OptCount = 0;
1482 Status = Dhcp6->Parse (Dhcp6, Reply, &OptCount, NULL);
1483 if (Status != EFI_BUFFER_TOO_SMALL) {
1484 return EFI_NOT_READY;
1485 }
1486
1487 OptList = AllocatePool (OptCount * sizeof (EFI_DHCP6_PACKET_OPTION *));
1488 if (OptList == NULL) {
1489 return EFI_NOT_READY;
1490 }
1491
1492 Status = Dhcp6->Parse (Dhcp6, Reply, &OptCount, OptList);
1493 if (EFI_ERROR (Status)) {
1494 Status = EFI_NOT_READY;
1495 goto ON_EXIT;
1496 }
1497
1498 Status = EFI_SUCCESS;
1499
1500 for (Index = 0; Index < OptCount; Index++) {
1501 //
1502 // Go through all the options to check the ones we are interested in.
1503 // The OpCode and Length are in network byte-order and may not be naturally
1504 // aligned.
1505 //
1506 CopyMem (&OpCode, &OptList[Index]->OpCode, sizeof (OpCode));
1507 OpCode = NTOHS (OpCode);
1508
1509 if (OpCode == DHCP6_OPT_DNS_SERVERS) {
1510 CopyMem (&Length, &OptList[Index]->OpLen, sizeof (Length));
1511 Length = NTOHS (Length);
1512
1513 if ((Length == 0) || ((Length % sizeof (EFI_IPv6_ADDRESS)) != 0)) {
1514 //
1515 // The length should be a multiple of 16 bytes.
1516 //
1517 Status = EFI_NOT_READY;
1518 break;
1519 }
1520
1521 //
1522 // Validate the DnsServers: whether they are unicast addresses.
1523 //
1524 DnsServer = (EFI_IPv6_ADDRESS *) OptList[Index]->Data;
1525 for (Index2 = 0; Index2 < Length / sizeof (EFI_IPv6_ADDRESS); Index2++) {
1526 if (!NetIp6IsValidUnicast (DnsServer)) {
1527 Status = EFI_NOT_READY;
1528 goto ON_EXIT;
1529 }
1530
1531 DnsServer++;
1532 }
1533
1534 Item = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];
1535
1536 if (Item->DataSize != Length) {
1537 if (Item->Data.Ptr != NULL) {
1538 FreePool (Item->Data.Ptr);
1539 }
1540
1541 Item->Data.Ptr = AllocatePool (Length);
1542 ASSERT (Item->Data.Ptr != NULL);
1543 }
1544
1545 CopyMem (Item->Data.Ptr, OptList[Index]->Data, Length);
1546 Item->DataSize = Length;
1547 Item->Status = EFI_SUCCESS;
1548
1549 //
1550 // Signal the waiting events.
1551 //
1552 NetMapIterate (&Item->EventMap, Ip6ConfigSignalEvent, NULL);
1553
1554 break;
1555 }
1556 }
1557
1558 ON_EXIT:
1559
1560 FreePool (OptList);
1561 return Status;
1562 }
1563
1564 /**
1565 The callback function for Ip6SetAddr. The prototype is defined
1566 as IP6_DAD_CALLBACK. It is called after Duplicate Address Detection is performed
1567 on the tentative address by DHCPv6 in Ip6ConfigOnDhcp6Event().
1568
1569 @param[in] IsDadPassed If TRUE, Duplicate Address Detection passes.
1570 @param[in] TargetAddress The tentative IPv6 address to be checked.
1571 @param[in] Context Pointer to the IP6 configuration instance data.
1572
1573 **/
1574 VOID
1575 Ip6ConfigSetStatefulAddrCallback (
1576 IN BOOLEAN IsDadPassed,
1577 IN EFI_IPv6_ADDRESS *TargetAddress,
1578 IN VOID *Context
1579 )
1580 {
1581 IP6_CONFIG_INSTANCE *Instance;
1582
1583 Instance = (IP6_CONFIG_INSTANCE *) Context;
1584 NET_CHECK_SIGNATURE (Instance, IP6_CONFIG_INSTANCE_SIGNATURE);
1585
1586 //
1587 // We should record the addresses that fail the DAD, and DECLINE them.
1588 //
1589 if (IsDadPassed) {
1590 //
1591 // Decrease the count, no interests in those passed DAD.
1592 //
1593 if (Instance->FailedIaAddressCount > 0 ) {
1594 Instance->FailedIaAddressCount--;
1595 }
1596 } else {
1597 //
1598 // Record it.
1599 //
1600 IP6_COPY_ADDRESS (Instance->DeclineAddress + Instance->DeclineAddressCount, TargetAddress);
1601 Instance->DeclineAddressCount++;
1602 }
1603
1604 if (Instance->FailedIaAddressCount == Instance->DeclineAddressCount) {
1605 //
1606 // The checking on all addresses are finished.
1607 //
1608 if (Instance->DeclineAddressCount != 0) {
1609 //
1610 // Decline those duplicates.
1611 //
1612 if (Instance->Dhcp6 != NULL) {
1613 Instance->Dhcp6->Decline (
1614 Instance->Dhcp6,
1615 Instance->DeclineAddressCount,
1616 Instance->DeclineAddress
1617 );
1618 }
1619 }
1620
1621 if (Instance->DeclineAddress != NULL) {
1622 FreePool (Instance->DeclineAddress);
1623 }
1624 Instance->DeclineAddress = NULL;
1625 Instance->DeclineAddressCount = 0;
1626 }
1627 }
1628
1629 /**
1630 The event handle routine when DHCPv6 process is finished or is updated.
1631
1632 @param[in] Event Not used.
1633 @param[in] Context The pointer to the IP6 configuration instance data.
1634
1635 **/
1636 VOID
1637 EFIAPI
1638 Ip6ConfigOnDhcp6Event (
1639 IN EFI_EVENT Event,
1640 IN VOID *Context
1641 )
1642 {
1643 IP6_CONFIG_INSTANCE *Instance;
1644 EFI_DHCP6_PROTOCOL *Dhcp6;
1645 EFI_STATUS Status;
1646 EFI_DHCP6_MODE_DATA Dhcp6ModeData;
1647 EFI_DHCP6_IA *Ia;
1648 EFI_DHCP6_IA_ADDRESS *IaAddr;
1649 UINT32 Index;
1650 IP6_SERVICE *IpSb;
1651 IP6_ADDRESS_INFO *AddrInfo;
1652 IP6_INTERFACE *IpIf;
1653
1654 Instance = (IP6_CONFIG_INSTANCE *) Context;
1655
1656 if ((Instance->Policy != Ip6ConfigPolicyAutomatic) || Instance->OtherInfoOnly) {
1657 //
1658 // IPv6 is not operating in the automatic policy now or
1659 // the DHCPv6 information request message exchange is aborted.
1660 //
1661 return ;
1662 }
1663
1664 //
1665 // The stateful address autoconfiguration is done or updated.
1666 //
1667 Dhcp6 = Instance->Dhcp6;
1668
1669 Status = Dhcp6->GetModeData (Dhcp6, &Dhcp6ModeData, NULL);
1670 if (EFI_ERROR (Status)) {
1671 return ;
1672 }
1673
1674 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
1675 IpIf = IpSb->DefaultInterface;
1676 Ia = Dhcp6ModeData.Ia;
1677 IaAddr = Ia->IaAddress;
1678
1679 if (Instance->DeclineAddress != NULL) {
1680 FreePool (Instance->DeclineAddress);
1681 }
1682
1683 Instance->DeclineAddress = (EFI_IPv6_ADDRESS *) AllocatePool (Ia->IaAddressCount * sizeof (EFI_IPv6_ADDRESS));
1684 if (Instance->DeclineAddress == NULL) {
1685 goto ON_EXIT;
1686 }
1687
1688 Instance->FailedIaAddressCount = Ia->IaAddressCount;
1689 Instance->DeclineAddressCount = 0;
1690
1691 for (Index = 0; Index < Ia->IaAddressCount; Index++, IaAddr++) {
1692 if (Ia->IaAddress[Index].ValidLifetime != 0 && Ia->State == Dhcp6Bound) {
1693 //
1694 // Set this address, either it's a new address or with updated lifetimes.
1695 // An appropriate prefix length will be set.
1696 //
1697 Ip6SetAddress (
1698 IpIf,
1699 &IaAddr->IpAddress,
1700 FALSE,
1701 0,
1702 IaAddr->ValidLifetime,
1703 IaAddr->PreferredLifetime,
1704 Ip6ConfigSetStatefulAddrCallback,
1705 Instance
1706 );
1707 } else {
1708 //
1709 // discard this address, artificially decrease the count as if this address
1710 // passed DAD.
1711 //
1712 if (Ip6IsOneOfSetAddress (IpSb, &IaAddr->IpAddress, NULL, &AddrInfo)) {
1713 ASSERT (AddrInfo != NULL);
1714 Ip6RemoveAddr (
1715 IpSb,
1716 &IpIf->AddressList,
1717 &IpIf->AddressCount,
1718 &AddrInfo->Address,
1719 AddrInfo->PrefixLength
1720 );
1721 }
1722
1723 if (Instance->FailedIaAddressCount > 0) {
1724 Instance->FailedIaAddressCount--;
1725 }
1726 }
1727 }
1728
1729 //
1730 // Parse the Reply packet to get the options we need.
1731 //
1732 if (Dhcp6ModeData.Ia->ReplyPacket != NULL) {
1733 Ip6ConfigParseDhcpReply (Dhcp6, Instance, Dhcp6ModeData.Ia->ReplyPacket);
1734 }
1735
1736 ON_EXIT:
1737
1738 FreePool (Dhcp6ModeData.ClientId);
1739 FreePool (Dhcp6ModeData.Ia);
1740 }
1741
1742 /**
1743 The event process routine when the DHCPv6 server is answered with a reply packet
1744 for an information request.
1745
1746 @param[in] This Points to the EFI_DHCP6_PROTOCOL.
1747 @param[in] Context The pointer to the IP6 configuration instance data.
1748 @param[in] Packet The DHCPv6 reply packet.
1749
1750 @retval EFI_SUCCESS The DNS server address was retrieved from the reply packet.
1751 @retval EFI_NOT_READY The reply packet does not contain the DNS server option, or
1752 the DNS server address is not valid.
1753
1754 **/
1755 EFI_STATUS
1756 EFIAPI
1757 Ip6ConfigOnDhcp6Reply (
1758 IN EFI_DHCP6_PROTOCOL *This,
1759 IN VOID *Context,
1760 IN EFI_DHCP6_PACKET *Packet
1761 )
1762 {
1763 return Ip6ConfigParseDhcpReply (This, (IP6_CONFIG_INSTANCE *) Context, Packet);
1764 }
1765
1766 /**
1767 The event process routine when the DHCPv6 service binding protocol is installed
1768 in the system.
1769
1770 @param[in] Event Not used.
1771 @param[in] Context The pointer to the IP6 config instance data.
1772
1773 **/
1774 VOID
1775 EFIAPI
1776 Ip6ConfigOnDhcp6SbInstalled (
1777 IN EFI_EVENT Event,
1778 IN VOID *Context
1779 )
1780 {
1781 IP6_CONFIG_INSTANCE *Instance;
1782
1783 Instance = (IP6_CONFIG_INSTANCE *) Context;
1784
1785 if ((Instance->Dhcp6Handle != NULL) || (Instance->Policy != Ip6ConfigPolicyAutomatic)) {
1786 //
1787 // The DHCP6 child is already created or the policy is no longer AUTOMATIC.
1788 //
1789 return ;
1790 }
1791
1792 Ip6ConfigStartStatefulAutoConfig (Instance, Instance->OtherInfoOnly);
1793 }
1794
1795 /**
1796 Set the configuration for the EFI IPv6 network stack running on the communication
1797 device this EFI IPv6 Configuration Protocol instance manages.
1798
1799 This function is used to set the configuration data of type DataType for the EFI
1800 IPv6 network stack that is running on the communication device that this EFI IPv6
1801 Configuration Protocol instance manages.
1802
1803 DataSize is used to calculate the count of structure instances in the Data for
1804 a DataType in which multiple structure instances are allowed.
1805
1806 This function is always non-blocking. When setting some type of configuration data,
1807 an asynchronous process is invoked to check the correctness of the data, such as
1808 performing Duplicate Address Detection on the manually set local IPv6 addresses.
1809 EFI_NOT_READY is returned immediately to indicate that such an asynchronous process
1810 is invoked, and the process is not finished yet. The caller wanting to get the result
1811 of the asynchronous process is required to call RegisterDataNotify() to register an
1812 event on the specified configuration data. Once the event is signaled, the caller
1813 can call GetData() to obtain the configuration data and know the result.
1814 For other types of configuration data that do not require an asynchronous configuration
1815 process, the result of the operation is immediately returned.
1816
1817 @param[in] This The pointer to the EFI_IP6_CONFIG_PROTOCOL instance.
1818 @param[in] DataType The type of data to set.
1819 @param[in] DataSize Size of the buffer pointed to by Data in bytes.
1820 @param[in] Data The data buffer to set. The type of the data buffer is
1821 associated with the DataType.
1822
1823 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6
1824 network stack was set successfully.
1825 @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
1826 - This is NULL.
1827 - Data is NULL.
1828 - One or more fields in Data do not match the requirement of the
1829 data type indicated by DataType.
1830 @retval EFI_WRITE_PROTECTED The specified configuration data is read-only or the specified
1831 configuration data cannot be set under the current policy.
1832 @retval EFI_ACCESS_DENIED Another set operation on the specified configuration
1833 data is already in process.
1834 @retval EFI_NOT_READY An asynchronous process was invoked to set the specified
1835 configuration data, and the process is not finished yet.
1836 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type
1837 indicated by DataType.
1838 @retval EFI_UNSUPPORTED This DataType is not supported.
1839 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1840 @retval EFI_DEVICE_ERROR An unexpected system error or network error occurred.
1841
1842 **/
1843 EFI_STATUS
1844 EFIAPI
1845 EfiIp6ConfigSetData (
1846 IN EFI_IP6_CONFIG_PROTOCOL *This,
1847 IN EFI_IP6_CONFIG_DATA_TYPE DataType,
1848 IN UINTN DataSize,
1849 IN VOID *Data
1850 )
1851 {
1852 EFI_TPL OldTpl;
1853 EFI_STATUS Status;
1854 IP6_CONFIG_INSTANCE *Instance;
1855 IP6_SERVICE *IpSb;
1856
1857 if ((This == NULL) || (Data == NULL)) {
1858 return EFI_INVALID_PARAMETER;
1859 }
1860
1861 if (DataType >= Ip6ConfigDataTypeMaximum) {
1862 return EFI_UNSUPPORTED;
1863 }
1864
1865 Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);
1866 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
1867 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
1868
1869 if (IpSb->LinkLocalDadFail) {
1870 return EFI_DEVICE_ERROR;
1871 }
1872
1873 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1874
1875 Status = Instance->DataItem[DataType].Status;
1876 if (Status != EFI_NOT_READY) {
1877
1878 if (Instance->DataItem[DataType].SetData == NULL) {
1879 //
1880 // This type of data is readonly.
1881 //
1882 Status = EFI_WRITE_PROTECTED;
1883 } else {
1884
1885 Status = Instance->DataItem[DataType].SetData (Instance, DataSize, Data);
1886 if (!EFI_ERROR (Status)) {
1887 //
1888 // Fire up the events registered with this type of data.
1889 //
1890 NetMapIterate (&Instance->DataItem[DataType].EventMap, Ip6ConfigSignalEvent, NULL);
1891 Ip6ConfigWriteConfigData (IpSb->MacString, Instance);
1892 } else if (Status == EFI_ABORTED) {
1893 //
1894 // The SetData is aborted because the data to set is the same with
1895 // the one maintained.
1896 //
1897 Status = EFI_SUCCESS;
1898 NetMapIterate (&Instance->DataItem[DataType].EventMap, Ip6ConfigSignalEvent, NULL);
1899 }
1900 }
1901 } else {
1902 //
1903 // Another asynchornous process is on the way.
1904 //
1905 Status = EFI_ACCESS_DENIED;
1906 }
1907
1908 gBS->RestoreTPL (OldTpl);
1909
1910 return Status;
1911 }
1912
1913 /**
1914 Get the configuration data for the EFI IPv6 network stack running on the communication
1915 device that this EFI IPv6 Configuration Protocol instance manages.
1916
1917 This function returns the configuration data of type DataType for the EFI IPv6 network
1918 stack running on the communication device that this EFI IPv6 Configuration Protocol instance
1919 manages.
1920
1921 The caller is responsible for allocating the buffer used to return the specified
1922 configuration data. The required size will be returned to the caller if the size of
1923 the buffer is too small.
1924
1925 EFI_NOT_READY is returned if the specified configuration data is not ready due to an
1926 asynchronous configuration process already in progress. The caller can call RegisterDataNotify()
1927 to register an event on the specified configuration data. Once the asynchronous configuration
1928 process is finished, the event will be signaled, and a subsequent GetData() call will return
1929 the specified configuration data.
1930
1931 @param[in] This Pointer to the EFI_IP6_CONFIG_PROTOCOL instance.
1932 @param[in] DataType The type of data to get.
1933 @param[in, out] DataSize On input, in bytes, the size of Data. On output, in bytes, the
1934 size of buffer required to store the specified configuration data.
1935 @param[in] Data The data buffer in which the configuration data is returned. The
1936 type of the data buffer is associated with the DataType.
1937 This is an optional parameter that may be NULL.
1938
1939 @retval EFI_SUCCESS The specified configuration data was obtained successfully.
1940 @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE:
1941 - This is NULL.
1942 - DataSize is NULL.
1943 - Data is NULL if *DataSize is not zero.
1944 @retval EFI_BUFFER_TOO_SMALL The size of Data is too small for the specified configuration data,
1945 and the required size is returned in DataSize.
1946 @retval EFI_NOT_READY The specified configuration data is not ready due to an
1947 asynchronous configuration process already in progress.
1948 @retval EFI_NOT_FOUND The specified configuration data is not found.
1949
1950 **/
1951 EFI_STATUS
1952 EFIAPI
1953 EfiIp6ConfigGetData (
1954 IN EFI_IP6_CONFIG_PROTOCOL *This,
1955 IN EFI_IP6_CONFIG_DATA_TYPE DataType,
1956 IN OUT UINTN *DataSize,
1957 IN VOID *Data OPTIONAL
1958 )
1959 {
1960 EFI_TPL OldTpl;
1961 EFI_STATUS Status;
1962 IP6_CONFIG_INSTANCE *Instance;
1963 IP6_CONFIG_DATA_ITEM *DataItem;
1964
1965 if ((This == NULL) || (DataSize == NULL) || ((*DataSize != 0) && (Data == NULL))) {
1966 return EFI_INVALID_PARAMETER;
1967 }
1968
1969 if (DataType >= Ip6ConfigDataTypeMaximum) {
1970 return EFI_NOT_FOUND;
1971 }
1972
1973 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1974
1975 Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);
1976 DataItem = &Instance->DataItem[DataType];
1977
1978 Status = Instance->DataItem[DataType].Status;
1979 if (!EFI_ERROR (Status)) {
1980
1981 if (DataItem->GetData != NULL) {
1982
1983 Status = DataItem->GetData (Instance, DataSize, Data);
1984 } else if (*DataSize < Instance->DataItem[DataType].DataSize) {
1985 //
1986 // Update the buffer length.
1987 //
1988 *DataSize = Instance->DataItem[DataType].DataSize;
1989 Status = EFI_BUFFER_TOO_SMALL;
1990 } else {
1991
1992 *DataSize = Instance->DataItem[DataType].DataSize;
1993 CopyMem (Data, Instance->DataItem[DataType].Data.Ptr, *DataSize);
1994 }
1995 }
1996
1997 gBS->RestoreTPL (OldTpl);
1998
1999 return Status;
2000 }
2001
2002 /**
2003 Register an event that is signaled whenever a configuration process on the specified
2004 configuration data is done.
2005
2006 This function registers an event that is to be signaled whenever a configuration
2007 process on the specified configuration data is performed. An event can be registered
2008 for a different DataType simultaneously. The caller is responsible for determining
2009 which type of configuration data causes the signaling of the event in such an event.
2010
2011 @param[in] This Pointer to the EFI_IP6_CONFIG_PROTOCOL instance.
2012 @param[in] DataType The type of data to unregister the event for.
2013 @param[in] Event The event to register.
2014
2015 @retval EFI_SUCCESS The notification event for the specified configuration data is
2016 registered.
2017 @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.
2018 @retval EFI_UNSUPPORTED The configuration data type specified by DataType is not
2019 supported.
2020 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
2021 @retval EFI_ACCESS_DENIED The Event is already registered for the DataType.
2022
2023 **/
2024 EFI_STATUS
2025 EFIAPI
2026 EfiIp6ConfigRegisterDataNotify (
2027 IN EFI_IP6_CONFIG_PROTOCOL *This,
2028 IN EFI_IP6_CONFIG_DATA_TYPE DataType,
2029 IN EFI_EVENT Event
2030 )
2031 {
2032 EFI_TPL OldTpl;
2033 EFI_STATUS Status;
2034 IP6_CONFIG_INSTANCE *Instance;
2035 NET_MAP *EventMap;
2036 NET_MAP_ITEM *Item;
2037
2038 if ((This == NULL) || (Event == NULL)) {
2039 return EFI_INVALID_PARAMETER;
2040 }
2041
2042 if (DataType >= Ip6ConfigDataTypeMaximum) {
2043 return EFI_UNSUPPORTED;
2044 }
2045
2046 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
2047
2048 Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);
2049 EventMap = &Instance->DataItem[DataType].EventMap;
2050
2051 //
2052 // Check whether this event is already registered for this DataType.
2053 //
2054 Item = NetMapFindKey (EventMap, Event);
2055 if (Item == NULL) {
2056
2057 Status = NetMapInsertTail (EventMap, Event, NULL);
2058
2059 if (EFI_ERROR (Status)) {
2060
2061 Status = EFI_OUT_OF_RESOURCES;
2062 }
2063
2064 } else {
2065
2066 Status = EFI_ACCESS_DENIED;
2067 }
2068
2069 gBS->RestoreTPL (OldTpl);
2070
2071 return Status;
2072 }
2073
2074 /**
2075 Remove a previously registered event for the specified configuration data.
2076
2077 @param This The pointer to the EFI_IP6_CONFIG_PROTOCOL instance.
2078 @param DataType The type of data to remove from the previously
2079 registered event.
2080 @param Event The event to be unregistered.
2081
2082 @retval EFI_SUCCESS The event registered for the specified
2083 configuration data was removed.
2084 @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.
2085 @retval EFI_NOT_FOUND The Event has not been registered for the
2086 specified DataType.
2087
2088 **/
2089 EFI_STATUS
2090 EFIAPI
2091 EfiIp6ConfigUnregisterDataNotify (
2092 IN EFI_IP6_CONFIG_PROTOCOL *This,
2093 IN EFI_IP6_CONFIG_DATA_TYPE DataType,
2094 IN EFI_EVENT Event
2095 )
2096 {
2097 EFI_TPL OldTpl;
2098 EFI_STATUS Status;
2099 IP6_CONFIG_INSTANCE *Instance;
2100 NET_MAP_ITEM *Item;
2101
2102 if ((This == NULL) || (Event == NULL)) {
2103 return EFI_INVALID_PARAMETER;
2104 }
2105
2106 if (DataType >= Ip6ConfigDataTypeMaximum) {
2107 return EFI_NOT_FOUND;
2108 }
2109
2110 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
2111
2112 Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);
2113
2114 Item = NetMapFindKey (&Instance->DataItem[DataType].EventMap, Event);
2115 if (Item != NULL) {
2116
2117 NetMapRemoveItem (&Instance->DataItem[DataType].EventMap, Item, NULL);
2118 Status = EFI_SUCCESS;
2119 } else {
2120
2121 Status = EFI_NOT_FOUND;
2122 }
2123
2124 gBS->RestoreTPL (OldTpl);
2125
2126 return Status;
2127 }
2128
2129 /**
2130 Initialize an IP6_CONFIG_INSTANCE.
2131
2132 @param[out] Instance The buffer of IP6_CONFIG_INSTANCE to be initialized.
2133
2134 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to complete the operation.
2135 @retval EFI_SUCCESS The IP6_CONFIG_INSTANCE initialized successfully.
2136
2137 **/
2138 EFI_STATUS
2139 Ip6ConfigInitInstance (
2140 OUT IP6_CONFIG_INSTANCE *Instance
2141 )
2142 {
2143 IP6_SERVICE *IpSb;
2144 IP6_CONFIG_INSTANCE *TmpInstance;
2145 LIST_ENTRY *Entry;
2146 EFI_STATUS Status;
2147 UINTN Index;
2148 UINT16 IfIndex;
2149 IP6_CONFIG_DATA_ITEM *DataItem;
2150
2151 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
2152
2153 Instance->Signature = IP6_CONFIG_INSTANCE_SIGNATURE;
2154
2155 //
2156 // Determine the index of this interface.
2157 //
2158 IfIndex = 0;
2159 NET_LIST_FOR_EACH (Entry, &mIp6ConfigInstanceList) {
2160 TmpInstance = NET_LIST_USER_STRUCT_S (Entry, IP6_CONFIG_INSTANCE, Link, IP6_CONFIG_INSTANCE_SIGNATURE);
2161
2162 if (TmpInstance->IfIndex > IfIndex) {
2163 //
2164 // There is a sequence hole because some interface is down.
2165 //
2166 break;
2167 }
2168
2169 IfIndex++;
2170 }
2171
2172 Instance->IfIndex = IfIndex;
2173 NetListInsertBefore (Entry, &Instance->Link);
2174
2175 for (Index = 0; Index < Ip6ConfigDataTypeMaximum; Index++) {
2176 //
2177 // Initialize the event map for each data item.
2178 //
2179 NetMapInit (&Instance->DataItem[Index].EventMap);
2180 }
2181
2182 //
2183 // Initialize the NET_MAPs used for DAD on manually configured source addresses.
2184 //
2185 NetMapInit (&Instance->DadFailedMap);
2186 NetMapInit (&Instance->DadPassedMap);
2187
2188 //
2189 // Initialize each data type: associate storage and set data size for the
2190 // fixed size data types, hook the SetData function, set the data attribute.
2191 //
2192 DataItem = &Instance->DataItem[Ip6ConfigDataTypeInterfaceInfo];
2193 DataItem->GetData = Ip6ConfigGetIfInfo;
2194 DataItem->Data.Ptr = &Instance->InterfaceInfo;
2195 DataItem->DataSize = sizeof (Instance->InterfaceInfo);
2196 SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED | DATA_ATTRIB_VOLATILE);
2197 Ip6ConfigInitIfInfo (IpSb, &Instance->InterfaceInfo);
2198
2199 DataItem = &Instance->DataItem[Ip6ConfigDataTypeAltInterfaceId];
2200 DataItem->SetData = Ip6ConfigSetAltIfId;
2201 DataItem->Data.Ptr = &Instance->AltIfId;
2202 DataItem->DataSize = sizeof (Instance->AltIfId);
2203 DataItem->Status = EFI_NOT_FOUND;
2204 SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED);
2205
2206 DataItem = &Instance->DataItem[Ip6ConfigDataTypePolicy];
2207 DataItem->SetData = Ip6ConfigSetPolicy;
2208 DataItem->Data.Ptr = &Instance->Policy;
2209 DataItem->DataSize = sizeof (Instance->Policy);
2210 Instance->Policy = Ip6ConfigPolicyManual;
2211 SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED);
2212
2213 DataItem = &Instance->DataItem[Ip6ConfigDataTypeDupAddrDetectTransmits];
2214 DataItem->SetData = Ip6ConfigSetDadXmits;
2215 DataItem->Data.Ptr = &Instance->DadXmits;
2216 DataItem->DataSize = sizeof (Instance->DadXmits);
2217 Instance->DadXmits.DupAddrDetectTransmits = IP6_CONFIG_DEFAULT_DAD_XMITS;
2218 SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED);
2219
2220 DataItem = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];
2221 DataItem->SetData = Ip6ConfigSetMaunualAddress;
2222 DataItem->Status = EFI_NOT_FOUND;
2223
2224 DataItem = &Instance->DataItem[Ip6ConfigDataTypeGateway];
2225 DataItem->SetData = Ip6ConfigSetGateway;
2226 DataItem->Status = EFI_NOT_FOUND;
2227
2228 DataItem = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];
2229 DataItem->SetData = Ip6ConfigSetDnsServer;
2230 DataItem->Status = EFI_NOT_FOUND;
2231
2232 //
2233 // Create the event used for DHCP.
2234 //
2235 Status = gBS->CreateEvent (
2236 EVT_NOTIFY_SIGNAL,
2237 TPL_CALLBACK,
2238 Ip6ConfigOnDhcp6Event,
2239 Instance,
2240 &Instance->Dhcp6Event
2241 );
2242 ASSERT_EFI_ERROR (Status);
2243
2244 Instance->Configured = TRUE;
2245
2246 //
2247 // Try to read the config data from NV variable.
2248 //
2249 Status = Ip6ConfigReadConfigData (IpSb->MacString, Instance);
2250 if (Status == EFI_NOT_FOUND) {
2251 //
2252 // The NV variable is not set, so generate a random IAID, and write down the
2253 // fresh new configuration as the NV variable now.
2254 //
2255 Instance->IaId = NET_RANDOM (NetRandomInitSeed ());
2256
2257 for (Index = 0; Index < IpSb->SnpMode.HwAddressSize; Index++) {
2258 Instance->IaId |= (IpSb->SnpMode.CurrentAddress.Addr[Index] << ((Index << 3) & 31));
2259 }
2260
2261 Ip6ConfigWriteConfigData (IpSb->MacString, Instance);
2262 } else if (EFI_ERROR (Status)) {
2263 return Status;
2264 }
2265
2266 Instance->Ip6Config.SetData = EfiIp6ConfigSetData;
2267 Instance->Ip6Config.GetData = EfiIp6ConfigGetData;
2268 Instance->Ip6Config.RegisterDataNotify = EfiIp6ConfigRegisterDataNotify;
2269 Instance->Ip6Config.UnregisterDataNotify = EfiIp6ConfigUnregisterDataNotify;
2270
2271
2272 //
2273 // Publish the IP6 configuration form
2274 //
2275 return Ip6ConfigFormInit (Instance);
2276 }
2277
2278 /**
2279 Release an IP6_CONFIG_INSTANCE.
2280
2281 @param[in, out] Instance The buffer of IP6_CONFIG_INSTANCE to be freed.
2282
2283 **/
2284 VOID
2285 Ip6ConfigCleanInstance (
2286 IN OUT IP6_CONFIG_INSTANCE *Instance
2287 )
2288 {
2289 UINTN Index;
2290 IP6_CONFIG_DATA_ITEM *DataItem;
2291
2292 if (Instance->DeclineAddress != NULL) {
2293 FreePool (Instance->DeclineAddress);
2294 }
2295
2296 if (!Instance->Configured) {
2297 return ;
2298 }
2299
2300 if (Instance->Dhcp6Handle != NULL) {
2301
2302 Ip6ConfigDestroyDhcp6 (Instance);
2303 }
2304
2305 //
2306 // Close the event.
2307 //
2308 if (Instance->Dhcp6Event != NULL) {
2309 gBS->CloseEvent (Instance->Dhcp6Event);
2310 }
2311
2312 NetMapClean (&Instance->DadPassedMap);
2313 NetMapClean (&Instance->DadFailedMap);
2314
2315 for (Index = 0; Index < Ip6ConfigDataTypeMaximum; Index++) {
2316
2317 DataItem = &Instance->DataItem[Index];
2318
2319 if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED)) {
2320 if (DataItem->Data.Ptr != NULL) {
2321 FreePool (DataItem->Data.Ptr);
2322 }
2323 DataItem->Data.Ptr = NULL;
2324 DataItem->DataSize = 0;
2325 }
2326
2327 NetMapClean (&Instance->DataItem[Index].EventMap);
2328 }
2329
2330 Ip6ConfigFormUnload (Instance);
2331
2332 RemoveEntryList (&Instance->Link);
2333 }
2334
2335 /**
2336 Destroy the Dhcp6 child in IP6_CONFIG_INSTANCE and release the resources.
2337
2338 @param[in, out] Instance The buffer of IP6_CONFIG_INSTANCE to be freed.
2339
2340 @retval EFI_SUCCESS The child was successfully destroyed.
2341 @retval Others Failed to destroy the child.
2342
2343 **/
2344 EFI_STATUS
2345 Ip6ConfigDestroyDhcp6 (
2346 IN OUT IP6_CONFIG_INSTANCE *Instance
2347 )
2348 {
2349 IP6_SERVICE *IpSb;
2350 EFI_STATUS Status;
2351 EFI_DHCP6_PROTOCOL *Dhcp6;
2352
2353 Dhcp6 = Instance->Dhcp6;
2354 ASSERT (Dhcp6 != NULL);
2355
2356 Dhcp6->Stop (Dhcp6);
2357 Dhcp6->Configure (Dhcp6, NULL);
2358 Instance->Dhcp6 = NULL;
2359
2360 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
2361
2362 //
2363 // Close DHCPv6 protocol and destroy the child.
2364 //
2365 Status = gBS->CloseProtocol (
2366 Instance->Dhcp6Handle,
2367 &gEfiDhcp6ProtocolGuid,
2368 IpSb->Image,
2369 IpSb->Controller
2370 );
2371 if (EFI_ERROR (Status)) {
2372 return Status;
2373 }
2374
2375 Status = NetLibDestroyServiceChild (
2376 IpSb->Controller,
2377 IpSb->Image,
2378 &gEfiDhcp6ServiceBindingProtocolGuid,
2379 Instance->Dhcp6Handle
2380 );
2381
2382 Instance->Dhcp6Handle = NULL;
2383
2384 return Status;
2385 }
2386