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.
261 IN EFI_HANDLE Controller
,
263 IN UDP_IO_CONFIG Configure
,
270 ASSERT (Configure
!= NULL
);
272 UdpIo
= AllocatePool (sizeof (UDP_IO_PORT
));
278 UdpIo
->Signature
= UDP_IO_SIGNATURE
;
279 InitializeListHead (&UdpIo
->Link
);
282 UdpIo
->Controller
= Controller
;
283 UdpIo
->Image
= Image
;
285 InitializeListHead (&UdpIo
->SentDatagram
);
286 UdpIo
->RecvRequest
= NULL
;
287 UdpIo
->UdpHandle
= NULL
;
290 // Create a UDP child then open and configure it
292 Status
= NetLibCreateServiceChild (
295 &gEfiUdp4ServiceBindingProtocolGuid
,
299 if (EFI_ERROR (Status
)) {
303 Status
= gBS
->OpenProtocol (
305 &gEfiUdp4ProtocolGuid
,
306 (VOID
**) &UdpIo
->Udp
,
309 EFI_OPEN_PROTOCOL_BY_DRIVER
312 if (EFI_ERROR (Status
)) {
316 if (EFI_ERROR (Configure (UdpIo
, Context
))) {
320 Status
= UdpIo
->Udp
->GetModeData (UdpIo
->Udp
, NULL
, NULL
, NULL
, &UdpIo
->SnpMode
);
322 if (EFI_ERROR (Status
)) {
329 gBS
->CloseProtocol (UdpIo
->UdpHandle
, &gEfiUdp4ProtocolGuid
, Image
, Controller
);
332 NetLibDestroyServiceChild (
335 &gEfiUdp4ServiceBindingProtocolGuid
,
340 gBS
->FreePool (UdpIo
);
346 Cancel all the sent datagram that pass the selection of ToCancel.
347 If ToCancel is NULL, all the datagrams are cancelled.
349 @param UdpIo The UDP IO port to cancel packet
350 @param IoStatus The IoStatus to return to the packet owners.
351 @param ToCancel The select funtion to test whether to cancel this
353 @param Context The opaque parameter to the ToCancel.
361 IN UDP_IO_PORT
*UdpIo
,
362 IN EFI_STATUS IoStatus
,
363 IN UDP_IO_TO_CANCEL ToCancel
, OPTIONAL
371 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &UdpIo
->SentDatagram
) {
372 Token
= NET_LIST_USER_STRUCT (Entry
, UDP_TX_TOKEN
, Link
);
374 if ((ToCancel
== NULL
) || (ToCancel (Token
, Context
))) {
375 UdpIo
->Udp
->Cancel (UdpIo
->Udp
, &Token
->UdpToken
);
382 Free the UDP IO port and all its related resources including
383 all the transmitted packet.
385 @param UdpIo The UDP IO port to free.
387 @retval EFI_SUCCESS The UDP IO port is freed.
393 IN UDP_IO_PORT
*UdpIo
396 UDP_RX_TOKEN
*RxToken
;
399 // Cancel all the sent datagram and receive requests. The
400 // callbacks of transmit requests are executed to allow the
401 // caller to release the resource. The callback of receive
402 // request are NOT executed. This is because it is most
403 // likely that the current user of the UDP IO port is closing
406 UdpIoCancelDgrams (UdpIo
, EFI_ABORTED
, NULL
, NULL
);
408 if ((RxToken
= UdpIo
->RecvRequest
) != NULL
) {
409 UdpIo
->Udp
->Cancel (UdpIo
->Udp
, &RxToken
->UdpToken
);
413 // Close then destory the UDP child
417 &gEfiUdp4ProtocolGuid
,
422 NetLibDestroyServiceChild (
425 &gEfiUdp4ServiceBindingProtocolGuid
,
429 if (!IsListEmpty(&UdpIo
->Link
)) {
430 RemoveEntryList (&UdpIo
->Link
);
433 gBS
->FreePool (UdpIo
);
439 Clean up the UDP IO port. It will release all the transmitted
440 datagrams and receive request. It will also configure NULL the
443 @param UdpIo UDP IO port to clean up.
451 IN UDP_IO_PORT
*UdpIo
454 UDP_RX_TOKEN
*RxToken
;
457 // Cancel all the sent datagram and receive requests.
459 UdpIoCancelDgrams (UdpIo
, EFI_ABORTED
, NULL
, NULL
);
461 if ((RxToken
= UdpIo
->RecvRequest
) != NULL
) {
462 UdpIo
->Udp
->Cancel (UdpIo
->Udp
, &RxToken
->UdpToken
);
465 UdpIo
->Udp
->Configure (UdpIo
->Udp
, NULL
);
470 The callback function when the packet is sent by UDP.
471 It will remove the packet from the local list then call
472 the packet owner's callback function.
474 @param Context The UDP TX Token.
482 UdpIoOnDgramSentDpc (
488 Token
= (UDP_TX_TOKEN
*) Context
;
489 ASSERT (Token
->Signature
== UDP_IO_TX_SIGNATURE
);
491 RemoveEntryList (&Token
->Link
);
492 Token
->CallBack (Token
->Packet
, NULL
, Token
->UdpToken
.Status
, Token
->Context
);
494 UdpIoFreeTxToken (Token
);
498 Request UdpIoOnDgramSentDpc as a DPC at TPL_CALLBACK.
500 @param Event The event signalled.
501 @param Context The UDP TX Token.
515 // Request UdpIoOnDgramSentDpc as a DPC at TPL_CALLBACK
517 NetLibQueueDpc (TPL_CALLBACK
, UdpIoOnDgramSentDpc
, Context
);
522 Send a packet through the UDP IO port.
524 @param UdpIo The UDP IO Port to send the packet through
525 @param Packet The packet to send
526 @param EndPoint The local and remote access point
527 @param Gateway The gateway to use
528 @param CallBack The call back function to call when packet is
529 transmitted or failed.
530 @param Context The opque parameter to the CallBack
532 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the packet
533 @retval EFI_SUCCESS The packet is successfully delivered to UDP for
540 IN UDP_IO_PORT
*UdpIo
,
542 IN UDP_POINTS
*EndPoint
, OPTIONAL
544 IN UDP_IO_CALLBACK CallBack
,
551 Token
= UdpIoWrapTx (UdpIo
, Packet
, EndPoint
, Gateway
, CallBack
, Context
);
554 return EFI_OUT_OF_RESOURCES
;
558 // Insert the tx token into SendDatagram list before transmitting it. Remove
559 // it from the list if the returned status is not EFI_SUCCESS.
561 InsertHeadList (&UdpIo
->SentDatagram
, &Token
->Link
);
562 Status
= UdpIo
->Udp
->Transmit (UdpIo
->Udp
, &Token
->UdpToken
);
563 if (EFI_ERROR (Status
)) {
564 RemoveEntryList (&Token
->Link
);
565 UdpIoFreeTxToken (Token
);
574 The selection function to cancel a single sent datagram.
576 @param Token The UDP TX token to test againist.
577 @param Context The context
579 @return TRUE if the packet is to be cancelled, otherwise FALSE.
584 UdpIoCancelSingleDgram (
585 IN UDP_TX_TOKEN
*Token
,
591 Packet
= (NET_BUF
*) Context
;
593 if (Token
->Packet
== Packet
) {
602 Cancel a single sent datagram.
604 @param UdpIo The UDP IO port to cancel the packet from
605 @param Packet The packet to cancel
612 UdpIoCancelSentDatagram (
613 IN UDP_IO_PORT
*UdpIo
,
617 UdpIoCancelDgrams (UdpIo
, EFI_ABORTED
, UdpIoCancelSingleDgram
, Packet
);
622 Recycle the received UDP data.
624 @param Context The UDP_RX_TOKEN
637 Token
= (UDP_RX_TOKEN
*) Context
;
638 gBS
->SignalEvent (Token
->UdpToken
.Packet
.RxData
->RecycleSignal
);
639 UdpIoFreeRxToken (Token
);
643 The event handle for UDP receive request. It will build
644 a NET_BUF from the recieved UDP data, then deliver it
647 @param Context The UDP RX token.
655 UdpIoOnDgramRcvdDpc (
659 EFI_UDP4_COMPLETION_TOKEN
*UdpToken
;
660 EFI_UDP4_RECEIVE_DATA
*UdpRxData
;
661 EFI_UDP4_SESSION_DATA
*UdpSession
;
666 Token
= (UDP_RX_TOKEN
*) Context
;
668 ASSERT ((Token
->Signature
== UDP_IO_RX_SIGNATURE
) &&
669 (Token
== Token
->UdpIo
->RecvRequest
));
672 // Clear the receive request first in case that the caller
673 // wants to restart the receive in the callback.
675 Token
->UdpIo
->RecvRequest
= NULL
;
677 UdpToken
= &Token
->UdpToken
;
678 UdpRxData
= UdpToken
->Packet
.RxData
;
680 if (EFI_ERROR (UdpToken
->Status
) || (UdpRxData
== NULL
)) {
681 if (UdpToken
->Status
!= EFI_ABORTED
) {
683 // Invoke the CallBack only if the reception is not actively aborted.
685 Token
->CallBack (NULL
, NULL
, UdpToken
->Status
, Token
->Context
);
688 UdpIoFreeRxToken (Token
);
693 // Build a NET_BUF from the UDP receive data, then deliver it up.
695 Netbuf
= NetbufFromExt (
696 (NET_FRAGMENT
*) UdpRxData
->FragmentTable
,
697 UdpRxData
->FragmentCount
,
699 (UINT32
) Token
->HeadLen
,
704 if (Netbuf
== NULL
) {
705 gBS
->SignalEvent (UdpRxData
->RecycleSignal
);
706 Token
->CallBack (NULL
, NULL
, EFI_OUT_OF_RESOURCES
, Token
->Context
);
708 UdpIoFreeRxToken (Token
);
712 UdpSession
= &UdpRxData
->UdpSession
;
713 Points
.LocalPort
= UdpSession
->DestinationPort
;
714 Points
.RemotePort
= UdpSession
->SourcePort
;
716 CopyMem (&Points
.LocalAddr
, &UdpSession
->DestinationAddress
, sizeof (IP4_ADDR
));
717 CopyMem (&Points
.RemoteAddr
, &UdpSession
->SourceAddress
, sizeof (IP4_ADDR
));
718 Points
.LocalAddr
= NTOHL (Points
.LocalAddr
);
719 Points
.RemoteAddr
= NTOHL (Points
.RemoteAddr
);
721 Token
->CallBack (Netbuf
, &Points
, EFI_SUCCESS
, Token
->Context
);
725 Request UdpIoOnDgramRcvdDpc as a DPC at TPL_CALLBACK.
727 @param Event The UDP receive request event.
728 @param Context The UDP RX token.
744 Request UdpIoOnDgramRcvdDpc as a DPC at TPL_CALLBACK
748 Event - The UDP receive request event
749 Context - The UDP RX token.
758 // Request UdpIoOnDgramRcvdDpc as a DPC at TPL_CALLBACK
760 NetLibQueueDpc (TPL_CALLBACK
, UdpIoOnDgramRcvdDpc
, Context
);
765 Issue a receive request to the UDP IO port.
767 @param UdpIo The UDP IO port to recieve the packet from.
768 @param CallBack The call back function to execute when receive
770 @param Context The opque context to the call back
771 @param HeadLen The lenght of the application's header
773 @retval EFI_ALREADY_STARTED There is already a pending receive request. Only
774 one receive request is supported.
775 @retval EFI_OUT_OF_RESOURCES Failed to allocate some resource.
776 @retval EFI_SUCCESS The receive request is issued successfully.
782 IN UDP_IO_PORT
*UdpIo
,
783 IN UDP_IO_CALLBACK CallBack
,
791 if (UdpIo
->RecvRequest
!= NULL
) {
792 return EFI_ALREADY_STARTED
;
795 Token
= UdpIoCreateRxToken (UdpIo
, CallBack
, Context
, HeadLen
);
798 return EFI_OUT_OF_RESOURCES
;
801 UdpIo
->RecvRequest
= Token
;
802 Status
= UdpIo
->Udp
->Receive (UdpIo
->Udp
, &Token
->UdpToken
);
804 if (EFI_ERROR (Status
)) {
805 UdpIo
->RecvRequest
= NULL
;
806 UdpIoFreeRxToken (Token
);