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