1 /** @file 2 Implement IP6 pesudo interface. 3 4 Copyright (c) 2009 - 2012, 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 /** 19 Request Ip6OnFrameSentDpc as a DPC at TPL_CALLBACK. 20 21 @param[in] Event The transmit token's event. 22 @param[in] Context The Context which is pointed to the token. 23 24 **/ 25 VOID 26 EFIAPI 27 Ip6OnFrameSent ( 28 IN EFI_EVENT Event, 29 IN VOID *Context 30 ); 31 32 /** 33 Fileter function to cancel all the frame related to an IP instance. 34 35 @param[in] Frame The transmit request to test whether to cancel. 36 @param[in] Context The context which is the Ip instance that issued 37 the transmit. 38 39 @retval TRUE The frame belongs to this instance and is to be 40 removed. 41 @retval FALSE The frame doesn't belong to this instance. 42 43 **/ 44 BOOLEAN 45 Ip6CancelInstanceFrame ( 46 IN IP6_LINK_TX_TOKEN *Frame, 47 IN VOID *Context 48 ) 49 { 50 if (Frame->IpInstance == (IP6_PROTOCOL *) Context) { 51 return TRUE; 52 } 53 54 return FALSE; 55 } 56 57 /** 58 Set the interface's address. This will trigger the DAD process for the 59 address to set. To set an already set address, the lifetimes wil be 60 updated to the new value passed in. 61 62 @param[in] Interface The interface to set the address. 63 @param[in] Ip6Addr The interface's to be assigned IPv6 address. 64 @param[in] IsAnycast If TRUE, the unicast IPv6 address is anycast. 65 Otherwise, it is not anycast. 66 @param[in] PrefixLength The prefix length of the Ip6Addr. 67 @param[in] ValidLifetime The valid lifetime for this address. 68 @param[in] PreferredLifetime The preferred lifetime for this address. 69 @param[in] DadCallback The caller's callback to trigger when DAD finishes. 70 This is an optional parameter that may be NULL. 71 @param[in] Context The context that will be passed to DadCallback. 72 This is an optional parameter that may be NULL. 73 74 @retval EFI_SUCCESS The interface is scheduled to be configured with 75 the specified address. 76 @retval EFI_OUT_OF_RESOURCES Failed to set the interface's address due to 77 lack of resources. 78 79 **/ 80 EFI_STATUS 81 Ip6SetAddress ( 82 IN IP6_INTERFACE *Interface, 83 IN EFI_IPv6_ADDRESS *Ip6Addr, 84 IN BOOLEAN IsAnycast, 85 IN UINT8 PrefixLength, 86 IN UINT32 ValidLifetime, 87 IN UINT32 PreferredLifetime, 88 IN IP6_DAD_CALLBACK DadCallback OPTIONAL, 89 IN VOID *Context OPTIONAL 90 ) 91 { 92 IP6_SERVICE *IpSb; 93 IP6_ADDRESS_INFO *AddressInfo; 94 LIST_ENTRY *Entry; 95 IP6_PREFIX_LIST_ENTRY *PrefixEntry; 96 UINT64 Delay; 97 IP6_DELAY_JOIN_LIST *DelayNode; 98 99 NET_CHECK_SIGNATURE (Interface, IP6_INTERFACE_SIGNATURE); 100 101 IpSb = Interface->Service; 102 103 if (Ip6IsOneOfSetAddress (IpSb, Ip6Addr, NULL, &AddressInfo)) { 104 ASSERT (AddressInfo != NULL); 105 // 106 // Update the lifetime. 107 // 108 AddressInfo->ValidLifetime = ValidLifetime; 109 AddressInfo->PreferredLifetime = PreferredLifetime; 110 111 if (DadCallback != NULL) { 112 DadCallback (TRUE, Ip6Addr, Context); 113 } 114 115 return EFI_SUCCESS; 116 } 117 118 AddressInfo = (IP6_ADDRESS_INFO *) AllocatePool (sizeof (IP6_ADDRESS_INFO)); 119 if (AddressInfo == NULL) { 120 return EFI_OUT_OF_RESOURCES; 121 } 122 123 AddressInfo->Signature = IP6_ADDR_INFO_SIGNATURE; 124 IP6_COPY_ADDRESS (&AddressInfo->Address, Ip6Addr); 125 AddressInfo->IsAnycast = IsAnycast; 126 AddressInfo->PrefixLength = PrefixLength; 127 AddressInfo->ValidLifetime = ValidLifetime; 128 AddressInfo->PreferredLifetime = PreferredLifetime; 129 130 if (AddressInfo->PrefixLength == 0) { 131 // 132 // Find an appropriate prefix from on-link prefixes and update the prefixlength. 133 // Longest prefix match is used here. 134 // 135 NET_LIST_FOR_EACH (Entry, &IpSb->OnlinkPrefix) { 136 PrefixEntry = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link); 137 138 if (NetIp6IsNetEqual (&PrefixEntry->Prefix, &AddressInfo->Address, PrefixEntry->PrefixLength)) { 139 AddressInfo->PrefixLength = PrefixEntry->PrefixLength; 140 break; 141 } 142 } 143 } 144 145 if (AddressInfo->PrefixLength == 0) { 146 // 147 // If the prefix length is still zero, try the autonomous prefixes. 148 // Longest prefix match is used here. 149 // 150 NET_LIST_FOR_EACH (Entry, &IpSb->AutonomousPrefix) { 151 PrefixEntry = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link); 152 153 if (NetIp6IsNetEqual (&PrefixEntry->Prefix, &AddressInfo->Address, PrefixEntry->PrefixLength)) { 154 AddressInfo->PrefixLength = PrefixEntry->PrefixLength; 155 break; 156 } 157 } 158 } 159 160 if (AddressInfo->PrefixLength == 0) { 161 // 162 // BUGBUG: Stil fail, use 64 as the default prefix length. 163 // 164 AddressInfo->PrefixLength = IP6_LINK_LOCAL_PREFIX_LENGTH; 165 } 166 167 168 // 169 // Node should delay joining the solicited-node mulitcast address by a random delay 170 // between 0 and MAX_RTR_SOLICITATION_DELAY (1 second). 171 // Thus queue the address to be processed in Duplicate Address Detection module 172 // after the delay time (in milliseconds). 173 // 174 Delay = (UINT64) NET_RANDOM (NetRandomInitSeed ()); 175 Delay = MultU64x32 (Delay, IP6_ONE_SECOND_IN_MS); 176 Delay = RShiftU64 (Delay, 32); 177 178 DelayNode = (IP6_DELAY_JOIN_LIST *) AllocatePool (sizeof (IP6_DELAY_JOIN_LIST)); 179 if (DelayNode == NULL) { 180 FreePool (AddressInfo); 181 return EFI_OUT_OF_RESOURCES; 182 } 183 184 DelayNode->DelayTime = (UINT32) (DivU64x32 (Delay, IP6_TIMER_INTERVAL_IN_MS)); 185 DelayNode->Interface = Interface; 186 DelayNode->AddressInfo = AddressInfo; 187 DelayNode->DadCallback = DadCallback; 188 DelayNode->Context = Context; 189 190 InsertTailList (&Interface->DelayJoinList, &DelayNode->Link); 191 return EFI_SUCCESS; 192 } 193 194 /** 195 Create an IP6_INTERFACE. 196 197 @param[in] IpSb The IP6 service binding instance. 198 @param[in] LinkLocal If TRUE, the instance is created for link-local address. 199 Otherwise, it is not for a link-local address. 200 201 @return Point to the created IP6_INTERFACE, otherwise NULL. 202 203 **/ 204 IP6_INTERFACE * 205 Ip6CreateInterface ( 206 IN IP6_SERVICE *IpSb, 207 IN BOOLEAN LinkLocal 208 ) 209 { 210 EFI_STATUS Status; 211 IP6_INTERFACE *Interface; 212 EFI_IPv6_ADDRESS *Ip6Addr; 213 214 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE); 215 216 Interface = AllocatePool (sizeof (IP6_INTERFACE)); 217 if (Interface == NULL) { 218 return NULL; 219 } 220 221 Interface->Signature = IP6_INTERFACE_SIGNATURE; 222 Interface->RefCnt = 1; 223 224 InitializeListHead (&Interface->AddressList); 225 Interface->AddressCount = 0; 226 Interface->Configured = FALSE; 227 228 Interface->Service = IpSb; 229 Interface->Controller = IpSb->Controller; 230 Interface->Image = IpSb->Image; 231 232 InitializeListHead (&Interface->ArpQues); 233 InitializeListHead (&Interface->SentFrames); 234 235 Interface->DupAddrDetect = IpSb->Ip6ConfigInstance.DadXmits.DupAddrDetectTransmits; 236 InitializeListHead (&Interface->DupAddrDetectList); 237 238 InitializeListHead (&Interface->DelayJoinList); 239 240 InitializeListHead (&Interface->IpInstances); 241 Interface->PromiscRecv = FALSE; 242 243 if (!LinkLocal) { 244 return Interface; 245 } 246 247 // 248 // Get the link local addr 249 // 250 Ip6Addr = Ip6CreateLinkLocalAddr (IpSb); 251 if (Ip6Addr == NULL) { 252 goto ON_ERROR; 253 } 254 255 // 256 // Perform DAD - Duplicate Address Detection. 257 // 258 Status = Ip6SetAddress ( 259 Interface, 260 Ip6Addr, 261 FALSE, 262 IP6_LINK_LOCAL_PREFIX_LENGTH, 263 (UINT32) IP6_INFINIT_LIFETIME, 264 (UINT32) IP6_INFINIT_LIFETIME, 265 NULL, 266 NULL 267 ); 268 269 FreePool (Ip6Addr); 270 271 if (EFI_ERROR (Status)) { 272 goto ON_ERROR; 273 } 274 275 return Interface; 276 277 ON_ERROR: 278 279 FreePool (Interface); 280 return NULL; 281 } 282 283 /** 284 Free the interface used by IpInstance. All the IP instance with 285 the same Ip/prefix pair share the same interface. It is reference 286 counted. All the frames that haven't been sent will be cancelled. 287 Because the IpInstance is optional, the caller must remove 288 IpInstance from the interface's instance list. 289 290 @param[in] Interface The interface used by the IpInstance. 291 @param[in] IpInstance The IP instance that free the interface. NULL if 292 the IP driver is releasing the default interface. 293 294 **/ 295 VOID 296 Ip6CleanInterface ( 297 IN IP6_INTERFACE *Interface, 298 IN IP6_PROTOCOL *IpInstance OPTIONAL 299 ) 300 { 301 IP6_DAD_ENTRY *Duplicate; 302 IP6_DELAY_JOIN_LIST *Delay; 303 304 NET_CHECK_SIGNATURE (Interface, IP6_INTERFACE_SIGNATURE); 305 ASSERT (Interface->RefCnt > 0); 306 307 // 308 // Remove all the pending transmit token related to this IP instance. 309 // 310 Ip6CancelFrames (Interface, EFI_ABORTED, Ip6CancelInstanceFrame, IpInstance); 311 312 if (--Interface->RefCnt > 0) { 313 return; 314 } 315 316 // 317 // Destroy the interface if this is the last IP instance. 318 // Remove all the system transmitted packets 319 // from this interface, cancel the receive request if exists. 320 // 321 Ip6CancelFrames (Interface, EFI_ABORTED, Ip6CancelInstanceFrame, NULL); 322 323 ASSERT (IsListEmpty (&Interface->IpInstances)); 324 ASSERT (IsListEmpty (&Interface->ArpQues)); 325 ASSERT (IsListEmpty (&Interface->SentFrames)); 326 327 while (!IsListEmpty (&Interface->DupAddrDetectList)) { 328 Duplicate = NET_LIST_HEAD (&Interface->DupAddrDetectList, IP6_DAD_ENTRY, Link); 329 NetListRemoveHead (&Interface->DupAddrDetectList); 330 FreePool (Duplicate); 331 } 332 333 while (!IsListEmpty (&Interface->DelayJoinList)) { 334 Delay = NET_LIST_HEAD (&Interface->DelayJoinList, IP6_DELAY_JOIN_LIST, Link); 335 NetListRemoveHead (&Interface->DelayJoinList); 336 FreePool (Delay); 337 } 338 339 Ip6RemoveAddr (Interface->Service, &Interface->AddressList, &Interface->AddressCount, NULL, 0); 340 341 RemoveEntryList (&Interface->Link); 342 FreePool (Interface); 343 } 344 345 /** 346 Create and wrap a transmit request into a newly allocated IP6_LINK_TX_TOKEN. 347 348 @param[in] Interface The interface to send out from. 349 @param[in] IpInstance The IpInstance that transmit the packet. NULL if 350 the packet is sent by the IP6 driver itself. 351 @param[in] Packet The packet to transmit 352 @param[in] CallBack Call back function to execute if transmission 353 finished. 354 @param[in] Context Opaque parameter to the callback. 355 356 @return The wrapped token if succeed or NULL. 357 358 **/ 359 IP6_LINK_TX_TOKEN * 360 Ip6CreateLinkTxToken ( 361 IN IP6_INTERFACE *Interface, 362 IN IP6_PROTOCOL *IpInstance OPTIONAL, 363 IN NET_BUF *Packet, 364 IN IP6_FRAME_CALLBACK CallBack, 365 IN VOID *Context 366 ) 367 { 368 EFI_MANAGED_NETWORK_COMPLETION_TOKEN *MnpToken; 369 EFI_MANAGED_NETWORK_TRANSMIT_DATA *MnpTxData; 370 IP6_LINK_TX_TOKEN *Token; 371 EFI_STATUS Status; 372 UINT32 Count; 373 374 Token = AllocatePool (sizeof (IP6_LINK_TX_TOKEN) + (Packet->BlockOpNum - 1) * sizeof (EFI_MANAGED_NETWORK_FRAGMENT_DATA)); 375 376 if (Token == NULL) { 377 return NULL; 378 } 379 380 Token->Signature = IP6_LINK_TX_SIGNATURE; 381 InitializeListHead (&Token->Link); 382 383 Token->IpInstance = IpInstance; 384 Token->CallBack = CallBack; 385 Token->Packet = Packet; 386 Token->Context = Context; 387 ZeroMem (&Token->DstMac, sizeof (EFI_MAC_ADDRESS)); 388 IP6_COPY_LINK_ADDRESS (&Token->SrcMac, &Interface->Service->SnpMode.CurrentAddress); 389 390 MnpToken = &(Token->MnpToken); 391 MnpToken->Status = EFI_NOT_READY; 392 393 Status = gBS->CreateEvent ( 394 EVT_NOTIFY_SIGNAL, 395 TPL_NOTIFY, 396 Ip6OnFrameSent, 397 Token, 398 &MnpToken->Event 399 ); 400 401 if (EFI_ERROR (Status)) { 402 FreePool (Token); 403 return NULL; 404 } 405 406 MnpTxData = &Token->MnpTxData; 407 MnpToken->Packet.TxData = MnpTxData; 408 409 MnpTxData->DestinationAddress = &Token->DstMac; 410 MnpTxData->SourceAddress = &Token->SrcMac; 411 MnpTxData->ProtocolType = IP6_ETHER_PROTO; 412 MnpTxData->DataLength = Packet->TotalSize; 413 MnpTxData->HeaderLength = 0; 414 415 Count = Packet->BlockOpNum; 416 417 NetbufBuildExt (Packet, (NET_FRAGMENT *) MnpTxData->FragmentTable, &Count); 418 MnpTxData->FragmentCount = (UINT16)Count; 419 420 return Token; 421 } 422 423 /** 424 Free the link layer transmit token. It will close the event, 425 then free the memory used. 426 427 @param[in] Token Token to free. 428 429 **/ 430 VOID 431 Ip6FreeLinkTxToken ( 432 IN IP6_LINK_TX_TOKEN *Token 433 ) 434 { 435 NET_CHECK_SIGNATURE (Token, IP6_LINK_TX_SIGNATURE); 436 437 gBS->CloseEvent (Token->MnpToken.Event); 438 FreePool (Token); 439 } 440 441 /** 442 Callback function when the received packet is freed. 443 Check Ip6OnFrameReceived for information. 444 445 @param[in] Context Points to EFI_MANAGED_NETWORK_RECEIVE_DATA. 446 447 **/ 448 VOID 449 EFIAPI 450 Ip6RecycleFrame ( 451 IN VOID *Context 452 ) 453 { 454 EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData; 455 456 RxData = (EFI_MANAGED_NETWORK_RECEIVE_DATA *) Context; 457 458 gBS->SignalEvent (RxData->RecycleEvent); 459 } 460 461 /** 462 Received a frame from MNP. Wrap it in net buffer then deliver 463 it to IP's input function. The ownship of the packet also 464 is transferred to IP. When Ip is finished with this packet, it 465 will call NetbufFree to release the packet, NetbufFree will 466 again call the Ip6RecycleFrame to signal MNP's event and free 467 the token used. 468 469 @param[in] Context Context for the callback. 470 471 **/ 472 VOID 473 EFIAPI 474 Ip6OnFrameReceivedDpc ( 475 IN VOID *Context 476 ) 477 { 478 EFI_MANAGED_NETWORK_COMPLETION_TOKEN *MnpToken; 479 EFI_MANAGED_NETWORK_RECEIVE_DATA *MnpRxData; 480 IP6_LINK_RX_TOKEN *Token; 481 NET_FRAGMENT Netfrag; 482 NET_BUF *Packet; 483 UINT32 Flag; 484 IP6_SERVICE *IpSb; 485 486 Token = (IP6_LINK_RX_TOKEN *) Context; 487 NET_CHECK_SIGNATURE (Token, IP6_LINK_RX_SIGNATURE); 488 489 // 490 // First clear the interface's receive request in case the 491 // caller wants to call Ip6ReceiveFrame in the callback. 492 // 493 IpSb = (IP6_SERVICE *) Token->Context; 494 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE); 495 496 497 MnpToken = &Token->MnpToken; 498 MnpRxData = MnpToken->Packet.RxData; 499 500 if (EFI_ERROR (MnpToken->Status) || (MnpRxData == NULL)) { 501 Token->CallBack (NULL, MnpToken->Status, 0, Token->Context); 502 return ; 503 } 504 505 // 506 // Wrap the frame in a net buffer then deliever it to IP input. 507 // IP will reassemble the packet, and deliver it to upper layer 508 // 509 Netfrag.Len = MnpRxData->DataLength; 510 Netfrag.Bulk = MnpRxData->PacketData; 511 512 Packet = NetbufFromExt (&Netfrag, 1, IP6_MAX_HEADLEN, 0, Ip6RecycleFrame, Token->MnpToken.Packet.RxData); 513 514 if (Packet == NULL) { 515 gBS->SignalEvent (MnpRxData->RecycleEvent); 516 517 Token->CallBack (NULL, EFI_OUT_OF_RESOURCES, 0, Token->Context); 518 519 return ; 520 } 521 522 Flag = (MnpRxData->BroadcastFlag ? IP6_LINK_BROADCAST : 0); 523 Flag |= (MnpRxData->MulticastFlag ? IP6_LINK_MULTICAST : 0); 524 Flag |= (MnpRxData->PromiscuousFlag ? IP6_LINK_PROMISC : 0); 525 526 Token->CallBack (Packet, EFI_SUCCESS, Flag, Token->Context); 527 } 528 529 /** 530 Request Ip6OnFrameReceivedDpc as a DPC at TPL_CALLBACK. 531 532 @param Event The receive event delivered to MNP for receive. 533 @param Context Context for the callback. 534 535 **/ 536 VOID 537 EFIAPI 538 Ip6OnFrameReceived ( 539 IN EFI_EVENT Event, 540 IN VOID *Context 541 ) 542 { 543 // 544 // Request Ip6OnFrameReceivedDpc as a DPC at TPL_CALLBACK 545 // 546 QueueDpc (TPL_CALLBACK, Ip6OnFrameReceivedDpc, Context); 547 } 548 549 /** 550 Request to receive the packet from the interface. 551 552 @param[in] CallBack Function to call when receive finished. 553 @param[in] IpSb Points to IP6 service binding instance. 554 555 @retval EFI_ALREADY_STARTED There is already a pending receive request. 556 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to receive. 557 @retval EFI_SUCCESS The recieve request has been started. 558 559 **/ 560 EFI_STATUS 561 Ip6ReceiveFrame ( 562 IN IP6_FRAME_CALLBACK CallBack, 563 IN IP6_SERVICE *IpSb 564 ) 565 { 566 EFI_STATUS Status; 567 IP6_LINK_RX_TOKEN *Token; 568 569 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE); 570 571 Token = &IpSb->RecvRequest; 572 Token->CallBack = CallBack; 573 Token->Context = (VOID *) IpSb; 574 575 Status = IpSb->Mnp->Receive (IpSb->Mnp, &Token->MnpToken); 576 if (EFI_ERROR (Status)) { 577 return Status; 578 } 579 580 return EFI_SUCCESS; 581 } 582 583 /** 584 Callback funtion when frame transmission is finished. It will 585 call the frame owner's callback function to tell it the result. 586 587 @param[in] Context Context which points to the token. 588 589 **/ 590 VOID 591 EFIAPI 592 Ip6OnFrameSentDpc ( 593 IN VOID *Context 594 ) 595 { 596 IP6_LINK_TX_TOKEN *Token; 597 598 Token = (IP6_LINK_TX_TOKEN *) Context; 599 NET_CHECK_SIGNATURE (Token, IP6_LINK_TX_SIGNATURE); 600 601 RemoveEntryList (&Token->Link); 602 603 Token->CallBack ( 604 Token->Packet, 605 Token->MnpToken.Status, 606 0, 607 Token->Context 608 ); 609 610 Ip6FreeLinkTxToken (Token); 611 } 612 613 /** 614 Request Ip6OnFrameSentDpc as a DPC at TPL_CALLBACK. 615 616 @param[in] Event The transmit token's event. 617 @param[in] Context Context which points to the token. 618 619 **/ 620 VOID 621 EFIAPI 622 Ip6OnFrameSent ( 623 IN EFI_EVENT Event, 624 IN VOID *Context 625 ) 626 { 627 // 628 // Request Ip6OnFrameSentDpc as a DPC at TPL_CALLBACK 629 // 630 QueueDpc (TPL_CALLBACK, Ip6OnFrameSentDpc, Context); 631 } 632 633 /** 634 Send a frame from the interface. If the next hop is a multicast address, 635 it is transmitted immediately. If the next hop is a unicast, 636 and the NextHop's MAC is not known, it will perform address resolution. 637 If an error occurred, the CallBack won't be called. So, the caller 638 must test the return value, and take action when there is an error. 639 640 @param[in] Interface The interface to send the frame from 641 @param[in] IpInstance The IP child that request the transmission. 642 NULL if it is the IP6 driver itself. 643 @param[in] Packet The packet to transmit. 644 @param[in] NextHop The immediate destination to transmit the packet to. 645 @param[in] CallBack Function to call back when transmit finished. 646 @param[in] Context Opaque parameter to the callback. 647 648 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to send the frame. 649 @retval EFI_NO_MAPPING Can't resolve the MAC for the nexthop. 650 @retval EFI_SUCCESS The packet successfully transmitted. 651 652 **/ 653 EFI_STATUS 654 Ip6SendFrame ( 655 IN IP6_INTERFACE *Interface, 656 IN IP6_PROTOCOL *IpInstance OPTIONAL, 657 IN NET_BUF *Packet, 658 IN EFI_IPv6_ADDRESS *NextHop, 659 IN IP6_FRAME_CALLBACK CallBack, 660 IN VOID *Context 661 ) 662 { 663 IP6_SERVICE *IpSb; 664 IP6_LINK_TX_TOKEN *Token; 665 EFI_STATUS Status; 666 IP6_NEIGHBOR_ENTRY *NeighborCache; 667 LIST_ENTRY *Entry; 668 IP6_NEIGHBOR_ENTRY *ArpQue; 669 670 IpSb = Interface->Service; 671 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE); 672 673 // 674 // Only when link local address is performing DAD, the interface could be used in unconfigured. 675 // 676 if (IpSb->LinkLocalOk) { 677 ASSERT (Interface->Configured); 678 } 679 680 Token = Ip6CreateLinkTxToken (Interface, IpInstance, Packet, CallBack, Context); 681 682 if (Token == NULL) { 683 return EFI_OUT_OF_RESOURCES; 684 } 685 686 if (IP6_IS_MULTICAST (NextHop)) { 687 Status = Ip6GetMulticastMac (IpSb->Mnp, NextHop, &Token->DstMac); 688 if (EFI_ERROR (Status)) { 689 goto Error; 690 } 691 692 goto SendNow; 693 } 694 695 // 696 // If send to itself, directly send out 697 // 698 if (EFI_IP6_EQUAL (&Packet->Ip.Ip6->DestinationAddress, &Packet->Ip.Ip6->SourceAddress)) { 699 IP6_COPY_LINK_ADDRESS (&Token->DstMac, &IpSb->SnpMode.CurrentAddress); 700 goto SendNow; 701 } 702 703 // 704 // If unicast, check the neighbor state. 705 // 706 707 NeighborCache = Ip6FindNeighborEntry (IpSb, NextHop); 708 ASSERT (NeighborCache != NULL); 709 710 if (NeighborCache->Interface == NULL) { 711 NeighborCache->Interface = Interface; 712 } 713 714 switch (NeighborCache->State) { 715 case EfiNeighborStale: 716 NeighborCache->State = EfiNeighborDelay; 717 NeighborCache->Ticks = (UINT32) IP6_GET_TICKS (IP6_DELAY_FIRST_PROBE_TIME); 718 // 719 // Fall through 720 // 721 case EfiNeighborReachable: 722 case EfiNeighborDelay: 723 case EfiNeighborProbe: 724 IP6_COPY_LINK_ADDRESS (&Token->DstMac, &NeighborCache->LinkAddress); 725 goto SendNow; 726 break; 727 728 default: 729 break; 730 } 731 732 // 733 // Have to do asynchronous ARP resolution. First check whether there is 734 // already a pending request. 735 // 736 NET_LIST_FOR_EACH (Entry, &Interface->ArpQues) { 737 ArpQue = NET_LIST_USER_STRUCT (Entry, IP6_NEIGHBOR_ENTRY, ArpList); 738 if (ArpQue == NeighborCache) { 739 InsertTailList (&NeighborCache->Frames, &Token->Link); 740 NeighborCache->ArpFree = TRUE; 741 return EFI_SUCCESS; 742 } 743 } 744 745 // 746 // First frame requires ARP. 747 // 748 InsertTailList (&NeighborCache->Frames, &Token->Link); 749 InsertTailList (&Interface->ArpQues, &NeighborCache->ArpList); 750 751 NeighborCache->ArpFree = TRUE; 752 753 return EFI_SUCCESS; 754 755 SendNow: 756 // 757 // Insert the tx token into the SentFrames list before calling Mnp->Transmit. 758 // Remove it if the returned status is not EFI_SUCCESS. 759 // 760 InsertTailList (&Interface->SentFrames, &Token->Link); 761 Status = IpSb->Mnp->Transmit (IpSb->Mnp, &Token->MnpToken); 762 if (EFI_ERROR (Status)) { 763 RemoveEntryList (&Token->Link); 764 goto Error; 765 } 766 767 return EFI_SUCCESS; 768 769 Error: 770 Ip6FreeLinkTxToken (Token); 771 return Status; 772 } 773 774 /** 775 The heartbeat timer of IP6 service instance. It times out 776 all of its IP6 children's received-but-not-delivered and 777 transmitted-but-not-recycle packets. 778 779 @param[in] Event The IP6 service instance's heartbeat timer. 780 @param[in] Context The IP6 service instance. 781 782 **/ 783 VOID 784 EFIAPI 785 Ip6TimerTicking ( 786 IN EFI_EVENT Event, 787 IN VOID *Context 788 ) 789 { 790 IP6_SERVICE *IpSb; 791 792 IpSb = (IP6_SERVICE *) Context; 793 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE); 794 795 Ip6PacketTimerTicking (IpSb); 796 Ip6NdTimerTicking (IpSb); 797 Ip6MldTimerTicking (IpSb); 798 } 799