3 Copyright (c) 2006 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 Help functions to access UDP service, it is used by both the DHCP and MTFTP.
26 #include <Protocol/Udp4.h>
28 #include <Library/UdpIoLib.h>
29 #include <Library/BaseLib.h>
30 #include <Library/DebugLib.h>
31 #include <Library/UefiBootServicesTableLib.h>
32 #include <Library/MemoryAllocationLib.h>
33 #include <Library/BaseMemoryLib.h>
60 Wrap a transmit request into a UDP_TX_TOKEN.
62 @param UdpIo The UdpIo port to send packet to
63 @param Packet The user's packet
64 @param EndPoint The local and remote access point
65 @param Gateway The overrided next hop
66 @param CallBack The function to call when transmission completed.
67 @param Context The opaque parameter to the call back
69 @return The wrapped transmission request or NULL if failed to allocate resources.
75 IN UDP_IO_PORT
*UdpIo
,
77 IN UDP_POINTS
*EndPoint
, OPTIONAL
79 IN UDP_IO_CALLBACK CallBack
,
84 EFI_UDP4_COMPLETION_TOKEN
*UdpToken
;
85 EFI_UDP4_TRANSMIT_DATA
*UdpTxData
;
90 Token
= AllocatePool (sizeof (UDP_TX_TOKEN
) +
91 sizeof (EFI_UDP4_FRAGMENT_DATA
) * (Packet
->BlockOpNum
- 1));
97 Token
->Signature
= UDP_IO_TX_SIGNATURE
;
98 InitializeListHead (&Token
->Link
);
100 Token
->UdpIo
= UdpIo
;
101 Token
->CallBack
= CallBack
;
102 Token
->Packet
= Packet
;
103 Token
->Context
= Context
;
105 UdpToken
= &(Token
->UdpToken
);
106 UdpToken
->Status
= EFI_NOT_READY
;
108 Status
= gBS
->CreateEvent (
116 if (EFI_ERROR (Status
)) {
117 gBS
->FreePool (Token
);
121 UdpTxData
= &Token
->UdpTxData
;
122 UdpToken
->Packet
.TxData
= UdpTxData
;
124 UdpTxData
->UdpSessionData
= NULL
;
125 UdpTxData
->GatewayAddress
= NULL
;
127 if (EndPoint
!= NULL
) {
128 Ip
= HTONL (EndPoint
->LocalAddr
);
129 CopyMem (&Token
->UdpSession
.SourceAddress
, &Ip
, sizeof (EFI_IPv4_ADDRESS
));
131 Ip
= HTONL (EndPoint
->RemoteAddr
);
132 CopyMem (&Token
->UdpSession
.DestinationAddress
, &Ip
, sizeof (EFI_IPv4_ADDRESS
));
134 Token
->UdpSession
.SourcePort
= EndPoint
->LocalPort
;
135 Token
->UdpSession
.DestinationPort
= EndPoint
->RemotePort
;
136 UdpTxData
->UdpSessionData
= &Token
->UdpSession
;
140 Ip
= HTONL (Gateway
);
141 CopyMem (&Token
->Gateway
, &Ip
, sizeof (EFI_IPv4_ADDRESS
));
143 UdpTxData
->GatewayAddress
= &Token
->Gateway
;
146 UdpTxData
->DataLength
= Packet
->TotalSize
;
147 Count
= Packet
->BlockOpNum
;
148 NetbufBuildExt (Packet
, (NET_FRAGMENT
*) UdpTxData
->FragmentTable
, &Count
);
149 UdpTxData
->FragmentCount
= Count
;
156 Free a UDP_TX_TOKEN. The event is closed and memory released.
158 @param Token The UDP_TX_TOKEN to release.
165 IN UDP_TX_TOKEN
*Token
168 gBS
->CloseEvent (Token
->UdpToken
.Event
);
169 gBS
->FreePool (Token
);
174 Create a UDP_RX_TOKEN to wrap the request.
176 @param UdpIo The UdpIo to receive packets from
177 @param CallBack The function to call when receive finished.
178 @param Context The opaque parameter to the CallBack
179 @param HeadLen The head length to reserver for the packet.
181 @return The Wrapped request or NULL if failed to allocate resources.
186 IN UDP_IO_PORT
*UdpIo
,
187 IN UDP_IO_CALLBACK CallBack
,
195 Token
= AllocatePool (sizeof (UDP_RX_TOKEN
));
201 Token
->Signature
= UDP_IO_RX_SIGNATURE
;
202 Token
->UdpIo
= UdpIo
;
203 Token
->CallBack
= CallBack
;
204 Token
->Context
= Context
;
205 Token
->HeadLen
= HeadLen
;
207 Token
->UdpToken
.Status
= EFI_NOT_READY
;
208 Token
->UdpToken
.Packet
.RxData
= NULL
;
210 Status
= gBS
->CreateEvent (
215 &Token
->UdpToken
.Event
218 if (EFI_ERROR (Status
)) {
219 gBS
->FreePool (Token
);
228 Free a receive request wrap.
230 @param Token The receive request to release.
237 IN UDP_RX_TOKEN
*Token
240 gBS
->CloseEvent (Token
->UdpToken
.Event
);
241 gBS
->FreePool (Token
);
246 Create a UDP IO port to access the UDP service. It will
247 create and configure a UDP child.
249 @param Controller The controller that has the UDP service binding
251 @param Image The image handle for the driver.
252 @param Configure The function to configure the created UDP child
253 @param Context The opaque parameter for the Configure funtion.
255 @return A point to just created UDP IO port or NULL if failed.
260 IN EFI_HANDLE Controller
,
262 IN UDP_IO_CONFIG Configure
,
269 ASSERT (Configure
!= NULL
);
271 UdpIo
= AllocatePool (sizeof (UDP_IO_PORT
));
277 UdpIo
->Signature
= UDP_IO_SIGNATURE
;
278 InitializeListHead (&UdpIo
->Link
);
281 UdpIo
->Controller
= Controller
;
282 UdpIo
->Image
= Image
;
284 InitializeListHead (&UdpIo
->SentDatagram
);
285 UdpIo
->RecvRequest
= NULL
;
286 UdpIo
->UdpHandle
= NULL
;
289 // Create a UDP child then open and configure it
291 Status
= NetLibCreateServiceChild (
294 &gEfiUdp4ServiceBindingProtocolGuid
,
298 if (EFI_ERROR (Status
)) {
302 Status
= gBS
->OpenProtocol (
304 &gEfiUdp4ProtocolGuid
,
305 (VOID
**) &UdpIo
->Udp
,
308 EFI_OPEN_PROTOCOL_BY_DRIVER
311 if (EFI_ERROR (Status
)) {
315 if (EFI_ERROR (Configure (UdpIo
, Context
))) {
319 Status
= UdpIo
->Udp
->GetModeData (UdpIo
->Udp
, NULL
, NULL
, NULL
, &UdpIo
->SnpMode
);
321 if (EFI_ERROR (Status
)) {
328 gBS
->CloseProtocol (UdpIo
->UdpHandle
, &gEfiUdp4ProtocolGuid
, Image
, Controller
);
331 NetLibDestroyServiceChild (
334 &gEfiUdp4ServiceBindingProtocolGuid
,
339 gBS
->FreePool (UdpIo
);
345 Cancel all the sent datagram that pass the selection of ToCancel.
346 If ToCancel is NULL, all the datagrams are cancelled.
348 @param UdpIo The UDP IO port to cancel packet
349 @param IoStatus The IoStatus to return to the packet owners.
350 @param ToCancel The select funtion to test whether to cancel this
352 @param Context The opaque parameter to the ToCancel.
360 IN UDP_IO_PORT
*UdpIo
,
361 IN EFI_STATUS IoStatus
,
362 IN UDP_IO_TO_CANCEL ToCancel
, OPTIONAL
370 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &UdpIo
->SentDatagram
) {
371 Token
= NET_LIST_USER_STRUCT (Entry
, UDP_TX_TOKEN
, Link
);
373 if ((ToCancel
== NULL
) || (ToCancel (Token
, Context
))) {
374 UdpIo
->Udp
->Cancel (UdpIo
->Udp
, &Token
->UdpToken
);
381 Free the UDP IO port and all its related resources including
382 all the transmitted packet.
384 @param UdpIo The UDP IO port to free.
386 @retval EFI_SUCCESS The UDP IO port is freed.
391 IN UDP_IO_PORT
*UdpIo
394 UDP_RX_TOKEN
*RxToken
;
397 // Cancel all the sent datagram and receive requests. The
398 // callbacks of transmit requests are executed to allow the
399 // caller to release the resource. The callback of receive
400 // request are NOT executed. This is because it is most
401 // likely that the current user of the UDP IO port is closing
404 UdpIoCancelDgrams (UdpIo
, EFI_ABORTED
, NULL
, NULL
);
406 if ((RxToken
= UdpIo
->RecvRequest
) != NULL
) {
407 UdpIo
->Udp
->Cancel (UdpIo
->Udp
, &RxToken
->UdpToken
);
411 // Close then destory the UDP child
415 &gEfiUdp4ProtocolGuid
,
420 NetLibDestroyServiceChild (
423 &gEfiUdp4ServiceBindingProtocolGuid
,
427 if (!IsListEmpty(&UdpIo
->Link
)) {
428 RemoveEntryList (&UdpIo
->Link
);
431 gBS
->FreePool (UdpIo
);
437 Clean up the UDP IO port. It will release all the transmitted
438 datagrams and receive request. It will also configure NULL the
441 @param UdpIo UDP IO port to clean up.
448 IN UDP_IO_PORT
*UdpIo
451 UDP_RX_TOKEN
*RxToken
;
454 // Cancel all the sent datagram and receive requests.
456 UdpIoCancelDgrams (UdpIo
, EFI_ABORTED
, NULL
, NULL
);
458 if ((RxToken
= UdpIo
->RecvRequest
) != NULL
) {
459 UdpIo
->Udp
->Cancel (UdpIo
->Udp
, &RxToken
->UdpToken
);
462 UdpIo
->Udp
->Configure (UdpIo
->Udp
, NULL
);
467 The callback function when the packet is sent by UDP.
468 It will remove the packet from the local list then call
469 the packet owner's callback function.
471 @param Context The UDP TX Token.
479 UdpIoOnDgramSentDpc (
485 Token
= (UDP_TX_TOKEN
*) Context
;
486 ASSERT (Token
->Signature
== UDP_IO_TX_SIGNATURE
);
488 RemoveEntryList (&Token
->Link
);
489 Token
->CallBack (Token
->Packet
, NULL
, Token
->UdpToken
.Status
, Token
->Context
);
491 UdpIoFreeTxToken (Token
);
495 Request UdpIoOnDgramSentDpc as a DPC at TPL_CALLBACK.
497 @param Event The event signalled.
498 @param Context The UDP TX Token.
512 // Request UdpIoOnDgramSentDpc as a DPC at TPL_CALLBACK
514 NetLibQueueDpc (TPL_CALLBACK
, UdpIoOnDgramSentDpc
, Context
);
519 Send a packet through the UDP IO port.
521 @param UdpIo The UDP IO Port to send the packet through
522 @param Packet The packet to send
523 @param EndPoint The local and remote access point
524 @param Gateway The gateway to use
525 @param CallBack The call back function to call when packet is
526 transmitted or failed.
527 @param Context The opque parameter to the CallBack
529 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the packet
530 @retval EFI_SUCCESS The packet is successfully delivered to UDP for
536 IN UDP_IO_PORT
*UdpIo
,
538 IN UDP_POINTS
*EndPoint
, OPTIONAL
540 IN UDP_IO_CALLBACK CallBack
,
547 Token
= UdpIoWrapTx (UdpIo
, Packet
, EndPoint
, Gateway
, CallBack
, Context
);
550 return EFI_OUT_OF_RESOURCES
;
554 // Insert the tx token into SendDatagram list before transmitting it. Remove
555 // it from the list if the returned status is not EFI_SUCCESS.
557 InsertHeadList (&UdpIo
->SentDatagram
, &Token
->Link
);
558 Status
= UdpIo
->Udp
->Transmit (UdpIo
->Udp
, &Token
->UdpToken
);
559 if (EFI_ERROR (Status
)) {
560 RemoveEntryList (&Token
->Link
);
561 UdpIoFreeTxToken (Token
);
570 The selection function to cancel a single sent datagram.
572 @param Token The UDP TX token to test againist.
573 @param Context The context
575 @return TRUE if the packet is to be cancelled, otherwise FALSE.
580 UdpIoCancelSingleDgram (
581 IN UDP_TX_TOKEN
*Token
,
587 Packet
= (NET_BUF
*) Context
;
589 if (Token
->Packet
== Packet
) {
598 Cancel a single sent datagram.
600 @param UdpIo The UDP IO port to cancel the packet from
601 @param Packet The packet to cancel
607 UdpIoCancelSentDatagram (
608 IN UDP_IO_PORT
*UdpIo
,
612 UdpIoCancelDgrams (UdpIo
, EFI_ABORTED
, UdpIoCancelSingleDgram
, Packet
);
617 Recycle the received UDP data.
619 @param Context The UDP_RX_TOKEN
632 Token
= (UDP_RX_TOKEN
*) Context
;
633 gBS
->SignalEvent (Token
->UdpToken
.Packet
.RxData
->RecycleSignal
);
634 UdpIoFreeRxToken (Token
);
638 The event handle for UDP receive request. It will build
639 a NET_BUF from the recieved UDP data, then deliver it
642 @param Context The UDP RX token.
650 UdpIoOnDgramRcvdDpc (
654 EFI_UDP4_COMPLETION_TOKEN
*UdpToken
;
655 EFI_UDP4_RECEIVE_DATA
*UdpRxData
;
656 EFI_UDP4_SESSION_DATA
*UdpSession
;
661 Token
= (UDP_RX_TOKEN
*) Context
;
663 ASSERT ((Token
->Signature
== UDP_IO_RX_SIGNATURE
) &&
664 (Token
== Token
->UdpIo
->RecvRequest
));
667 // Clear the receive request first in case that the caller
668 // wants to restart the receive in the callback.
670 Token
->UdpIo
->RecvRequest
= NULL
;
672 UdpToken
= &Token
->UdpToken
;
673 UdpRxData
= UdpToken
->Packet
.RxData
;
675 if (EFI_ERROR (UdpToken
->Status
) || (UdpRxData
== NULL
)) {
676 if (UdpToken
->Status
!= EFI_ABORTED
) {
678 // Invoke the CallBack only if the reception is not actively aborted.
680 Token
->CallBack (NULL
, NULL
, UdpToken
->Status
, Token
->Context
);
683 UdpIoFreeRxToken (Token
);
688 // Build a NET_BUF from the UDP receive data, then deliver it up.
690 Netbuf
= NetbufFromExt (
691 (NET_FRAGMENT
*) UdpRxData
->FragmentTable
,
692 UdpRxData
->FragmentCount
,
694 (UINT32
) Token
->HeadLen
,
699 if (Netbuf
== NULL
) {
700 gBS
->SignalEvent (UdpRxData
->RecycleSignal
);
701 Token
->CallBack (NULL
, NULL
, EFI_OUT_OF_RESOURCES
, Token
->Context
);
703 UdpIoFreeRxToken (Token
);
707 UdpSession
= &UdpRxData
->UdpSession
;
708 Points
.LocalPort
= UdpSession
->DestinationPort
;
709 Points
.RemotePort
= UdpSession
->SourcePort
;
711 CopyMem (&Points
.LocalAddr
, &UdpSession
->DestinationAddress
, sizeof (IP4_ADDR
));
712 CopyMem (&Points
.RemoteAddr
, &UdpSession
->SourceAddress
, sizeof (IP4_ADDR
));
713 Points
.LocalAddr
= NTOHL (Points
.LocalAddr
);
714 Points
.RemoteAddr
= NTOHL (Points
.RemoteAddr
);
716 Token
->CallBack (Netbuf
, &Points
, EFI_SUCCESS
, Token
->Context
);
720 Request UdpIoOnDgramRcvdDpc as a DPC at TPL_CALLBACK.
722 @param Event The UDP receive request event.
723 @param Context The UDP RX token.
739 Request UdpIoOnDgramRcvdDpc as a DPC at TPL_CALLBACK
743 Event - The UDP receive request event
744 Context - The UDP RX token.
753 // Request UdpIoOnDgramRcvdDpc as a DPC at TPL_CALLBACK
755 NetLibQueueDpc (TPL_CALLBACK
, UdpIoOnDgramRcvdDpc
, Context
);
760 Issue a receive request to the UDP IO port.
762 @param UdpIo The UDP IO port to recieve the packet from.
763 @param CallBack The call back function to execute when receive
765 @param Context The opque context to the call back
766 @param HeadLen The lenght of the application's header
768 @retval EFI_ALREADY_STARTED There is already a pending receive request. Only
769 one receive request is supported.
770 @retval EFI_OUT_OF_RESOURCES Failed to allocate some resource.
771 @retval EFI_SUCCESS The receive request is issued successfully.
776 IN UDP_IO_PORT
*UdpIo
,
777 IN UDP_IO_CALLBACK CallBack
,
785 if (UdpIo
->RecvRequest
!= NULL
) {
786 return EFI_ALREADY_STARTED
;
789 Token
= UdpIoCreateRxToken (UdpIo
, CallBack
, Context
, HeadLen
);
792 return EFI_OUT_OF_RESOURCES
;
795 UdpIo
->RecvRequest
= Token
;
796 Status
= UdpIo
->Udp
->Receive (UdpIo
->Udp
, &Token
->UdpToken
);
798 if (EFI_ERROR (Status
)) {
799 UdpIo
->RecvRequest
= NULL
;
800 UdpIoFreeRxToken (Token
);