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