]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.c
3e95393221aa6c5e5b9a3ad3fc0d87296df3aa22
[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 EFIAPI
486 UdpIoCancelDgrams (
487 IN UDP_IO_PORT *UdpIo,
488 IN EFI_STATUS IoStatus,
489 IN UDP_IO_TO_CANCEL ToCancel, OPTIONAL
490 IN VOID *Context
491 )
492 {
493 LIST_ENTRY *Entry;
494 LIST_ENTRY *Next;
495 UDP_TX_TOKEN *Token;
496
497 NET_LIST_FOR_EACH_SAFE (Entry, Next, &UdpIo->SentDatagram) {
498 Token = NET_LIST_USER_STRUCT (Entry, UDP_TX_TOKEN, Link);
499
500 if ((ToCancel == NULL) || (ToCancel (Token, Context))) {
501 UdpIo->Udp->Cancel (UdpIo->Udp, &Token->UdpToken);
502 }
503 }
504 }
505
506 /**
507 Free the UDP_IO_PORT and all its related resources.
508
509 The function will cancel all sent datagram and receive request.
510
511 @param[in] UdpIo The UDP_IO_PORT to free.
512
513 @retval EFI_SUCCESS The UDP_IO_PORT is freed.
514
515 **/
516 EFI_STATUS
517 EFIAPI
518 UdpIoFreePort (
519 IN UDP_IO_PORT *UdpIo
520 )
521 {
522 UDP_RX_TOKEN *RxToken;
523
524 //
525 // Cancel all the sent datagram and receive requests. The
526 // callbacks of transmit requests are executed to allow the
527 // caller to release the resource. The callback of receive
528 // request are NOT executed. This is because it is most
529 // likely that the current user of the UDP IO port is closing
530 // itself.
531 //
532 UdpIoCancelDgrams (UdpIo, EFI_ABORTED, NULL, NULL);
533
534 if ((RxToken = UdpIo->RecvRequest) != NULL) {
535 UdpIo->Udp->Cancel (UdpIo->Udp, &RxToken->UdpToken);
536 }
537
538 //
539 // Close then destory the UDP child
540 //
541 gBS->CloseProtocol (
542 UdpIo->UdpHandle,
543 &gEfiUdp4ProtocolGuid,
544 UdpIo->Image,
545 UdpIo->Controller
546 );
547
548 NetLibDestroyServiceChild (
549 UdpIo->Controller,
550 UdpIo->Image,
551 &gEfiUdp4ServiceBindingProtocolGuid,
552 UdpIo->UdpHandle
553 );
554
555 if (!IsListEmpty(&UdpIo->Link)) {
556 RemoveEntryList (&UdpIo->Link);
557 }
558
559 gBS->FreePool (UdpIo);
560 return EFI_SUCCESS;
561 }
562
563
564 /**
565 Clean up the UDP_IO_PORT without freeing it. The function is called when
566 user wants to re-use the UDP_IO_PORT later.
567
568 It will release all the transmitted datagrams and receive request. It will
569 also configure NULL for the UDP instance.
570
571 @param[in] UdpIo The UDP_IO_PORT to clean up.
572
573 **/
574 VOID
575 EFIAPI
576 UdpIoCleanPort (
577 IN UDP_IO_PORT *UdpIo
578 )
579 {
580 UDP_RX_TOKEN *RxToken;
581
582 //
583 // Cancel all the sent datagram and receive requests.
584 //
585 UdpIoCancelDgrams (UdpIo, EFI_ABORTED, NULL, NULL);
586
587 if ((RxToken = UdpIo->RecvRequest) != NULL) {
588 UdpIo->Udp->Cancel (UdpIo->Udp, &RxToken->UdpToken);
589 }
590
591 UdpIo->Udp->Configure (UdpIo->Udp, NULL);
592 }
593
594 /**
595 Send a packet through the UDP_IO_PORT.
596
597 The packet will be wrapped in UDP_TX_TOKEN. Function Callback will be called
598 when the packet is sent. The optional parameter EndPoint overrides the default
599 address pair if specified.
600
601 @param[in] UdpIo The UDP_IO_PORT to send the packet through.
602 @param[in] Packet The packet to send.
603 @param[in] EndPoint The local and remote access point. Override the
604 default address pair set during configuration.
605 @param[in] Gateway The gateway to use.
606 @param[in] CallBack The function being called when packet is
607 transmitted or failed.
608 @param[in] Context The opaque parameter passed to CallBack.
609
610 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the packet.
611 @retval EFI_SUCCESS The packet is successfully delivered to UDP for
612 transmission.
613
614 **/
615 EFI_STATUS
616 EFIAPI
617 UdpIoSendDatagram (
618 IN UDP_IO_PORT *UdpIo,
619 IN NET_BUF *Packet,
620 IN UDP_POINTS *EndPoint, OPTIONAL
621 IN IP4_ADDR Gateway,
622 IN UDP_IO_CALLBACK CallBack,
623 IN VOID *Context
624 )
625 {
626 UDP_TX_TOKEN *Token;
627 EFI_STATUS Status;
628
629 Token = UdpIoWrapTx (UdpIo, Packet, EndPoint, Gateway, CallBack, Context);
630
631 if (Token == NULL) {
632 return EFI_OUT_OF_RESOURCES;
633 }
634
635 //
636 // Insert the tx token into SendDatagram list before transmitting it. Remove
637 // it from the list if the returned status is not EFI_SUCCESS.
638 //
639 InsertHeadList (&UdpIo->SentDatagram, &Token->Link);
640 Status = UdpIo->Udp->Transmit (UdpIo->Udp, &Token->UdpToken);
641 if (EFI_ERROR (Status)) {
642 RemoveEntryList (&Token->Link);
643 UdpIoFreeTxToken (Token);
644 return Status;
645 }
646
647 return EFI_SUCCESS;
648 }
649
650
651 /**
652 The select function to cancel a single sent datagram.
653
654 @param[in] Token The UDP_TX_TOKEN to test against
655 @param[in] Context The NET_BUF of the sent datagram
656
657 @retval TRUE The packet is to be cancelled.
658 @retval FALSE The packet is not to be cancelled.
659 **/
660 BOOLEAN
661 UdpIoCancelSingleDgram (
662 IN UDP_TX_TOKEN *Token,
663 IN VOID *Context
664 )
665 {
666 NET_BUF *Packet;
667
668 Packet = (NET_BUF *) Context;
669
670 if (Token->Packet == Packet) {
671 return TRUE;
672 }
673
674 return FALSE;
675 }
676
677 /**
678 Cancel a single sent datagram.
679
680 @param[in] UdpIo The UDP_IO_PORT to cancel the packet from
681 @param[in] Packet The packet to cancel
682
683 **/
684 VOID
685 EFIAPI
686 UdpIoCancelSentDatagram (
687 IN UDP_IO_PORT *UdpIo,
688 IN NET_BUF *Packet
689 )
690 {
691 UdpIoCancelDgrams (UdpIo, EFI_ABORTED, UdpIoCancelSingleDgram, Packet);
692 }
693
694 /**
695 Issue a receive request to the UDP_IO_PORT.
696
697 This function is called when upper-layer needs packet from UDP for processing.
698 Only one receive request is acceptable at a time so a common usage model is
699 to invoke this function inside its Callback function when the former packet
700 is processed.
701
702 @param[in] UdpIo The UDP_IO_PORT to receive the packet from.
703 @param[in] CallBack The call back function to execute when the packet
704 is received.
705 @param[in] Context The opaque context passed to Callback.
706 @param[in] HeadLen The length of the upper-layer's protocol header.
707
708 @retval EFI_ALREADY_STARTED There is already a pending receive request. Only
709 one receive request is supported at a time.
710 @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.
711 @retval EFI_SUCCESS The receive request is issued successfully.
712
713 **/
714 EFI_STATUS
715 EFIAPI
716 UdpIoRecvDatagram (
717 IN UDP_IO_PORT *UdpIo,
718 IN UDP_IO_CALLBACK CallBack,
719 IN VOID *Context,
720 IN UINT32 HeadLen
721 )
722 {
723 UDP_RX_TOKEN *Token;
724 EFI_STATUS Status;
725
726 if (UdpIo->RecvRequest != NULL) {
727 return EFI_ALREADY_STARTED;
728 }
729
730 Token = UdpIoCreateRxToken (UdpIo, CallBack, Context, HeadLen);
731
732 if (Token == NULL) {
733 return EFI_OUT_OF_RESOURCES;
734 }
735
736 UdpIo->RecvRequest = Token;
737 Status = UdpIo->Udp->Receive (UdpIo->Udp, &Token->UdpToken);
738
739 if (EFI_ERROR (Status)) {
740 UdpIo->RecvRequest = NULL;
741 UdpIoFreeRxToken (Token);
742 }
743
744 return Status;
745 }