1 /** @file
2   Implement IP4 pesudo 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 whethter the ARP
13 // resolve succeeded. Failed ARP requests zero the MAC address buffer.
14 //
15 EFI_MAC_ADDRESS  mZeroMacAddress;
16 
17 /**
18   Callback funtion 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   Interface = AllocatePool (sizeof (IP4_INTERFACE));
495 
496   if ((Interface == NULL) || (Mnp == NULL)) {
497     return NULL;
498   }
499 
500   Interface->Signature = IP4_INTERFACE_SIGNATURE;
501   InitializeListHead (&Interface->Link);
502   Interface->RefCnt     = 1;
503 
504   Interface->Ip         = IP4_ALLZERO_ADDRESS;
505   Interface->SubnetMask = IP4_ALLZERO_ADDRESS;
506   Interface->Configured = FALSE;
507 
508   Interface->Controller = Controller;
509   Interface->Image      = ImageHandle;
510   Interface->Mnp        = Mnp;
511   Interface->Arp        = NULL;
512   Interface->ArpHandle  = NULL;
513 
514   InitializeListHead (&Interface->ArpQues);
515   InitializeListHead (&Interface->SentFrames);
516 
517   Interface->RecvRequest = NULL;
518 
519   //
520   // Get the interface's Mac address and broadcast mac address from SNP
521   //
522   if (EFI_ERROR (Mnp->GetModeData (Mnp, NULL, &SnpMode))) {
523     FreePool (Interface);
524     return NULL;
525   }
526 
527   CopyMem (&Interface->Mac, &SnpMode.CurrentAddress, sizeof (Interface->Mac));
528   CopyMem (&Interface->BroadcastMac, &SnpMode.BroadcastAddress, sizeof (Interface->BroadcastMac));
529   Interface->HwaddrLen    = SnpMode.HwAddressSize;
530 
531   InitializeListHead (&Interface->IpInstances);
532   Interface->PromiscRecv = FALSE;
533 
534   return Interface;
535 }
536 
537 
538 /**
539   Set the interface's address, create and configure
540   the ARP child if necessary.
541 
542   @param  Interface         The interface to set the address.
543   @param  IpAddr            The interface's IP address.
544   @param  SubnetMask        The interface's netmask.
545 
546   @retval EFI_SUCCESS           The interface is configured with Ip/netmask pair,
547                                 and a ARP is created for it.
548   @retval Others                Failed to set the interface's address.
549 
550 **/
551 EFI_STATUS
Ip4SetAddress(IN OUT IP4_INTERFACE * Interface,IN IP4_ADDR IpAddr,IN IP4_ADDR SubnetMask)552 Ip4SetAddress (
553   IN OUT IP4_INTERFACE      *Interface,
554   IN     IP4_ADDR           IpAddr,
555   IN     IP4_ADDR           SubnetMask
556   )
557 {
558   EFI_ARP_CONFIG_DATA       ArpConfig;
559   EFI_STATUS                Status;
560 
561   NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);
562 
563   //
564   // Set the ip/netmask, then compute the subnet broadcast
565   // and network broadcast for easy access. When computing
566   // nework broadcast, the subnet mask is most like longer
567   // than the default netmask (not subneted) as defined in
568   // RFC793. If that isn't the case, we are aggregating the
569   // networks, use the subnet's mask instead.
570   //
571   Interface->Ip             = IpAddr;
572   Interface->SubnetMask     = SubnetMask;
573   Interface->SubnetBrdcast  = (IpAddr | ~SubnetMask);
574   Interface->NetBrdcast     = (IpAddr | ~SubnetMask);
575 
576   //
577   // Do clean up for Arp child
578   //
579   if (Interface->ArpHandle != NULL) {
580     if (Interface->Arp != NULL) {
581       gBS->CloseProtocol (
582              Interface->ArpHandle,
583              &gEfiArpProtocolGuid,
584              Interface->Image,
585              Interface->Controller
586              );
587 
588       Interface->Arp = NULL;
589     }
590 
591     NetLibDestroyServiceChild (
592       Interface->Controller,
593       Interface->Image,
594       &gEfiArpServiceBindingProtocolGuid,
595       &Interface->ArpHandle
596       );
597 
598     Interface->ArpHandle = NULL;
599   }
600 
601   //
602   // If the address is NOT all zero, create then configure an ARP child.
603   // Pay attention: DHCP configures its station address as 0.0.0.0/0
604   //
605   if (IpAddr != IP4_ALLZERO_ADDRESS) {
606     Status = NetLibCreateServiceChild (
607                Interface->Controller,
608                Interface->Image,
609                &gEfiArpServiceBindingProtocolGuid,
610                &Interface->ArpHandle
611                );
612 
613     if (EFI_ERROR (Status)) {
614       return Status;
615     }
616 
617     Status = gBS->OpenProtocol (
618                     Interface->ArpHandle,
619                     &gEfiArpProtocolGuid,
620                     (VOID **) &Interface->Arp,
621                     Interface->Image,
622                     Interface->Controller,
623                     EFI_OPEN_PROTOCOL_BY_DRIVER
624                     );
625 
626     if (EFI_ERROR (Status)) {
627       goto ON_ERROR;
628     }
629 
630     IpAddr                    = HTONL (IpAddr);
631     ArpConfig.SwAddressType   = IP4_ETHER_PROTO;
632     ArpConfig.SwAddressLength = 4;
633     ArpConfig.StationAddress  = &IpAddr;
634     ArpConfig.EntryTimeOut    = 0;
635     ArpConfig.RetryCount      = 0;
636     ArpConfig.RetryTimeOut    = 0;
637 
638     Status = Interface->Arp->Configure (Interface->Arp, &ArpConfig);
639 
640     if (EFI_ERROR (Status)) {
641       gBS->CloseProtocol (
642              Interface->ArpHandle,
643              &gEfiArpProtocolGuid,
644              Interface->Image,
645              Interface->Controller
646              );
647 
648       goto ON_ERROR;
649     }
650   }
651 
652   Interface->Configured = TRUE;
653   return EFI_SUCCESS;
654 
655 ON_ERROR:
656   NetLibDestroyServiceChild (
657     Interface->Controller,
658     Interface->Image,
659     &gEfiArpServiceBindingProtocolGuid,
660     &Interface->ArpHandle
661     );
662 
663   return Status;
664 }
665 
666 
667 /**
668   Filter function to cancel all the frame related to an IP instance.
669 
670   @param[in]  Frame             The transmit request to test whether to cancel
671   @param[in]  Context           The context which is the Ip instance that issued
672                                 the transmit.
673 
674   @retval TRUE                  The frame belongs to this instance and is to be
675                                 removed
676   @retval FALSE                 The frame doesn't belong to this instance.
677 
678 **/
679 BOOLEAN
Ip4CancelInstanceFrame(IN IP4_LINK_TX_TOKEN * Frame,IN VOID * Context)680 Ip4CancelInstanceFrame (
681   IN IP4_LINK_TX_TOKEN *Frame,
682   IN VOID              *Context
683   )
684 {
685   if (Frame->IpInstance == (IP4_PROTOCOL *) Context) {
686     return TRUE;
687   }
688 
689   return FALSE;
690 }
691 
692 
693 
694 /**
695   If there is a pending receive request, cancel it. Don't call
696   the receive request's callback because this function can be only
697   called if the instance or driver is tearing itself down. It
698   doesn't make sense to call it back. But it is necessary to call
699   the transmit token's callback to give it a chance to free the
700   packet and update the upper layer's transmit request status, say
701   that from the UDP.
702 
703   @param[in]  Interface         The interface used by the IpInstance
704 
705 **/
706 VOID
Ip4CancelReceive(IN IP4_INTERFACE * Interface)707 Ip4CancelReceive (
708   IN IP4_INTERFACE          *Interface
709   )
710 {
711   EFI_TPL                   OldTpl;
712   IP4_LINK_RX_TOKEN         *Token;
713 
714   if ((Token = Interface->RecvRequest) != NULL) {
715     OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
716 
717     Interface->RecvRequest = NULL;
718     Interface->Mnp->Cancel (Interface->Mnp, &Token->MnpToken);
719 
720     gBS->RestoreTPL (OldTpl);
721   }
722 }
723 
724 
725 /**
726   Free the interface used by IpInstance. All the IP instance with
727   the same Ip/Netmask pair share the same interface. It is reference
728   counted. All the frames haven't been sent will be cancelled.
729   Because the IpInstance is optional, the caller must remove
730   IpInstance from the interface's instance list itself.
731 
732   @param[in]  Interface         The interface used by the IpInstance.
733   @param[in]  IpInstance        The Ip instance that free the interface. NULL if
734                                 the Ip driver is releasing the default interface.
735 
736   @retval EFI_SUCCESS           The interface use IpInstance is freed.
737 
738 **/
739 EFI_STATUS
Ip4FreeInterface(IN IP4_INTERFACE * Interface,IN IP4_PROTOCOL * IpInstance OPTIONAL)740 Ip4FreeInterface (
741   IN  IP4_INTERFACE         *Interface,
742   IN  IP4_PROTOCOL          *IpInstance           OPTIONAL
743   )
744 {
745   NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);
746   ASSERT (Interface->RefCnt > 0);
747 
748   //
749   // Remove all the pending transmit token related to this IP instance.
750   //
751   Ip4CancelFrames (Interface, EFI_ABORTED, Ip4CancelInstanceFrame, IpInstance);
752 
753   if (--Interface->RefCnt > 0) {
754     return EFI_SUCCESS;
755   }
756 
757   //
758   // Destroy the interface if this is the last IP instance that
759   // has the address. Remove all the system transmitted packets
760   // from this interface, cancel the receive request if there is
761   // one, and destroy the ARP requests.
762   //
763   Ip4CancelFrames (Interface, EFI_ABORTED, Ip4CancelInstanceFrame, NULL);
764   Ip4CancelReceive (Interface);
765 
766   ASSERT (IsListEmpty (&Interface->IpInstances));
767   ASSERT (IsListEmpty (&Interface->ArpQues));
768   ASSERT (IsListEmpty (&Interface->SentFrames));
769 
770   if (Interface->Arp != NULL) {
771     gBS->CloseProtocol (
772           Interface->ArpHandle,
773           &gEfiArpProtocolGuid,
774           Interface->Image,
775           Interface->Controller
776           );
777 
778     NetLibDestroyServiceChild (
779       Interface->Controller,
780       Interface->Image,
781       &gEfiArpServiceBindingProtocolGuid,
782       Interface->ArpHandle
783       );
784   }
785 
786   RemoveEntryList (&Interface->Link);
787   FreePool (Interface);
788 
789   return EFI_SUCCESS;
790 }
791 
792 /**
793   This function tries to send all the queued frames in ArpQue to the default gateway if
794   the ARP resolve for direct destination address is failed when using /32 subnet mask.
795 
796   @param[in]   ArpQue           The ARP queue of a failed request.
797 
798   @retval EFI_SUCCESS           All the queued frames have been send to the default route.
799   @retval Others                Failed to send the queued frames.
800 
801 **/
802 EFI_STATUS
Ip4SendFrameToDefaultRoute(IN IP4_ARP_QUE * ArpQue)803 Ip4SendFrameToDefaultRoute (
804   IN  IP4_ARP_QUE               *ArpQue
805   )
806 {
807   LIST_ENTRY                *Entry;
808   LIST_ENTRY                *Next;
809   IP4_ROUTE_CACHE_ENTRY     *RtCacheEntry;
810   IP4_LINK_TX_TOKEN         *Token;
811   IP4_ADDR                  Gateway;
812   EFI_STATUS                Status;
813   IP4_ROUTE_ENTRY           *DefaultRoute;
814 
815   //
816   // ARP resolve failed when using /32 subnet mask.
817   //
818   NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {
819     RemoveEntryList (Entry);
820     Token = NET_LIST_USER_STRUCT (Entry, IP4_LINK_TX_TOKEN, Link);
821     ASSERT (Token->Interface->SubnetMask == IP4_ALLONE_ADDRESS);
822     //
823     // Find the default gateway IP address. The default route was saved to the RtCacheEntry->Tag in Ip4Route().
824     //
825     RtCacheEntry = NULL;
826     if (Token->IpInstance != NULL) {
827       RtCacheEntry = Ip4FindRouteCache (Token->IpInstance->RouteTable, NTOHL (ArpQue->Ip), Token->Interface->Ip);
828     }
829     if (RtCacheEntry == NULL) {
830       RtCacheEntry = Ip4FindRouteCache (Token->IpSb->DefaultRouteTable, NTOHL (ArpQue->Ip), Token->Interface->Ip);
831     }
832     if (RtCacheEntry == NULL) {
833       Status= EFI_NO_MAPPING;
834       goto ON_ERROR;
835     }
836     DefaultRoute = (IP4_ROUTE_ENTRY*)RtCacheEntry->Tag;
837     if (DefaultRoute == NULL) {
838       Status= EFI_NO_MAPPING;
839       goto ON_ERROR;
840     }
841     //
842     // Try to send the frame to the default route.
843     //
844     Gateway = DefaultRoute->NextHop;
845     if (ArpQue->Ip == Gateway) {
846       //
847       // ARP resolve for the default route is failed, return error to caller.
848       //
849       Status= EFI_NO_MAPPING;
850       goto ON_ERROR;
851     }
852     RtCacheEntry->NextHop = Gateway;
853     Status = Ip4SendFrame (Token->Interface,Token->IpInstance,Token->Packet,Gateway,Token->CallBack,Token->Context,Token->IpSb);
854     if (EFI_ERROR (Status)) {
855       Status= EFI_NO_MAPPING;
856       goto ON_ERROR;
857     }
858     Ip4FreeRouteCacheEntry (RtCacheEntry);
859   }
860 
861   return EFI_SUCCESS;
862 
863 ON_ERROR:
864   if (RtCacheEntry != NULL) {
865     Ip4FreeRouteCacheEntry (RtCacheEntry);
866   }
867   Token->CallBack (Token->IpInstance, Token->Packet, Status, 0, Token->Context);
868   Ip4FreeLinkTxToken (Token);
869   return Status;
870 }
871 
872 
873 /**
874   Callback function when ARP request are finished. It will cancel
875   all the queued frame if the ARP requests failed. Or transmit them
876   if the request succeed.
877 
878   @param[in]  Context           The context of the callback, a point to the ARP
879                                 queue
880 
881 **/
882 VOID
883 EFIAPI
Ip4OnArpResolvedDpc(IN VOID * Context)884 Ip4OnArpResolvedDpc (
885   IN VOID                   *Context
886   )
887 {
888   LIST_ENTRY                *Entry;
889   LIST_ENTRY                *Next;
890   IP4_ARP_QUE               *ArpQue;
891   IP4_INTERFACE             *Interface;
892   IP4_LINK_TX_TOKEN         *Token;
893   EFI_STATUS                Status;
894   EFI_STATUS                IoStatus;
895 
896   ArpQue = (IP4_ARP_QUE *) Context;
897   NET_CHECK_SIGNATURE (ArpQue, IP4_FRAME_ARP_SIGNATURE);
898 
899   RemoveEntryList (&ArpQue->Link);
900 
901   //
902   // ARP resolve failed for some reason.
903   //
904   if (NET_MAC_EQUAL (&ArpQue->Mac, &mZeroMacAddress, ArpQue->Interface->HwaddrLen)) {
905     if (ArpQue->Interface->SubnetMask != IP4_ALLONE_ADDRESS) {
906       //
907       // Release all the frame and ARP queue itself. Ip4FreeArpQue will call the frame's
908       // owner back.
909       //
910       IoStatus = EFI_NO_MAPPING;
911     } else {
912       //
913       // ARP resolve failed when using 32bit subnet mask, try to send the packets to the
914       // default route.
915       //
916       IoStatus = Ip4SendFrameToDefaultRoute (ArpQue);
917     }
918     goto ON_EXIT;
919   }
920 
921   //
922   // ARP resolve succeeded, Transmit all the frame. Release the ARP
923   // queue. It isn't necessary for us to cache the ARP binding because
924   // we always check the ARP cache first before transmit.
925   //
926   IoStatus = EFI_SUCCESS;
927   Interface = ArpQue->Interface;
928 
929   NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {
930     RemoveEntryList (Entry);
931 
932     Token         = NET_LIST_USER_STRUCT (Entry, IP4_LINK_TX_TOKEN, Link);
933     CopyMem (&Token->DstMac, &ArpQue->Mac, sizeof (Token->DstMac));
934 
935     //
936     // Insert the tx token before transmitting it via MNP as the FrameSentDpc
937     // may be called before Mnp->Transmit returns which will remove this tx
938     // token from the SentFrames list. Remove it from the list if the returned
939     // Status of Mnp->Transmit is not EFI_SUCCESS as in this case the
940     // FrameSentDpc won't be queued.
941     //
942     InsertTailList (&Interface->SentFrames, &Token->Link);
943 
944     Status = Interface->Mnp->Transmit (Interface->Mnp, &Token->MnpToken);
945     if (EFI_ERROR (Status)) {
946       RemoveEntryList (&Token->Link);
947       Token->CallBack (Token->IpInstance, Token->Packet, Status, 0, Token->Context);
948 
949       Ip4FreeLinkTxToken (Token);
950       continue;
951     }
952   }
953 
954 ON_EXIT:
955   Ip4FreeArpQue (ArpQue, IoStatus);
956 }
957 
958 /**
959   Request Ip4OnArpResolvedDpc as a DPC at TPL_CALLBACK.
960 
961   @param  Event             The Arp request event.
962   @param  Context           The context of the callback, a point to the ARP
963                             queue.
964 
965 **/
966 VOID
967 EFIAPI
Ip4OnArpResolved(IN EFI_EVENT Event,IN VOID * Context)968 Ip4OnArpResolved (
969   IN EFI_EVENT              Event,
970   IN VOID                   *Context
971   )
972 {
973   //
974   // Request Ip4OnArpResolvedDpc as a DPC at TPL_CALLBACK
975   //
976   QueueDpc (TPL_CALLBACK, Ip4OnArpResolvedDpc, Context);
977 }
978 
979 
980 
981 /**
982   Callback funtion when frame transmission is finished. It will
983   call the frame owner's callback function to tell it the result.
984 
985   @param[in]  Context            Context which is point to the token.
986 
987 **/
988 VOID
989 EFIAPI
Ip4OnFrameSentDpc(IN VOID * Context)990 Ip4OnFrameSentDpc (
991   IN VOID                    *Context
992   )
993 {
994   IP4_LINK_TX_TOKEN         *Token;
995 
996   Token = (IP4_LINK_TX_TOKEN *) Context;
997   NET_CHECK_SIGNATURE (Token, IP4_FRAME_TX_SIGNATURE);
998 
999   RemoveEntryList (&Token->Link);
1000 
1001   Token->CallBack (
1002           Token->IpInstance,
1003           Token->Packet,
1004           Token->MnpToken.Status,
1005           0,
1006           Token->Context
1007           );
1008 
1009   Ip4FreeLinkTxToken (Token);
1010 }
1011 
1012 /**
1013   Request Ip4OnFrameSentDpc as a DPC at TPL_CALLBACK.
1014 
1015   @param[in]  Event              The transmit token's event.
1016   @param[in]  Context            Context which is point to the token.
1017 
1018 **/
1019 VOID
1020 EFIAPI
Ip4OnFrameSent(IN EFI_EVENT Event,IN VOID * Context)1021 Ip4OnFrameSent (
1022   IN EFI_EVENT               Event,
1023   IN VOID                    *Context
1024   )
1025 {
1026   //
1027   // Request Ip4OnFrameSentDpc as a DPC at TPL_CALLBACK
1028   //
1029   QueueDpc (TPL_CALLBACK, Ip4OnFrameSentDpc, Context);
1030 }
1031 
1032 
1033 
1034 /**
1035   Send a frame from the interface. If the next hop is broadcast or
1036   multicast address, it is transmitted immediately. If the next hop
1037   is a unicast, it will consult ARP to resolve the NextHop's MAC.
1038   If some error happened, the CallBack won't be called. So, the caller
1039   must test the return value, and take action when there is an error.
1040 
1041   @param[in]  Interface         The interface to send the frame from
1042   @param[in]  IpInstance        The IP child that request the transmission.  NULL
1043                                 if it is the IP4 driver itself.
1044   @param[in]  Packet            The packet to transmit.
1045   @param[in]  NextHop           The immediate destination to transmit the packet
1046                                 to.
1047   @param[in]  CallBack          Function to call back when transmit finished.
1048   @param[in]  Context           Opaque parameter to the call back.
1049   @param[in]  IpSb              The pointer to the IP4 service binding instance.
1050 
1051   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource to send the frame
1052   @retval EFI_NO_MAPPING        Can't resolve the MAC for the nexthop
1053   @retval EFI_SUCCESS           The packet is successfully transmitted.
1054   @retval other                 Other error occurs.
1055 
1056 **/
1057 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)1058 Ip4SendFrame (
1059   IN  IP4_INTERFACE         *Interface,
1060   IN  IP4_PROTOCOL          *IpInstance       OPTIONAL,
1061   IN  NET_BUF               *Packet,
1062   IN  IP4_ADDR              NextHop,
1063   IN  IP4_FRAME_CALLBACK    CallBack,
1064   IN  VOID                  *Context,
1065   IN IP4_SERVICE            *IpSb
1066   )
1067 {
1068   IP4_LINK_TX_TOKEN         *Token;
1069   LIST_ENTRY                *Entry;
1070   IP4_ARP_QUE               *ArpQue;
1071   EFI_ARP_PROTOCOL          *Arp;
1072   EFI_STATUS                Status;
1073 
1074   ASSERT (Interface->Configured);
1075 
1076   Token = Ip4WrapLinkTxToken (Interface, IpInstance, Packet, CallBack, Context, IpSb);
1077 
1078   if (Token == NULL) {
1079     return EFI_OUT_OF_RESOURCES;
1080   }
1081 
1082   //
1083   // Get the destination MAC address for multicast and broadcasts.
1084   // Don't depend on ARP to solve the address since there maybe no
1085   // ARP at all. Ip4Output has set NextHop to 255.255.255.255 for
1086   // all the broadcasts.
1087   //
1088   if (NextHop == IP4_ALLONE_ADDRESS) {
1089     CopyMem (&Token->DstMac, &Interface->BroadcastMac, sizeof (Token->DstMac));
1090     goto SEND_NOW;
1091 
1092   } else if (IP4_IS_MULTICAST (NextHop)) {
1093 
1094     Status = Ip4GetMulticastMac (Interface->Mnp, NextHop, &Token->DstMac);
1095 
1096     if (EFI_ERROR (Status)) {
1097       goto ON_ERROR;
1098     }
1099 
1100     goto SEND_NOW;
1101   }
1102 
1103   //
1104   // Can only send out multicast/broadcast if the IP address is zero
1105   //
1106   if ((Arp = Interface->Arp) == NULL) {
1107     Status = EFI_NO_MAPPING;
1108     goto ON_ERROR;
1109   }
1110 
1111   //
1112   // First check whether this binding is in the ARP cache.
1113   //
1114   NextHop = HTONL (NextHop);
1115   Status  = Arp->Request (Arp, &NextHop, NULL, &Token->DstMac);
1116 
1117   if (Status == EFI_SUCCESS) {
1118     goto SEND_NOW;
1119 
1120   } else if (Status != EFI_NOT_READY) {
1121     goto ON_ERROR;
1122   }
1123 
1124   //
1125   // Have to do asynchronous ARP resolution. First check
1126   // whether there is already a pending request.
1127   //
1128   ArpQue = NULL;
1129 
1130   NET_LIST_FOR_EACH (Entry, &Interface->ArpQues) {
1131     ArpQue = NET_LIST_USER_STRUCT (Entry, IP4_ARP_QUE, Link);
1132 
1133     if (ArpQue->Ip == NextHop) {
1134       break;
1135     }
1136   }
1137 
1138   //
1139   // Found a pending ARP request, enqueue the frame then return
1140   //
1141   if (Entry != &Interface->ArpQues) {
1142     InsertTailList (&ArpQue->Frames, &Token->Link);
1143     return EFI_SUCCESS;
1144   }
1145 
1146   //
1147   // First frame to NextHop, issue an asynchronous ARP requests
1148   //
1149   ArpQue = Ip4CreateArpQue (Interface, NextHop);
1150 
1151   if (ArpQue == NULL) {
1152     Status = EFI_OUT_OF_RESOURCES;
1153     goto ON_ERROR;
1154   }
1155 
1156   Status = Arp->Request (Arp, &ArpQue->Ip, ArpQue->OnResolved, ArpQue->Mac.Addr);
1157 
1158   if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {
1159     Ip4FreeArpQue (ArpQue, EFI_NO_MAPPING);
1160     goto ON_ERROR;
1161   }
1162 
1163   InsertHeadList (&ArpQue->Frames, &Token->Link);
1164   InsertHeadList (&Interface->ArpQues, &ArpQue->Link);
1165   return EFI_SUCCESS;
1166 
1167 SEND_NOW:
1168   //
1169   // Insert the tx token into the SentFrames list before calling Mnp->Transmit.
1170   // Remove it if the returned status is not EFI_SUCCESS.
1171   //
1172   InsertTailList (&Interface->SentFrames, &Token->Link);
1173   Status = Interface->Mnp->Transmit (Interface->Mnp, &Token->MnpToken);
1174   if (EFI_ERROR (Status)) {
1175     RemoveEntryList (&Token->Link);
1176     goto ON_ERROR;
1177   }
1178 
1179   return EFI_SUCCESS;
1180 
1181 ON_ERROR:
1182   Ip4FreeLinkTxToken (Token);
1183   return Status;
1184 }
1185 
1186 
1187 /**
1188   Call back function when the received packet is freed.
1189   Check Ip4OnFrameReceived for information.
1190 
1191   @param  Context          Context, which is the IP4_LINK_RX_TOKEN.
1192 
1193 **/
1194 VOID
1195 EFIAPI
Ip4RecycleFrame(IN VOID * Context)1196 Ip4RecycleFrame (
1197   IN VOID                   *Context
1198   )
1199 {
1200   IP4_LINK_RX_TOKEN         *Frame;
1201 
1202   Frame = (IP4_LINK_RX_TOKEN *) Context;
1203   NET_CHECK_SIGNATURE (Frame, IP4_FRAME_RX_SIGNATURE);
1204 
1205   gBS->SignalEvent (Frame->MnpToken.Packet.RxData->RecycleEvent);
1206   Ip4FreeFrameRxToken (Frame);
1207 }
1208 
1209 
1210 /**
1211   Received a frame from MNP, wrap it in net buffer then deliver
1212   it to IP's input function. The ownship of the packet also
1213   transferred to IP. When Ip is finished with this packet, it
1214   will call NetbufFree to release the packet, NetbufFree will
1215   again call the Ip4RecycleFrame to signal MNP's event and free
1216   the token used.
1217 
1218   @param  Context               Context for the callback.
1219 
1220 **/
1221 VOID
1222 EFIAPI
Ip4OnFrameReceivedDpc(IN VOID * Context)1223 Ip4OnFrameReceivedDpc (
1224   IN VOID                     *Context
1225   )
1226 {
1227   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *MnpToken;
1228   EFI_MANAGED_NETWORK_RECEIVE_DATA      *MnpRxData;
1229   IP4_LINK_RX_TOKEN                     *Token;
1230   NET_FRAGMENT                          Netfrag;
1231   NET_BUF                               *Packet;
1232   UINT32                                Flag;
1233 
1234   Token = (IP4_LINK_RX_TOKEN *) Context;
1235   NET_CHECK_SIGNATURE (Token, IP4_FRAME_RX_SIGNATURE);
1236 
1237   //
1238   // First clear the interface's receive request in case the
1239   // caller wants to call Ip4ReceiveFrame in the callback.
1240   //
1241   Token->Interface->RecvRequest = NULL;
1242 
1243   MnpToken  = &Token->MnpToken;
1244   MnpRxData = MnpToken->Packet.RxData;
1245 
1246   if (EFI_ERROR (MnpToken->Status) || (MnpRxData == NULL)) {
1247     Token->CallBack (Token->IpInstance, NULL, MnpToken->Status, 0, Token->Context);
1248     Ip4FreeFrameRxToken (Token);
1249 
1250     return ;
1251   }
1252 
1253   //
1254   // Wrap the frame in a net buffer then deliever it to IP input.
1255   // IP will reassemble the packet, and deliver it to upper layer
1256   //
1257   Netfrag.Len  = MnpRxData->DataLength;
1258   Netfrag.Bulk = MnpRxData->PacketData;
1259 
1260   Packet = NetbufFromExt (&Netfrag, 1, 0, IP4_MAX_HEADLEN, Ip4RecycleFrame, Token);
1261 
1262   if (Packet == NULL) {
1263     gBS->SignalEvent (MnpRxData->RecycleEvent);
1264 
1265     Token->CallBack (Token->IpInstance, NULL, EFI_OUT_OF_RESOURCES, 0, Token->Context);
1266     Ip4FreeFrameRxToken (Token);
1267 
1268     return ;
1269   }
1270 
1271   Flag  = (MnpRxData->BroadcastFlag ? IP4_LINK_BROADCAST : 0);
1272   Flag |= (MnpRxData->MulticastFlag ? IP4_LINK_MULTICAST : 0);
1273   Flag |= (MnpRxData->PromiscuousFlag ? IP4_LINK_PROMISC : 0);
1274 
1275   Token->CallBack (Token->IpInstance, Packet, EFI_SUCCESS, Flag, Token->Context);
1276 }
1277 
1278 /**
1279   Request Ip4OnFrameReceivedDpc as a DPC at TPL_CALLBACK.
1280 
1281   @param Event      The receive event delivered to MNP for receive.
1282   @param Context    Context for the callback.
1283 
1284 **/
1285 VOID
1286 EFIAPI
Ip4OnFrameReceived(IN EFI_EVENT Event,IN VOID * Context)1287 Ip4OnFrameReceived (
1288   IN EFI_EVENT                Event,
1289   IN VOID                     *Context
1290   )
1291 {
1292   //
1293   // Request Ip4OnFrameReceivedDpc as a DPC at TPL_CALLBACK
1294   //
1295   QueueDpc (TPL_CALLBACK, Ip4OnFrameReceivedDpc, Context);
1296 }
1297 
1298 
1299 /**
1300   Request to receive the packet from the interface.
1301 
1302   @param[in]  Interface         The interface to receive the frames from.
1303   @param[in]  IpInstance        The instance that requests the receive. NULL for
1304                                 the driver itself.
1305   @param[in]  CallBack          Function to call when receive finished.
1306   @param[in]  Context           Opaque parameter to the callback.
1307 
1308   @retval EFI_ALREADY_STARTED   There is already a pending receive request.
1309   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource to receive.
1310   @retval EFI_SUCCESS           The recieve request has been started.
1311   @retval other                 Other error occurs.
1312 
1313 **/
1314 EFI_STATUS
Ip4ReceiveFrame(IN IP4_INTERFACE * Interface,IN IP4_PROTOCOL * IpInstance OPTIONAL,IN IP4_FRAME_CALLBACK CallBack,IN VOID * Context)1315 Ip4ReceiveFrame (
1316   IN  IP4_INTERFACE         *Interface,
1317   IN  IP4_PROTOCOL          *IpInstance       OPTIONAL,
1318   IN  IP4_FRAME_CALLBACK    CallBack,
1319   IN  VOID                  *Context
1320   )
1321 {
1322   IP4_LINK_RX_TOKEN *Token;
1323   EFI_STATUS        Status;
1324 
1325   NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);
1326 
1327   if (Interface->RecvRequest != NULL) {
1328     return EFI_ALREADY_STARTED;
1329   }
1330 
1331   Token = Ip4CreateLinkRxToken (Interface, IpInstance, CallBack, Context);
1332 
1333   if (Token == NULL) {
1334     return EFI_OUT_OF_RESOURCES;
1335   }
1336 
1337   Interface->RecvRequest = Token;
1338   Status = Interface->Mnp->Receive (Interface->Mnp, &Token->MnpToken);
1339   if (EFI_ERROR (Status)) {
1340     Interface->RecvRequest = NULL;
1341     Ip4FreeFrameRxToken (Token);
1342     return Status;
1343   }
1344   return EFI_SUCCESS;
1345 }
1346