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