VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/NetworkPkg/Ip6Dxe/Ip6If.c

Last change on this file was 105670, checked in by vboxsync, 8 months ago

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

  • Property svn:eol-style set to native
File size: 22.2 KB
Line 
1/** @file
2 Implement IP6 pseudo interface.
3
4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) Microsoft Corporation
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8**/
9
10#include "Ip6Impl.h"
11
12/**
13 Request Ip6OnFrameSentDpc as a DPC at TPL_CALLBACK.
14
15 @param[in] Event The transmit token's event.
16 @param[in] Context The Context which is pointed to the token.
17
18**/
19VOID
20EFIAPI
21Ip6OnFrameSent (
22 IN EFI_EVENT Event,
23 IN VOID *Context
24 );
25
26/**
27 Fileter function to cancel all the frame related to an IP instance.
28
29 @param[in] Frame The transmit request to test whether to cancel.
30 @param[in] Context The context which is the Ip instance that issued
31 the transmit.
32
33 @retval TRUE The frame belongs to this instance and is to be
34 removed.
35 @retval FALSE The frame doesn't belong to this instance.
36
37**/
38BOOLEAN
39Ip6CancelInstanceFrame (
40 IN IP6_LINK_TX_TOKEN *Frame,
41 IN VOID *Context
42 )
43{
44 if (Frame->IpInstance == (IP6_PROTOCOL *)Context) {
45 return TRUE;
46 }
47
48 return FALSE;
49}
50
51/**
52 Set the interface's address. This will trigger the DAD process for the
53 address to set. To set an already set address, the lifetimes wil be
54 updated to the new value passed in.
55
56 @param[in] Interface The interface to set the address.
57 @param[in] Ip6Addr The interface's to be assigned IPv6 address.
58 @param[in] IsAnycast If TRUE, the unicast IPv6 address is anycast.
59 Otherwise, it is not anycast.
60 @param[in] PrefixLength The prefix length of the Ip6Addr.
61 @param[in] ValidLifetime The valid lifetime for this address.
62 @param[in] PreferredLifetime The preferred lifetime for this address.
63 @param[in] DadCallback The caller's callback to trigger when DAD finishes.
64 This is an optional parameter that may be NULL.
65 @param[in] Context The context that will be passed to DadCallback.
66 This is an optional parameter that may be NULL.
67
68 @retval EFI_SUCCESS The interface is scheduled to be configured with
69 the specified address.
70 @retval EFI_OUT_OF_RESOURCES Failed to set the interface's address due to
71 lack of resources.
72
73**/
74EFI_STATUS
75Ip6SetAddress (
76 IN IP6_INTERFACE *Interface,
77 IN EFI_IPv6_ADDRESS *Ip6Addr,
78 IN BOOLEAN IsAnycast,
79 IN UINT8 PrefixLength,
80 IN UINT32 ValidLifetime,
81 IN UINT32 PreferredLifetime,
82 IN IP6_DAD_CALLBACK DadCallback OPTIONAL,
83 IN VOID *Context OPTIONAL
84 )
85{
86 IP6_SERVICE *IpSb;
87 IP6_ADDRESS_INFO *AddressInfo;
88 LIST_ENTRY *Entry;
89 IP6_PREFIX_LIST_ENTRY *PrefixEntry;
90 UINT64 Delay;
91 IP6_DELAY_JOIN_LIST *DelayNode;
92 EFI_STATUS Status;
93 UINT32 Random;
94
95 Status = PseudoRandomU32 (&Random);
96 if (EFI_ERROR (Status)) {
97 DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status));
98 return Status;
99 }
100
101 NET_CHECK_SIGNATURE (Interface, IP6_INTERFACE_SIGNATURE);
102
103 IpSb = Interface->Service;
104
105 if (Ip6IsOneOfSetAddress (IpSb, Ip6Addr, NULL, &AddressInfo)) {
106 ASSERT (AddressInfo != NULL);
107 //
108 // Update the lifetime.
109 //
110 AddressInfo->ValidLifetime = ValidLifetime;
111 AddressInfo->PreferredLifetime = PreferredLifetime;
112
113 if (DadCallback != NULL) {
114 DadCallback (TRUE, Ip6Addr, Context);
115 }
116
117 return EFI_SUCCESS;
118 }
119
120 AddressInfo = (IP6_ADDRESS_INFO *)AllocatePool (sizeof (IP6_ADDRESS_INFO));
121 if (AddressInfo == NULL) {
122 return EFI_OUT_OF_RESOURCES;
123 }
124
125 AddressInfo->Signature = IP6_ADDR_INFO_SIGNATURE;
126 IP6_COPY_ADDRESS (&AddressInfo->Address, Ip6Addr);
127 AddressInfo->IsAnycast = IsAnycast;
128 AddressInfo->PrefixLength = PrefixLength;
129 AddressInfo->ValidLifetime = ValidLifetime;
130 AddressInfo->PreferredLifetime = PreferredLifetime;
131
132 if (AddressInfo->PrefixLength == 0) {
133 //
134 // Find an appropriate prefix from on-link prefixes and update the prefixlength.
135 // Longest prefix match is used here.
136 //
137 NET_LIST_FOR_EACH (Entry, &IpSb->OnlinkPrefix) {
138 PrefixEntry = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
139
140 if (NetIp6IsNetEqual (&PrefixEntry->Prefix, &AddressInfo->Address, PrefixEntry->PrefixLength)) {
141 AddressInfo->PrefixLength = PrefixEntry->PrefixLength;
142 break;
143 }
144 }
145 }
146
147 if (AddressInfo->PrefixLength == 0) {
148 //
149 // If the prefix length is still zero, try the autonomous prefixes.
150 // Longest prefix match is used here.
151 //
152 NET_LIST_FOR_EACH (Entry, &IpSb->AutonomousPrefix) {
153 PrefixEntry = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
154
155 if (NetIp6IsNetEqual (&PrefixEntry->Prefix, &AddressInfo->Address, PrefixEntry->PrefixLength)) {
156 AddressInfo->PrefixLength = PrefixEntry->PrefixLength;
157 break;
158 }
159 }
160 }
161
162 if (AddressInfo->PrefixLength == 0) {
163 //
164 // BUGBUG: Stil fail, use 64 as the default prefix length.
165 //
166 AddressInfo->PrefixLength = IP6_LINK_LOCAL_PREFIX_LENGTH;
167 }
168
169 //
170 // Node should delay joining the solicited-node multicast address by a random delay
171 // between 0 and MAX_RTR_SOLICITATION_DELAY (1 second).
172 // Thus queue the address to be processed in Duplicate Address Detection module
173 // after the delay time (in milliseconds).
174 //
175 Delay = (UINT64)Random;
176 Delay = MultU64x32 (Delay, IP6_ONE_SECOND_IN_MS);
177 Delay = RShiftU64 (Delay, 32);
178
179 DelayNode = (IP6_DELAY_JOIN_LIST *)AllocatePool (sizeof (IP6_DELAY_JOIN_LIST));
180 if (DelayNode == NULL) {
181 FreePool (AddressInfo);
182 return EFI_OUT_OF_RESOURCES;
183 }
184
185 DelayNode->DelayTime = (UINT32)(DivU64x32 (Delay, IP6_TIMER_INTERVAL_IN_MS));
186 DelayNode->Interface = Interface;
187 DelayNode->AddressInfo = AddressInfo;
188 DelayNode->DadCallback = DadCallback;
189 DelayNode->Context = Context;
190
191 InsertTailList (&Interface->DelayJoinList, &DelayNode->Link);
192 return EFI_SUCCESS;
193}
194
195/**
196 Create an IP6_INTERFACE.
197
198 @param[in] IpSb The IP6 service binding instance.
199 @param[in] LinkLocal If TRUE, the instance is created for link-local address.
200 Otherwise, it is not for a link-local address.
201
202 @return Point to the created IP6_INTERFACE, otherwise NULL.
203
204**/
205IP6_INTERFACE *
206Ip6CreateInterface (
207 IN IP6_SERVICE *IpSb,
208 IN BOOLEAN LinkLocal
209 )
210{
211 EFI_STATUS Status;
212 IP6_INTERFACE *Interface;
213 EFI_IPv6_ADDRESS *Ip6Addr;
214
215 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
216
217 Interface = AllocatePool (sizeof (IP6_INTERFACE));
218 if (Interface == NULL) {
219 return NULL;
220 }
221
222 Interface->Signature = IP6_INTERFACE_SIGNATURE;
223 Interface->RefCnt = 1;
224
225 InitializeListHead (&Interface->AddressList);
226 Interface->AddressCount = 0;
227 Interface->Configured = FALSE;
228
229 Interface->Service = IpSb;
230 Interface->Controller = IpSb->Controller;
231 Interface->Image = IpSb->Image;
232
233 InitializeListHead (&Interface->ArpQues);
234 InitializeListHead (&Interface->SentFrames);
235
236 Interface->DupAddrDetect = IpSb->Ip6ConfigInstance.DadXmits.DupAddrDetectTransmits;
237 InitializeListHead (&Interface->DupAddrDetectList);
238
239 InitializeListHead (&Interface->DelayJoinList);
240
241 InitializeListHead (&Interface->IpInstances);
242 Interface->PromiscRecv = FALSE;
243
244 if (!LinkLocal) {
245 return Interface;
246 }
247
248 //
249 // Get the link local addr
250 //
251 Ip6Addr = Ip6CreateLinkLocalAddr (IpSb);
252 if (Ip6Addr == NULL) {
253 goto ON_ERROR;
254 }
255
256 //
257 // Perform DAD - Duplicate Address Detection.
258 //
259 Status = Ip6SetAddress (
260 Interface,
261 Ip6Addr,
262 FALSE,
263 IP6_LINK_LOCAL_PREFIX_LENGTH,
264 (UINT32)IP6_INFINIT_LIFETIME,
265 (UINT32)IP6_INFINIT_LIFETIME,
266 NULL,
267 NULL
268 );
269
270 FreePool (Ip6Addr);
271
272 if (EFI_ERROR (Status)) {
273 goto ON_ERROR;
274 }
275
276 return Interface;
277
278ON_ERROR:
279
280 FreePool (Interface);
281 return NULL;
282}
283
284/**
285 Free the interface used by IpInstance. All the IP instance with
286 the same Ip/prefix pair share the same interface. It is reference
287 counted. All the frames that haven't been sent will be cancelled.
288 Because the IpInstance is optional, the caller must remove
289 IpInstance from the interface's instance list.
290
291 @param[in] Interface The interface used by the IpInstance.
292 @param[in] IpInstance The IP instance that free the interface. NULL if
293 the IP driver is releasing the default interface.
294
295**/
296VOID
297Ip6CleanInterface (
298 IN IP6_INTERFACE *Interface,
299 IN IP6_PROTOCOL *IpInstance OPTIONAL
300 )
301{
302 IP6_DAD_ENTRY *Duplicate;
303 IP6_DELAY_JOIN_LIST *Delay;
304
305 NET_CHECK_SIGNATURE (Interface, IP6_INTERFACE_SIGNATURE);
306 ASSERT (Interface->RefCnt > 0);
307
308 //
309 // Remove all the pending transmit token related to this IP instance.
310 //
311 Ip6CancelFrames (Interface, EFI_ABORTED, Ip6CancelInstanceFrame, IpInstance);
312
313 if (--Interface->RefCnt > 0) {
314 return;
315 }
316
317 //
318 // Destroy the interface if this is the last IP instance.
319 // Remove all the system transmitted packets
320 // from this interface, cancel the receive request if exists.
321 //
322 Ip6CancelFrames (Interface, EFI_ABORTED, Ip6CancelInstanceFrame, NULL);
323
324 ASSERT (IsListEmpty (&Interface->IpInstances));
325 ASSERT (IsListEmpty (&Interface->ArpQues));
326 ASSERT (IsListEmpty (&Interface->SentFrames));
327
328 while (!IsListEmpty (&Interface->DupAddrDetectList)) {
329 Duplicate = NET_LIST_HEAD (&Interface->DupAddrDetectList, IP6_DAD_ENTRY, Link);
330 NetListRemoveHead (&Interface->DupAddrDetectList);
331 FreePool (Duplicate);
332 }
333
334 while (!IsListEmpty (&Interface->DelayJoinList)) {
335 Delay = NET_LIST_HEAD (&Interface->DelayJoinList, IP6_DELAY_JOIN_LIST, Link);
336 NetListRemoveHead (&Interface->DelayJoinList);
337 FreePool (Delay);
338 }
339
340 Ip6RemoveAddr (Interface->Service, &Interface->AddressList, &Interface->AddressCount, NULL, 0);
341
342 RemoveEntryList (&Interface->Link);
343 FreePool (Interface);
344}
345
346/**
347 Create and wrap a transmit request into a newly allocated IP6_LINK_TX_TOKEN.
348
349 @param[in] Interface The interface to send out from.
350 @param[in] IpInstance The IpInstance that transmit the packet. NULL if
351 the packet is sent by the IP6 driver itself.
352 @param[in] Packet The packet to transmit
353 @param[in] CallBack Call back function to execute if transmission
354 finished.
355 @param[in] Context Opaque parameter to the callback.
356
357 @return The wrapped token if succeed or NULL.
358
359**/
360IP6_LINK_TX_TOKEN *
361Ip6CreateLinkTxToken (
362 IN IP6_INTERFACE *Interface,
363 IN IP6_PROTOCOL *IpInstance OPTIONAL,
364 IN NET_BUF *Packet,
365 IN IP6_FRAME_CALLBACK CallBack,
366 IN VOID *Context
367 )
368{
369 EFI_MANAGED_NETWORK_COMPLETION_TOKEN *MnpToken;
370 EFI_MANAGED_NETWORK_TRANSMIT_DATA *MnpTxData;
371 IP6_LINK_TX_TOKEN *Token;
372 EFI_STATUS Status;
373 UINT32 Count;
374
375 Token = AllocatePool (sizeof (IP6_LINK_TX_TOKEN) + (Packet->BlockOpNum - 1) * sizeof (EFI_MANAGED_NETWORK_FRAGMENT_DATA));
376
377 if (Token == NULL) {
378 return NULL;
379 }
380
381 Token->Signature = IP6_LINK_TX_SIGNATURE;
382 InitializeListHead (&Token->Link);
383
384 Token->IpInstance = IpInstance;
385 Token->CallBack = CallBack;
386 Token->Packet = Packet;
387 Token->Context = Context;
388 ZeroMem (&Token->DstMac, sizeof (EFI_MAC_ADDRESS));
389 IP6_COPY_LINK_ADDRESS (&Token->SrcMac, &Interface->Service->SnpMode.CurrentAddress);
390
391 MnpToken = &(Token->MnpToken);
392 MnpToken->Status = EFI_NOT_READY;
393
394 Status = gBS->CreateEvent (
395 EVT_NOTIFY_SIGNAL,
396 TPL_NOTIFY,
397 Ip6OnFrameSent,
398 Token,
399 &MnpToken->Event
400 );
401
402 if (EFI_ERROR (Status)) {
403 FreePool (Token);
404 return NULL;
405 }
406
407 MnpTxData = &Token->MnpTxData;
408 MnpToken->Packet.TxData = MnpTxData;
409
410 MnpTxData->DestinationAddress = &Token->DstMac;
411 MnpTxData->SourceAddress = &Token->SrcMac;
412 MnpTxData->ProtocolType = IP6_ETHER_PROTO;
413 MnpTxData->DataLength = Packet->TotalSize;
414 MnpTxData->HeaderLength = 0;
415
416 Count = Packet->BlockOpNum;
417
418 NetbufBuildExt (Packet, (NET_FRAGMENT *)MnpTxData->FragmentTable, &Count);
419 MnpTxData->FragmentCount = (UINT16)Count;
420
421 return Token;
422}
423
424/**
425 Free the link layer transmit token. It will close the event,
426 then free the memory used.
427
428 @param[in] Token Token to free.
429
430**/
431VOID
432Ip6FreeLinkTxToken (
433 IN IP6_LINK_TX_TOKEN *Token
434 )
435{
436 NET_CHECK_SIGNATURE (Token, IP6_LINK_TX_SIGNATURE);
437
438 gBS->CloseEvent (Token->MnpToken.Event);
439 FreePool (Token);
440}
441
442/**
443 Callback function when the received packet is freed.
444 Check Ip6OnFrameReceived for information.
445
446 @param[in] Context Points to EFI_MANAGED_NETWORK_RECEIVE_DATA.
447
448**/
449VOID
450EFIAPI
451Ip6RecycleFrame (
452 IN VOID *Context
453 )
454{
455 EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData;
456
457 RxData = (EFI_MANAGED_NETWORK_RECEIVE_DATA *)Context;
458
459 gBS->SignalEvent (RxData->RecycleEvent);
460}
461
462/**
463 Received a frame from MNP. Wrap it in net buffer then deliver
464 it to IP's input function. The ownship of the packet also
465 is transferred to IP. When Ip is finished with this packet, it
466 will call NetbufFree to release the packet, NetbufFree will
467 again call the Ip6RecycleFrame to signal MNP's event and free
468 the token used.
469
470 @param[in] Context Context for the callback.
471
472**/
473VOID
474EFIAPI
475Ip6OnFrameReceivedDpc (
476 IN VOID *Context
477 )
478{
479 EFI_MANAGED_NETWORK_COMPLETION_TOKEN *MnpToken;
480 EFI_MANAGED_NETWORK_RECEIVE_DATA *MnpRxData;
481 IP6_LINK_RX_TOKEN *Token;
482 NET_FRAGMENT Netfrag;
483 NET_BUF *Packet;
484 UINT32 Flag;
485 IP6_SERVICE *IpSb;
486
487 Token = (IP6_LINK_RX_TOKEN *)Context;
488 NET_CHECK_SIGNATURE (Token, IP6_LINK_RX_SIGNATURE);
489
490 //
491 // First clear the interface's receive request in case the
492 // caller wants to call Ip6ReceiveFrame in the callback.
493 //
494 IpSb = (IP6_SERVICE *)Token->Context;
495 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
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 deliver 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**/
536VOID
537EFIAPI
538Ip6OnFrameReceived (
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 receive request has been started.
558
559**/
560EFI_STATUS
561Ip6ReceiveFrame (
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 function 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**/
590VOID
591EFIAPI
592Ip6OnFrameSentDpc (
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**/
620VOID
621EFIAPI
622Ip6OnFrameSent (
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**/
653EFI_STATUS
654Ip6SendFrame (
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
755SendNow:
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
769Error:
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**/
783VOID
784EFIAPI
785Ip6TimerTicking (
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}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette