]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.c
pure UEFI should not include “PiDxe.h” and “PiPei.h”
[mirror_edk2.git] / MdeModulePkg / 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 - 2007, Intel Corporation.<BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 **/
13
14 #include <Uefi.h>
15
16 #include <Protocol/Udp4.h>
17
18 #include <Library/UdpIoLib.h>
19 #include <Library/BaseLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/UefiBootServicesTableLib.h>
22 #include <Library/MemoryAllocationLib.h>
23 #include <Library/BaseMemoryLib.h>
24
25
26 /**
27 Free a UDP_TX_TOKEN. The event is closed and memory released.
28
29 @param Token The UDP_TX_TOKEN to release.
30
31 **/
32 VOID
33 UdpIoFreeTxToken (
34 IN UDP_TX_TOKEN *Token
35 )
36 {
37 gBS->CloseEvent (Token->UdpToken.Event);
38 gBS->FreePool (Token);
39 }
40
41 /**
42 Free a receive request wrap.
43
44 @param Token The receive request to release.
45
46 **/
47 VOID
48 UdpIoFreeRxToken (
49 IN UDP_RX_TOKEN *Token
50 )
51 {
52 gBS->CloseEvent (Token->UdpToken.Event);
53 gBS->FreePool (Token);
54 }
55
56 /**
57 The callback function when the packet is sent by UDP.
58 It will remove the packet from the local list then call
59 the packet owner's callback function.
60
61 @param Context The UDP TX Token.
62
63 **/
64 VOID
65 EFIAPI
66 UdpIoOnDgramSentDpc (
67 IN VOID *Context
68 )
69 {
70 UDP_TX_TOKEN *Token;
71
72 Token = (UDP_TX_TOKEN *) Context;
73 ASSERT (Token->Signature == UDP_IO_TX_SIGNATURE);
74
75 RemoveEntryList (&Token->Link);
76 Token->CallBack (Token->Packet, NULL, Token->UdpToken.Status, Token->Context);
77
78 UdpIoFreeTxToken (Token);
79 }
80
81 /**
82 Request UdpIoOnDgramSentDpc as a DPC at TPL_CALLBACK.
83
84 @param Event The event signaled.
85 @param Context The UDP TX Token.
86
87 **/
88 VOID
89 EFIAPI
90 UdpIoOnDgramSent (
91 IN EFI_EVENT Event,
92 IN VOID *Context
93 )
94 {
95 //
96 // Request UdpIoOnDgramSentDpc as a DPC at TPL_CALLBACK
97 //
98 NetLibQueueDpc (TPL_CALLBACK, UdpIoOnDgramSentDpc, Context);
99 }
100
101 /**
102 Recycle the received UDP data.
103
104 @param Context The UDP_RX_TOKEN
105
106 **/
107 VOID
108 UdpIoRecycleDgram (
109 IN VOID *Context
110 )
111 {
112 UDP_RX_TOKEN *Token;
113
114 Token = (UDP_RX_TOKEN *) Context;
115 gBS->SignalEvent (Token->UdpToken.Packet.RxData->RecycleSignal);
116 UdpIoFreeRxToken (Token);
117 }
118
119 /**
120 The event handle for UDP receive request. It will build
121 a NET_BUF from the recieved UDP data, then deliver it
122 to the receiver.
123
124 @param Context The UDP RX token.
125
126 **/
127 VOID
128 EFIAPI
129 UdpIoOnDgramRcvdDpc (
130 IN VOID *Context
131 )
132 {
133 EFI_UDP4_COMPLETION_TOKEN *UdpToken;
134 EFI_UDP4_RECEIVE_DATA *UdpRxData;
135 EFI_UDP4_SESSION_DATA *UdpSession;
136 UDP_RX_TOKEN *Token;
137 UDP_POINTS Points;
138 NET_BUF *Netbuf;
139
140 Token = (UDP_RX_TOKEN *) Context;
141
142 ASSERT ((Token->Signature == UDP_IO_RX_SIGNATURE) &&
143 (Token == Token->UdpIo->RecvRequest));
144
145 //
146 // Clear the receive request first in case that the caller
147 // wants to restart the receive in the callback.
148 //
149 Token->UdpIo->RecvRequest = NULL;
150
151 UdpToken = &Token->UdpToken;
152 UdpRxData = UdpToken->Packet.RxData;
153
154 if (EFI_ERROR (UdpToken->Status) || (UdpRxData == NULL)) {
155 if (UdpToken->Status != EFI_ABORTED) {
156 //
157 // Invoke the CallBack only if the reception is not actively aborted.
158 //
159 Token->CallBack (NULL, NULL, UdpToken->Status, Token->Context);
160 }
161
162 UdpIoFreeRxToken (Token);
163 return;
164 }
165
166 //
167 // Build a NET_BUF from the UDP receive data, then deliver it up.
168 //
169 Netbuf = NetbufFromExt (
170 (NET_FRAGMENT *) UdpRxData->FragmentTable,
171 UdpRxData->FragmentCount,
172 0,
173 (UINT32) Token->HeadLen,
174 UdpIoRecycleDgram,
175 Token
176 );
177
178 if (Netbuf == NULL) {
179 gBS->SignalEvent (UdpRxData->RecycleSignal);
180 Token->CallBack (NULL, NULL, EFI_OUT_OF_RESOURCES, Token->Context);
181
182 UdpIoFreeRxToken (Token);
183 return;
184 }
185
186 UdpSession = &UdpRxData->UdpSession;
187 Points.LocalPort = UdpSession->DestinationPort;
188 Points.RemotePort = UdpSession->SourcePort;
189
190 CopyMem (&Points.LocalAddr, &UdpSession->DestinationAddress, sizeof (IP4_ADDR));
191 CopyMem (&Points.RemoteAddr, &UdpSession->SourceAddress, sizeof (IP4_ADDR));
192 Points.LocalAddr = NTOHL (Points.LocalAddr);
193 Points.RemoteAddr = NTOHL (Points.RemoteAddr);
194
195 Token->CallBack (Netbuf, &Points, EFI_SUCCESS, Token->Context);
196 }
197
198 /**
199 Request UdpIoOnDgramRcvdDpc as a DPC at TPL_CALLBACK.
200
201 @param Event The UDP receive request event.
202 @param Context The UDP RX token.
203
204 **/
205 VOID
206 EFIAPI
207 UdpIoOnDgramRcvd (
208 IN EFI_EVENT Event,
209 IN VOID *Context
210 )
211 {
212 //
213 // Request UdpIoOnDgramRcvdDpc as a DPC at TPL_CALLBACK
214 //
215 NetLibQueueDpc (TPL_CALLBACK, UdpIoOnDgramRcvdDpc, Context);
216 }
217
218 /**
219 Create a UDP_RX_TOKEN to wrap the request.
220
221 @param UdpIo The UdpIo to receive packets from
222 @param CallBack The function to call when receive finished.
223 @param Context The opaque parameter to the CallBack
224 @param HeadLen The head length to reserver for the packet.
225
226 @return The Wrapped request or NULL if failed to allocate resources or some errors happened.
227
228 **/
229 UDP_RX_TOKEN *
230 UdpIoCreateRxToken (
231 IN UDP_IO_PORT *UdpIo,
232 IN UDP_IO_CALLBACK CallBack,
233 IN VOID *Context,
234 IN UINT32 HeadLen
235 )
236 {
237 UDP_RX_TOKEN *Token;
238 EFI_STATUS Status;
239
240 Token = AllocatePool (sizeof (UDP_RX_TOKEN));
241
242 if (Token == NULL) {
243 return NULL;
244 }
245
246 Token->Signature = UDP_IO_RX_SIGNATURE;
247 Token->UdpIo = UdpIo;
248 Token->CallBack = CallBack;
249 Token->Context = Context;
250 Token->HeadLen = HeadLen;
251
252 Token->UdpToken.Status = EFI_NOT_READY;
253 Token->UdpToken.Packet.RxData = NULL;
254
255 Status = gBS->CreateEvent (
256 EVT_NOTIFY_SIGNAL,
257 TPL_NOTIFY,
258 UdpIoOnDgramRcvd,
259 Token,
260 &Token->UdpToken.Event
261 );
262
263 if (EFI_ERROR (Status)) {
264 gBS->FreePool (Token);
265 return NULL;
266 }
267
268 return Token;
269 }
270
271 /**
272 Wrap a transmit request into a UDP_TX_TOKEN.
273
274 @param UdpIo The UdpIo port to send packet to
275 @param Packet The user's packet
276 @param EndPoint The local and remote access point
277 @param Gateway The overrided next hop
278 @param CallBack The function to call when transmission completed.
279 @param Context The opaque parameter to the call back
280
281 @return The wrapped transmission request or NULL if failed to allocate resources
282 or for some errors.
283
284 **/
285 UDP_TX_TOKEN *
286 UdpIoWrapTx (
287 IN UDP_IO_PORT *UdpIo,
288 IN NET_BUF *Packet,
289 IN UDP_POINTS *EndPoint, OPTIONAL
290 IN IP4_ADDR Gateway,
291 IN UDP_IO_CALLBACK CallBack,
292 IN VOID *Context
293 )
294 {
295 UDP_TX_TOKEN *Token;
296 EFI_UDP4_COMPLETION_TOKEN *UdpToken;
297 EFI_UDP4_TRANSMIT_DATA *UdpTxData;
298 EFI_STATUS Status;
299 UINT32 Count;
300 IP4_ADDR Ip;
301
302 Token = AllocatePool (sizeof (UDP_TX_TOKEN) +
303 sizeof (EFI_UDP4_FRAGMENT_DATA) * (Packet->BlockOpNum - 1));
304
305 if (Token == NULL) {
306 return NULL;
307 }
308
309 Token->Signature = UDP_IO_TX_SIGNATURE;
310 InitializeListHead (&Token->Link);
311
312 Token->UdpIo = UdpIo;
313 Token->CallBack = CallBack;
314 Token->Packet = Packet;
315 Token->Context = Context;
316
317 UdpToken = &(Token->UdpToken);
318 UdpToken->Status = EFI_NOT_READY;
319
320 Status = gBS->CreateEvent (
321 EVT_NOTIFY_SIGNAL,
322 TPL_NOTIFY,
323 UdpIoOnDgramSent,
324 Token,
325 &UdpToken->Event
326 );
327
328 if (EFI_ERROR (Status)) {
329 gBS->FreePool (Token);
330 return NULL;
331 }
332
333 UdpTxData = &Token->UdpTxData;
334 UdpToken->Packet.TxData = UdpTxData;
335
336 UdpTxData->UdpSessionData = NULL;
337 UdpTxData->GatewayAddress = NULL;
338
339 if (EndPoint != NULL) {
340 Ip = HTONL (EndPoint->LocalAddr);
341 CopyMem (&Token->UdpSession.SourceAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));
342
343 Ip = HTONL (EndPoint->RemoteAddr);
344 CopyMem (&Token->UdpSession.DestinationAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));
345
346 Token->UdpSession.SourcePort = EndPoint->LocalPort;
347 Token->UdpSession.DestinationPort = EndPoint->RemotePort;
348 UdpTxData->UdpSessionData = &Token->UdpSession;
349 }
350
351 if (Gateway != 0) {
352 Ip = HTONL (Gateway);
353 CopyMem (&Token->Gateway, &Ip, sizeof (EFI_IPv4_ADDRESS));
354
355 UdpTxData->GatewayAddress = &Token->Gateway;
356 }
357
358 UdpTxData->DataLength = Packet->TotalSize;
359 Count = Packet->BlockOpNum;
360 NetbufBuildExt (Packet, (NET_FRAGMENT *) UdpTxData->FragmentTable, &Count);
361 UdpTxData->FragmentCount = Count;
362
363 return Token;
364 }
365
366
367
368
369 /**
370 Create a UDP IO port to access the UDP service. It will
371 create and configure a UDP child.
372
373 @param Controller The controller that has the UDP service binding
374 protocol installed.
375 @param Image The image handle for the driver.
376 @param Configure The function to configure the created UDP child
377 @param Context The opaque parameter for the Configure funtion.
378
379 @return A point to just created UDP IO port or NULL if some error happened.
380
381 **/
382 UDP_IO_PORT *
383 EFIAPI
384 UdpIoCreatePort (
385 IN EFI_HANDLE Controller,
386 IN EFI_HANDLE Image,
387 IN UDP_IO_CONFIG Configure,
388 IN VOID *Context
389 )
390 {
391 UDP_IO_PORT *UdpIo;
392 EFI_STATUS Status;
393
394 ASSERT (Configure != NULL);
395
396 UdpIo = AllocatePool (sizeof (UDP_IO_PORT));
397
398 if (UdpIo == NULL) {
399 return NULL;
400 }
401
402 UdpIo->Signature = UDP_IO_SIGNATURE;
403 InitializeListHead (&UdpIo->Link);
404 UdpIo->RefCnt = 1;
405
406 UdpIo->Controller = Controller;
407 UdpIo->Image = Image;
408
409 InitializeListHead (&UdpIo->SentDatagram);
410 UdpIo->RecvRequest = NULL;
411 UdpIo->UdpHandle = NULL;
412
413 //
414 // Create a UDP child then open and configure it
415 //
416 Status = NetLibCreateServiceChild (
417 Controller,
418 Image,
419 &gEfiUdp4ServiceBindingProtocolGuid,
420 &UdpIo->UdpHandle
421 );
422
423 if (EFI_ERROR (Status)) {
424 goto FREE_MEM;
425 }
426
427 Status = gBS->OpenProtocol (
428 UdpIo->UdpHandle,
429 &gEfiUdp4ProtocolGuid,
430 (VOID **) &UdpIo->Udp,
431 Image,
432 Controller,
433 EFI_OPEN_PROTOCOL_BY_DRIVER
434 );
435
436 if (EFI_ERROR (Status)) {
437 goto FREE_CHILD;
438 }
439
440 if (EFI_ERROR (Configure (UdpIo, Context))) {
441 goto CLOSE_PROTOCOL;
442 }
443
444 Status = UdpIo->Udp->GetModeData (UdpIo->Udp, NULL, NULL, NULL, &UdpIo->SnpMode);
445
446 if (EFI_ERROR (Status)) {
447 goto CLOSE_PROTOCOL;
448 }
449
450 return UdpIo;
451
452 CLOSE_PROTOCOL:
453 gBS->CloseProtocol (UdpIo->UdpHandle, &gEfiUdp4ProtocolGuid, Image, Controller);
454
455 FREE_CHILD:
456 NetLibDestroyServiceChild (
457 Controller,
458 Image,
459 &gEfiUdp4ServiceBindingProtocolGuid,
460 UdpIo->UdpHandle
461 );
462
463 FREE_MEM:
464 gBS->FreePool (UdpIo);
465 return NULL;
466 }
467
468
469 /**
470 Cancel all the sent datagram that pass the selection of ToCancel.
471 If ToCancel is NULL, all the datagrams are cancelled.
472
473 @param UdpIo The UDP IO port to cancel packet
474 @param IoStatus The IoStatus to return to the packet owners.
475 @param ToCancel The select funtion to test whether to cancel this
476 packet or not.
477 @param Context The opaque parameter to the ToCancel.
478
479 **/
480 VOID
481 UdpIoCancelDgrams (
482 IN UDP_IO_PORT *UdpIo,
483 IN EFI_STATUS IoStatus,
484 IN UDP_IO_TO_CANCEL ToCancel, OPTIONAL
485 IN VOID *Context
486 )
487 {
488 LIST_ENTRY *Entry;
489 LIST_ENTRY *Next;
490 UDP_TX_TOKEN *Token;
491
492 NET_LIST_FOR_EACH_SAFE (Entry, Next, &UdpIo->SentDatagram) {
493 Token = NET_LIST_USER_STRUCT (Entry, UDP_TX_TOKEN, Link);
494
495 if ((ToCancel == NULL) || (ToCancel (Token, Context))) {
496 UdpIo->Udp->Cancel (UdpIo->Udp, &Token->UdpToken);
497 }
498 }
499 }
500
501
502 /**
503 Free the UDP IO port and all its related resources including
504 all the transmitted packet.
505
506 @param UdpIo The UDP IO port to free.
507
508 @retval EFI_SUCCESS The UDP IO port is freed.
509
510 **/
511 EFI_STATUS
512 EFIAPI
513 UdpIoFreePort (
514 IN UDP_IO_PORT *UdpIo
515 )
516 {
517 UDP_RX_TOKEN *RxToken;
518
519 //
520 // Cancel all the sent datagram and receive requests. The
521 // callbacks of transmit requests are executed to allow the
522 // caller to release the resource. The callback of receive
523 // request are NOT executed. This is because it is most
524 // likely that the current user of the UDP IO port is closing
525 // itself.
526 //
527 UdpIoCancelDgrams (UdpIo, EFI_ABORTED, NULL, NULL);
528
529 if ((RxToken = UdpIo->RecvRequest) != NULL) {
530 UdpIo->Udp->Cancel (UdpIo->Udp, &RxToken->UdpToken);
531 }
532
533 //
534 // Close then destory the UDP child
535 //
536 gBS->CloseProtocol (
537 UdpIo->UdpHandle,
538 &gEfiUdp4ProtocolGuid,
539 UdpIo->Image,
540 UdpIo->Controller
541 );
542
543 NetLibDestroyServiceChild (
544 UdpIo->Controller,
545 UdpIo->Image,
546 &gEfiUdp4ServiceBindingProtocolGuid,
547 UdpIo->UdpHandle
548 );
549
550 if (!IsListEmpty(&UdpIo->Link)) {
551 RemoveEntryList (&UdpIo->Link);
552 }
553
554 gBS->FreePool (UdpIo);
555 return EFI_SUCCESS;
556 }
557
558
559 /**
560 Clean up the UDP IO port. It will release all the transmitted
561 datagrams and receive request. It will also configure NULL the
562 UDP child.
563
564 @param UdpIo UDP IO port to clean up.
565
566 **/
567 VOID
568 EFIAPI
569 UdpIoCleanPort (
570 IN UDP_IO_PORT *UdpIo
571 )
572 {
573 UDP_RX_TOKEN *RxToken;
574
575 //
576 // Cancel all the sent datagram and receive requests.
577 //
578 UdpIoCancelDgrams (UdpIo, EFI_ABORTED, NULL, NULL);
579
580 if ((RxToken = UdpIo->RecvRequest) != NULL) {
581 UdpIo->Udp->Cancel (UdpIo->Udp, &RxToken->UdpToken);
582 }
583
584 UdpIo->Udp->Configure (UdpIo->Udp, NULL);
585 }
586
587 /**
588 Send a packet through the UDP IO port.
589
590 @param UdpIo The UDP IO Port to send the packet through
591 @param Packet The packet to send
592 @param EndPoint The local and remote access point
593 @param Gateway The gateway to use
594 @param CallBack The call back function to call when packet is
595 transmitted or failed.
596 @param Context The opque parameter to the CallBack
597
598 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the packet
599 @retval EFI_SUCCESS The packet is successfully delivered to UDP for
600 transmission.
601
602 **/
603 EFI_STATUS
604 EFIAPI
605 UdpIoSendDatagram (
606 IN UDP_IO_PORT *UdpIo,
607 IN NET_BUF *Packet,
608 IN UDP_POINTS *EndPoint, OPTIONAL
609 IN IP4_ADDR Gateway,
610 IN UDP_IO_CALLBACK CallBack,
611 IN VOID *Context
612 )
613 {
614 UDP_TX_TOKEN *Token;
615 EFI_STATUS Status;
616
617 Token = UdpIoWrapTx (UdpIo, Packet, EndPoint, Gateway, CallBack, Context);
618
619 if (Token == NULL) {
620 return EFI_OUT_OF_RESOURCES;
621 }
622
623 //
624 // Insert the tx token into SendDatagram list before transmitting it. Remove
625 // it from the list if the returned status is not EFI_SUCCESS.
626 //
627 InsertHeadList (&UdpIo->SentDatagram, &Token->Link);
628 Status = UdpIo->Udp->Transmit (UdpIo->Udp, &Token->UdpToken);
629 if (EFI_ERROR (Status)) {
630 RemoveEntryList (&Token->Link);
631 UdpIoFreeTxToken (Token);
632 return Status;
633 }
634
635 return EFI_SUCCESS;
636 }
637
638
639 /**
640 The selection function to cancel a single sent datagram.
641
642 @param Token The UDP TX token to test againist.
643 @param Context The context
644
645 @retval TRUE The packet is to be cancelled.
646 @retval FALSE The packet is not to be cancelled.
647 **/
648 BOOLEAN
649 UdpIoCancelSingleDgram (
650 IN UDP_TX_TOKEN *Token,
651 IN VOID *Context
652 )
653 {
654 NET_BUF *Packet;
655
656 Packet = (NET_BUF *) Context;
657
658 if (Token->Packet == Packet) {
659 return TRUE;
660 }
661
662 return FALSE;
663 }
664
665
666 /**
667 Cancel a single sent datagram.
668
669 @param UdpIo The UDP IO port to cancel the packet from
670 @param Packet The packet to cancel
671
672 **/
673 VOID
674 EFIAPI
675 UdpIoCancelSentDatagram (
676 IN UDP_IO_PORT *UdpIo,
677 IN NET_BUF *Packet
678 )
679 {
680 UdpIoCancelDgrams (UdpIo, EFI_ABORTED, UdpIoCancelSingleDgram, Packet);
681 }
682
683 /**
684 Issue a receive request to the UDP IO port.
685
686 @param UdpIo The UDP IO port to recieve the packet from.
687 @param CallBack The call back function to execute when receive
688 finished.
689 @param Context The opque context to the call back
690 @param HeadLen The lenght of the application's header
691
692 @retval EFI_ALREADY_STARTED There is already a pending receive request. Only
693 one receive request is supported.
694 @retval EFI_OUT_OF_RESOURCES Failed to allocate some resource.
695 @retval EFI_SUCCESS The receive request is issued successfully.
696
697 **/
698 EFI_STATUS
699 EFIAPI
700 UdpIoRecvDatagram (
701 IN UDP_IO_PORT *UdpIo,
702 IN UDP_IO_CALLBACK CallBack,
703 IN VOID *Context,
704 IN UINT32 HeadLen
705 )
706 {
707 UDP_RX_TOKEN *Token;
708 EFI_STATUS Status;
709
710 if (UdpIo->RecvRequest != NULL) {
711 return EFI_ALREADY_STARTED;
712 }
713
714 Token = UdpIoCreateRxToken (UdpIo, CallBack, Context, HeadLen);
715
716 if (Token == NULL) {
717 return EFI_OUT_OF_RESOURCES;
718 }
719
720 UdpIo->RecvRequest = Token;
721 Status = UdpIo->Udp->Receive (UdpIo->Udp, &Token->UdpToken);
722
723 if (EFI_ERROR (Status)) {
724 UdpIo->RecvRequest = NULL;
725 UdpIoFreeRxToken (Token);
726 }
727
728 return Status;
729 }