]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.c
refine the code and add more security check.
[mirror_edk2.git] / MdeModulePkg / Library / DxeUdpIoLib / DxeUdpIoLib.c
CommitLineData
cbf316f2 1/** @file\r
9a3293ac 2 Help functions to access UDP service, it is used by both the DHCP and MTFTP.\r
e2851998 3\r
b45b45b2 4Copyright (c) 2005 - 2009, Intel Corporation.<BR>\r
cbf316f2 5All rights reserved. This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
cab450cc 7which accompanies this distribution. The full text of the license may be found at<BR>\r
cbf316f2 8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
cbf316f2 12**/\r
13\r
6c5dc2b0 14#include <Uefi.h>\r
cbf316f2 15\r
16#include <Protocol/Udp4.h>\r
b45b45b2 17#include <Protocol/Udp6.h>\r
cbf316f2 18\r
19#include <Library/UdpIoLib.h>\r
20#include <Library/BaseLib.h>\r
21#include <Library/DebugLib.h>\r
22#include <Library/UefiBootServicesTableLib.h>\r
23#include <Library/MemoryAllocationLib.h>\r
ba0f75a3 24#include <Library/BaseMemoryLib.h>\r
d8d26fb2 25#include <Library/DpcLib.h>\r
cbf316f2 26\r
9a3293ac 27\r
28/**\r
cab450cc 29 Free a UDP_TX_TOKEN. The TX event is closed.\r
9a3293ac 30\r
b45b45b2 31 @param[in] TxToken The UDP_TX_TOKEN to release.\r
9a3293ac 32\r
33**/\r
34VOID\r
35UdpIoFreeTxToken (\r
b45b45b2 36 IN UDP_TX_TOKEN *TxToken\r
9a3293ac 37 )\r
38{\r
b45b45b2 39\r
40 if (TxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {\r
41 gBS->CloseEvent (TxToken->Token.Udp4.Event);\r
42 } else if (TxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION) {\r
43 gBS->CloseEvent (TxToken->Token.Udp6.Event);\r
44 } else {\r
45 ASSERT (FALSE);\r
46 }\r
e2851998 47\r
b45b45b2 48 FreePool (TxToken);\r
9a3293ac 49}\r
50\r
51/**\r
cab450cc 52 Free a UDP_RX_TOKEN. The RX event is closed.\r
9a3293ac 53\r
b45b45b2 54 @param[in] RxToken The UDP_RX_TOKEN to release.\r
9a3293ac 55\r
56**/\r
57VOID\r
58UdpIoFreeRxToken (\r
b45b45b2 59 IN UDP_RX_TOKEN *RxToken\r
9a3293ac 60 )\r
61{\r
b45b45b2 62 if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {\r
63 gBS->CloseEvent (RxToken->Token.Udp4.Event);\r
64 } else if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION) {\r
65 gBS->CloseEvent (RxToken->Token.Udp6.Event);\r
66 } else {\r
67 ASSERT (FALSE);\r
e2851998 68 }\r
b45b45b2 69\r
70 FreePool (RxToken);\r
9a3293ac 71}\r
72\r
73/**\r
74 The callback function when the packet is sent by UDP.\r
e2851998 75\r
9a3293ac 76 It will remove the packet from the local list then call\r
cab450cc 77 the packet owner's callback function set by UdpIoSendDatagram.\r
9a3293ac 78\r
8f5e6151 79 @param[in] Context The UDP TX Token.\r
9a3293ac 80\r
81**/\r
36ee91ca 82VOID\r
83EFIAPI\r
84UdpIoOnDgramSentDpc (\r
85 IN VOID *Context\r
9a3293ac 86 )\r
87{\r
b45b45b2 88 UDP_TX_TOKEN *TxToken;\r
9a3293ac 89\r
b45b45b2 90 TxToken = (UDP_TX_TOKEN *) Context;\r
91 ASSERT (TxToken->Signature == UDP_IO_TX_SIGNATURE);\r
92 ASSERT ((TxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||\r
93 (TxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));\r
e2851998 94\r
b45b45b2 95 RemoveEntryList (&TxToken->Link);\r
9a3293ac 96\r
b45b45b2 97 if (TxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {\r
98 TxToken->CallBack (TxToken->Packet, NULL, TxToken->Token.Udp4.Status, TxToken->Context);\r
99 } else {\r
100 TxToken->CallBack (TxToken->Packet, NULL, TxToken->Token.Udp6.Status, TxToken->Context);\r
101 }\r
9a3293ac 102\r
b45b45b2 103 UdpIoFreeTxToken (TxToken);\r
9a3293ac 104}\r
105\r
106/**\r
107 Request UdpIoOnDgramSentDpc as a DPC at TPL_CALLBACK.\r
e2851998 108\r
8f5e6151 109 @param[in] Event The event signaled.\r
110 @param[in] Context The UDP TX Token.\r
36ee91ca 111\r
9a3293ac 112**/\r
cbf316f2 113VOID\r
114EFIAPI\r
115UdpIoOnDgramSent (\r
116 IN EFI_EVENT Event,\r
117 IN VOID *Context\r
9a3293ac 118 )\r
119{\r
120 //\r
121 // Request UdpIoOnDgramSentDpc as a DPC at TPL_CALLBACK\r
122 //\r
d8d26fb2 123 QueueDpc (TPL_CALLBACK, UdpIoOnDgramSentDpc, Context);\r
9a3293ac 124}\r
125\r
126/**\r
127 Recycle the received UDP data.\r
128\r
8f5e6151 129 @param[in] Context The UDP_RX_TOKEN.\r
cbf316f2 130\r
9a3293ac 131**/\r
132VOID\r
133UdpIoRecycleDgram (\r
134 IN VOID *Context\r
135 )\r
e2851998 136{\r
b45b45b2 137 UDP_RX_TOKEN *RxToken;\r
138\r
139 RxToken = (UDP_RX_TOKEN *) Context;\r
140\r
141 if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {\r
142 gBS->SignalEvent (RxToken->Token.Udp4.Packet.RxData->RecycleSignal);\r
143 } else if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION) {\r
144 gBS->SignalEvent (RxToken->Token.Udp6.Packet.RxData->RecycleSignal);\r
145 } else {\r
146 ASSERT (FALSE);\r
147 }\r
9a3293ac 148\r
b45b45b2 149 UdpIoFreeRxToken (RxToken);\r
9a3293ac 150}\r
151\r
152/**\r
cab450cc 153 The event handle for UDP receive request.\r
e2851998 154\r
cab450cc 155 It will build a NET_BUF from the recieved UDP data, then deliver it\r
9a3293ac 156 to the receiver.\r
157\r
8f5e6151 158 @param[in] Context The UDP RX token.\r
9a3293ac 159\r
160**/\r
161VOID\r
162EFIAPI\r
163UdpIoOnDgramRcvdDpc (\r
164 IN VOID *Context\r
165 )\r
166{\r
b45b45b2 167 EFI_STATUS Status;\r
168 VOID *Token;\r
169 VOID *RxData;\r
170 VOID *Session;\r
171 UDP_RX_TOKEN *RxToken;\r
172 UDP_END_POINT EndPoint;\r
9a3293ac 173 NET_BUF *Netbuf;\r
174\r
b45b45b2 175 RxToken = (UDP_RX_TOKEN *) Context;\r
9a3293ac 176\r
b45b45b2 177 ZeroMem (&EndPoint, sizeof(UDP_END_POINT));\r
178\r
e2851998 179 ASSERT ((RxToken->Signature == UDP_IO_RX_SIGNATURE) &&\r
b45b45b2 180 (RxToken == RxToken->UdpIo->RecvRequest));\r
181\r
182 ASSERT ((RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||\r
183 (RxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));\r
9a3293ac 184\r
185 //\r
186 // Clear the receive request first in case that the caller\r
187 // wants to restart the receive in the callback.\r
188 //\r
b45b45b2 189 RxToken->UdpIo->RecvRequest = NULL;\r
190\r
191 if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {\r
192 Token = &RxToken->Token.Udp4;\r
193 RxData = ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Packet.RxData;\r
194 Status = ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Status;\r
195 } else {\r
196 Token = &RxToken->Token.Udp6;\r
197 RxData = ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Packet.RxData;\r
198 Status = ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Status;\r
199 }\r
9a3293ac 200\r
b45b45b2 201 if (EFI_ERROR (Status) || RxData == NULL) {\r
202 if (Status != EFI_ABORTED) {\r
9a3293ac 203 //\r
204 // Invoke the CallBack only if the reception is not actively aborted.\r
205 //\r
b45b45b2 206 RxToken->CallBack (NULL, NULL, Status, RxToken->Context);\r
9a3293ac 207 }\r
208\r
b45b45b2 209 UdpIoFreeRxToken (RxToken);\r
9a3293ac 210 return;\r
211 }\r
212\r
213 //\r
214 // Build a NET_BUF from the UDP receive data, then deliver it up.\r
215 //\r
b45b45b2 216 if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {\r
e2851998 217\r
b45b45b2 218 Netbuf = NetbufFromExt (\r
219 (NET_FRAGMENT *)((EFI_UDP4_RECEIVE_DATA *) RxData)->FragmentTable,\r
220 ((EFI_UDP4_RECEIVE_DATA *) RxData)->FragmentCount,\r
221 0,\r
222 (UINT32) RxToken->HeadLen,\r
223 UdpIoRecycleDgram,\r
224 RxToken\r
225 );\r
226\r
227 if (Netbuf == NULL) {\r
228 gBS->SignalEvent (((EFI_UDP4_RECEIVE_DATA *) RxData)->RecycleSignal);\r
229 RxToken->CallBack (NULL, NULL, EFI_OUT_OF_RESOURCES, RxToken->Context);\r
230\r
231 UdpIoFreeRxToken (RxToken);\r
232 return;\r
233 }\r
9a3293ac 234\r
b45b45b2 235 Session = &((EFI_UDP4_RECEIVE_DATA *) RxData)->UdpSession;\r
236 EndPoint.LocalPort = ((EFI_UDP4_SESSION_DATA *) Session)->DestinationPort;\r
237 EndPoint.RemotePort = ((EFI_UDP4_SESSION_DATA *) Session)->SourcePort;\r
238\r
239 CopyMem (\r
240 &EndPoint.LocalAddr,\r
241 &((EFI_UDP4_SESSION_DATA *) Session)->DestinationAddress,\r
242 sizeof (EFI_IPv4_ADDRESS)\r
243 );\r
244\r
245 CopyMem (\r
246 &EndPoint.RemoteAddr,\r
247 &((EFI_UDP4_SESSION_DATA *) Session)->SourceAddress,\r
248 sizeof (EFI_IPv4_ADDRESS)\r
249 );\r
250\r
251 EndPoint.LocalAddr.Addr[0] = NTOHL (EndPoint.LocalAddr.Addr[0]);\r
252 EndPoint.RemoteAddr.Addr[0] = NTOHL (EndPoint.RemoteAddr.Addr[0]);\r
253 } else {\r
e2851998 254\r
b45b45b2 255 Netbuf = NetbufFromExt (\r
256 (NET_FRAGMENT *)((EFI_UDP6_RECEIVE_DATA *) RxData)->FragmentTable,\r
257 ((EFI_UDP6_RECEIVE_DATA *) RxData)->FragmentCount,\r
258 0,\r
259 (UINT32) RxToken->HeadLen,\r
260 UdpIoRecycleDgram,\r
261 RxToken\r
262 );\r
e2851998 263\r
b45b45b2 264 if (Netbuf == NULL) {\r
265 gBS->SignalEvent (((EFI_UDP6_RECEIVE_DATA *) RxData)->RecycleSignal);\r
266 RxToken->CallBack (NULL, NULL, EFI_OUT_OF_RESOURCES, RxToken->Context);\r
e2851998 267\r
b45b45b2 268 UdpIoFreeRxToken (RxToken);\r
269 return;\r
270 }\r
e2851998 271\r
b45b45b2 272 Session = &((EFI_UDP6_RECEIVE_DATA *) RxData)->UdpSession;\r
273 EndPoint.LocalPort = ((EFI_UDP6_SESSION_DATA *) Session)->DestinationPort;\r
274 EndPoint.RemotePort = ((EFI_UDP6_SESSION_DATA *) Session)->SourcePort;\r
e2851998 275\r
b45b45b2 276 CopyMem (\r
277 &EndPoint.LocalAddr,\r
278 &((EFI_UDP6_SESSION_DATA *) Session)->DestinationAddress,\r
279 sizeof (EFI_IPv6_ADDRESS)\r
280 );\r
281\r
282 CopyMem (\r
283 &EndPoint.RemoteAddr,\r
284 &((EFI_UDP6_SESSION_DATA *) Session)->SourceAddress,\r
285 sizeof (EFI_IPv6_ADDRESS)\r
286 );\r
287\r
288 Ip6Swap128 (&EndPoint.LocalAddr.v6);\r
289 Ip6Swap128 (&EndPoint.RemoteAddr.v6);\r
290 }\r
9a3293ac 291\r
b45b45b2 292 RxToken->CallBack (Netbuf, &EndPoint, EFI_SUCCESS, RxToken->Context);\r
9a3293ac 293}\r
294\r
295/**\r
ca9d3a9d 296 Request UdpIoOnDgramRcvdDpc() as a DPC at TPL_CALLBACK.\r
9a3293ac 297\r
8f5e6151 298 @param[in] Event The UDP receive request event.\r
299 @param[in] Context The UDP RX token.\r
9a3293ac 300\r
301**/\r
cbf316f2 302VOID\r
303EFIAPI\r
304UdpIoOnDgramRcvd (\r
305 IN EFI_EVENT Event,\r
306 IN VOID *Context\r
9a3293ac 307 )\r
308{\r
309 //\r
310 // Request UdpIoOnDgramRcvdDpc as a DPC at TPL_CALLBACK\r
311 //\r
d8d26fb2 312 QueueDpc (TPL_CALLBACK, UdpIoOnDgramRcvdDpc, Context);\r
9a3293ac 313}\r
cbf316f2 314\r
9a3293ac 315/**\r
316 Create a UDP_RX_TOKEN to wrap the request.\r
317\r
8f5e6151 318 @param[in] UdpIo The UdpIo to receive packets from.\r
319 @param[in] CallBack The function to call when receive finished.\r
320 @param[in] Context The opaque parameter to the CallBack.\r
321 @param[in] HeadLen The head length to reserver for the packet.\r
9a3293ac 322\r
323 @return The Wrapped request or NULL if failed to allocate resources or some errors happened.\r
324\r
325**/\r
326UDP_RX_TOKEN *\r
327UdpIoCreateRxToken (\r
b45b45b2 328 IN UDP_IO *UdpIo,\r
9a3293ac 329 IN UDP_IO_CALLBACK CallBack,\r
330 IN VOID *Context,\r
331 IN UINT32 HeadLen\r
332 )\r
333{\r
334 UDP_RX_TOKEN *Token;\r
335 EFI_STATUS Status;\r
336\r
b45b45b2 337 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||\r
338 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));\r
339\r
9a3293ac 340 Token = AllocatePool (sizeof (UDP_RX_TOKEN));\r
341\r
342 if (Token == NULL) {\r
343 return NULL;\r
344 }\r
345\r
346 Token->Signature = UDP_IO_RX_SIGNATURE;\r
347 Token->UdpIo = UdpIo;\r
348 Token->CallBack = CallBack;\r
349 Token->Context = Context;\r
350 Token->HeadLen = HeadLen;\r
351\r
b45b45b2 352 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {\r
353\r
354 Token->Token.Udp4.Status = EFI_NOT_READY;\r
355 Token->Token.Udp4.Packet.RxData = NULL;\r
356\r
357 Status = gBS->CreateEvent (\r
358 EVT_NOTIFY_SIGNAL,\r
359 TPL_NOTIFY,\r
360 UdpIoOnDgramRcvd,\r
361 Token,\r
362 &Token->Token.Udp4.Event\r
363 );\r
364 } else {\r
e2851998 365\r
b45b45b2 366 Token->Token.Udp6.Status = EFI_NOT_READY;\r
367 Token->Token.Udp6.Packet.RxData = NULL;\r
368\r
369 Status = gBS->CreateEvent (\r
370 EVT_NOTIFY_SIGNAL,\r
371 TPL_NOTIFY,\r
372 UdpIoOnDgramRcvd,\r
373 Token,\r
374 &Token->Token.Udp6.Event\r
375 );\r
e2851998 376 }\r
9a3293ac 377\r
9a3293ac 378\r
379 if (EFI_ERROR (Status)) {\r
b45b45b2 380 FreePool (Token);\r
9a3293ac 381 return NULL;\r
382 }\r
383\r
384 return Token;\r
385}\r
cbf316f2 386\r
387/**\r
b45b45b2 388 Wrap a transmit request into a new created UDP_TX_TOKEN.\r
cbf316f2 389\r
b45b45b2 390 @param[in] UdpIo The UdpIo to send packet to.\r
8f5e6151 391 @param[in] Packet The user's packet.\r
392 @param[in] EndPoint The local and remote access point.\r
393 @param[in] Gateway The overrided next hop.\r
394 @param[in] CallBack The function to call when transmission completed.\r
395 @param[in] Context The opaque parameter to the call back.\r
cbf316f2 396\r
e2851998 397 @return The wrapped transmission request or NULL if failed to allocate resources\r
9a3293ac 398 or for some errors.\r
cbf316f2 399\r
400**/\r
cbf316f2 401UDP_TX_TOKEN *\r
b45b45b2 402UdpIoCreateTxToken (\r
403 IN UDP_IO *UdpIo,\r
cbf316f2 404 IN NET_BUF *Packet,\r
b45b45b2 405 IN UDP_END_POINT *EndPoint OPTIONAL,\r
406 IN EFI_IP_ADDRESS *Gateway OPTIONAL,\r
cbf316f2 407 IN UDP_IO_CALLBACK CallBack,\r
408 IN VOID *Context\r
409 )\r
410{\r
b45b45b2 411 UDP_TX_TOKEN *TxToken;\r
412 VOID *Token;\r
413 VOID *Data;\r
cbf316f2 414 EFI_STATUS Status;\r
415 UINT32 Count;\r
b45b45b2 416 UINTN Size;\r
e2851998 417 IP4_ADDR Ip;\r
cbf316f2 418\r
b45b45b2 419 ASSERT (Packet != NULL);\r
420 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||\r
421 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));\r
cbf316f2 422\r
b45b45b2 423 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {\r
424 Size = sizeof (UDP_TX_TOKEN) + sizeof (EFI_UDP4_FRAGMENT_DATA) * (Packet->BlockOpNum - 1);\r
425 } else {\r
426 Size = sizeof (UDP_TX_TOKEN) + sizeof (EFI_UDP6_FRAGMENT_DATA) * (Packet->BlockOpNum - 1);\r
cbf316f2 427 }\r
428\r
b45b45b2 429 TxToken = AllocatePool (Size);\r
cbf316f2 430\r
b45b45b2 431 if (TxToken == NULL) {\r
432 return NULL;\r
433 }\r
cbf316f2 434\r
b45b45b2 435 TxToken->Signature = UDP_IO_TX_SIGNATURE;\r
436 InitializeListHead (&TxToken->Link);\r
cbf316f2 437\r
b45b45b2 438 TxToken->UdpIo = UdpIo;\r
439 TxToken->CallBack = CallBack;\r
440 TxToken->Packet = Packet;\r
441 TxToken->Context = Context;\r
cbf316f2 442\r
b45b45b2 443 Token = &(TxToken->Token);\r
444 Count = Packet->BlockOpNum;\r
cbf316f2 445\r
b45b45b2 446 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {\r
cbf316f2 447\r
b45b45b2 448 ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Status = EFI_NOT_READY;\r
cbf316f2 449\r
b45b45b2 450 Status = gBS->CreateEvent (\r
451 EVT_NOTIFY_SIGNAL,\r
452 TPL_NOTIFY,\r
453 UdpIoOnDgramSent,\r
454 TxToken,\r
455 &((EFI_UDP4_COMPLETION_TOKEN *) Token)->Event\r
456 );\r
b61439a7 457\r
b45b45b2 458 if (EFI_ERROR (Status)) {\r
459 FreePool (TxToken);\r
460 return NULL;\r
461 }\r
b61439a7 462\r
b45b45b2 463 Data = &(TxToken->Data.Udp4);\r
464 ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Packet.TxData = Data;\r
465\r
466 ((EFI_UDP4_TRANSMIT_DATA *) Data)->UdpSessionData = NULL;\r
467 ((EFI_UDP4_TRANSMIT_DATA *) Data)->GatewayAddress = NULL;\r
468 ((EFI_UDP4_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize;\r
469\r
470 NetbufBuildExt (\r
471 Packet,\r
472 (NET_FRAGMENT *)((EFI_UDP4_TRANSMIT_DATA *) Data)->FragmentTable,\r
473 &Count\r
474 );\r
475\r
476 ((EFI_UDP4_TRANSMIT_DATA *) Data)->FragmentCount = Count;\r
477\r
478 if (EndPoint != NULL) {\r
479 Ip = HTONL (EndPoint->LocalAddr.Addr[0]);\r
480 CopyMem (\r
e2851998 481 &TxToken->Session.Udp4.SourceAddress,\r
482 &Ip,\r
b45b45b2 483 sizeof (EFI_IPv4_ADDRESS)\r
484 );\r
485\r
486 Ip = HTONL (EndPoint->RemoteAddr.Addr[0]);\r
487 CopyMem (\r
e2851998 488 &TxToken->Session.Udp4.DestinationAddress,\r
489 &Ip,\r
b45b45b2 490 sizeof (EFI_IPv4_ADDRESS)\r
491 );\r
492\r
493 TxToken->Session.Udp4.SourcePort = EndPoint->LocalPort;\r
494 TxToken->Session.Udp4.DestinationPort = EndPoint->RemotePort;\r
495 ((EFI_UDP4_TRANSMIT_DATA *) Data)->UdpSessionData = &(TxToken->Session.Udp4);\r
496 }\r
cbf316f2 497\r
b45b45b2 498 if (Gateway != NULL && (Gateway->Addr[0] != 0)) {\r
499 Ip = HTONL (Gateway->Addr[0]);\r
500 CopyMem (&TxToken->Gateway, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
e2851998 501 ((EFI_UDP4_TRANSMIT_DATA *) Data)->GatewayAddress = &TxToken->Gateway;\r
b45b45b2 502 }\r
b61439a7 503\r
b45b45b2 504 } else {\r
e2851998 505\r
b45b45b2 506 ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Status = EFI_NOT_READY;\r
e2851998 507\r
b45b45b2 508 Status = gBS->CreateEvent (\r
509 EVT_NOTIFY_SIGNAL,\r
510 TPL_NOTIFY,\r
511 UdpIoOnDgramSent,\r
512 TxToken,\r
513 &((EFI_UDP6_COMPLETION_TOKEN *) Token)->Event\r
514 );\r
515\r
516 if (EFI_ERROR (Status)) {\r
517 FreePool (TxToken);\r
518 return NULL;\r
519 }\r
e2851998 520\r
b45b45b2 521 Data = &(TxToken->Data.Udp6);\r
522 ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Packet.TxData = Data;\r
523 ((EFI_UDP6_TRANSMIT_DATA *) Data)->UdpSessionData = NULL;\r
524 ((EFI_UDP6_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize;\r
525\r
526 NetbufBuildExt (\r
527 Packet,\r
528 (NET_FRAGMENT *)((EFI_UDP6_TRANSMIT_DATA *) Data)->FragmentTable,\r
529 &Count\r
530 );\r
531\r
532 ((EFI_UDP6_TRANSMIT_DATA *) Data)->FragmentCount = Count;\r
533\r
534 if (EndPoint != NULL) {\r
535 CopyMem (\r
e2851998 536 &TxToken->Session.Udp6.SourceAddress,\r
537 &EndPoint->LocalAddr.v6,\r
b45b45b2 538 sizeof(EFI_IPv6_ADDRESS)\r
539 );\r
540\r
541 CopyMem (\r
e2851998 542 &TxToken->Session.Udp6.DestinationAddress,\r
543 &EndPoint->RemoteAddr.v6,\r
b45b45b2 544 sizeof(EFI_IPv6_ADDRESS)\r
545 );\r
546\r
547 TxToken->Session.Udp6.SourcePort = EndPoint->LocalPort;\r
548 TxToken->Session.Udp6.DestinationPort = EndPoint->RemotePort;\r
549 ((EFI_UDP6_TRANSMIT_DATA *) Data)->UdpSessionData = &(TxToken->Session.Udp6);\r
e2851998 550 }\r
cbf316f2 551 }\r
552\r
b45b45b2 553 return TxToken;\r
cbf316f2 554}\r
555\r
cbf316f2 556/**\r
b45b45b2 557 Creates a UDP_IO to access the UDP service. It creates and configures\r
cab450cc 558 a UDP child.\r
e2851998 559\r
560 It locates the UDP service binding prototype on the Controller parameter\r
561 uses the UDP service binding prototype to create a UDP child (also known as\r
562 a UDP instance) configures the UDP child by calling Configure function prototype.\r
563 Any failures in creating or configuring the UDP child return NULL for failure.\r
cbf316f2 564\r
8f5e6151 565 @param[in] Controller The controller that has the UDP service binding.\r
566 protocol installed.\r
b45b45b2 567 @param[in] ImageHandle The image handle for the driver.\r
8f5e6151 568 @param[in] Configure The function to configure the created UDP child.\r
b45b45b2 569 @param[in] UdpVersion The UDP protocol version, UDP4 or UDP6.\r
8f5e6151 570 @param[in] Context The opaque parameter for the Configure funtion.\r
cbf316f2 571\r
b45b45b2 572 @return Newly-created UDP_IO or NULL if failed.\r
cbf316f2 573\r
574**/\r
b45b45b2 575UDP_IO *\r
7b414b4e 576EFIAPI\r
b45b45b2 577UdpIoCreateIo (\r
cbf316f2 578 IN EFI_HANDLE Controller,\r
b45b45b2 579 IN EFI_HANDLE ImageHandle,\r
cbf316f2 580 IN UDP_IO_CONFIG Configure,\r
b45b45b2 581 IN UINT8 UdpVersion,\r
cbf316f2 582 IN VOID *Context\r
583 )\r
584{\r
b45b45b2 585 UDP_IO *UdpIo;\r
cbf316f2 586 EFI_STATUS Status;\r
587\r
588 ASSERT (Configure != NULL);\r
b45b45b2 589 ASSERT ((UdpVersion == UDP_IO_UDP4_VERSION) || (UdpVersion == UDP_IO_UDP6_VERSION));\r
cbf316f2 590\r
b45b45b2 591 UdpIo = AllocatePool (sizeof (UDP_IO));\r
cbf316f2 592\r
593 if (UdpIo == NULL) {\r
594 return NULL;\r
595 }\r
596\r
b45b45b2 597 UdpIo->UdpVersion = UdpVersion;\r
cbf316f2 598 UdpIo->Signature = UDP_IO_SIGNATURE;\r
e48e37fc 599 InitializeListHead (&UdpIo->Link);\r
cbf316f2 600 UdpIo->RefCnt = 1;\r
601\r
602 UdpIo->Controller = Controller;\r
b45b45b2 603 UdpIo->Image = ImageHandle;\r
cbf316f2 604\r
e48e37fc 605 InitializeListHead (&UdpIo->SentDatagram);\r
cbf316f2 606 UdpIo->RecvRequest = NULL;\r
607 UdpIo->UdpHandle = NULL;\r
608\r
b45b45b2 609 if (UdpVersion == UDP_IO_UDP4_VERSION) {\r
610 //\r
611 // Create a UDP child then open and configure it\r
612 //\r
613 Status = NetLibCreateServiceChild (\r
614 Controller,\r
615 ImageHandle,\r
616 &gEfiUdp4ServiceBindingProtocolGuid,\r
617 &UdpIo->UdpHandle\r
618 );\r
e2851998 619\r
b45b45b2 620 if (EFI_ERROR (Status)) {\r
621 goto FREE_MEM;\r
622 }\r
cbf316f2 623\r
b45b45b2 624 Status = gBS->OpenProtocol (\r
625 UdpIo->UdpHandle,\r
626 &gEfiUdp4ProtocolGuid,\r
627 (VOID **) &UdpIo->Protocol.Udp4,\r
628 ImageHandle,\r
629 Controller,\r
630 EFI_OPEN_PROTOCOL_BY_DRIVER\r
631 );\r
632\r
633 if (EFI_ERROR (Status)) {\r
634 goto FREE_CHILD;\r
635 }\r
cbf316f2 636\r
b45b45b2 637 if (EFI_ERROR (Configure (UdpIo, Context))) {\r
638 goto CLOSE_PROTOCOL;\r
639 }\r
e2851998 640\r
b45b45b2 641 Status = UdpIo->Protocol.Udp4->GetModeData (\r
e2851998 642 UdpIo->Protocol.Udp4,\r
643 NULL,\r
644 NULL,\r
645 NULL,\r
b45b45b2 646 &UdpIo->SnpMode\r
647 );\r
e2851998 648\r
b45b45b2 649 if (EFI_ERROR (Status)) {\r
650 goto CLOSE_PROTOCOL;\r
651 }\r
cbf316f2 652\r
b45b45b2 653 } else {\r
e2851998 654\r
b45b45b2 655 Status = NetLibCreateServiceChild (\r
656 Controller,\r
657 ImageHandle,\r
658 &gEfiUdp6ServiceBindingProtocolGuid,\r
659 &UdpIo->UdpHandle\r
660 );\r
e2851998 661\r
b45b45b2 662 if (EFI_ERROR (Status)) {\r
663 goto FREE_MEM;\r
664 }\r
e2851998 665\r
b45b45b2 666 Status = gBS->OpenProtocol (\r
667 UdpIo->UdpHandle,\r
668 &gEfiUdp6ProtocolGuid,\r
669 (VOID **) &UdpIo->Protocol.Udp6,\r
670 ImageHandle,\r
671 Controller,\r
672 EFI_OPEN_PROTOCOL_BY_DRIVER\r
673 );\r
e2851998 674\r
b45b45b2 675 if (EFI_ERROR (Status)) {\r
676 goto FREE_CHILD;\r
677 }\r
e2851998 678\r
b45b45b2 679 if (EFI_ERROR (Configure (UdpIo, Context))) {\r
680 goto CLOSE_PROTOCOL;\r
681 }\r
e2851998 682\r
b45b45b2 683 Status = UdpIo->Protocol.Udp6->GetModeData (\r
e2851998 684 UdpIo->Protocol.Udp6,\r
685 NULL,\r
686 NULL,\r
687 NULL,\r
b45b45b2 688 &UdpIo->SnpMode\r
689 );\r
e2851998 690\r
b45b45b2 691 if (EFI_ERROR (Status)) {\r
692 goto CLOSE_PROTOCOL;\r
693 }\r
cbf316f2 694 }\r
695\r
696 return UdpIo;\r
697\r
698CLOSE_PROTOCOL:\r
b45b45b2 699 if (UdpVersion == UDP_IO_UDP4_VERSION) {\r
700 gBS->CloseProtocol (UdpIo->UdpHandle, &gEfiUdp4ProtocolGuid, ImageHandle, Controller);\r
701 } else {\r
702 gBS->CloseProtocol (UdpIo->UdpHandle, &gEfiUdp6ProtocolGuid, ImageHandle, Controller);\r
703 }\r
cbf316f2 704\r
705FREE_CHILD:\r
b45b45b2 706 if (UdpVersion == UDP_IO_UDP4_VERSION) {\r
707 NetLibDestroyServiceChild (\r
708 Controller,\r
709 ImageHandle,\r
710 &gEfiUdp4ServiceBindingProtocolGuid,\r
711 UdpIo->UdpHandle\r
712 );\r
713 } else {\r
714 NetLibDestroyServiceChild (\r
715 Controller,\r
716 ImageHandle,\r
717 &gEfiUdp6ServiceBindingProtocolGuid,\r
718 UdpIo->UdpHandle\r
719 );\r
720 }\r
cbf316f2 721\r
722FREE_MEM:\r
b45b45b2 723 FreePool (UdpIo);\r
cbf316f2 724 return NULL;\r
725}\r
726\r
cbf316f2 727/**\r
cab450cc 728 Cancel all the sent datagram that pass the selection criteria of ToCancel.\r
cbf316f2 729 If ToCancel is NULL, all the datagrams are cancelled.\r
730\r
b45b45b2 731 @param[in] UdpIo The UDP_IO to cancel packet.\r
8f5e6151 732 @param[in] IoStatus The IoStatus to return to the packet owners.\r
733 @param[in] ToCancel The select funtion to test whether to cancel this\r
734 packet or not.\r
735 @param[in] Context The opaque parameter to the ToCancel.\r
cbf316f2 736\r
cbf316f2 737**/\r
cbf316f2 738VOID\r
e4b99ad9 739EFIAPI\r
cbf316f2 740UdpIoCancelDgrams (\r
b45b45b2 741 IN UDP_IO *UdpIo,\r
cbf316f2 742 IN EFI_STATUS IoStatus,\r
743 IN UDP_IO_TO_CANCEL ToCancel, OPTIONAL\r
744 IN VOID *Context\r
745 )\r
746{\r
e48e37fc 747 LIST_ENTRY *Entry;\r
748 LIST_ENTRY *Next;\r
b45b45b2 749 UDP_TX_TOKEN *TxToken;\r
750\r
751 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||\r
752 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));\r
cbf316f2 753\r
754 NET_LIST_FOR_EACH_SAFE (Entry, Next, &UdpIo->SentDatagram) {\r
b45b45b2 755 TxToken = NET_LIST_USER_STRUCT (Entry, UDP_TX_TOKEN, Link);\r
756\r
757 if ((ToCancel == NULL) || (ToCancel (TxToken, Context))) {\r
cbf316f2 758\r
b45b45b2 759 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {\r
760 UdpIo->Protocol.Udp4->Cancel (UdpIo->Protocol.Udp4, &TxToken->Token.Udp4);\r
761 } else {\r
762 UdpIo->Protocol.Udp6->Cancel (UdpIo->Protocol.Udp6, &TxToken->Token.Udp6);\r
763 }\r
cbf316f2 764 }\r
e2851998 765 }\r
cbf316f2 766}\r
767\r
cbf316f2 768/**\r
b45b45b2 769 Free the UDP_IO and all its related resources.\r
e2851998 770\r
cab450cc 771 The function will cancel all sent datagram and receive request.\r
cbf316f2 772\r
b45b45b2 773 @param[in] UdpIo The UDP_IO to free.\r
cbf316f2 774\r
b45b45b2 775 @retval EFI_SUCCESS The UDP_IO is freed.\r
cbf316f2 776\r
777**/\r
778EFI_STATUS\r
7b414b4e 779EFIAPI\r
b45b45b2 780UdpIoFreeIo (\r
781 IN UDP_IO *UdpIo\r
cbf316f2 782 )\r
783{\r
b45b45b2 784 UDP_RX_TOKEN *RxToken;\r
785\r
786 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||\r
787 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));\r
cbf316f2 788\r
789 //\r
790 // Cancel all the sent datagram and receive requests. The\r
791 // callbacks of transmit requests are executed to allow the\r
792 // caller to release the resource. The callback of receive\r
793 // request are NOT executed. This is because it is most\r
794 // likely that the current user of the UDP IO port is closing\r
795 // itself.\r
796 //\r
797 UdpIoCancelDgrams (UdpIo, EFI_ABORTED, NULL, NULL);\r
798\r
b45b45b2 799 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {\r
cbf316f2 800\r
b45b45b2 801 if ((RxToken = UdpIo->RecvRequest) != NULL) {\r
802 UdpIo->Protocol.Udp4->Cancel (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);\r
803 }\r
804\r
805 //\r
806 // Close then destory the Udp4 child\r
807 //\r
808 gBS->CloseProtocol (\r
809 UdpIo->UdpHandle,\r
810 &gEfiUdp4ProtocolGuid,\r
811 UdpIo->Image,\r
812 UdpIo->Controller\r
813 );\r
814\r
815 NetLibDestroyServiceChild (\r
816 UdpIo->Controller,\r
817 UdpIo->Image,\r
818 &gEfiUdp4ServiceBindingProtocolGuid,\r
819 UdpIo->UdpHandle\r
820 );\r
821\r
822 } else {\r
823\r
824 if ((RxToken = UdpIo->RecvRequest) != NULL) {\r
825 UdpIo->Protocol.Udp6->Cancel (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6);\r
826 }\r
e2851998 827\r
b45b45b2 828 //\r
829 // Close then destory the Udp6 child\r
830 //\r
831 gBS->CloseProtocol (\r
832 UdpIo->UdpHandle,\r
833 &gEfiUdp6ProtocolGuid,\r
834 UdpIo->Image,\r
835 UdpIo->Controller\r
836 );\r
e2851998 837\r
b45b45b2 838 NetLibDestroyServiceChild (\r
839 UdpIo->Controller,\r
840 UdpIo->Image,\r
841 &gEfiUdp6ServiceBindingProtocolGuid,\r
842 UdpIo->UdpHandle\r
843 );\r
844 }\r
cbf316f2 845\r
687a2e5f 846 if (!IsListEmpty(&UdpIo->Link)) {\r
e48e37fc 847 RemoveEntryList (&UdpIo->Link);\r
687a2e5f 848 }\r
849\r
b45b45b2 850 FreePool (UdpIo);\r
cbf316f2 851 return EFI_SUCCESS;\r
852}\r
853\r
854\r
855/**\r
b45b45b2 856 Clean up the UDP_IO without freeing it. The function is called when\r
857 user wants to re-use the UDP_IO later.\r
e2851998 858\r
cab450cc 859 It will release all the transmitted datagrams and receive request. It will\r
860 also configure NULL for the UDP instance.\r
cbf316f2 861\r
b45b45b2 862 @param[in] UdpIo The UDP_IO to clean up.\r
cbf316f2 863\r
cbf316f2 864**/\r
865VOID\r
7b414b4e 866EFIAPI\r
b45b45b2 867UdpIoCleanIo (\r
868 IN UDP_IO *UdpIo\r
cbf316f2 869 )\r
870{\r
871 UDP_RX_TOKEN *RxToken;\r
872\r
b45b45b2 873 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||\r
874 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));\r
875\r
cbf316f2 876 //\r
877 // Cancel all the sent datagram and receive requests.\r
878 //\r
879 UdpIoCancelDgrams (UdpIo, EFI_ABORTED, NULL, NULL);\r
880\r
b45b45b2 881 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {\r
882 if ((RxToken = UdpIo->RecvRequest) != NULL) {\r
883 UdpIo->Protocol.Udp4->Cancel (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);\r
884 }\r
885\r
886 UdpIo->Protocol.Udp4->Configure (UdpIo->Protocol.Udp4, NULL);\r
cbf316f2 887\r
b45b45b2 888 } else {\r
889 if ((RxToken = UdpIo->RecvRequest) != NULL) {\r
890 UdpIo->Protocol.Udp6->Cancel (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6);\r
891 }\r
892\r
893 UdpIo->Protocol.Udp6->Configure (UdpIo->Protocol.Udp6, NULL);\r
894 }\r
cbf316f2 895}\r
896\r
cbf316f2 897/**\r
b45b45b2 898 Send a packet through the UDP_IO.\r
e2851998 899\r
cab450cc 900 The packet will be wrapped in UDP_TX_TOKEN. Function Callback will be called\r
901 when the packet is sent. The optional parameter EndPoint overrides the default\r
902 address pair if specified.\r
cbf316f2 903\r
b45b45b2 904 @param[in] UdpIo The UDP_IO to send the packet through.\r
8f5e6151 905 @param[in] Packet The packet to send.\r
906 @param[in] EndPoint The local and remote access point. Override the\r
907 default address pair set during configuration.\r
e2851998 908 @param[in] Gateway The gateway to use.\r
8f5e6151 909 @param[in] CallBack The function being called when packet is\r
910 transmitted or failed.\r
911 @param[in] Context The opaque parameter passed to CallBack.\r
cbf316f2 912\r
8f5e6151 913 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the packet.\r
cbf316f2 914 @retval EFI_SUCCESS The packet is successfully delivered to UDP for\r
915 transmission.\r
916\r
917**/\r
918EFI_STATUS\r
7b414b4e 919EFIAPI\r
cbf316f2 920UdpIoSendDatagram (\r
b45b45b2 921 IN UDP_IO *UdpIo,\r
cbf316f2 922 IN NET_BUF *Packet,\r
b45b45b2 923 IN UDP_END_POINT *EndPoint OPTIONAL,\r
924 IN EFI_IP_ADDRESS *Gateway OPTIONAL,\r
cbf316f2 925 IN UDP_IO_CALLBACK CallBack,\r
926 IN VOID *Context\r
927 )\r
928{\r
b45b45b2 929 UDP_TX_TOKEN *TxToken;\r
cbf316f2 930 EFI_STATUS Status;\r
931\r
b45b45b2 932 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||\r
933 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));\r
cbf316f2 934\r
b45b45b2 935 TxToken = UdpIoCreateTxToken (UdpIo, Packet, EndPoint, Gateway, CallBack, Context);\r
936\r
937 if (TxToken == NULL) {\r
cbf316f2 938 return EFI_OUT_OF_RESOURCES;\r
939 }\r
940\r
36ee91ca 941 //\r
942 // Insert the tx token into SendDatagram list before transmitting it. Remove\r
943 // it from the list if the returned status is not EFI_SUCCESS.\r
944 //\r
b45b45b2 945 InsertHeadList (&UdpIo->SentDatagram, &TxToken->Link);\r
946\r
947 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {\r
948 Status = UdpIo->Protocol.Udp4->Transmit (UdpIo->Protocol.Udp4, &TxToken->Token.Udp4);\r
949 } else {\r
950 Status = UdpIo->Protocol.Udp6->Transmit (UdpIo->Protocol.Udp6, &TxToken->Token.Udp6);\r
951 }\r
952\r
cbf316f2 953 if (EFI_ERROR (Status)) {\r
b45b45b2 954 RemoveEntryList (&TxToken->Link);\r
955 UdpIoFreeTxToken (TxToken);\r
cbf316f2 956 return Status;\r
957 }\r
958\r
cbf316f2 959 return EFI_SUCCESS;\r
960}\r
961\r
962\r
963/**\r
cab450cc 964 The select function to cancel a single sent datagram.\r
cbf316f2 965\r
8f5e6151 966 @param[in] Token The UDP_TX_TOKEN to test against\r
967 @param[in] Context The NET_BUF of the sent datagram\r
cbf316f2 968\r
9a3293ac 969 @retval TRUE The packet is to be cancelled.\r
970 @retval FALSE The packet is not to be cancelled.\r
cbf316f2 971**/\r
cbf316f2 972BOOLEAN\r
973UdpIoCancelSingleDgram (\r
974 IN UDP_TX_TOKEN *Token,\r
975 IN VOID *Context\r
976 )\r
977{\r
978 NET_BUF *Packet;\r
979\r
980 Packet = (NET_BUF *) Context;\r
981\r
982 if (Token->Packet == Packet) {\r
983 return TRUE;\r
984 }\r
985\r
986 return FALSE;\r
987}\r
988\r
cbf316f2 989/**\r
990 Cancel a single sent datagram.\r
991\r
b45b45b2 992 @param[in] UdpIo The UDP_IO to cancel the packet from\r
8f5e6151 993 @param[in] Packet The packet to cancel\r
cbf316f2 994\r
cbf316f2 995**/\r
996VOID\r
7b414b4e 997EFIAPI\r
cbf316f2 998UdpIoCancelSentDatagram (\r
b45b45b2 999 IN UDP_IO *UdpIo,\r
cbf316f2 1000 IN NET_BUF *Packet\r
1001 )\r
1002{\r
1003 UdpIoCancelDgrams (UdpIo, EFI_ABORTED, UdpIoCancelSingleDgram, Packet);\r
1004}\r
1005\r
cbf316f2 1006/**\r
b45b45b2 1007 Issue a receive request to the UDP_IO.\r
e2851998 1008\r
cab450cc 1009 This function is called when upper-layer needs packet from UDP for processing.\r
1010 Only one receive request is acceptable at a time so a common usage model is\r
1011 to invoke this function inside its Callback function when the former packet\r
1012 is processed.\r
cbf316f2 1013\r
b45b45b2 1014 @param[in] UdpIo The UDP_IO to receive the packet from.\r
8f5e6151 1015 @param[in] CallBack The call back function to execute when the packet\r
1016 is received.\r
1017 @param[in] Context The opaque context passed to Callback.\r
b45b45b2 1018 @param[in] HeadLen The length of the upper-layer's protocol header.\r
cbf316f2 1019\r
1020 @retval EFI_ALREADY_STARTED There is already a pending receive request. Only\r
cab450cc 1021 one receive request is supported at a time.\r
1022 @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.\r
cbf316f2 1023 @retval EFI_SUCCESS The receive request is issued successfully.\r
b45b45b2 1024 @retval EFI_UNSUPPORTED The UDP version in UDP_IO is not supported.\r
cbf316f2 1025\r
1026**/\r
1027EFI_STATUS\r
7b414b4e 1028EFIAPI\r
cbf316f2 1029UdpIoRecvDatagram (\r
b45b45b2 1030 IN UDP_IO *UdpIo,\r
cbf316f2 1031 IN UDP_IO_CALLBACK CallBack,\r
1032 IN VOID *Context,\r
1033 IN UINT32 HeadLen\r
1034 )\r
1035{\r
b45b45b2 1036 UDP_RX_TOKEN *RxToken;\r
cbf316f2 1037 EFI_STATUS Status;\r
1038\r
b45b45b2 1039 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||\r
1040 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));\r
1041\r
cbf316f2 1042 if (UdpIo->RecvRequest != NULL) {\r
1043 return EFI_ALREADY_STARTED;\r
1044 }\r
1045\r
b45b45b2 1046 RxToken = UdpIoCreateRxToken (UdpIo, CallBack, Context, HeadLen);\r
cbf316f2 1047\r
b45b45b2 1048 if (RxToken == NULL) {\r
cbf316f2 1049 return EFI_OUT_OF_RESOURCES;\r
1050 }\r
1051\r
b45b45b2 1052 UdpIo->RecvRequest = RxToken;\r
1053 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {\r
1054 Status = UdpIo->Protocol.Udp4->Receive (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);\r
1055 } else {\r
1056 Status = UdpIo->Protocol.Udp6->Receive (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6);\r
1057 }\r
cbf316f2 1058\r
1059 if (EFI_ERROR (Status)) {\r
36ee91ca 1060 UdpIo->RecvRequest = NULL;\r
b45b45b2 1061 UdpIoFreeRxToken (RxToken);\r
cbf316f2 1062 }\r
1063\r
36ee91ca 1064 return Status;\r
cbf316f2 1065}\r