Patch to remove STATIC modifier. This is on longer recommended by EFI Framework codin...
[mirror_edk2.git] / MdeModulePkg / Library / DxeUdpIoLib / DxeUdpIoLib.c
1 /** @file\r
2 \r
3 Copyright (c) 2006 - 2007, Intel Corporation\r
4 All rights reserved. This program and the accompanying materials\r
5 are licensed and made available under the terms and conditions of the BSD License\r
6 which accompanies this distribution.  The full text of the license may be found at\r
7 http://opensource.org/licenses/bsd-license.php\r
8 \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11 \r
12 \r
13 Module Name:\r
14 \r
15   Udp4Io.c\r
16 \r
17 Abstract:\r
18 \r
19   Help functions to access UDP service, it is used by both the DHCP and MTFTP.\r
20 \r
21 \r
22 **/\r
23 \r
24 #include <PiDxe.h>\r
25 \r
26 #include <Protocol/Udp4.h>\r
27 \r
28 #include <Library/UdpIoLib.h>\r
29 #include <Library/BaseLib.h>\r
30 #include <Library/DebugLib.h>\r
31 #include <Library/UefiBootServicesTableLib.h>\r
32 #include <Library/MemoryAllocationLib.h>\r
33 #include <Library/BaseMemoryLib.h>\r
34 \r
35 VOID\r
36 EFIAPI\r
37 UdpIoOnDgramSentDpc (\r
38   IN VOID                   *Context\r
39   );\r
40 \r
41 VOID\r
42 EFIAPI\r
43 UdpIoOnDgramSent (\r
44   IN EFI_EVENT              Event,\r
45   IN VOID                   *Context\r
46   );\r
47 \r
48 VOID\r
49 EFIAPI\r
50 UdpIoOnDgramRcvd (\r
51   IN EFI_EVENT              Event,\r
52   IN VOID                   *Context\r
53   );\r
54 \r
55 \r
56 /**\r
57   Wrap a transmit request into a UDP_TX_TOKEN.\r
58 \r
59   @param  UdpIo                 The UdpIo port to send packet to\r
60   @param  Packet                The user's packet\r
61   @param  EndPoint              The local and remote access point\r
62   @param  Gateway               The overrided next hop\r
63   @param  CallBack              The function to call when transmission completed.\r
64   @param  Context               The opaque parameter to the call back\r
65 \r
66   @return The wrapped transmission request or NULL if failed to allocate resources.\r
67 \r
68 **/\r
69 UDP_TX_TOKEN *\r
70 UdpIoWrapTx (\r
71   IN UDP_IO_PORT            *UdpIo,\r
72   IN NET_BUF                *Packet,\r
73   IN UDP_POINTS             *EndPoint, OPTIONAL\r
74   IN IP4_ADDR               Gateway,\r
75   IN UDP_IO_CALLBACK        CallBack,\r
76   IN VOID                   *Context\r
77   )\r
78 {\r
79   UDP_TX_TOKEN              *Token;\r
80   EFI_UDP4_COMPLETION_TOKEN *UdpToken;\r
81   EFI_UDP4_TRANSMIT_DATA    *UdpTxData;\r
82   EFI_STATUS                Status;\r
83   UINT32                    Count;\r
84   IP4_ADDR                  Ip;\r
85 \r
86   Token = AllocatePool (sizeof (UDP_TX_TOKEN) +\r
87                            sizeof (EFI_UDP4_FRAGMENT_DATA) * (Packet->BlockOpNum - 1));\r
88 \r
89   if (Token == NULL) {\r
90     return NULL;\r
91   }\r
92 \r
93   Token->Signature  = UDP_IO_TX_SIGNATURE;\r
94   InitializeListHead (&Token->Link);\r
95 \r
96   Token->UdpIo      = UdpIo;\r
97   Token->CallBack   = CallBack;\r
98   Token->Packet     = Packet;\r
99   Token->Context    = Context;\r
100 \r
101   UdpToken          = &(Token->UdpToken);\r
102   UdpToken->Status  = EFI_NOT_READY;\r
103 \r
104   Status = gBS->CreateEvent (\r
105                   EVT_NOTIFY_SIGNAL,\r
106                   TPL_NOTIFY,\r
107                   UdpIoOnDgramSent,\r
108                   Token,\r
109                   &UdpToken->Event\r
110                   );\r
111 \r
112   if (EFI_ERROR (Status)) {\r
113     gBS->FreePool (Token);\r
114     return NULL;\r
115   }\r
116 \r
117   UdpTxData                 = &Token->UdpTxData;\r
118   UdpToken->Packet.TxData   = UdpTxData;\r
119 \r
120   UdpTxData->UdpSessionData = NULL;\r
121   UdpTxData->GatewayAddress = NULL;\r
122 \r
123   if (EndPoint != NULL) {\r
124     Ip = HTONL (EndPoint->LocalAddr);\r
125     CopyMem (&Token->UdpSession.SourceAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
126 \r
127     Ip = HTONL (EndPoint->RemoteAddr);\r
128     CopyMem (&Token->UdpSession.DestinationAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
129 \r
130     Token->UdpSession.SourcePort      = EndPoint->LocalPort;\r
131     Token->UdpSession.DestinationPort = EndPoint->RemotePort;\r
132     UdpTxData->UdpSessionData         = &Token->UdpSession;\r
133   }\r
134 \r
135   if (Gateway != 0) {\r
136     Ip = HTONL (Gateway);\r
137     CopyMem (&Token->Gateway, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
138 \r
139     UdpTxData->GatewayAddress = &Token->Gateway;\r
140   }\r
141 \r
142   UdpTxData->DataLength = Packet->TotalSize;\r
143   Count                 = Packet->BlockOpNum;\r
144   NetbufBuildExt (Packet, (NET_FRAGMENT *) UdpTxData->FragmentTable, &Count);\r
145   UdpTxData->FragmentCount = Count;\r
146 \r
147   return Token;\r
148 }\r
149 \r
150 \r
151 /**\r
152   Free a UDP_TX_TOKEN. The event is closed and memory released.\r
153 \r
154   @param  Token                 The UDP_TX_TOKEN to release.\r
155 \r
156   @return None\r
157 \r
158 **/\r
159 VOID\r
160 UdpIoFreeTxToken (\r
161   IN UDP_TX_TOKEN           *Token\r
162   )\r
163 {\r
164   gBS->CloseEvent (Token->UdpToken.Event);\r
165   gBS->FreePool (Token);\r
166 }\r
167 \r
168 \r
169 /**\r
170   Create a UDP_RX_TOKEN to wrap the request.\r
171 \r
172   @param  UdpIo                 The UdpIo to receive packets from\r
173   @param  CallBack              The function to call when receive finished.\r
174   @param  Context               The opaque parameter to the CallBack\r
175   @param  HeadLen               The head length to reserver for the packet.\r
176 \r
177   @return The Wrapped request or NULL if failed to allocate resources.\r
178 \r
179 **/\r
180 UDP_RX_TOKEN *\r
181 UdpIoCreateRxToken (\r
182   IN UDP_IO_PORT            *UdpIo,\r
183   IN UDP_IO_CALLBACK        CallBack,\r
184   IN VOID                   *Context,\r
185   IN UINT32                 HeadLen\r
186   )\r
187 {\r
188   UDP_RX_TOKEN              *Token;\r
189   EFI_STATUS                Status;\r
190 \r
191   Token = AllocatePool (sizeof (UDP_RX_TOKEN));\r
192 \r
193   if (Token == NULL) {\r
194     return NULL;\r
195   }\r
196 \r
197   Token->Signature              = UDP_IO_RX_SIGNATURE;\r
198   Token->UdpIo                  = UdpIo;\r
199   Token->CallBack               = CallBack;\r
200   Token->Context                = Context;\r
201   Token->HeadLen                = HeadLen;\r
202 \r
203   Token->UdpToken.Status        = EFI_NOT_READY;\r
204   Token->UdpToken.Packet.RxData = NULL;\r
205 \r
206   Status = gBS->CreateEvent (\r
207                   EVT_NOTIFY_SIGNAL,\r
208                   TPL_NOTIFY,\r
209                   UdpIoOnDgramRcvd,\r
210                   Token,\r
211                   &Token->UdpToken.Event\r
212                   );\r
213 \r
214   if (EFI_ERROR (Status)) {\r
215     gBS->FreePool (Token);\r
216     return NULL;\r
217   }\r
218 \r
219   return Token;\r
220 }\r
221 \r
222 \r
223 /**\r
224   Free a receive request wrap.\r
225 \r
226   @param  Token                 The receive request to release.\r
227 \r
228   @return None\r
229 \r
230 **/\r
231 VOID\r
232 UdpIoFreeRxToken (\r
233   IN UDP_RX_TOKEN           *Token\r
234   )\r
235 {\r
236   gBS->CloseEvent (Token->UdpToken.Event);\r
237   gBS->FreePool (Token);\r
238 }\r
239 \r
240 \r
241 /**\r
242   Create a UDP IO port to access the UDP service. It will\r
243   create and configure a UDP child.\r
244 \r
245   @param  Controller            The controller that has the UDP service binding\r
246                                 protocol installed.\r
247   @param  Image                 The image handle for the driver.\r
248   @param  Configure             The function to configure the created UDP child\r
249   @param  Context               The opaque parameter for the Configure funtion.\r
250 \r
251   @return A point to just created UDP IO port or NULL if failed.\r
252 \r
253 **/\r
254 UDP_IO_PORT *\r
255 EFIAPI\r
256 UdpIoCreatePort (\r
257   IN  EFI_HANDLE            Controller,\r
258   IN  EFI_HANDLE            Image,\r
259   IN  UDP_IO_CONFIG         Configure,\r
260   IN  VOID                  *Context\r
261   )\r
262 {\r
263   UDP_IO_PORT               *UdpIo;\r
264   EFI_STATUS                Status;\r
265 \r
266   ASSERT (Configure != NULL);\r
267 \r
268   UdpIo = AllocatePool (sizeof (UDP_IO_PORT));\r
269 \r
270   if (UdpIo == NULL) {\r
271     return NULL;\r
272   }\r
273 \r
274   UdpIo->Signature    = UDP_IO_SIGNATURE;\r
275   InitializeListHead (&UdpIo->Link);\r
276   UdpIo->RefCnt       = 1;\r
277 \r
278   UdpIo->Controller   = Controller;\r
279   UdpIo->Image        = Image;\r
280 \r
281   InitializeListHead (&UdpIo->SentDatagram);\r
282   UdpIo->RecvRequest  = NULL;\r
283   UdpIo->UdpHandle    = NULL;\r
284 \r
285   //\r
286   // Create a UDP child then open and configure it\r
287   //\r
288   Status = NetLibCreateServiceChild (\r
289              Controller,\r
290              Image,\r
291              &gEfiUdp4ServiceBindingProtocolGuid,\r
292              &UdpIo->UdpHandle\r
293              );\r
294 \r
295   if (EFI_ERROR (Status)) {\r
296     goto FREE_MEM;\r
297   }\r
298 \r
299   Status = gBS->OpenProtocol (\r
300                   UdpIo->UdpHandle,\r
301                   &gEfiUdp4ProtocolGuid,\r
302                   (VOID **) &UdpIo->Udp,\r
303                   Image,\r
304                   Controller,\r
305                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
306                   );\r
307 \r
308   if (EFI_ERROR (Status)) {\r
309     goto FREE_CHILD;\r
310   }\r
311 \r
312   if (EFI_ERROR (Configure (UdpIo, Context))) {\r
313     goto CLOSE_PROTOCOL;\r
314   }\r
315 \r
316   Status = UdpIo->Udp->GetModeData (UdpIo->Udp, NULL, NULL, NULL, &UdpIo->SnpMode);\r
317 \r
318   if (EFI_ERROR (Status)) {\r
319     goto CLOSE_PROTOCOL;\r
320   }\r
321 \r
322   return UdpIo;\r
323 \r
324 CLOSE_PROTOCOL:\r
325   gBS->CloseProtocol (UdpIo->UdpHandle, &gEfiUdp4ProtocolGuid, Image, Controller);\r
326 \r
327 FREE_CHILD:\r
328   NetLibDestroyServiceChild (\r
329     Controller,\r
330     Image,\r
331     &gEfiUdp4ServiceBindingProtocolGuid,\r
332     UdpIo->UdpHandle\r
333     );\r
334 \r
335 FREE_MEM:\r
336   gBS->FreePool (UdpIo);\r
337   return NULL;\r
338 }\r
339 \r
340 \r
341 /**\r
342   Cancel all the sent datagram that pass the selection of ToCancel.\r
343   If ToCancel is NULL, all the datagrams are cancelled.\r
344 \r
345   @param  UdpIo                 The UDP IO port to cancel packet\r
346   @param  IoStatus              The IoStatus to return to the packet owners.\r
347   @param  ToCancel              The select funtion to test whether to cancel this\r
348                                 packet or not.\r
349   @param  Context               The opaque parameter to the ToCancel.\r
350 \r
351   @return None\r
352 \r
353 **/\r
354 VOID\r
355 UdpIoCancelDgrams (\r
356   IN UDP_IO_PORT            *UdpIo,\r
357   IN EFI_STATUS             IoStatus,\r
358   IN UDP_IO_TO_CANCEL       ToCancel,        OPTIONAL\r
359   IN VOID                   *Context\r
360   )\r
361 {\r
362   LIST_ENTRY                *Entry;\r
363   LIST_ENTRY                *Next;\r
364   UDP_TX_TOKEN              *Token;\r
365 \r
366   NET_LIST_FOR_EACH_SAFE (Entry, Next, &UdpIo->SentDatagram) {\r
367     Token = NET_LIST_USER_STRUCT (Entry, UDP_TX_TOKEN, Link);\r
368 \r
369     if ((ToCancel == NULL) || (ToCancel (Token, Context))) {\r
370       UdpIo->Udp->Cancel (UdpIo->Udp, &Token->UdpToken);\r
371     }\r
372   }\r
373 }\r
374 \r
375 \r
376 /**\r
377   Free the UDP IO port and all its related resources including\r
378   all the transmitted packet.\r
379 \r
380   @param  UdpIo                 The UDP IO port to free.\r
381 \r
382   @retval EFI_SUCCESS           The UDP IO port is freed.\r
383 \r
384 **/\r
385 EFI_STATUS\r
386 EFIAPI\r
387 UdpIoFreePort (\r
388   IN  UDP_IO_PORT           *UdpIo\r
389   )\r
390 {\r
391   UDP_RX_TOKEN  *RxToken;\r
392 \r
393   //\r
394   // Cancel all the sent datagram and receive requests. The\r
395   // callbacks of transmit requests are executed to allow the\r
396   // caller to release the resource. The callback of receive\r
397   // request are NOT executed. This is because it is most\r
398   // likely that the current user of the UDP IO port is closing\r
399   // itself.\r
400   //\r
401   UdpIoCancelDgrams (UdpIo, EFI_ABORTED, NULL, NULL);\r
402 \r
403   if ((RxToken = UdpIo->RecvRequest) != NULL) {\r
404     UdpIo->Udp->Cancel (UdpIo->Udp, &RxToken->UdpToken);\r
405   }\r
406 \r
407   //\r
408   // Close then destory the UDP child\r
409   //\r
410   gBS->CloseProtocol (\r
411          UdpIo->UdpHandle,\r
412          &gEfiUdp4ProtocolGuid,\r
413          UdpIo->Image,\r
414          UdpIo->Controller\r
415          );\r
416 \r
417   NetLibDestroyServiceChild (\r
418     UdpIo->Controller,\r
419     UdpIo->Image,\r
420     &gEfiUdp4ServiceBindingProtocolGuid,\r
421     UdpIo->UdpHandle\r
422     );\r
423 \r
424   if (!IsListEmpty(&UdpIo->Link)) {\r
425     RemoveEntryList (&UdpIo->Link);\r
426   }\r
427 \r
428   gBS->FreePool (UdpIo);\r
429   return EFI_SUCCESS;\r
430 }\r
431 \r
432 \r
433 /**\r
434   Clean up the UDP IO port. It will release all the transmitted\r
435   datagrams and receive request. It will also configure NULL the\r
436   UDP child.\r
437 \r
438   @param  UdpIo                 UDP IO port to clean up.\r
439 \r
440   @return None\r
441 \r
442 **/\r
443 VOID\r
444 EFIAPI\r
445 UdpIoCleanPort (\r
446   IN  UDP_IO_PORT           *UdpIo\r
447   )\r
448 {\r
449   UDP_RX_TOKEN              *RxToken;\r
450 \r
451   //\r
452   // Cancel all the sent datagram and receive requests.\r
453   //\r
454   UdpIoCancelDgrams (UdpIo, EFI_ABORTED, NULL, NULL);\r
455 \r
456   if ((RxToken = UdpIo->RecvRequest) != NULL) {\r
457     UdpIo->Udp->Cancel (UdpIo->Udp, &RxToken->UdpToken);\r
458   }\r
459 \r
460   UdpIo->Udp->Configure (UdpIo->Udp, NULL);\r
461 }\r
462 \r
463 \r
464 /**\r
465   The callback function when the packet is sent by UDP.\r
466   It will remove the packet from the local list then call\r
467   the packet owner's callback function.\r
468 \r
469   @param  Context               The UDP TX Token.\r
470 \r
471   @return None\r
472 \r
473 **/\r
474 VOID\r
475 EFIAPI\r
476 UdpIoOnDgramSentDpc (\r
477   IN VOID                   *Context\r
478   )\r
479 {\r
480   UDP_TX_TOKEN              *Token;\r
481 \r
482   Token   = (UDP_TX_TOKEN *) Context;\r
483   ASSERT (Token->Signature == UDP_IO_TX_SIGNATURE);\r
484 \r
485   RemoveEntryList (&Token->Link);\r
486   Token->CallBack (Token->Packet, NULL, Token->UdpToken.Status, Token->Context);\r
487 \r
488   UdpIoFreeTxToken (Token);\r
489 }\r
490 \r
491 /**\r
492   Request UdpIoOnDgramSentDpc as a DPC at TPL_CALLBACK.\r
493 \r
494   @param  Event                 The event signalled.\r
495   @param  Context               The UDP TX Token.\r
496 \r
497   @return None\r
498 \r
499 **/\r
500 VOID\r
501 EFIAPI\r
502 UdpIoOnDgramSent (\r
503   IN EFI_EVENT              Event,\r
504   IN VOID                   *Context\r
505   )\r
506 {\r
507   //\r
508   // Request UdpIoOnDgramSentDpc as a DPC at TPL_CALLBACK\r
509   //\r
510   NetLibQueueDpc (TPL_CALLBACK, UdpIoOnDgramSentDpc, Context);\r
511 }\r
512 \r
513 \r
514 /**\r
515   Send a packet through the UDP IO port.\r
516 \r
517   @param  UdpIo                 The UDP IO Port to send the packet through\r
518   @param  Packet                The packet to send\r
519   @param  EndPoint              The local and remote access point\r
520   @param  Gateway               The gateway to use\r
521   @param  CallBack              The call back function to call when packet is\r
522                                 transmitted or failed.\r
523   @param  Context               The opque parameter to the CallBack\r
524 \r
525   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource for the packet\r
526   @retval EFI_SUCCESS           The packet is successfully delivered to UDP  for\r
527                                 transmission.\r
528 \r
529 **/\r
530 EFI_STATUS\r
531 EFIAPI\r
532 UdpIoSendDatagram (\r
533   IN  UDP_IO_PORT           *UdpIo,\r
534   IN  NET_BUF               *Packet,\r
535   IN  UDP_POINTS            *EndPoint, OPTIONAL\r
536   IN  IP4_ADDR              Gateway,\r
537   IN  UDP_IO_CALLBACK       CallBack,\r
538   IN  VOID                  *Context\r
539   )\r
540 {\r
541   UDP_TX_TOKEN              *Token;\r
542   EFI_STATUS                Status;\r
543 \r
544   Token = UdpIoWrapTx (UdpIo, Packet, EndPoint, Gateway, CallBack, Context);\r
545 \r
546   if (Token == NULL) {\r
547     return EFI_OUT_OF_RESOURCES;\r
548   }\r
549 \r
550   //\r
551   // Insert the tx token into SendDatagram list before transmitting it. Remove\r
552   // it from the list if the returned status is not EFI_SUCCESS.\r
553   //\r
554   InsertHeadList (&UdpIo->SentDatagram, &Token->Link);\r
555   Status = UdpIo->Udp->Transmit (UdpIo->Udp, &Token->UdpToken);\r
556   if (EFI_ERROR (Status)) {\r
557     RemoveEntryList (&Token->Link);\r
558     UdpIoFreeTxToken (Token);\r
559     return Status;\r
560   }\r
561 \r
562   return EFI_SUCCESS;\r
563 }\r
564 \r
565 \r
566 /**\r
567   The selection function to cancel a single sent datagram.\r
568 \r
569   @param  Token                 The UDP TX token to test againist.\r
570   @param  Context               The context\r
571 \r
572   @return TRUE if the packet is to be cancelled, otherwise FALSE.\r
573 \r
574 **/\r
575 BOOLEAN\r
576 UdpIoCancelSingleDgram (\r
577   IN UDP_TX_TOKEN           *Token,\r
578   IN VOID                   *Context\r
579   )\r
580 {\r
581   NET_BUF                   *Packet;\r
582 \r
583   Packet = (NET_BUF *) Context;\r
584 \r
585   if (Token->Packet == Packet) {\r
586     return TRUE;\r
587   }\r
588 \r
589   return FALSE;\r
590 }\r
591 \r
592 \r
593 /**\r
594   Cancel a single sent datagram.\r
595 \r
596   @param  UdpIo                 The UDP IO port to cancel the packet from\r
597   @param  Packet                The packet to cancel\r
598 \r
599   @return None\r
600 \r
601 **/\r
602 VOID\r
603 EFIAPI\r
604 UdpIoCancelSentDatagram (\r
605   IN  UDP_IO_PORT           *UdpIo,\r
606   IN  NET_BUF               *Packet\r
607   )\r
608 {\r
609   UdpIoCancelDgrams (UdpIo, EFI_ABORTED, UdpIoCancelSingleDgram, Packet);\r
610 }\r
611 \r
612 \r
613 /**\r
614   Recycle the received UDP data.\r
615 \r
616   @param  Context               The UDP_RX_TOKEN\r
617 \r
618   @return None\r
619 \r
620 **/\r
621 VOID\r
622 UdpIoRecycleDgram (\r
623   IN VOID                   *Context\r
624   )\r
625 {\r
626   UDP_RX_TOKEN              *Token;\r
627 \r
628   Token = (UDP_RX_TOKEN *) Context;\r
629   gBS->SignalEvent (Token->UdpToken.Packet.RxData->RecycleSignal);\r
630   UdpIoFreeRxToken (Token);\r
631 }\r
632 \r
633 /**\r
634   The event handle for UDP receive request. It will build\r
635   a NET_BUF from the recieved UDP data, then deliver it\r
636   to the receiver.\r
637 \r
638   @param  Context               The UDP RX token.\r
639 \r
640   @return None\r
641 \r
642 **/\r
643 VOID\r
644 EFIAPI\r
645 UdpIoOnDgramRcvdDpc (\r
646   IN VOID                   *Context\r
647   )\r
648 {\r
649   EFI_UDP4_COMPLETION_TOKEN *UdpToken;\r
650   EFI_UDP4_RECEIVE_DATA     *UdpRxData;\r
651   EFI_UDP4_SESSION_DATA     *UdpSession;\r
652   UDP_RX_TOKEN              *Token;\r
653   UDP_POINTS                Points;\r
654   NET_BUF                   *Netbuf;\r
655 \r
656   Token   = (UDP_RX_TOKEN *) Context;\r
657 \r
658   ASSERT ((Token->Signature == UDP_IO_RX_SIGNATURE) &&\r
659           (Token == Token->UdpIo->RecvRequest));\r
660 \r
661   //\r
662   // Clear the receive request first in case that the caller\r
663   // wants to restart the receive in the callback.\r
664   //\r
665   Token->UdpIo->RecvRequest = NULL;\r
666 \r
667   UdpToken  = &Token->UdpToken;\r
668   UdpRxData = UdpToken->Packet.RxData;\r
669 \r
670   if (EFI_ERROR (UdpToken->Status) || (UdpRxData == NULL)) {\r
671     if (UdpToken->Status != EFI_ABORTED) {\r
672       //\r
673       // Invoke the CallBack only if the reception is not actively aborted.\r
674       //\r
675       Token->CallBack (NULL, NULL, UdpToken->Status, Token->Context);\r
676     }\r
677 \r
678     UdpIoFreeRxToken (Token);\r
679     return;\r
680   }\r
681 \r
682   //\r
683   // Build a NET_BUF from the UDP receive data, then deliver it up.\r
684   //\r
685   Netbuf = NetbufFromExt (\r
686              (NET_FRAGMENT *) UdpRxData->FragmentTable,\r
687              UdpRxData->FragmentCount,\r
688              0,\r
689              (UINT32) Token->HeadLen,\r
690              UdpIoRecycleDgram,\r
691              Token\r
692              );\r
693 \r
694   if (Netbuf == NULL) {\r
695     gBS->SignalEvent (UdpRxData->RecycleSignal);\r
696     Token->CallBack (NULL, NULL, EFI_OUT_OF_RESOURCES, Token->Context);\r
697 \r
698     UdpIoFreeRxToken (Token);\r
699     return;\r
700   }\r
701 \r
702   UdpSession        = &UdpRxData->UdpSession;\r
703   Points.LocalPort  = UdpSession->DestinationPort;\r
704   Points.RemotePort = UdpSession->SourcePort;\r
705 \r
706   CopyMem (&Points.LocalAddr, &UdpSession->DestinationAddress, sizeof (IP4_ADDR));\r
707   CopyMem (&Points.RemoteAddr, &UdpSession->SourceAddress, sizeof (IP4_ADDR));\r
708   Points.LocalAddr  = NTOHL (Points.LocalAddr);\r
709   Points.RemoteAddr = NTOHL (Points.RemoteAddr);\r
710 \r
711   Token->CallBack (Netbuf, &Points, EFI_SUCCESS, Token->Context);\r
712 }\r
713 \r
714 /**\r
715   Request UdpIoOnDgramRcvdDpc as a DPC at TPL_CALLBACK.\r
716 \r
717   @param  Event                 The UDP receive request event.\r
718   @param  Context               The UDP RX token.\r
719 \r
720   @return None\r
721 \r
722 **/\r
723 VOID\r
724 EFIAPI\r
725 UdpIoOnDgramRcvd (\r
726   IN EFI_EVENT              Event,\r
727   IN VOID                   *Context\r
728   )\r
729 /*++\r
730 \r
731 Routine Description:\r
732 \r
733   Request UdpIoOnDgramRcvdDpc as a DPC at TPL_CALLBACK\r
734 \r
735 Arguments:\r
736 \r
737   Event   - The UDP receive request event\r
738   Context - The UDP RX token.\r
739 \r
740 Returns:\r
741 \r
742   None\r
743 \r
744 --*/\r
745 {\r
746   //\r
747   // Request UdpIoOnDgramRcvdDpc as a DPC at TPL_CALLBACK\r
748   //\r
749   NetLibQueueDpc (TPL_CALLBACK, UdpIoOnDgramRcvdDpc, Context);\r
750 }\r
751 \r
752 \r
753 /**\r
754   Issue a receive request to the UDP IO port.\r
755 \r
756   @param  UdpIo                 The UDP IO port to recieve the packet from.\r
757   @param  CallBack              The call back function to execute when receive\r
758                                 finished.\r
759   @param  Context               The opque context to the call back\r
760   @param  HeadLen               The lenght of the application's header\r
761 \r
762   @retval EFI_ALREADY_STARTED   There is already a pending receive request. Only\r
763                                 one receive request is supported.\r
764   @retval EFI_OUT_OF_RESOURCES  Failed to allocate some resource.\r
765   @retval EFI_SUCCESS           The receive request is issued successfully.\r
766 \r
767 **/\r
768 EFI_STATUS\r
769 EFIAPI\r
770 UdpIoRecvDatagram (\r
771   IN  UDP_IO_PORT           *UdpIo,\r
772   IN  UDP_IO_CALLBACK       CallBack,\r
773   IN  VOID                  *Context,\r
774   IN  UINT32                HeadLen\r
775   )\r
776 {\r
777   UDP_RX_TOKEN              *Token;\r
778   EFI_STATUS                Status;\r
779 \r
780   if (UdpIo->RecvRequest != NULL) {\r
781     return EFI_ALREADY_STARTED;\r
782   }\r
783 \r
784   Token = UdpIoCreateRxToken (UdpIo, CallBack, Context, HeadLen);\r
785 \r
786   if (Token == NULL) {\r
787     return EFI_OUT_OF_RESOURCES;\r
788   }\r
789 \r
790   UdpIo->RecvRequest = Token;\r
791   Status = UdpIo->Udp->Receive (UdpIo->Udp, &Token->UdpToken);\r
792 \r
793   if (EFI_ERROR (Status)) {\r
794     UdpIo->RecvRequest = NULL;\r
795     UdpIoFreeRxToken (Token);\r
796   }\r
797 \r
798   return Status;\r
799 }\r