1 /** @file
2   Implement IP4 pseudo interface.
3 
4 Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "Ip4Impl.h"
10 
11 //
12 // Mac address with all zero, used to determine whether the ARP
13 // resolve succeeded. Failed ARP requests zero the MAC address buffer.
14 //
15 EFI_MAC_ADDRESS  mZeroMacAddress;
16 
17 /**
18   Callback function when frame transmission is finished. It will
19   call the frame owner's callback function to tell it the result.
20 
21   @param[in]  Context            Context which is point to the token.
22 
23 **/
24 VOID
25 EFIAPI
26 Ip4OnFrameSentDpc (
27   IN VOID                    *Context
28   );
29 
30 /**
31   Request Ip4OnFrameSentDpc as a DPC at TPL_CALLBACK.
32 
33   @param[in]  Event              The transmit token's event.
34   @param[in]  Context            Context which is point to the token.
35 
36 **/
37 VOID
38 EFIAPI
39 Ip4OnFrameSent (
40   IN EFI_EVENT               Event,
41   IN VOID                    *Context
42   );
43 
44 /**
45   Callback function when ARP request are finished. It will cancelled
46   all the queued frame if the ARP requests failed. Or transmit them
47   if the request succeed.
48 
49   @param[in]  Context           The context of the callback, a point to the ARP
50                                 queue
51 
52 **/
53 VOID
54 EFIAPI
55 Ip4OnArpResolvedDpc (
56   IN VOID                   *Context
57   );
58 
59 /**
60   Request Ip4OnArpResolvedDpc as a DPC at TPL_CALLBACK.
61 
62   @param  Event             The Arp request event.
63   @param  Context           The context of the callback, a point to the ARP
64                             queue.
65 
66 **/
67 VOID
68 EFIAPI
69 Ip4OnArpResolved (
70   IN EFI_EVENT              Event,
71   IN VOID                   *Context
72   );
73 
74 /**
75   Received a frame from MNP, wrap it in net buffer then deliver
76   it to IP's input function. The ownship of the packet also
77   transferred to IP. When Ip is finished with this packet, it
78   will call NetbufFree to release the packet, NetbufFree will
79   again call the Ip4RecycleFrame to signal MNP's event and free
80   the token used.
81 
82   @param  Context               Context for the callback.
83 
84 **/
85 VOID
86 EFIAPI
87 Ip4OnFrameReceivedDpc (
88   IN VOID                     *Context
89   );
90 
91 /**
92   Request Ip4OnFrameReceivedDpc as a DPC at TPL_CALLBACK.
93 
94   @param Event      The receive event delivered to MNP for receive.
95   @param Context    Context for the callback.
96 
97 **/
98 VOID
99 EFIAPI
100 Ip4OnFrameReceived (
101   IN EFI_EVENT                Event,
102   IN VOID                     *Context
103   );
104 
105 /**
106   Remove all the frames on the ARP queue that pass the FrameToCancel,
107   that is, either FrameToCancel is NULL or it returns true for the frame.
108 
109   @param[in]  ArpQue            ARP frame to remove the frames from.
110   @param[in]  IoStatus          The status returned to the cancelled frames'
111                                 callback function.
112   @param[in]  FrameToCancel     Function to select which frame to cancel.
113   @param[in]  Context           Opaque parameter to the FrameToCancel.
114 
115 **/
116 VOID
117 Ip4CancelFrameArp (
118   IN IP4_ARP_QUE            *ArpQue,
119   IN EFI_STATUS             IoStatus,
120   IN IP4_FRAME_TO_CANCEL    FrameToCancel  OPTIONAL,
121   IN VOID                   *Context
122   );
123 
124 
125 /**
126   Wrap a transmit request into a newly allocated IP4_LINK_TX_TOKEN.
127 
128   @param[in]  Interface         The interface to send out to.
129   @param[in]  IpInstance        The IpInstance that transmit the packet.  NULL if
130                                 the packet is sent by the IP4 driver itself.
131   @param[in]  Packet            The packet to transmit
132   @param[in]  CallBack          Call back function to execute if transmission
133                                 finished.
134   @param[in]  Context           Opaque parameter to the call back.
135   @param[in]  IpSb              The pointer to the IP4 service binding instance.
136 
137   @retval   Token               The wrapped token if succeed
138   @retval   NULL                The wrapped token if NULL
139 
140 **/
141 IP4_LINK_TX_TOKEN *
Ip4WrapLinkTxToken(IN IP4_INTERFACE * Interface,IN IP4_PROTOCOL * IpInstance OPTIONAL,IN NET_BUF * Packet,IN IP4_FRAME_CALLBACK CallBack,IN VOID * Context,IN IP4_SERVICE * IpSb)142 Ip4WrapLinkTxToken (
143   IN IP4_INTERFACE          *Interface,
144   IN IP4_PROTOCOL           *IpInstance     OPTIONAL,
145   IN NET_BUF                *Packet,
146   IN IP4_FRAME_CALLBACK     CallBack,
147   IN VOID                   *Context,
148   IN IP4_SERVICE            *IpSb
149   )
150 {
151   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *MnpToken;
152   EFI_MANAGED_NETWORK_TRANSMIT_DATA     *MnpTxData;
153   IP4_LINK_TX_TOKEN                     *Token;
154   EFI_STATUS                            Status;
155   UINT32                                Count;
156 
157   Token = AllocatePool (sizeof (IP4_LINK_TX_TOKEN) + \
158             (Packet->BlockOpNum - 1) * sizeof (EFI_MANAGED_NETWORK_FRAGMENT_DATA));
159 
160   if (Token == NULL) {
161     return NULL;
162   }
163 
164   Token->Signature = IP4_FRAME_TX_SIGNATURE;
165   InitializeListHead (&Token->Link);
166 
167   Token->Interface  = Interface;
168   Token->IpInstance = IpInstance;
169   Token->IpSb       = IpSb;
170   Token->CallBack   = CallBack;
171   Token->Packet     = Packet;
172   Token->Context    = Context;
173   CopyMem (&Token->DstMac, &mZeroMacAddress, sizeof (Token->DstMac));
174   CopyMem (&Token->SrcMac, &Interface->Mac, sizeof (Token->SrcMac));
175 
176   MnpToken          = &(Token->MnpToken);
177   MnpToken->Status  = EFI_NOT_READY;
178 
179   Status = gBS->CreateEvent (
180                   EVT_NOTIFY_SIGNAL,
181                   TPL_NOTIFY,
182                   Ip4OnFrameSent,
183                   Token,
184                   &MnpToken->Event
185                   );
186 
187   if (EFI_ERROR (Status)) {
188     FreePool (Token);
189     return NULL;
190   }
191 
192   MnpTxData                     = &Token->MnpTxData;
193   MnpToken->Packet.TxData       = MnpTxData;
194 
195   MnpTxData->DestinationAddress = &Token->DstMac;
196   MnpTxData->SourceAddress      = &Token->SrcMac;
197   MnpTxData->ProtocolType       = IP4_ETHER_PROTO;
198   MnpTxData->DataLength         = Packet->TotalSize;
199   MnpTxData->HeaderLength       = 0;
200 
201   Count                         = Packet->BlockOpNum;
202 
203   NetbufBuildExt (Packet, (NET_FRAGMENT *) MnpTxData->FragmentTable, &Count);
204   MnpTxData->FragmentCount      = (UINT16)Count;
205 
206   return Token;
207 }
208 
209 
210 /**
211   Free the link layer transmit token. It will close the event
212   then free the memory used.
213 
214   @param[in]  Token                 Token to free
215 
216 **/
217 VOID
Ip4FreeLinkTxToken(IN IP4_LINK_TX_TOKEN * Token)218 Ip4FreeLinkTxToken (
219   IN IP4_LINK_TX_TOKEN      *Token
220   )
221 {
222   NET_CHECK_SIGNATURE (Token, IP4_FRAME_TX_SIGNATURE);
223 
224   gBS->CloseEvent (Token->MnpToken.Event);
225   FreePool (Token);
226 }
227 
228 
229 /**
230   Create an IP_ARP_QUE structure to request ARP service.
231 
232   @param[in]  Interface         The interface to send ARP from.
233   @param[in]  DestIp            The destination IP (host byte order) to request MAC
234                                 for
235 
236   @return Point to newly created IP4_ARP_QUE if succeed, otherwise NULL.
237 
238 **/
239 IP4_ARP_QUE *
Ip4CreateArpQue(IN IP4_INTERFACE * Interface,IN IP4_ADDR DestIp)240 Ip4CreateArpQue (
241   IN IP4_INTERFACE          *Interface,
242   IN IP4_ADDR               DestIp
243   )
244 {
245   IP4_ARP_QUE               *ArpQue;
246   EFI_STATUS                Status;
247 
248   ArpQue = AllocatePool (sizeof (IP4_ARP_QUE));
249 
250   if (ArpQue == NULL) {
251     return NULL;
252   }
253 
254   ArpQue->Signature = IP4_FRAME_ARP_SIGNATURE;
255   InitializeListHead (&ArpQue->Link);
256 
257   InitializeListHead (&ArpQue->Frames);
258   ArpQue->Interface = Interface;
259 
260   Status = gBS->CreateEvent (
261                   EVT_NOTIFY_SIGNAL,
262                   TPL_NOTIFY,
263                   Ip4OnArpResolved,
264                   ArpQue,
265                   &ArpQue->OnResolved
266                   );
267 
268   if (EFI_ERROR (Status)) {
269     FreePool (ArpQue);
270     return NULL;
271   }
272 
273   ArpQue->Ip  = DestIp;
274   CopyMem (&ArpQue->Mac, &mZeroMacAddress, sizeof (ArpQue->Mac));
275 
276   return ArpQue;
277 }
278 
279 
280 /**
281   Remove all the transmit requests queued on the ARP queue, then free it.
282 
283   @param[in]  ArpQue            Arp queue to free
284   @param[in]  IoStatus          The transmit status returned to transmit requests'
285                                 callback.
286 
287 **/
288 VOID
Ip4FreeArpQue(IN IP4_ARP_QUE * ArpQue,IN EFI_STATUS IoStatus)289 Ip4FreeArpQue (
290   IN IP4_ARP_QUE            *ArpQue,
291   IN EFI_STATUS             IoStatus
292   )
293 {
294   NET_CHECK_SIGNATURE (ArpQue, IP4_FRAME_ARP_SIGNATURE);
295 
296   //
297   // Remove all the frame waiting the ARP response
298   //
299   Ip4CancelFrameArp (ArpQue, IoStatus, NULL, NULL);
300 
301   gBS->CloseEvent (ArpQue->OnResolved);
302   FreePool (ArpQue);
303 }
304 
305 
306 /**
307   Create a link layer receive token to wrap the receive request
308 
309   @param[in]  Interface         The interface to receive from
310   @param[in]  IpInstance        The instance that request the receive (NULL for IP4
311                                 driver itself)
312   @param[in]  CallBack          Call back function to execute when finished.
313   @param[in]  Context           Opaque parameters to the callback
314 
315   @return Point to created IP4_LINK_RX_TOKEN if succeed, otherwise NULL.
316 
317 **/
318 IP4_LINK_RX_TOKEN *
Ip4CreateLinkRxToken(IN IP4_INTERFACE * Interface,IN IP4_PROTOCOL * IpInstance,IN IP4_FRAME_CALLBACK CallBack,IN VOID * Context)319 Ip4CreateLinkRxToken (
320   IN IP4_INTERFACE          *Interface,
321   IN IP4_PROTOCOL           *IpInstance,
322   IN IP4_FRAME_CALLBACK     CallBack,
323   IN VOID                   *Context
324   )
325 {
326   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *MnpToken;
327   IP4_LINK_RX_TOKEN                     *Token;
328   EFI_STATUS                            Status;
329 
330   Token = AllocatePool (sizeof (IP4_LINK_RX_TOKEN));
331   if (Token == NULL) {
332     return NULL;
333   }
334 
335   Token->Signature  = IP4_FRAME_RX_SIGNATURE;
336   Token->Interface  = Interface;
337   Token->IpInstance = IpInstance;
338   Token->CallBack   = CallBack;
339   Token->Context    = Context;
340 
341   MnpToken          = &Token->MnpToken;
342   MnpToken->Status  = EFI_NOT_READY;
343 
344   Status = gBS->CreateEvent (
345                   EVT_NOTIFY_SIGNAL,
346                   TPL_NOTIFY,
347                   Ip4OnFrameReceived,
348                   Token,
349                   &MnpToken->Event
350                   );
351 
352   if (EFI_ERROR (Status)) {
353     FreePool (Token);
354     return NULL;
355   }
356 
357   MnpToken->Packet.RxData = NULL;
358   return Token;
359 }
360 
361 
362 /**
363   Free the link layer request token. It will close the event
364   then free the memory used.
365 
366   @param[in]  Token                 Request token to free.
367 
368 **/
369 VOID
Ip4FreeFrameRxToken(IN IP4_LINK_RX_TOKEN * Token)370 Ip4FreeFrameRxToken (
371   IN IP4_LINK_RX_TOKEN      *Token
372   )
373 {
374 
375   NET_CHECK_SIGNATURE (Token, IP4_FRAME_RX_SIGNATURE);
376 
377   gBS->CloseEvent (Token->MnpToken.Event);
378   FreePool (Token);
379 }
380 
381 
382 /**
383   Remove all the frames on the ARP queue that pass the FrameToCancel,
384   that is, either FrameToCancel is NULL or it returns true for the frame.
385 
386   @param[in]  ArpQue            ARP frame to remove the frames from.
387   @param[in]  IoStatus          The status returned to the cancelled frames'
388                                 callback function.
389   @param[in]  FrameToCancel     Function to select which frame to cancel.
390   @param[in]  Context           Opaque parameter to the FrameToCancel.
391 
392 **/
393 VOID
Ip4CancelFrameArp(IN IP4_ARP_QUE * ArpQue,IN EFI_STATUS IoStatus,IN IP4_FRAME_TO_CANCEL FrameToCancel OPTIONAL,IN VOID * Context)394 Ip4CancelFrameArp (
395   IN IP4_ARP_QUE            *ArpQue,
396   IN EFI_STATUS             IoStatus,
397   IN IP4_FRAME_TO_CANCEL    FrameToCancel  OPTIONAL,
398   IN VOID                   *Context
399   )
400 {
401   LIST_ENTRY                *Entry;
402   LIST_ENTRY                *Next;
403   IP4_LINK_TX_TOKEN         *Token;
404 
405   NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {
406     Token = NET_LIST_USER_STRUCT (Entry, IP4_LINK_TX_TOKEN, Link);
407 
408     if ((FrameToCancel == NULL) || FrameToCancel (Token, Context)) {
409       RemoveEntryList (Entry);
410 
411       Token->CallBack (Token->IpInstance, Token->Packet, IoStatus, 0, Token->Context);
412       Ip4FreeLinkTxToken (Token);
413     }
414   }
415 }
416 
417 
418 /**
419   Remove all the frames on the interface that pass the FrameToCancel,
420   either queued on ARP queues or that have already been delivered to
421   MNP and not yet recycled.
422 
423   @param[in]  Interface         Interface to remove the frames from.
424   @param[in]  IoStatus          The transmit status returned to the frames'
425                                 callback.
426   @param[in]  FrameToCancel     Function to select the frame to cancel, NULL to
427                                 select all.
428   @param[in]  Context           Opaque parameters passed to FrameToCancel.
429 
430 **/
431 VOID
Ip4CancelFrames(IN IP4_INTERFACE * Interface,IN EFI_STATUS IoStatus,IN IP4_FRAME_TO_CANCEL FrameToCancel OPTIONAL,IN VOID * Context)432 Ip4CancelFrames (
433   IN IP4_INTERFACE          *Interface,
434   IN EFI_STATUS             IoStatus,
435   IN IP4_FRAME_TO_CANCEL    FrameToCancel    OPTIONAL,
436   IN VOID                   *Context
437   )
438 {
439   LIST_ENTRY                *Entry;
440   LIST_ENTRY                *Next;
441   IP4_ARP_QUE               *ArpQue;
442   IP4_LINK_TX_TOKEN         *Token;
443 
444   //
445   // Cancel all the pending frames on ARP requests
446   //
447   NET_LIST_FOR_EACH_SAFE (Entry, Next, &Interface->ArpQues) {
448     ArpQue = NET_LIST_USER_STRUCT (Entry, IP4_ARP_QUE, Link);
449 
450     Ip4CancelFrameArp (ArpQue, IoStatus, FrameToCancel, Context);
451 
452     if (IsListEmpty (&ArpQue->Frames)) {
453       Interface->Arp->Cancel (Interface->Arp, &ArpQue->Ip, ArpQue->OnResolved);
454     }
455   }
456 
457   //
458   // Cancel all the frames that have been delivered to MNP
459   // but not yet recycled.
460   //
461   NET_LIST_FOR_EACH_SAFE (Entry, Next, &Interface->SentFrames) {
462     Token = NET_LIST_USER_STRUCT (Entry, IP4_LINK_TX_TOKEN, Link);
463 
464     if ((FrameToCancel == NULL) || FrameToCancel (Token, Context)) {
465       Interface->Mnp->Cancel (Interface->Mnp, &Token->MnpToken);
466     }
467   }
468 }
469 
470 
471 /**
472   Create an IP4_INTERFACE. Delay the creation of ARP instance until
473   the interface is configured.
474 
475   @param[in]  Mnp               The shared MNP child of this IP4 service binding
476                                 instance.
477   @param[in]  Controller        The controller this IP4 service binding instance
478                                 is installed. Most like the UNDI handle.
479   @param[in]  ImageHandle       This driver's image handle.
480 
481   @return Point to the created IP4_INTERFACE, otherwise NULL.
482 
483 **/
484 IP4_INTERFACE *
Ip4CreateInterface(IN EFI_MANAGED_NETWORK_PROTOCOL * Mnp,IN EFI_HANDLE Controller,IN EFI_HANDLE ImageHandle)485 Ip4CreateInterface (
486   IN  EFI_MANAGED_NETWORK_PROTOCOL  *Mnp,
487   IN  EFI_HANDLE                    Controller,
488   IN  EFI_HANDLE                    ImageHandle
489   )
490 {
491   IP4_INTERFACE             *Interface;
492   EFI_SIMPLE_NETWORK_MODE   SnpMode;
493 
494   if (Mnp == NULL) {
495     return NULL;
496   }
497 
498   Interface = AllocatePool (sizeof (IP4_INTERFACE));
499 
500   if (Interface == NULL) {
501     return NULL;
502   }
503 
504   Interface->Signature = IP4_INTERFACE_SIGNATURE;
505   InitializeListHead (&Interface->Link);
506   Interface->RefCnt     = 1;
507 
508   Interface->Ip         = IP4_ALLZERO_ADDRESS;
509   Interface->SubnetMask = IP4_ALLZERO_ADDRESS;
510   Interface->Configured = FALSE;
511 
512   Interface->Controller = Controller;
513   Interface->Image      = ImageHandle;
514   Interface->Mnp        = Mnp;
515   Interface->Arp        = NULL;
516   Interface->ArpHandle  = NULL;
517 
518   InitializeListHead (&Interface->ArpQues);
519   InitializeListHead (&Interface->SentFrames);
520 
521   Interface->RecvRequest = NULL;
522 
523   //
524   // Get the interface's Mac address and broadcast mac address from SNP
525   //
526   if (EFI_ERROR (Mnp->GetModeData (Mnp, NULL, &SnpMode))) {
527     FreePool (Interface);
528     return NULL;
529   }
530 
531   CopyMem (&Interface->Mac, &SnpMode.CurrentAddress, sizeof (Interface->Mac));
532   CopyMem (&Interface->BroadcastMac, &SnpMode.BroadcastAddress, sizeof (Interface->BroadcastMac));
533   Interface->HwaddrLen    = SnpMode.HwAddressSize;
534 
535   InitializeListHead (&Interface->IpInstances);
536   Interface->PromiscRecv = FALSE;
537 
538   return Interface;
539 }
540 
541 
542 /**
543   Set the interface's address, create and configure
544   the ARP child if necessary.
545 
546   @param  Interface         The interface to set the address.
547   @param  IpAddr            The interface's IP address.
548   @param  SubnetMask        The interface's netmask.
549 
550   @retval EFI_SUCCESS           The interface is configured with Ip/netmask pair,
551                                 and a ARP is created for it.
552   @retval Others                Failed to set the interface's address.
553 
554 **/
555 EFI_STATUS
Ip4SetAddress(IN OUT IP4_INTERFACE * Interface,IN IP4_ADDR IpAddr,IN IP4_ADDR SubnetMask)556 Ip4SetAddress (
557   IN OUT IP4_INTERFACE      *Interface,
558   IN     IP4_ADDR           IpAddr,
559   IN     IP4_ADDR           SubnetMask
560   )
561 {
562   EFI_ARP_CONFIG_DATA       ArpConfig;
563   EFI_STATUS                Status;
564 
565   NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);
566 
567   //
568   // Set the ip/netmask, then compute the subnet broadcast
569   // and network broadcast for easy access. When computing
570   // network broadcast, the subnet mask is most like longer
571   // than the default netmask (not subneted) as defined in
572   // RFC793. If that isn't the case, we are aggregating the
573   // networks, use the subnet's mask instead.
574   //
575   Interface->Ip             = IpAddr;
576   Interface->SubnetMask     = SubnetMask;
577   Interface->SubnetBrdcast  = (IpAddr | ~SubnetMask);
578   Interface->NetBrdcast     = (IpAddr | ~SubnetMask);
579 
580   //
581   // Do clean up for Arp child
582   //
583   if (Interface->ArpHandle != NULL) {
584     if (Interface->Arp != NULL) {
585       gBS->CloseProtocol (
586              Interface->ArpHandle,
587              &gEfiArpProtocolGuid,
588              Interface->Image,
589              Interface->Controller
590              );
591 
592       Interface->Arp = NULL;
593     }
594 
595     NetLibDestroyServiceChild (
596       Interface->Controller,
597       Interface->Image,
598       &gEfiArpServiceBindingProtocolGuid,
599       Interface->ArpHandle
600       );
601 
602     Interface->ArpHandle = NULL;
603   }
604 
605   //
606   // If the address is NOT all zero, create then configure an ARP child.
607   // Pay attention: DHCP configures its station address as 0.0.0.0/0
608   //
609   if (IpAddr != IP4_ALLZERO_ADDRESS) {
610     Status = NetLibCreateServiceChild (
611                Interface->Controller,
612                Interface->Image,
613                &gEfiArpServiceBindingProtocolGuid,
614                &Interface->ArpHandle
615                );
616 
617     if (EFI_ERROR (Status)) {
618       return Status;
619     }
620 
621     Status = gBS->OpenProtocol (
622                     Interface->ArpHandle,
623                     &gEfiArpProtocolGuid,
624                     (VOID **) &Interface->Arp,
625                     Interface->Image,
626                     Interface->Controller,
627                     EFI_OPEN_PROTOCOL_BY_DRIVER
628                     );
629 
630     if (EFI_ERROR (Status)) {
631       goto ON_ERROR;
632     }
633 
634     IpAddr                    = HTONL (IpAddr);
635     ArpConfig.SwAddressType   = IP4_ETHER_PROTO;
636     ArpConfig.SwAddressLength = 4;
637     ArpConfig.StationAddress  = &IpAddr;
638     ArpConfig.EntryTimeOut    = 0;
639     ArpConfig.RetryCount      = 0;
640     ArpConfig.RetryTimeOut    = 0;
641 
642     Status = Interface->Arp->Configure (Interface->Arp, &ArpConfig);
643 
644     if (EFI_ERROR (Status)) {
645       gBS->CloseProtocol (
646              Interface->ArpHandle,
647              &gEfiArpProtocolGuid,
648              Interface->Image,
649              Interface->Controller
650              );
651 
652       goto ON_ERROR;
653     }
654   }
655 
656   Interface->Configured = TRUE;
657   return EFI_SUCCESS;
658 
659 ON_ERROR:
660   NetLibDestroyServiceChild (
661     Interface->Controller,
662     Interface->Image,
663     &gEfiArpServiceBindingProtocolGuid,
664     Interface->ArpHandle
665     );
666 
667   return Status;
668 }
669 
670 
671 /**
672   Filter function to cancel all the frame related to an IP instance.
673 
674   @param[in]  Frame             The transmit request to test whether to cancel
675   @param[in]  Context           The context which is the Ip instance that issued
676                                 the transmit.
677 
678   @retval TRUE                  The frame belongs to this instance and is to be
679                                 removed
680   @retval FALSE                 The frame doesn't belong to this instance.
681 
682 **/
683 BOOLEAN
Ip4CancelInstanceFrame(IN IP4_LINK_TX_TOKEN * Frame,IN VOID * Context)684 Ip4CancelInstanceFrame (
685   IN IP4_LINK_TX_TOKEN *Frame,
686   IN VOID              *Context
687   )
688 {
689   if (Frame->IpInstance == (IP4_PROTOCOL *) Context) {
690     return TRUE;
691   }
692 
693   return FALSE;
694 }
695 
696 
697 
698 /**
699   If there is a pending receive request, cancel it. Don't call
700   the receive request's callback because this function can be only
701   called if the instance or driver is tearing itself down. It
702   doesn't make sense to call it back. But it is necessary to call
703   the transmit token's callback to give it a chance to free the
704   packet and update the upper layer's transmit request status, say
705   that from the UDP.
706 
707   @param[in]  Interface         The interface used by the IpInstance
708 
709 **/
710 VOID
Ip4CancelReceive(IN IP4_INTERFACE * Interface)711 Ip4CancelReceive (
712   IN IP4_INTERFACE          *Interface
713   )
714 {
715   EFI_TPL                   OldTpl;
716   IP4_LINK_RX_TOKEN         *Token;
717 
718   if ((Token = Interface->RecvRequest) != NULL) {
719     OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
720 
721     Interface->RecvRequest = NULL;
722     Interface->Mnp->Cancel (Interface->Mnp, &Token->MnpToken);
723 
724     gBS->RestoreTPL (OldTpl);
725   }
726 }
727 
728 
729 /**
730   Free the interface used by IpInstance. All the IP instance with
731   the same Ip/Netmask pair share the same interface. It is reference
732   counted. All the frames haven't been sent will be cancelled.
733   Because the IpInstance is optional, the caller must remove
734   IpInstance from the interface's instance list itself.
735 
736   @param[in]  Interface         The interface used by the IpInstance.
737   @param[in]  IpInstance        The Ip instance that free the interface. NULL if
738                                 the Ip driver is releasing the default interface.
739 
740   @retval EFI_SUCCESS           The interface use IpInstance is freed.
741 
742 **/
743 EFI_STATUS
Ip4FreeInterface(IN IP4_INTERFACE * Interface,IN IP4_PROTOCOL * IpInstance OPTIONAL)744 Ip4FreeInterface (
745   IN  IP4_INTERFACE         *Interface,
746   IN  IP4_PROTOCOL          *IpInstance           OPTIONAL
747   )
748 {
749   NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);
750   ASSERT (Interface->RefCnt > 0);
751 
752   //
753   // Remove all the pending transmit token related to this IP instance.
754   //
755   Ip4CancelFrames (Interface, EFI_ABORTED, Ip4CancelInstanceFrame, IpInstance);
756 
757   if (--Interface->RefCnt > 0) {
758     return EFI_SUCCESS;
759   }
760 
761   //
762   // Destroy the interface if this is the last IP instance that
763   // has the address. Remove all the system transmitted packets
764   // from this interface, cancel the receive request if there is
765   // one, and destroy the ARP requests.
766   //
767   Ip4CancelFrames (Interface, EFI_ABORTED, Ip4CancelInstanceFrame, NULL);
768   Ip4CancelReceive (Interface);
769 
770   ASSERT (IsListEmpty (&Interface->IpInstances));
771   ASSERT (IsListEmpty (&Interface->ArpQues));
772   ASSERT (IsListEmpty (&Interface->SentFrames));
773 
774   if (Interface->Arp != NULL) {
775     gBS->CloseProtocol (
776           Interface->ArpHandle,
777           &gEfiArpProtocolGuid,
778           Interface->Image,
779           Interface->Controller
780           );
781 
782     NetLibDestroyServiceChild (
783       Interface->Controller,
784       Interface->Image,
785       &gEfiArpServiceBindingProtocolGuid,
786       Interface->ArpHandle
787       );
788   }
789 
790   RemoveEntryList (&Interface->Link);
791   FreePool (Interface);
792 
793   return EFI_SUCCESS;
794 }
795 
796 /**
797   This function tries to send all the queued frames in ArpQue to the default gateway if
798   the ARP resolve for direct destination address is failed when using /32 subnet mask.
799 
800   @param[in]   ArpQue           The ARP queue of a failed request.
801 
802   @retval EFI_SUCCESS           All the queued frames have been send to the default route.
803   @retval Others                Failed to send the queued frames.
804 
805 **/
806 EFI_STATUS
Ip4SendFrameToDefaultRoute(IN IP4_ARP_QUE * ArpQue)807 Ip4SendFrameToDefaultRoute (
808   IN  IP4_ARP_QUE               *ArpQue
809   )
810 {
811   LIST_ENTRY                *Entry;
812   LIST_ENTRY                *Next;
813   IP4_ROUTE_CACHE_ENTRY     *RtCacheEntry;
814   IP4_LINK_TX_TOKEN         *Token;
815   IP4_ADDR                  Gateway;
816   EFI_STATUS                Status;
817   IP4_ROUTE_ENTRY           *DefaultRoute;
818 
819   //
820   // ARP resolve failed when using /32 subnet mask.
821   //
822   NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {
823     RemoveEntryList (Entry);
824     Token = NET_LIST_USER_STRUCT (Entry, IP4_LINK_TX_TOKEN, Link);
825     ASSERT (Token->Interface->SubnetMask == IP4_ALLONE_ADDRESS);
826     //
827     // Find the default gateway IP address. The default route was saved to the RtCacheEntry->Tag in Ip4Route().
828     //
829     RtCacheEntry = NULL;
830     if (Token->IpInstance != NULL) {
831       RtCacheEntry = Ip4FindRouteCache (Token->IpInstance->RouteTable, NTOHL (ArpQue->Ip), Token->Interface->Ip);
832     }
833     if (RtCacheEntry == NULL) {
834       RtCacheEntry = Ip4FindRouteCache (Token->IpSb->DefaultRouteTable, NTOHL (ArpQue->Ip), Token->Interface->Ip);
835     }
836     if (RtCacheEntry == NULL) {
837       Status= EFI_NO_MAPPING;
838       goto ON_ERROR;
839     }
840     DefaultRoute = (IP4_ROUTE_ENTRY*)RtCacheEntry->Tag;
841     if (DefaultRoute == NULL) {
842       Status= EFI_NO_MAPPING;
843       goto ON_ERROR;
844     }
845     //
846     // Try to send the frame to the default route.
847     //
848     Gateway = DefaultRoute->NextHop;
849     if (ArpQue->Ip == Gateway) {
850       //
851       // ARP resolve for the default route is failed, return error to caller.
852       //
853       Status= EFI_NO_MAPPING;
854       goto ON_ERROR;
855     }
856     RtCacheEntry->NextHop = Gateway;
857     Status = Ip4SendFrame (Token->Interface,Token->IpInstance,Token->Packet,Gateway,Token->CallBack,Token->Context,Token->IpSb);
858     if (EFI_ERROR (Status)) {
859       Status= EFI_NO_MAPPING;
860       goto ON_ERROR;
861     }
862     Ip4FreeRouteCacheEntry (RtCacheEntry);
863   }
864 
865   return EFI_SUCCESS;
866 
867 ON_ERROR:
868   if (RtCacheEntry != NULL) {
869     Ip4FreeRouteCacheEntry (RtCacheEntry);
870   }
871   Token->CallBack (Token->IpInstance, Token->Packet, Status, 0, Token->Context);
872   Ip4FreeLinkTxToken (Token);
873   return Status;
874 }
875 
876 
877 /**
878   Callback function when ARP request are finished. It will cancel
879   all the queued frame if the ARP requests failed. Or transmit them
880   if the request succeed.
881 
882   @param[in]  Context           The context of the callback, a point to the ARP
883                                 queue
884 
885 **/
886 VOID
887 EFIAPI
Ip4OnArpResolvedDpc(IN VOID * Context)888 Ip4OnArpResolvedDpc (
889   IN VOID                   *Context
890   )
891 {
892   LIST_ENTRY                *Entry;
893   LIST_ENTRY                *Next;
894   IP4_ARP_QUE               *ArpQue;
895   IP4_INTERFACE             *Interface;
896   IP4_LINK_TX_TOKEN         *Token;
897   EFI_STATUS                Status;
898   EFI_STATUS                IoStatus;
899 
900   ArpQue = (IP4_ARP_QUE *) Context;
901   NET_CHECK_SIGNATURE (ArpQue, IP4_FRAME_ARP_SIGNATURE);
902 
903   RemoveEntryList (&ArpQue->Link);
904 
905   //
906   // ARP resolve failed for some reason.
907   //
908   if (NET_MAC_EQUAL (&ArpQue->Mac, &mZeroMacAddress, ArpQue->Interface->HwaddrLen)) {
909     if (ArpQue->Interface->SubnetMask != IP4_ALLONE_ADDRESS) {
910       //
911       // Release all the frame and ARP queue itself. Ip4FreeArpQue will call the frame's
912       // owner back.
913       //
914       IoStatus = EFI_NO_MAPPING;
915     } else {
916       //
917       // ARP resolve failed when using 32bit subnet mask, try to send the packets to the
918       // default route.
919       //
920       IoStatus = Ip4SendFrameToDefaultRoute (ArpQue);
921     }
922     goto ON_EXIT;
923   }
924 
925   //
926   // ARP resolve succeeded, Transmit all the frame. Release the ARP
927   // queue. It isn't necessary for us to cache the ARP binding because
928   // we always check the ARP cache first before transmit.
929   //
930   IoStatus = EFI_SUCCESS;
931   Interface = ArpQue->Interface;
932 
933   NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {
934     RemoveEntryList (Entry);
935 
936     Token         = NET_LIST_USER_STRUCT (Entry, IP4_LINK_TX_TOKEN, Link);
937     CopyMem (&Token->DstMac, &ArpQue->Mac, sizeof (Token->DstMac));
938 
939     //
940     // Insert the tx token before transmitting it via MNP as the FrameSentDpc
941     // may be called before Mnp->Transmit returns which will remove this tx
942     // token from the SentFrames list. Remove it from the list if the returned
943     // Status of Mnp->Transmit is not EFI_SUCCESS as in this case the
944     // FrameSentDpc won't be queued.
945     //
946     InsertTailList (&Interface->SentFrames, &Token->Link);
947 
948     Status = Interface->Mnp->Transmit (Interface->Mnp, &Token->MnpToken);
949     if (EFI_ERROR (Status)) {
950       RemoveEntryList (&Token->Link);
951       Token->CallBack (Token->IpInstance, Token->Packet, Status, 0, Token->Context);
952 
953       Ip4FreeLinkTxToken (Token);
954       continue;
955     }
956   }
957 
958 ON_EXIT:
959   Ip4FreeArpQue (ArpQue, IoStatus);
960 }
961 
962 /**
963   Request Ip4OnArpResolvedDpc as a DPC at TPL_CALLBACK.
964 
965   @param  Event             The Arp request event.
966   @param  Context           The context of the callback, a point to the ARP
967                             queue.
968 
969 **/
970 VOID
971 EFIAPI
Ip4OnArpResolved(IN EFI_EVENT Event,IN VOID * Context)972 Ip4OnArpResolved (
973   IN EFI_EVENT              Event,
974   IN VOID                   *Context
975   )
976 {
977   //
978   // Request Ip4OnArpResolvedDpc as a DPC at TPL_CALLBACK
979   //
980   QueueDpc (TPL_CALLBACK, Ip4OnArpResolvedDpc, Context);
981 }
982 
983 
984 
985 /**
986   Callback function when frame transmission is finished. It will
987   call the frame owner's callback function to tell it the result.
988 
989   @param[in]  Context            Context which is point to the token.
990 
991 **/
992 VOID
993 EFIAPI
Ip4OnFrameSentDpc(IN VOID * Context)994 Ip4OnFrameSentDpc (
995   IN VOID                    *Context
996   )
997 {
998   IP4_LINK_TX_TOKEN         *Token;
999 
1000   Token = (IP4_LINK_TX_TOKEN *) Context;
1001   NET_CHECK_SIGNATURE (Token, IP4_FRAME_TX_SIGNATURE);
1002 
1003   RemoveEntryList (&Token->Link);
1004 
1005   Token->CallBack (
1006           Token->IpInstance,
1007           Token->Packet,
1008           Token->MnpToken.Status,
1009           0,
1010           Token->Context
1011           );
1012 
1013   Ip4FreeLinkTxToken (Token);
1014 }
1015 
1016 /**
1017   Request Ip4OnFrameSentDpc as a DPC at TPL_CALLBACK.
1018 
1019   @param[in]  Event              The transmit token's event.
1020   @param[in]  Context            Context which is point to the token.
1021 
1022 **/
1023 VOID
1024 EFIAPI
Ip4OnFrameSent(IN EFI_EVENT Event,IN VOID * Context)1025 Ip4OnFrameSent (
1026   IN EFI_EVENT               Event,
1027   IN VOID                    *Context
1028   )
1029 {
1030   //
1031   // Request Ip4OnFrameSentDpc as a DPC at TPL_CALLBACK
1032   //
1033   QueueDpc (TPL_CALLBACK, Ip4OnFrameSentDpc, Context);
1034 }
1035 
1036 
1037 
1038 /**
1039   Send a frame from the interface. If the next hop is broadcast or
1040   multicast address, it is transmitted immediately. If the next hop
1041   is a unicast, it will consult ARP to resolve the NextHop's MAC.
1042   If some error happened, the CallBack won't be called. So, the caller
1043   must test the return value, and take action when there is an error.
1044 
1045   @param[in]  Interface         The interface to send the frame from
1046   @param[in]  IpInstance        The IP child that request the transmission.  NULL
1047                                 if it is the IP4 driver itself.
1048   @param[in]  Packet            The packet to transmit.
1049   @param[in]  NextHop           The immediate destination to transmit the packet
1050                                 to.
1051   @param[in]  CallBack          Function to call back when transmit finished.
1052   @param[in]  Context           Opaque parameter to the call back.
1053   @param[in]  IpSb              The pointer to the IP4 service binding instance.
1054 
1055   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource to send the frame
1056   @retval EFI_NO_MAPPING        Can't resolve the MAC for the nexthop
1057   @retval EFI_SUCCESS           The packet is successfully transmitted.
1058   @retval other                 Other error occurs.
1059 
1060 **/
1061 EFI_STATUS
Ip4SendFrame(IN IP4_INTERFACE * Interface,IN IP4_PROTOCOL * IpInstance OPTIONAL,IN NET_BUF * Packet,IN IP4_ADDR NextHop,IN IP4_FRAME_CALLBACK CallBack,IN VOID * Context,IN IP4_SERVICE * IpSb)1062 Ip4SendFrame (
1063   IN  IP4_INTERFACE         *Interface,
1064   IN  IP4_PROTOCOL          *IpInstance       OPTIONAL,
1065   IN  NET_BUF               *Packet,
1066   IN  IP4_ADDR              NextHop,
1067   IN  IP4_FRAME_CALLBACK    CallBack,
1068   IN  VOID                  *Context,
1069   IN IP4_SERVICE            *IpSb
1070   )
1071 {
1072   IP4_LINK_TX_TOKEN         *Token;
1073   LIST_ENTRY                *Entry;
1074   IP4_ARP_QUE               *ArpQue;
1075   EFI_ARP_PROTOCOL          *Arp;
1076   EFI_STATUS                Status;
1077 
1078   ASSERT (Interface->Configured);
1079 
1080   Token = Ip4WrapLinkTxToken (Interface, IpInstance, Packet, CallBack, Context, IpSb);
1081 
1082   if (Token == NULL) {
1083     return EFI_OUT_OF_RESOURCES;
1084   }
1085 
1086   //
1087   // Get the destination MAC address for multicast and broadcasts.
1088   // Don't depend on ARP to solve the address since there maybe no
1089   // ARP at all. Ip4Output has set NextHop to 255.255.255.255 for
1090   // all the broadcasts.
1091   //
1092   if (NextHop == IP4_ALLONE_ADDRESS) {
1093     CopyMem (&Token->DstMac, &Interface->BroadcastMac, sizeof (Token->DstMac));
1094     goto SEND_NOW;
1095 
1096   } else if (IP4_IS_MULTICAST (NextHop)) {
1097 
1098     Status = Ip4GetMulticastMac (Interface->Mnp, NextHop, &Token->DstMac);
1099 
1100     if (EFI_ERROR (Status)) {
1101       goto ON_ERROR;
1102     }
1103 
1104     goto SEND_NOW;
1105   }
1106 
1107   //
1108   // Can only send out multicast/broadcast if the IP address is zero
1109   //
1110   if ((Arp = Interface->Arp) == NULL) {
1111     Status = EFI_NO_MAPPING;
1112     goto ON_ERROR;
1113   }
1114 
1115   //
1116   // First check whether this binding is in the ARP cache.
1117   //
1118   NextHop = HTONL (NextHop);
1119   Status  = Arp->Request (Arp, &NextHop, NULL, &Token->DstMac);
1120 
1121   if (Status == EFI_SUCCESS) {
1122     goto SEND_NOW;
1123 
1124   } else if (Status != EFI_NOT_READY) {
1125     goto ON_ERROR;
1126   }
1127 
1128   //
1129   // Have to do asynchronous ARP resolution. First check
1130   // whether there is already a pending request.
1131   //
1132   ArpQue = NULL;
1133 
1134   NET_LIST_FOR_EACH (Entry, &Interface->ArpQues) {
1135     ArpQue = NET_LIST_USER_STRUCT (Entry, IP4_ARP_QUE, Link);
1136 
1137     if (ArpQue->Ip == NextHop) {
1138       break;
1139     }
1140   }
1141 
1142   //
1143   // Found a pending ARP request, enqueue the frame then return
1144   //
1145   if (Entry != &Interface->ArpQues) {
1146     InsertTailList (&ArpQue->Frames, &Token->Link);
1147     return EFI_SUCCESS;
1148   }
1149 
1150   //
1151   // First frame to NextHop, issue an asynchronous ARP requests
1152   //
1153   ArpQue = Ip4CreateArpQue (Interface, NextHop);
1154 
1155   if (ArpQue == NULL) {
1156     Status = EFI_OUT_OF_RESOURCES;
1157     goto ON_ERROR;
1158   }
1159 
1160   Status = Arp->Request (Arp, &ArpQue->Ip, ArpQue->OnResolved, ArpQue->Mac.Addr);
1161 
1162   if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {
1163     Ip4FreeArpQue (ArpQue, EFI_NO_MAPPING);
1164     goto ON_ERROR;
1165   }
1166 
1167   InsertHeadList (&ArpQue->Frames, &Token->Link);
1168   InsertHeadList (&Interface->ArpQues, &ArpQue->Link);
1169   return EFI_SUCCESS;
1170 
1171 SEND_NOW:
1172   //
1173   // Insert the tx token into the SentFrames list before calling Mnp->Transmit.
1174   // Remove it if the returned status is not EFI_SUCCESS.
1175   //
1176   InsertTailList (&Interface->SentFrames, &Token->Link);
1177   Status = Interface->Mnp->Transmit (Interface->Mnp, &Token->MnpToken);
1178   if (EFI_ERROR (Status)) {
1179     RemoveEntryList (&Token->Link);
1180     goto ON_ERROR;
1181   }
1182 
1183   return EFI_SUCCESS;
1184 
1185 ON_ERROR:
1186   Ip4FreeLinkTxToken (Token);
1187   return Status;
1188 }
1189 
1190 
1191 /**
1192   Call back function when the received packet is freed.
1193   Check Ip4OnFrameReceived for information.
1194 
1195   @param  Context          Context, which is the IP4_LINK_RX_TOKEN.
1196 
1197 **/
1198 VOID
1199 EFIAPI
Ip4RecycleFrame(IN VOID * Context)1200 Ip4RecycleFrame (
1201   IN VOID                   *Context
1202   )
1203 {
1204   IP4_LINK_RX_TOKEN         *Frame;
1205 
1206   Frame = (IP4_LINK_RX_TOKEN *) Context;
1207   NET_CHECK_SIGNATURE (Frame, IP4_FRAME_RX_SIGNATURE);
1208 
1209   gBS->SignalEvent (Frame->MnpToken.Packet.RxData->RecycleEvent);
1210   Ip4FreeFrameRxToken (Frame);
1211 }
1212 
1213 
1214 /**
1215   Received a frame from MNP, wrap it in net buffer then deliver
1216   it to IP's input function. The ownship of the packet also
1217   transferred to IP. When Ip is finished with this packet, it
1218   will call NetbufFree to release the packet, NetbufFree will
1219   again call the Ip4RecycleFrame to signal MNP's event and free
1220   the token used.
1221 
1222   @param  Context               Context for the callback.
1223 
1224 **/
1225 VOID
1226 EFIAPI
Ip4OnFrameReceivedDpc(IN VOID * Context)1227 Ip4OnFrameReceivedDpc (
1228   IN VOID                     *Context
1229   )
1230 {
1231   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *MnpToken;
1232   EFI_MANAGED_NETWORK_RECEIVE_DATA      *MnpRxData;
1233   IP4_LINK_RX_TOKEN                     *Token;
1234   NET_FRAGMENT                          Netfrag;
1235   NET_BUF                               *Packet;
1236   UINT32                                Flag;
1237 
1238   Token = (IP4_LINK_RX_TOKEN *) Context;
1239   NET_CHECK_SIGNATURE (Token, IP4_FRAME_RX_SIGNATURE);
1240 
1241   //
1242   // First clear the interface's receive request in case the
1243   // caller wants to call Ip4ReceiveFrame in the callback.
1244   //
1245   Token->Interface->RecvRequest = NULL;
1246 
1247   MnpToken  = &Token->MnpToken;
1248   MnpRxData = MnpToken->Packet.RxData;
1249 
1250   if (EFI_ERROR (MnpToken->Status) || (MnpRxData == NULL)) {
1251     Token->CallBack (Token->IpInstance, NULL, MnpToken->Status, 0, Token->Context);
1252     Ip4FreeFrameRxToken (Token);
1253 
1254     return ;
1255   }
1256 
1257   //
1258   // Wrap the frame in a net buffer then deliver it to IP input.
1259   // IP will reassemble the packet, and deliver it to upper layer
1260   //
1261   Netfrag.Len  = MnpRxData->DataLength;
1262   Netfrag.Bulk = MnpRxData->PacketData;
1263 
1264   Packet = NetbufFromExt (&Netfrag, 1, 0, IP4_MAX_HEADLEN, Ip4RecycleFrame, Token);
1265 
1266   if (Packet == NULL) {
1267     gBS->SignalEvent (MnpRxData->RecycleEvent);
1268 
1269     Token->CallBack (Token->IpInstance, NULL, EFI_OUT_OF_RESOURCES, 0, Token->Context);
1270     Ip4FreeFrameRxToken (Token);
1271 
1272     return ;
1273   }
1274 
1275   Flag  = (MnpRxData->BroadcastFlag ? IP4_LINK_BROADCAST : 0);
1276   Flag |= (MnpRxData->MulticastFlag ? IP4_LINK_MULTICAST : 0);
1277   Flag |= (MnpRxData->PromiscuousFlag ? IP4_LINK_PROMISC : 0);
1278 
1279   Token->CallBack (Token->IpInstance, Packet, EFI_SUCCESS, Flag, Token->Context);
1280 }
1281 
1282 /**
1283   Request Ip4OnFrameReceivedDpc as a DPC at TPL_CALLBACK.
1284 
1285   @param Event      The receive event delivered to MNP for receive.
1286   @param Context    Context for the callback.
1287 
1288 **/
1289 VOID
1290 EFIAPI
Ip4OnFrameReceived(IN EFI_EVENT Event,IN VOID * Context)1291 Ip4OnFrameReceived (
1292   IN EFI_EVENT                Event,
1293   IN VOID                     *Context
1294   )
1295 {
1296   //
1297   // Request Ip4OnFrameReceivedDpc as a DPC at TPL_CALLBACK
1298   //
1299   QueueDpc (TPL_CALLBACK, Ip4OnFrameReceivedDpc, Context);
1300 }
1301 
1302 
1303 /**
1304   Request to receive the packet from the interface.
1305 
1306   @param[in]  Interface         The interface to receive the frames from.
1307   @param[in]  IpInstance        The instance that requests the receive. NULL for
1308                                 the driver itself.
1309   @param[in]  CallBack          Function to call when receive finished.
1310   @param[in]  Context           Opaque parameter to the callback.
1311 
1312   @retval EFI_ALREADY_STARTED   There is already a pending receive request.
1313   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource to receive.
1314   @retval EFI_SUCCESS           The receive request has been started.
1315   @retval other                 Other error occurs.
1316 
1317 **/
1318 EFI_STATUS
Ip4ReceiveFrame(IN IP4_INTERFACE * Interface,IN IP4_PROTOCOL * IpInstance OPTIONAL,IN IP4_FRAME_CALLBACK CallBack,IN VOID * Context)1319 Ip4ReceiveFrame (
1320   IN  IP4_INTERFACE         *Interface,
1321   IN  IP4_PROTOCOL          *IpInstance       OPTIONAL,
1322   IN  IP4_FRAME_CALLBACK    CallBack,
1323   IN  VOID                  *Context
1324   )
1325 {
1326   IP4_LINK_RX_TOKEN *Token;
1327   EFI_STATUS        Status;
1328 
1329   NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);
1330 
1331   if (Interface->RecvRequest != NULL) {
1332     return EFI_ALREADY_STARTED;
1333   }
1334 
1335   Token = Ip4CreateLinkRxToken (Interface, IpInstance, CallBack, Context);
1336 
1337   if (Token == NULL) {
1338     return EFI_OUT_OF_RESOURCES;
1339   }
1340 
1341   Interface->RecvRequest = Token;
1342   Status = Interface->Mnp->Receive (Interface->Mnp, &Token->MnpToken);
1343   if (EFI_ERROR (Status)) {
1344     Interface->RecvRequest = NULL;
1345     Ip4FreeFrameRxToken (Token);
1346     return Status;
1347   }
1348   return EFI_SUCCESS;
1349 }
1350