2 Help functions to access UDP service, it is used by both the DHCP and MTFTP.
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<BR>
8 http://opensource.org/licenses/bsd-license.php
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.
16 #include <Protocol/Udp4.h>
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 #include <Library/DpcLib.h>
28 Free a UDP_TX_TOKEN. The TX event is closed.
30 @param[in] Token The UDP_TX_TOKEN to release.
35 IN UDP_TX_TOKEN
*Token
38 gBS
->CloseEvent (Token
->UdpToken
.Event
);
39 gBS
->FreePool (Token
);
43 Free a UDP_RX_TOKEN. The RX event is closed.
45 @param[in] Token The UDP_RX_TOKEN to release.
50 IN UDP_RX_TOKEN
*Token
53 gBS
->CloseEvent (Token
->UdpToken
.Event
);
54 gBS
->FreePool (Token
);
58 The callback function when the packet is sent by UDP.
60 It will remove the packet from the local list then call
61 the packet owner's callback function set by UdpIoSendDatagram.
63 @param[in] Context The UDP TX Token.
74 Token
= (UDP_TX_TOKEN
*) Context
;
75 ASSERT (Token
->Signature
== UDP_IO_TX_SIGNATURE
);
77 RemoveEntryList (&Token
->Link
);
78 Token
->CallBack (Token
->Packet
, NULL
, Token
->UdpToken
.Status
, Token
->Context
);
80 UdpIoFreeTxToken (Token
);
84 Request UdpIoOnDgramSentDpc as a DPC at TPL_CALLBACK.
86 @param[in] Event The event signaled.
87 @param[in] Context The UDP TX Token.
98 // Request UdpIoOnDgramSentDpc as a DPC at TPL_CALLBACK
100 QueueDpc (TPL_CALLBACK
, UdpIoOnDgramSentDpc
, Context
);
104 Recycle the received UDP data.
106 @param[in] Context The UDP_RX_TOKEN.
116 Token
= (UDP_RX_TOKEN
*) Context
;
117 gBS
->SignalEvent (Token
->UdpToken
.Packet
.RxData
->RecycleSignal
);
118 UdpIoFreeRxToken (Token
);
122 The event handle for UDP receive request.
124 It will build a NET_BUF from the recieved UDP data, then deliver it
127 @param[in] Context The UDP RX token.
132 UdpIoOnDgramRcvdDpc (
136 EFI_UDP4_COMPLETION_TOKEN
*UdpToken
;
137 EFI_UDP4_RECEIVE_DATA
*UdpRxData
;
138 EFI_UDP4_SESSION_DATA
*UdpSession
;
143 Token
= (UDP_RX_TOKEN
*) Context
;
145 ASSERT ((Token
->Signature
== UDP_IO_RX_SIGNATURE
) &&
146 (Token
== Token
->UdpIo
->RecvRequest
));
149 // Clear the receive request first in case that the caller
150 // wants to restart the receive in the callback.
152 Token
->UdpIo
->RecvRequest
= NULL
;
154 UdpToken
= &Token
->UdpToken
;
155 UdpRxData
= UdpToken
->Packet
.RxData
;
157 if (EFI_ERROR (UdpToken
->Status
) || (UdpRxData
== NULL
)) {
158 if (UdpToken
->Status
!= EFI_ABORTED
) {
160 // Invoke the CallBack only if the reception is not actively aborted.
162 Token
->CallBack (NULL
, NULL
, UdpToken
->Status
, Token
->Context
);
165 UdpIoFreeRxToken (Token
);
170 // Build a NET_BUF from the UDP receive data, then deliver it up.
172 Netbuf
= NetbufFromExt (
173 (NET_FRAGMENT
*) UdpRxData
->FragmentTable
,
174 UdpRxData
->FragmentCount
,
176 (UINT32
) Token
->HeadLen
,
181 if (Netbuf
== NULL
) {
182 gBS
->SignalEvent (UdpRxData
->RecycleSignal
);
183 Token
->CallBack (NULL
, NULL
, EFI_OUT_OF_RESOURCES
, Token
->Context
);
185 UdpIoFreeRxToken (Token
);
189 UdpSession
= &UdpRxData
->UdpSession
;
190 Points
.LocalPort
= UdpSession
->DestinationPort
;
191 Points
.RemotePort
= UdpSession
->SourcePort
;
193 CopyMem (&Points
.LocalAddr
, &UdpSession
->DestinationAddress
, sizeof (IP4_ADDR
));
194 CopyMem (&Points
.RemoteAddr
, &UdpSession
->SourceAddress
, sizeof (IP4_ADDR
));
195 Points
.LocalAddr
= NTOHL (Points
.LocalAddr
);
196 Points
.RemoteAddr
= NTOHL (Points
.RemoteAddr
);
198 Token
->CallBack (Netbuf
, &Points
, EFI_SUCCESS
, Token
->Context
);
202 Request UdpIoOnDgramRcvdDpc() as a DPC at TPL_CALLBACK.
204 @param[in] Event The UDP receive request event.
205 @param[in] Context The UDP RX token.
216 // Request UdpIoOnDgramRcvdDpc as a DPC at TPL_CALLBACK
218 QueueDpc (TPL_CALLBACK
, UdpIoOnDgramRcvdDpc
, Context
);
222 Create a UDP_RX_TOKEN to wrap the request.
224 @param[in] UdpIo The UdpIo to receive packets from.
225 @param[in] CallBack The function to call when receive finished.
226 @param[in] Context The opaque parameter to the CallBack.
227 @param[in] HeadLen The head length to reserver for the packet.
229 @return The Wrapped request or NULL if failed to allocate resources or some errors happened.
234 IN UDP_IO_PORT
*UdpIo
,
235 IN UDP_IO_CALLBACK CallBack
,
243 Token
= AllocatePool (sizeof (UDP_RX_TOKEN
));
249 Token
->Signature
= UDP_IO_RX_SIGNATURE
;
250 Token
->UdpIo
= UdpIo
;
251 Token
->CallBack
= CallBack
;
252 Token
->Context
= Context
;
253 Token
->HeadLen
= HeadLen
;
255 Token
->UdpToken
.Status
= EFI_NOT_READY
;
256 Token
->UdpToken
.Packet
.RxData
= NULL
;
258 Status
= gBS
->CreateEvent (
263 &Token
->UdpToken
.Event
266 if (EFI_ERROR (Status
)) {
267 gBS
->FreePool (Token
);
275 Wrap a transmit request into a UDP_TX_TOKEN.
277 @param[in] UdpIo The UdpIo port to send packet to.
278 @param[in] Packet The user's packet.
279 @param[in] EndPoint The local and remote access point.
280 @param[in] Gateway The overrided next hop.
281 @param[in] CallBack The function to call when transmission completed.
282 @param[in] Context The opaque parameter to the call back.
284 @return The wrapped transmission request or NULL if failed to allocate resources
290 IN UDP_IO_PORT
*UdpIo
,
292 IN UDP_POINTS
*EndPoint OPTIONAL
,
294 IN UDP_IO_CALLBACK CallBack
,
299 EFI_UDP4_COMPLETION_TOKEN
*UdpToken
;
300 EFI_UDP4_TRANSMIT_DATA
*UdpTxData
;
305 Token
= AllocatePool (sizeof (UDP_TX_TOKEN
) +
306 sizeof (EFI_UDP4_FRAGMENT_DATA
) * (Packet
->BlockOpNum
- 1));
312 Token
->Signature
= UDP_IO_TX_SIGNATURE
;
313 InitializeListHead (&Token
->Link
);
315 Token
->UdpIo
= UdpIo
;
316 Token
->CallBack
= CallBack
;
317 Token
->Packet
= Packet
;
318 Token
->Context
= Context
;
320 UdpToken
= &(Token
->UdpToken
);
321 UdpToken
->Status
= EFI_NOT_READY
;
323 Status
= gBS
->CreateEvent (
331 if (EFI_ERROR (Status
)) {
332 gBS
->FreePool (Token
);
336 UdpTxData
= &Token
->UdpTxData
;
337 UdpToken
->Packet
.TxData
= UdpTxData
;
339 UdpTxData
->UdpSessionData
= NULL
;
340 UdpTxData
->GatewayAddress
= NULL
;
342 if (EndPoint
!= NULL
) {
343 Ip
= HTONL (EndPoint
->LocalAddr
);
344 CopyMem (&Token
->UdpSession
.SourceAddress
, &Ip
, sizeof (EFI_IPv4_ADDRESS
));
346 Ip
= HTONL (EndPoint
->RemoteAddr
);
347 CopyMem (&Token
->UdpSession
.DestinationAddress
, &Ip
, sizeof (EFI_IPv4_ADDRESS
));
349 Token
->UdpSession
.SourcePort
= EndPoint
->LocalPort
;
350 Token
->UdpSession
.DestinationPort
= EndPoint
->RemotePort
;
351 UdpTxData
->UdpSessionData
= &Token
->UdpSession
;
355 Ip
= HTONL (Gateway
);
356 CopyMem (&Token
->Gateway
, &Ip
, sizeof (EFI_IPv4_ADDRESS
));
358 UdpTxData
->GatewayAddress
= &Token
->Gateway
;
361 UdpTxData
->DataLength
= Packet
->TotalSize
;
362 Count
= Packet
->BlockOpNum
;
363 NetbufBuildExt (Packet
, (NET_FRAGMENT
*) UdpTxData
->FragmentTable
, &Count
);
364 UdpTxData
->FragmentCount
= Count
;
370 Create a UDP_IO_PORT to access the UDP service. It will create and configure
373 The function will locate the UDP service binding prototype on the Controller
374 parameter and use it to create a UDP child (aka Udp instance). Then the UDP
375 child will be configured by calling Configure function prototype. Any failures
376 in creating or configure the UDP child will lead to the failure of UDP_IO_PORT
379 @param[in] Controller The controller that has the UDP service binding.
381 @param[in] Image The image handle for the driver.
382 @param[in] Configure The function to configure the created UDP child.
383 @param[in] Context The opaque parameter for the Configure funtion.
385 @return Newly-created UDP_IO_PORT or NULL if failed.
391 IN EFI_HANDLE Controller
,
393 IN UDP_IO_CONFIG Configure
,
400 ASSERT (Configure
!= NULL
);
402 UdpIo
= AllocatePool (sizeof (UDP_IO_PORT
));
408 UdpIo
->Signature
= UDP_IO_SIGNATURE
;
409 InitializeListHead (&UdpIo
->Link
);
412 UdpIo
->Controller
= Controller
;
413 UdpIo
->Image
= Image
;
415 InitializeListHead (&UdpIo
->SentDatagram
);
416 UdpIo
->RecvRequest
= NULL
;
417 UdpIo
->UdpHandle
= NULL
;
420 // Create a UDP child then open and configure it
422 Status
= NetLibCreateServiceChild (
425 &gEfiUdp4ServiceBindingProtocolGuid
,
429 if (EFI_ERROR (Status
)) {
433 Status
= gBS
->OpenProtocol (
435 &gEfiUdp4ProtocolGuid
,
436 (VOID
**) &UdpIo
->Udp
,
439 EFI_OPEN_PROTOCOL_BY_DRIVER
442 if (EFI_ERROR (Status
)) {
446 if (EFI_ERROR (Configure (UdpIo
, Context
))) {
450 Status
= UdpIo
->Udp
->GetModeData (UdpIo
->Udp
, NULL
, NULL
, NULL
, &UdpIo
->SnpMode
);
452 if (EFI_ERROR (Status
)) {
459 gBS
->CloseProtocol (UdpIo
->UdpHandle
, &gEfiUdp4ProtocolGuid
, Image
, Controller
);
462 NetLibDestroyServiceChild (
465 &gEfiUdp4ServiceBindingProtocolGuid
,
470 gBS
->FreePool (UdpIo
);
475 Cancel all the sent datagram that pass the selection criteria of ToCancel.
476 If ToCancel is NULL, all the datagrams are cancelled.
478 @param[in] UdpIo The UDP_IO_PORT to cancel packet.
479 @param[in] IoStatus The IoStatus to return to the packet owners.
480 @param[in] ToCancel The select funtion to test whether to cancel this
482 @param[in] Context The opaque parameter to the ToCancel.
488 IN UDP_IO_PORT
*UdpIo
,
489 IN EFI_STATUS IoStatus
,
490 IN UDP_IO_TO_CANCEL ToCancel
, OPTIONAL
498 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &UdpIo
->SentDatagram
) {
499 Token
= NET_LIST_USER_STRUCT (Entry
, UDP_TX_TOKEN
, Link
);
501 if ((ToCancel
== NULL
) || (ToCancel (Token
, Context
))) {
502 UdpIo
->Udp
->Cancel (UdpIo
->Udp
, &Token
->UdpToken
);
508 Free the UDP_IO_PORT and all its related resources.
510 The function will cancel all sent datagram and receive request.
512 @param[in] UdpIo The UDP_IO_PORT to free.
514 @retval EFI_SUCCESS The UDP_IO_PORT is freed.
520 IN UDP_IO_PORT
*UdpIo
523 UDP_RX_TOKEN
*RxToken
;
526 // Cancel all the sent datagram and receive requests. The
527 // callbacks of transmit requests are executed to allow the
528 // caller to release the resource. The callback of receive
529 // request are NOT executed. This is because it is most
530 // likely that the current user of the UDP IO port is closing
533 UdpIoCancelDgrams (UdpIo
, EFI_ABORTED
, NULL
, NULL
);
535 if ((RxToken
= UdpIo
->RecvRequest
) != NULL
) {
536 UdpIo
->Udp
->Cancel (UdpIo
->Udp
, &RxToken
->UdpToken
);
540 // Close then destory the UDP child
544 &gEfiUdp4ProtocolGuid
,
549 NetLibDestroyServiceChild (
552 &gEfiUdp4ServiceBindingProtocolGuid
,
556 if (!IsListEmpty(&UdpIo
->Link
)) {
557 RemoveEntryList (&UdpIo
->Link
);
560 gBS
->FreePool (UdpIo
);
566 Clean up the UDP_IO_PORT without freeing it. The function is called when
567 user wants to re-use the UDP_IO_PORT later.
569 It will release all the transmitted datagrams and receive request. It will
570 also configure NULL for the UDP instance.
572 @param[in] UdpIo The UDP_IO_PORT to clean up.
578 IN UDP_IO_PORT
*UdpIo
581 UDP_RX_TOKEN
*RxToken
;
584 // Cancel all the sent datagram and receive requests.
586 UdpIoCancelDgrams (UdpIo
, EFI_ABORTED
, NULL
, NULL
);
588 if ((RxToken
= UdpIo
->RecvRequest
) != NULL
) {
589 UdpIo
->Udp
->Cancel (UdpIo
->Udp
, &RxToken
->UdpToken
);
592 UdpIo
->Udp
->Configure (UdpIo
->Udp
, NULL
);
596 Send a packet through the UDP_IO_PORT.
598 The packet will be wrapped in UDP_TX_TOKEN. Function Callback will be called
599 when the packet is sent. The optional parameter EndPoint overrides the default
600 address pair if specified.
602 @param[in] UdpIo The UDP_IO_PORT to send the packet through.
603 @param[in] Packet The packet to send.
604 @param[in] EndPoint The local and remote access point. Override the
605 default address pair set during configuration.
606 @param[in] Gateway The gateway to use.
607 @param[in] CallBack The function being called when packet is
608 transmitted or failed.
609 @param[in] Context The opaque parameter passed to CallBack.
611 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the packet.
612 @retval EFI_SUCCESS The packet is successfully delivered to UDP for
619 IN UDP_IO_PORT
*UdpIo
,
621 IN UDP_POINTS
*EndPoint
, OPTIONAL
623 IN UDP_IO_CALLBACK CallBack
,
630 Token
= UdpIoWrapTx (UdpIo
, Packet
, EndPoint
, Gateway
, CallBack
, Context
);
633 return EFI_OUT_OF_RESOURCES
;
637 // Insert the tx token into SendDatagram list before transmitting it. Remove
638 // it from the list if the returned status is not EFI_SUCCESS.
640 InsertHeadList (&UdpIo
->SentDatagram
, &Token
->Link
);
641 Status
= UdpIo
->Udp
->Transmit (UdpIo
->Udp
, &Token
->UdpToken
);
642 if (EFI_ERROR (Status
)) {
643 RemoveEntryList (&Token
->Link
);
644 UdpIoFreeTxToken (Token
);
653 The select function to cancel a single sent datagram.
655 @param[in] Token The UDP_TX_TOKEN to test against
656 @param[in] Context The NET_BUF of the sent datagram
658 @retval TRUE The packet is to be cancelled.
659 @retval FALSE The packet is not to be cancelled.
662 UdpIoCancelSingleDgram (
663 IN UDP_TX_TOKEN
*Token
,
669 Packet
= (NET_BUF
*) Context
;
671 if (Token
->Packet
== Packet
) {
679 Cancel a single sent datagram.
681 @param[in] UdpIo The UDP_IO_PORT to cancel the packet from
682 @param[in] Packet The packet to cancel
687 UdpIoCancelSentDatagram (
688 IN UDP_IO_PORT
*UdpIo
,
692 UdpIoCancelDgrams (UdpIo
, EFI_ABORTED
, UdpIoCancelSingleDgram
, Packet
);
696 Issue a receive request to the UDP_IO_PORT.
698 This function is called when upper-layer needs packet from UDP for processing.
699 Only one receive request is acceptable at a time so a common usage model is
700 to invoke this function inside its Callback function when the former packet
703 @param[in] UdpIo The UDP_IO_PORT to receive the packet from.
704 @param[in] CallBack The call back function to execute when the packet
706 @param[in] Context The opaque context passed to Callback.
707 @param[in] HeadLen The length of the upper-layer's protocol header.
709 @retval EFI_ALREADY_STARTED There is already a pending receive request. Only
710 one receive request is supported at a time.
711 @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.
712 @retval EFI_SUCCESS The receive request is issued successfully.
718 IN UDP_IO_PORT
*UdpIo
,
719 IN UDP_IO_CALLBACK CallBack
,
727 if (UdpIo
->RecvRequest
!= NULL
) {
728 return EFI_ALREADY_STARTED
;
731 Token
= UdpIoCreateRxToken (UdpIo
, CallBack
, Context
, HeadLen
);
734 return EFI_OUT_OF_RESOURCES
;
737 UdpIo
->RecvRequest
= Token
;
738 Status
= UdpIo
->Udp
->Receive (UdpIo
->Udp
, &Token
->UdpToken
);
740 if (EFI_ERROR (Status
)) {
741 UdpIo
->RecvRequest
= NULL
;
742 UdpIoFreeRxToken (Token
);