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