]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.c
1. Fix a bug in PXE driver that the PXE boot do not restart if a new boot option...
[mirror_edk2.git] / MdeModulePkg / Library / DxeUdpIoLib / DxeUdpIoLib.c
... / ...
CommitLineData
1/** @file\r
2 Help functions to access UDP service, it is used by both the DHCP and MTFTP.\r
3\r
4Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR>\r
5This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at<BR>\r
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
12**/\r
13\r
14#include <Uefi.h>\r
15\r
16#include <Protocol/Udp4.h>\r
17#include <Protocol/Udp6.h>\r
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
24#include <Library/BaseMemoryLib.h>\r
25#include <Library/DpcLib.h>\r
26\r
27\r
28/**\r
29 Free a UDP_TX_TOKEN. The TX event is closed.\r
30\r
31 @param[in] TxToken The UDP_TX_TOKEN to release.\r
32\r
33**/\r
34VOID\r
35UdpIoFreeTxToken (\r
36 IN UDP_TX_TOKEN *TxToken\r
37 )\r
38{\r
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
47\r
48 FreePool (TxToken);\r
49}\r
50\r
51/**\r
52 Free a UDP_RX_TOKEN. The RX event is closed.\r
53\r
54 @param[in] RxToken The UDP_RX_TOKEN to release.\r
55\r
56**/\r
57VOID\r
58UdpIoFreeRxToken (\r
59 IN UDP_RX_TOKEN *RxToken\r
60 )\r
61{\r
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
68 }\r
69\r
70 FreePool (RxToken);\r
71}\r
72\r
73/**\r
74 The callback function when the packet is sent by UDP.\r
75\r
76 It will remove the packet from the local list then call\r
77 the packet owner's callback function set by UdpIoSendDatagram.\r
78\r
79 @param[in] Context The UDP TX Token.\r
80\r
81**/\r
82VOID\r
83EFIAPI\r
84UdpIoOnDgramSentDpc (\r
85 IN VOID *Context\r
86 )\r
87{\r
88 UDP_TX_TOKEN *TxToken;\r
89\r
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
94\r
95 RemoveEntryList (&TxToken->Link);\r
96\r
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
102\r
103 UdpIoFreeTxToken (TxToken);\r
104}\r
105\r
106/**\r
107 Request UdpIoOnDgramSentDpc as a DPC at TPL_CALLBACK.\r
108\r
109 @param[in] Event The event signaled.\r
110 @param[in] Context The UDP TX Token.\r
111\r
112**/\r
113VOID\r
114EFIAPI\r
115UdpIoOnDgramSent (\r
116 IN EFI_EVENT Event,\r
117 IN VOID *Context\r
118 )\r
119{\r
120 //\r
121 // Request UdpIoOnDgramSentDpc as a DPC at TPL_CALLBACK\r
122 //\r
123 QueueDpc (TPL_CALLBACK, UdpIoOnDgramSentDpc, Context);\r
124}\r
125\r
126/**\r
127 Recycle the received UDP data.\r
128\r
129 @param[in] Context The UDP_RX_TOKEN.\r
130\r
131**/\r
132VOID\r
133EFIAPI\r
134UdpIoRecycleDgram (\r
135 IN VOID *Context\r
136 )\r
137{\r
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
149\r
150 UdpIoFreeRxToken (RxToken);\r
151}\r
152\r
153/**\r
154 The event handle for UDP receive request.\r
155\r
156 It will build a NET_BUF from the recieved UDP data, then deliver it\r
157 to the receiver.\r
158\r
159 @param[in] Context The UDP RX token.\r
160\r
161**/\r
162VOID\r
163EFIAPI\r
164UdpIoOnDgramRcvdDpc (\r
165 IN VOID *Context\r
166 )\r
167{\r
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
174 NET_BUF *Netbuf;\r
175\r
176 RxToken = (UDP_RX_TOKEN *) Context;\r
177\r
178 ZeroMem (&EndPoint, sizeof(UDP_END_POINT));\r
179\r
180 ASSERT ((RxToken->Signature == UDP_IO_RX_SIGNATURE) &&\r
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
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
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
201\r
202 if (EFI_ERROR (Status) || RxData == NULL) {\r
203 if (Status != EFI_ABORTED) {\r
204 //\r
205 // Invoke the CallBack only if the reception is not actively aborted.\r
206 //\r
207 RxToken->CallBack (NULL, NULL, Status, RxToken->Context);\r
208 }\r
209\r
210 UdpIoFreeRxToken (RxToken);\r
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
217 if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {\r
218\r
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
235\r
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
255\r
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
264\r
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
268\r
269 UdpIoFreeRxToken (RxToken);\r
270 return;\r
271 }\r
272\r
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
276\r
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
292\r
293 RxToken->CallBack (Netbuf, &EndPoint, EFI_SUCCESS, RxToken->Context);\r
294}\r
295\r
296/**\r
297 Request UdpIoOnDgramRcvdDpc() as a DPC at TPL_CALLBACK.\r
298\r
299 @param[in] Event The UDP receive request event.\r
300 @param[in] Context The UDP RX token.\r
301\r
302**/\r
303VOID\r
304EFIAPI\r
305UdpIoOnDgramRcvd (\r
306 IN EFI_EVENT Event,\r
307 IN VOID *Context\r
308 )\r
309{\r
310 //\r
311 // Request UdpIoOnDgramRcvdDpc as a DPC at TPL_CALLBACK\r
312 //\r
313 QueueDpc (TPL_CALLBACK, UdpIoOnDgramRcvdDpc, Context);\r
314}\r
315\r
316/**\r
317 Create a UDP_RX_TOKEN to wrap the request.\r
318\r
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
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
329 IN UDP_IO *UdpIo,\r
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
338 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||\r
339 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));\r
340\r
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
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
366\r
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
377 }\r
378\r
379\r
380 if (EFI_ERROR (Status)) {\r
381 FreePool (Token);\r
382 return NULL;\r
383 }\r
384\r
385 return Token;\r
386}\r
387\r
388/**\r
389 Wrap a transmit request into a new created UDP_TX_TOKEN.\r
390\r
391 @param[in] UdpIo The UdpIo to send packet to.\r
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
397\r
398 @return The wrapped transmission request or NULL if failed to allocate resources\r
399 or for some errors.\r
400\r
401**/\r
402UDP_TX_TOKEN *\r
403UdpIoCreateTxToken (\r
404 IN UDP_IO *UdpIo,\r
405 IN NET_BUF *Packet,\r
406 IN UDP_END_POINT *EndPoint OPTIONAL,\r
407 IN EFI_IP_ADDRESS *Gateway OPTIONAL,\r
408 IN UDP_IO_CALLBACK CallBack,\r
409 IN VOID *Context\r
410 )\r
411{\r
412 UDP_TX_TOKEN *TxToken;\r
413 VOID *Token;\r
414 VOID *Data;\r
415 EFI_STATUS Status;\r
416 UINT32 Count;\r
417 UINTN Size;\r
418 IP4_ADDR Ip;\r
419\r
420 ASSERT (Packet != NULL);\r
421 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||\r
422 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));\r
423\r
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
428 }\r
429\r
430 TxToken = AllocatePool (Size);\r
431\r
432 if (TxToken == NULL) {\r
433 return NULL;\r
434 }\r
435\r
436 TxToken->Signature = UDP_IO_TX_SIGNATURE;\r
437 InitializeListHead (&TxToken->Link);\r
438\r
439 TxToken->UdpIo = UdpIo;\r
440 TxToken->CallBack = CallBack;\r
441 TxToken->Packet = Packet;\r
442 TxToken->Context = Context;\r
443\r
444 Token = &(TxToken->Token);\r
445 Count = Packet->BlockOpNum;\r
446\r
447 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {\r
448\r
449 ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Status = EFI_NOT_READY;\r
450\r
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
458\r
459 if (EFI_ERROR (Status)) {\r
460 FreePool (TxToken);\r
461 return NULL;\r
462 }\r
463\r
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
482 &TxToken->Session.Udp4.SourceAddress,\r
483 &Ip,\r
484 sizeof (EFI_IPv4_ADDRESS)\r
485 );\r
486\r
487 Ip = HTONL (EndPoint->RemoteAddr.Addr[0]);\r
488 CopyMem (\r
489 &TxToken->Session.Udp4.DestinationAddress,\r
490 &Ip,\r
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
498\r
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
502 ((EFI_UDP4_TRANSMIT_DATA *) Data)->GatewayAddress = &TxToken->Gateway;\r
503 }\r
504\r
505 } else {\r
506\r
507 ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Status = EFI_NOT_READY;\r
508\r
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
521\r
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
537 &TxToken->Session.Udp6.SourceAddress,\r
538 &EndPoint->LocalAddr.v6,\r
539 sizeof(EFI_IPv6_ADDRESS)\r
540 );\r
541\r
542 CopyMem (\r
543 &TxToken->Session.Udp6.DestinationAddress,\r
544 &EndPoint->RemoteAddr.v6,\r
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
551 }\r
552 }\r
553\r
554 return TxToken;\r
555}\r
556\r
557/**\r
558 Creates a UDP_IO to access the UDP service. It creates and configures\r
559 a UDP child.\r
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
565\r
566 @param[in] Controller The controller that has the UDP service binding.\r
567 protocol installed.\r
568 @param[in] ImageHandle The image handle for the driver.\r
569 @param[in] Configure The function to configure the created UDP child.\r
570 @param[in] UdpVersion The UDP protocol version, UDP4 or UDP6.\r
571 @param[in] Context The opaque parameter for the Configure funtion.\r
572\r
573 @return Newly-created UDP_IO or NULL if failed.\r
574\r
575**/\r
576UDP_IO *\r
577EFIAPI\r
578UdpIoCreateIo (\r
579 IN EFI_HANDLE Controller,\r
580 IN EFI_HANDLE ImageHandle,\r
581 IN UDP_IO_CONFIG Configure,\r
582 IN UINT8 UdpVersion,\r
583 IN VOID *Context\r
584 )\r
585{\r
586 UDP_IO *UdpIo;\r
587 EFI_STATUS Status;\r
588\r
589 ASSERT (Configure != NULL);\r
590 ASSERT ((UdpVersion == UDP_IO_UDP4_VERSION) || (UdpVersion == UDP_IO_UDP6_VERSION));\r
591\r
592 UdpIo = AllocatePool (sizeof (UDP_IO));\r
593\r
594 if (UdpIo == NULL) {\r
595 return NULL;\r
596 }\r
597\r
598 UdpIo->UdpVersion = UdpVersion;\r
599 UdpIo->Signature = UDP_IO_SIGNATURE;\r
600 InitializeListHead (&UdpIo->Link);\r
601 UdpIo->RefCnt = 1;\r
602\r
603 UdpIo->Controller = Controller;\r
604 UdpIo->Image = ImageHandle;\r
605\r
606 InitializeListHead (&UdpIo->SentDatagram);\r
607 UdpIo->RecvRequest = NULL;\r
608 UdpIo->UdpHandle = NULL;\r
609\r
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
620\r
621 if (EFI_ERROR (Status)) {\r
622 goto FREE_MEM;\r
623 }\r
624\r
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
637\r
638 if (EFI_ERROR (Configure (UdpIo, Context))) {\r
639 goto CLOSE_PROTOCOL;\r
640 }\r
641\r
642 Status = UdpIo->Protocol.Udp4->GetModeData (\r
643 UdpIo->Protocol.Udp4,\r
644 NULL,\r
645 NULL,\r
646 NULL,\r
647 &UdpIo->SnpMode\r
648 );\r
649\r
650 if (EFI_ERROR (Status)) {\r
651 goto CLOSE_PROTOCOL;\r
652 }\r
653\r
654 } else {\r
655\r
656 Status = NetLibCreateServiceChild (\r
657 Controller,\r
658 ImageHandle,\r
659 &gEfiUdp6ServiceBindingProtocolGuid,\r
660 &UdpIo->UdpHandle\r
661 );\r
662\r
663 if (EFI_ERROR (Status)) {\r
664 goto FREE_MEM;\r
665 }\r
666\r
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
675\r
676 if (EFI_ERROR (Status)) {\r
677 goto FREE_CHILD;\r
678 }\r
679\r
680 if (EFI_ERROR (Configure (UdpIo, Context))) {\r
681 goto CLOSE_PROTOCOL;\r
682 }\r
683\r
684 Status = UdpIo->Protocol.Udp6->GetModeData (\r
685 UdpIo->Protocol.Udp6,\r
686 NULL,\r
687 NULL,\r
688 NULL,\r
689 &UdpIo->SnpMode\r
690 );\r
691\r
692 if (EFI_ERROR (Status)) {\r
693 goto CLOSE_PROTOCOL;\r
694 }\r
695 }\r
696\r
697 return UdpIo;\r
698\r
699CLOSE_PROTOCOL:\r
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
705\r
706FREE_CHILD:\r
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
722\r
723FREE_MEM:\r
724 FreePool (UdpIo);\r
725 return NULL;\r
726}\r
727\r
728/**\r
729 Cancel all the sent datagram that pass the selection criteria of ToCancel.\r
730 If ToCancel is NULL, all the datagrams are cancelled.\r
731\r
732 @param[in] UdpIo The UDP_IO to cancel packet.\r
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
737\r
738**/\r
739VOID\r
740EFIAPI\r
741UdpIoCancelDgrams (\r
742 IN UDP_IO *UdpIo,\r
743 IN EFI_STATUS IoStatus,\r
744 IN UDP_IO_TO_CANCEL ToCancel, OPTIONAL\r
745 IN VOID *Context\r
746 )\r
747{\r
748 LIST_ENTRY *Entry;\r
749 LIST_ENTRY *Next;\r
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
754\r
755 NET_LIST_FOR_EACH_SAFE (Entry, Next, &UdpIo->SentDatagram) {\r
756 TxToken = NET_LIST_USER_STRUCT (Entry, UDP_TX_TOKEN, Link);\r
757\r
758 if ((ToCancel == NULL) || (ToCancel (TxToken, Context))) {\r
759\r
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
765 }\r
766 }\r
767}\r
768\r
769/**\r
770 Free the UDP_IO and all its related resources.\r
771\r
772 The function will cancel all sent datagram and receive request.\r
773\r
774 @param[in] UdpIo The UDP_IO to free.\r
775\r
776 @retval EFI_SUCCESS The UDP_IO is freed.\r
777\r
778**/\r
779EFI_STATUS\r
780EFIAPI\r
781UdpIoFreeIo (\r
782 IN UDP_IO *UdpIo\r
783 )\r
784{\r
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
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
800 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {\r
801\r
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 destroy 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
828\r
829 //\r
830 // Close then destroy 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
838\r
839 NetLibDestroyServiceChild (\r
840 UdpIo->Controller,\r
841 UdpIo->Image,\r
842 &gEfiUdp6ServiceBindingProtocolGuid,\r
843 UdpIo->UdpHandle\r
844 );\r
845 }\r
846\r
847 if (!IsListEmpty(&UdpIo->Link)) {\r
848 RemoveEntryList (&UdpIo->Link);\r
849 }\r
850\r
851 FreePool (UdpIo);\r
852 return EFI_SUCCESS;\r
853}\r
854\r
855\r
856/**\r
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
859\r
860 It will release all the transmitted datagrams and receive request. It will\r
861 also configure NULL for the UDP instance.\r
862\r
863 @param[in] UdpIo The UDP_IO to clean up.\r
864\r
865**/\r
866VOID\r
867EFIAPI\r
868UdpIoCleanIo (\r
869 IN UDP_IO *UdpIo\r
870 )\r
871{\r
872 UDP_RX_TOKEN *RxToken;\r
873\r
874 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||\r
875 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));\r
876\r
877 //\r
878 // Cancel all the sent datagram and receive requests.\r
879 //\r
880 UdpIoCancelDgrams (UdpIo, EFI_ABORTED, NULL, NULL);\r
881\r
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
888\r
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
896}\r
897\r
898/**\r
899 Send a packet through the UDP_IO.\r
900\r
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
904\r
905 @param[in] UdpIo The UDP_IO to send the packet through.\r
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
909 @param[in] Gateway The gateway to use.\r
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
913\r
914 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the packet.\r
915 @retval EFI_SUCCESS The packet is successfully delivered to UDP for\r
916 transmission.\r
917\r
918**/\r
919EFI_STATUS\r
920EFIAPI\r
921UdpIoSendDatagram (\r
922 IN UDP_IO *UdpIo,\r
923 IN NET_BUF *Packet,\r
924 IN UDP_END_POINT *EndPoint OPTIONAL,\r
925 IN EFI_IP_ADDRESS *Gateway OPTIONAL,\r
926 IN UDP_IO_CALLBACK CallBack,\r
927 IN VOID *Context\r
928 )\r
929{\r
930 UDP_TX_TOKEN *TxToken;\r
931 EFI_STATUS Status;\r
932\r
933 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||\r
934 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));\r
935\r
936 TxToken = UdpIoCreateTxToken (UdpIo, Packet, EndPoint, Gateway, CallBack, Context);\r
937\r
938 if (TxToken == NULL) {\r
939 return EFI_OUT_OF_RESOURCES;\r
940 }\r
941\r
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
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
954 if (EFI_ERROR (Status)) {\r
955 RemoveEntryList (&TxToken->Link);\r
956 UdpIoFreeTxToken (TxToken);\r
957 return Status;\r
958 }\r
959\r
960 return EFI_SUCCESS;\r
961}\r
962\r
963\r
964/**\r
965 The select function to cancel a single sent datagram.\r
966\r
967 @param[in] Token The UDP_TX_TOKEN to test against\r
968 @param[in] Context The NET_BUF of the sent datagram\r
969\r
970 @retval TRUE The packet is to be cancelled.\r
971 @retval FALSE The packet is not to be cancelled.\r
972**/\r
973BOOLEAN\r
974EFIAPI\r
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
991/**\r
992 Cancel a single sent datagram.\r
993\r
994 @param[in] UdpIo The UDP_IO to cancel the packet from\r
995 @param[in] Packet The packet to cancel\r
996\r
997**/\r
998VOID\r
999EFIAPI\r
1000UdpIoCancelSentDatagram (\r
1001 IN UDP_IO *UdpIo,\r
1002 IN NET_BUF *Packet\r
1003 )\r
1004{\r
1005 UdpIoCancelDgrams (UdpIo, EFI_ABORTED, UdpIoCancelSingleDgram, Packet);\r
1006}\r
1007\r
1008/**\r
1009 Issue a receive request to the UDP_IO.\r
1010\r
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
1015\r
1016 @param[in] UdpIo The UDP_IO to receive the packet from.\r
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
1020 @param[in] HeadLen The length of the upper-layer's protocol header.\r
1021\r
1022 @retval EFI_ALREADY_STARTED There is already a pending receive request. Only\r
1023 one receive request is supported at a time.\r
1024 @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.\r
1025 @retval EFI_SUCCESS The receive request is issued successfully.\r
1026 @retval EFI_UNSUPPORTED The UDP version in UDP_IO is not supported.\r
1027\r
1028**/\r
1029EFI_STATUS\r
1030EFIAPI\r
1031UdpIoRecvDatagram (\r
1032 IN UDP_IO *UdpIo,\r
1033 IN UDP_IO_CALLBACK CallBack,\r
1034 IN VOID *Context,\r
1035 IN UINT32 HeadLen\r
1036 )\r
1037{\r
1038 UDP_RX_TOKEN *RxToken;\r
1039 EFI_STATUS Status;\r
1040\r
1041 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||\r
1042 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));\r
1043\r
1044 if (UdpIo->RecvRequest != NULL) {\r
1045 return EFI_ALREADY_STARTED;\r
1046 }\r
1047\r
1048 RxToken = UdpIoCreateRxToken (UdpIo, CallBack, Context, HeadLen);\r
1049\r
1050 if (RxToken == NULL) {\r
1051 return EFI_OUT_OF_RESOURCES;\r
1052 }\r
1053\r
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
1060\r
1061 if (EFI_ERROR (Status)) {\r
1062 UdpIo->RecvRequest = NULL;\r
1063 UdpIoFreeRxToken (RxToken);\r
1064 }\r
1065\r
1066 return Status;\r
1067}\r