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