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