1 /** @file
2   Implement IP6 pesudo 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
Ip6CancelInstanceFrame(IN IP6_LINK_TX_TOKEN * Frame,IN VOID * Context)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
Ip6SetAddress(IN IP6_INTERFACE * Interface,IN EFI_IPv6_ADDRESS * Ip6Addr,IN BOOLEAN IsAnycast,IN UINT8 PrefixLength,IN UINT32 ValidLifetime,IN UINT32 PreferredLifetime,IN IP6_DAD_CALLBACK DadCallback OPTIONAL,IN VOID * Context OPTIONAL)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 mulitcast 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 *
Ip6CreateInterface(IN IP6_SERVICE * IpSb,IN BOOLEAN LinkLocal)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
Ip6CleanInterface(IN IP6_INTERFACE * Interface,IN IP6_PROTOCOL * IpInstance OPTIONAL)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 *
Ip6CreateLinkTxToken(IN IP6_INTERFACE * Interface,IN IP6_PROTOCOL * IpInstance OPTIONAL,IN NET_BUF * Packet,IN IP6_FRAME_CALLBACK CallBack,IN VOID * Context)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
Ip6FreeLinkTxToken(IN IP6_LINK_TX_TOKEN * Token)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
Ip6RecycleFrame(IN VOID * Context)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
Ip6OnFrameReceivedDpc(IN VOID * Context)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 deliever 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
Ip6OnFrameReceived(IN EFI_EVENT Event,IN VOID * Context)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 recieve request has been started.
552 
553 **/
554 EFI_STATUS
Ip6ReceiveFrame(IN IP6_FRAME_CALLBACK CallBack,IN IP6_SERVICE * IpSb)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 funtion 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
Ip6OnFrameSentDpc(IN VOID * Context)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
Ip6OnFrameSent(IN EFI_EVENT Event,IN VOID * Context)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
Ip6SendFrame(IN IP6_INTERFACE * Interface,IN IP6_PROTOCOL * IpInstance OPTIONAL,IN NET_BUF * Packet,IN EFI_IPv6_ADDRESS * NextHop,IN IP6_FRAME_CALLBACK CallBack,IN VOID * Context)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
Ip6TimerTicking(IN EFI_EVENT Event,IN VOID * Context)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 }
793