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>
57 Wrap a transmit request into a UDP_TX_TOKEN.
59 @param UdpIo The UdpIo port to send packet to
60 @param Packet The user's packet
61 @param EndPoint The local and remote access point
62 @param Gateway The overrided next hop
63 @param CallBack The function to call when transmission completed.
64 @param Context The opaque parameter to the call back
66 @return The wrapped transmission request or NULL if failed to allocate resources.
71 IN UDP_IO_PORT
*UdpIo
,
73 IN UDP_POINTS
*EndPoint
, OPTIONAL
75 IN UDP_IO_CALLBACK CallBack
,
80 EFI_UDP4_COMPLETION_TOKEN
*UdpToken
;
81 EFI_UDP4_TRANSMIT_DATA
*UdpTxData
;
86 Token
= AllocatePool (sizeof (UDP_TX_TOKEN
) +
87 sizeof (EFI_UDP4_FRAGMENT_DATA
) * (Packet
->BlockOpNum
- 1));
93 Token
->Signature
= UDP_IO_TX_SIGNATURE
;
94 InitializeListHead (&Token
->Link
);
97 Token
->CallBack
= CallBack
;
98 Token
->Packet
= Packet
;
99 Token
->Context
= Context
;
101 UdpToken
= &(Token
->UdpToken
);
102 UdpToken
->Status
= EFI_NOT_READY
;
104 Status
= gBS
->CreateEvent (
112 if (EFI_ERROR (Status
)) {
113 gBS
->FreePool (Token
);
117 UdpTxData
= &Token
->UdpTxData
;
118 UdpToken
->Packet
.TxData
= UdpTxData
;
120 UdpTxData
->UdpSessionData
= NULL
;
121 UdpTxData
->GatewayAddress
= NULL
;
123 if (EndPoint
!= NULL
) {
124 Ip
= HTONL (EndPoint
->LocalAddr
);
125 CopyMem (&Token
->UdpSession
.SourceAddress
, &Ip
, sizeof (EFI_IPv4_ADDRESS
));
127 Ip
= HTONL (EndPoint
->RemoteAddr
);
128 CopyMem (&Token
->UdpSession
.DestinationAddress
, &Ip
, sizeof (EFI_IPv4_ADDRESS
));
130 Token
->UdpSession
.SourcePort
= EndPoint
->LocalPort
;
131 Token
->UdpSession
.DestinationPort
= EndPoint
->RemotePort
;
132 UdpTxData
->UdpSessionData
= &Token
->UdpSession
;
136 Ip
= HTONL (Gateway
);
137 CopyMem (&Token
->Gateway
, &Ip
, sizeof (EFI_IPv4_ADDRESS
));
139 UdpTxData
->GatewayAddress
= &Token
->Gateway
;
142 UdpTxData
->DataLength
= Packet
->TotalSize
;
143 Count
= Packet
->BlockOpNum
;
144 NetbufBuildExt (Packet
, (NET_FRAGMENT
*) UdpTxData
->FragmentTable
, &Count
);
145 UdpTxData
->FragmentCount
= Count
;
152 Free a UDP_TX_TOKEN. The event is closed and memory released.
154 @param Token The UDP_TX_TOKEN to release.
161 IN UDP_TX_TOKEN
*Token
164 gBS
->CloseEvent (Token
->UdpToken
.Event
);
165 gBS
->FreePool (Token
);
170 Create a UDP_RX_TOKEN to wrap the request.
172 @param UdpIo The UdpIo to receive packets from
173 @param CallBack The function to call when receive finished.
174 @param Context The opaque parameter to the CallBack
175 @param HeadLen The head length to reserver for the packet.
177 @return The Wrapped request or NULL if failed to allocate resources.
182 IN UDP_IO_PORT
*UdpIo
,
183 IN UDP_IO_CALLBACK CallBack
,
191 Token
= AllocatePool (sizeof (UDP_RX_TOKEN
));
197 Token
->Signature
= UDP_IO_RX_SIGNATURE
;
198 Token
->UdpIo
= UdpIo
;
199 Token
->CallBack
= CallBack
;
200 Token
->Context
= Context
;
201 Token
->HeadLen
= HeadLen
;
203 Token
->UdpToken
.Status
= EFI_NOT_READY
;
204 Token
->UdpToken
.Packet
.RxData
= NULL
;
206 Status
= gBS
->CreateEvent (
211 &Token
->UdpToken
.Event
214 if (EFI_ERROR (Status
)) {
215 gBS
->FreePool (Token
);
224 Free a receive request wrap.
226 @param Token The receive request to release.
233 IN UDP_RX_TOKEN
*Token
236 gBS
->CloseEvent (Token
->UdpToken
.Event
);
237 gBS
->FreePool (Token
);
242 Create a UDP IO port to access the UDP service. It will
243 create and configure a UDP child.
245 @param Controller The controller that has the UDP service binding
247 @param Image The image handle for the driver.
248 @param Configure The function to configure the created UDP child
249 @param Context The opaque parameter for the Configure funtion.
251 @return A point to just created UDP IO port or NULL if failed.
257 IN EFI_HANDLE Controller
,
259 IN UDP_IO_CONFIG Configure
,
266 ASSERT (Configure
!= NULL
);
268 UdpIo
= AllocatePool (sizeof (UDP_IO_PORT
));
274 UdpIo
->Signature
= UDP_IO_SIGNATURE
;
275 InitializeListHead (&UdpIo
->Link
);
278 UdpIo
->Controller
= Controller
;
279 UdpIo
->Image
= Image
;
281 InitializeListHead (&UdpIo
->SentDatagram
);
282 UdpIo
->RecvRequest
= NULL
;
283 UdpIo
->UdpHandle
= NULL
;
286 // Create a UDP child then open and configure it
288 Status
= NetLibCreateServiceChild (
291 &gEfiUdp4ServiceBindingProtocolGuid
,
295 if (EFI_ERROR (Status
)) {
299 Status
= gBS
->OpenProtocol (
301 &gEfiUdp4ProtocolGuid
,
302 (VOID
**) &UdpIo
->Udp
,
305 EFI_OPEN_PROTOCOL_BY_DRIVER
308 if (EFI_ERROR (Status
)) {
312 if (EFI_ERROR (Configure (UdpIo
, Context
))) {
316 Status
= UdpIo
->Udp
->GetModeData (UdpIo
->Udp
, NULL
, NULL
, NULL
, &UdpIo
->SnpMode
);
318 if (EFI_ERROR (Status
)) {
325 gBS
->CloseProtocol (UdpIo
->UdpHandle
, &gEfiUdp4ProtocolGuid
, Image
, Controller
);
328 NetLibDestroyServiceChild (
331 &gEfiUdp4ServiceBindingProtocolGuid
,
336 gBS
->FreePool (UdpIo
);
342 Cancel all the sent datagram that pass the selection of ToCancel.
343 If ToCancel is NULL, all the datagrams are cancelled.
345 @param UdpIo The UDP IO port to cancel packet
346 @param IoStatus The IoStatus to return to the packet owners.
347 @param ToCancel The select funtion to test whether to cancel this
349 @param Context The opaque parameter to the ToCancel.
356 IN UDP_IO_PORT
*UdpIo
,
357 IN EFI_STATUS IoStatus
,
358 IN UDP_IO_TO_CANCEL ToCancel
, OPTIONAL
366 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &UdpIo
->SentDatagram
) {
367 Token
= NET_LIST_USER_STRUCT (Entry
, UDP_TX_TOKEN
, Link
);
369 if ((ToCancel
== NULL
) || (ToCancel (Token
, Context
))) {
370 UdpIo
->Udp
->Cancel (UdpIo
->Udp
, &Token
->UdpToken
);
377 Free the UDP IO port and all its related resources including
378 all the transmitted packet.
380 @param UdpIo The UDP IO port to free.
382 @retval EFI_SUCCESS The UDP IO port is freed.
388 IN UDP_IO_PORT
*UdpIo
391 UDP_RX_TOKEN
*RxToken
;
394 // Cancel all the sent datagram and receive requests. The
395 // callbacks of transmit requests are executed to allow the
396 // caller to release the resource. The callback of receive
397 // request are NOT executed. This is because it is most
398 // likely that the current user of the UDP IO port is closing
401 UdpIoCancelDgrams (UdpIo
, EFI_ABORTED
, NULL
, NULL
);
403 if ((RxToken
= UdpIo
->RecvRequest
) != NULL
) {
404 UdpIo
->Udp
->Cancel (UdpIo
->Udp
, &RxToken
->UdpToken
);
408 // Close then destory the UDP child
412 &gEfiUdp4ProtocolGuid
,
417 NetLibDestroyServiceChild (
420 &gEfiUdp4ServiceBindingProtocolGuid
,
424 if (!IsListEmpty(&UdpIo
->Link
)) {
425 RemoveEntryList (&UdpIo
->Link
);
428 gBS
->FreePool (UdpIo
);
434 Clean up the UDP IO port. It will release all the transmitted
435 datagrams and receive request. It will also configure NULL the
438 @param UdpIo UDP IO port to clean up.
446 IN UDP_IO_PORT
*UdpIo
449 UDP_RX_TOKEN
*RxToken
;
452 // Cancel all the sent datagram and receive requests.
454 UdpIoCancelDgrams (UdpIo
, EFI_ABORTED
, NULL
, NULL
);
456 if ((RxToken
= UdpIo
->RecvRequest
) != NULL
) {
457 UdpIo
->Udp
->Cancel (UdpIo
->Udp
, &RxToken
->UdpToken
);
460 UdpIo
->Udp
->Configure (UdpIo
->Udp
, NULL
);
465 The callback function when the packet is sent by UDP.
466 It will remove the packet from the local list then call
467 the packet owner's callback function.
469 @param Context The UDP TX Token.
476 UdpIoOnDgramSentDpc (
482 Token
= (UDP_TX_TOKEN
*) Context
;
483 ASSERT (Token
->Signature
== UDP_IO_TX_SIGNATURE
);
485 RemoveEntryList (&Token
->Link
);
486 Token
->CallBack (Token
->Packet
, NULL
, Token
->UdpToken
.Status
, Token
->Context
);
488 UdpIoFreeTxToken (Token
);
492 Request UdpIoOnDgramSentDpc as a DPC at TPL_CALLBACK.
494 @param Event The event signalled.
495 @param Context The UDP TX Token.
508 // Request UdpIoOnDgramSentDpc as a DPC at TPL_CALLBACK
510 NetLibQueueDpc (TPL_CALLBACK
, UdpIoOnDgramSentDpc
, Context
);
515 Send a packet through the UDP IO port.
517 @param UdpIo The UDP IO Port to send the packet through
518 @param Packet The packet to send
519 @param EndPoint The local and remote access point
520 @param Gateway The gateway to use
521 @param CallBack The call back function to call when packet is
522 transmitted or failed.
523 @param Context The opque parameter to the CallBack
525 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the packet
526 @retval EFI_SUCCESS The packet is successfully delivered to UDP for
533 IN UDP_IO_PORT
*UdpIo
,
535 IN UDP_POINTS
*EndPoint
, OPTIONAL
537 IN UDP_IO_CALLBACK CallBack
,
544 Token
= UdpIoWrapTx (UdpIo
, Packet
, EndPoint
, Gateway
, CallBack
, Context
);
547 return EFI_OUT_OF_RESOURCES
;
551 // Insert the tx token into SendDatagram list before transmitting it. Remove
552 // it from the list if the returned status is not EFI_SUCCESS.
554 InsertHeadList (&UdpIo
->SentDatagram
, &Token
->Link
);
555 Status
= UdpIo
->Udp
->Transmit (UdpIo
->Udp
, &Token
->UdpToken
);
556 if (EFI_ERROR (Status
)) {
557 RemoveEntryList (&Token
->Link
);
558 UdpIoFreeTxToken (Token
);
567 The selection function to cancel a single sent datagram.
569 @param Token The UDP TX token to test againist.
570 @param Context The context
572 @return TRUE if the packet is to be cancelled, otherwise FALSE.
576 UdpIoCancelSingleDgram (
577 IN UDP_TX_TOKEN
*Token
,
583 Packet
= (NET_BUF
*) Context
;
585 if (Token
->Packet
== Packet
) {
594 Cancel a single sent datagram.
596 @param UdpIo The UDP IO port to cancel the packet from
597 @param Packet The packet to cancel
604 UdpIoCancelSentDatagram (
605 IN UDP_IO_PORT
*UdpIo
,
609 UdpIoCancelDgrams (UdpIo
, EFI_ABORTED
, UdpIoCancelSingleDgram
, Packet
);
614 Recycle the received UDP data.
616 @param Context The UDP_RX_TOKEN
628 Token
= (UDP_RX_TOKEN
*) Context
;
629 gBS
->SignalEvent (Token
->UdpToken
.Packet
.RxData
->RecycleSignal
);
630 UdpIoFreeRxToken (Token
);
634 The event handle for UDP receive request. It will build
635 a NET_BUF from the recieved UDP data, then deliver it
638 @param Context The UDP RX token.
645 UdpIoOnDgramRcvdDpc (
649 EFI_UDP4_COMPLETION_TOKEN
*UdpToken
;
650 EFI_UDP4_RECEIVE_DATA
*UdpRxData
;
651 EFI_UDP4_SESSION_DATA
*UdpSession
;
656 Token
= (UDP_RX_TOKEN
*) Context
;
658 ASSERT ((Token
->Signature
== UDP_IO_RX_SIGNATURE
) &&
659 (Token
== Token
->UdpIo
->RecvRequest
));
662 // Clear the receive request first in case that the caller
663 // wants to restart the receive in the callback.
665 Token
->UdpIo
->RecvRequest
= NULL
;
667 UdpToken
= &Token
->UdpToken
;
668 UdpRxData
= UdpToken
->Packet
.RxData
;
670 if (EFI_ERROR (UdpToken
->Status
) || (UdpRxData
== NULL
)) {
671 if (UdpToken
->Status
!= EFI_ABORTED
) {
673 // Invoke the CallBack only if the reception is not actively aborted.
675 Token
->CallBack (NULL
, NULL
, UdpToken
->Status
, Token
->Context
);
678 UdpIoFreeRxToken (Token
);
683 // Build a NET_BUF from the UDP receive data, then deliver it up.
685 Netbuf
= NetbufFromExt (
686 (NET_FRAGMENT
*) UdpRxData
->FragmentTable
,
687 UdpRxData
->FragmentCount
,
689 (UINT32
) Token
->HeadLen
,
694 if (Netbuf
== NULL
) {
695 gBS
->SignalEvent (UdpRxData
->RecycleSignal
);
696 Token
->CallBack (NULL
, NULL
, EFI_OUT_OF_RESOURCES
, Token
->Context
);
698 UdpIoFreeRxToken (Token
);
702 UdpSession
= &UdpRxData
->UdpSession
;
703 Points
.LocalPort
= UdpSession
->DestinationPort
;
704 Points
.RemotePort
= UdpSession
->SourcePort
;
706 CopyMem (&Points
.LocalAddr
, &UdpSession
->DestinationAddress
, sizeof (IP4_ADDR
));
707 CopyMem (&Points
.RemoteAddr
, &UdpSession
->SourceAddress
, sizeof (IP4_ADDR
));
708 Points
.LocalAddr
= NTOHL (Points
.LocalAddr
);
709 Points
.RemoteAddr
= NTOHL (Points
.RemoteAddr
);
711 Token
->CallBack (Netbuf
, &Points
, EFI_SUCCESS
, Token
->Context
);
715 Request UdpIoOnDgramRcvdDpc as a DPC at TPL_CALLBACK.
717 @param Event The UDP receive request event.
718 @param Context The UDP RX token.
733 Request UdpIoOnDgramRcvdDpc as a DPC at TPL_CALLBACK
737 Event - The UDP receive request event
738 Context - The UDP RX token.
747 // Request UdpIoOnDgramRcvdDpc as a DPC at TPL_CALLBACK
749 NetLibQueueDpc (TPL_CALLBACK
, UdpIoOnDgramRcvdDpc
, Context
);
754 Issue a receive request to the UDP IO port.
756 @param UdpIo The UDP IO port to recieve the packet from.
757 @param CallBack The call back function to execute when receive
759 @param Context The opque context to the call back
760 @param HeadLen The lenght of the application's header
762 @retval EFI_ALREADY_STARTED There is already a pending receive request. Only
763 one receive request is supported.
764 @retval EFI_OUT_OF_RESOURCES Failed to allocate some resource.
765 @retval EFI_SUCCESS The receive request is issued successfully.
771 IN UDP_IO_PORT
*UdpIo
,
772 IN UDP_IO_CALLBACK CallBack
,
780 if (UdpIo
->RecvRequest
!= NULL
) {
781 return EFI_ALREADY_STARTED
;
784 Token
= UdpIoCreateRxToken (UdpIo
, CallBack
, Context
, HeadLen
);
787 return EFI_OUT_OF_RESOURCES
;
790 UdpIo
->RecvRequest
= Token
;
791 Status
= UdpIo
->Udp
->Receive (UdpIo
->Udp
, &Token
->UdpToken
);
793 if (EFI_ERROR (Status
)) {
794 UdpIo
->RecvRequest
= NULL
;
795 UdpIoFreeRxToken (Token
);