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