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