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