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