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