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