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