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