]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.c
b66348c284c9c7401e5f725c99c52fc7cd79cc5e
[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 (VOID **) &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 if (!IsListEmpty(&UdpIo->Link)) {
418 NetListRemoveEntry (&UdpIo->Link);
419 }
420
421 NetFreePool (UdpIo);
422 return EFI_SUCCESS;
423 }
424
425
426 /**
427 Clean up the UDP IO port. It will release all the transmitted
428 datagrams and receive request. It will also configure NULL the
429 UDP child.
430
431 @param UdpIo UDP IO port to clean up.
432
433 @return None
434
435 **/
436 VOID
437 UdpIoCleanPort (
438 IN UDP_IO_PORT *UdpIo
439 )
440 {
441 UDP_RX_TOKEN *RxToken;
442
443 //
444 // Cancel all the sent datagram and receive requests.
445 //
446 UdpIoCancelDgrams (UdpIo, EFI_ABORTED, NULL, NULL);
447
448 if ((RxToken = UdpIo->RecvRequest) != NULL) {
449 UdpIo->RecvRequest = NULL;
450 UdpIo->Udp->Cancel (UdpIo->Udp, &RxToken->UdpToken);
451 UdpIoFreeRxToken (RxToken);
452 }
453
454 UdpIo->Udp->Configure (UdpIo->Udp, NULL);
455 }
456
457
458 /**
459 The callback function when the packet is sent by UDP.
460 It will remove the packet from the local list then call
461 the packet owner's callback function.
462
463 @param Event The event signalled.
464 @param Context The UDP TX Token.
465
466 @return None
467
468 **/
469 STATIC
470 VOID
471 EFIAPI
472 UdpIoOnDgramSent (
473 IN EFI_EVENT Event,
474 IN VOID *Context
475 )
476 {
477 UDP_TX_TOKEN *Token;
478
479 Token = (UDP_TX_TOKEN *) Context;
480 ASSERT (Token->Signature == UDP_IO_TX_SIGNATURE);
481
482 NetListRemoveEntry (&Token->Link);
483 Token->CallBack (Token->Packet, NULL, Token->UdpToken.Status, Token->Context);
484
485 UdpIoFreeTxToken (Token);
486 }
487
488
489 /**
490 Send a packet through the UDP IO port.
491
492 @param UdpIo The UDP IO Port to send the packet through
493 @param Packet The packet to send
494 @param EndPoint The local and remote access point
495 @param Gateway The gateway to use
496 @param CallBack The call back function to call when packet is
497 transmitted or failed.
498 @param Context The opque parameter to the CallBack
499
500 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the packet
501 @retval EFI_SUCCESS The packet is successfully delivered to UDP for
502 transmission.
503
504 **/
505 EFI_STATUS
506 UdpIoSendDatagram (
507 IN UDP_IO_PORT *UdpIo,
508 IN NET_BUF *Packet,
509 IN UDP_POINTS *EndPoint, OPTIONAL
510 IN IP4_ADDR Gateway,
511 IN UDP_IO_CALLBACK CallBack,
512 IN VOID *Context
513 )
514 {
515 UDP_TX_TOKEN *Token;
516 EFI_STATUS Status;
517
518 Token = UdpIoWrapTx (UdpIo, Packet, EndPoint, Gateway, CallBack, Context);
519
520 if (Token == NULL) {
521 return EFI_OUT_OF_RESOURCES;
522 }
523
524 Status = UdpIo->Udp->Transmit (UdpIo->Udp, &Token->UdpToken);
525
526 if (EFI_ERROR (Status)) {
527 UdpIoFreeTxToken (Token);
528 return Status;
529 }
530
531 NetListInsertHead (&UdpIo->SentDatagram, &Token->Link);
532 return EFI_SUCCESS;
533 }
534
535
536 /**
537 The selection function to cancel a single sent datagram.
538
539 @param Token The UDP TX token to test againist.
540 @param Context The context
541
542 @return TRUE if the packet is to be cancelled, otherwise FALSE.
543
544 **/
545 STATIC
546 BOOLEAN
547 UdpIoCancelSingleDgram (
548 IN UDP_TX_TOKEN *Token,
549 IN VOID *Context
550 )
551 {
552 NET_BUF *Packet;
553
554 Packet = (NET_BUF *) Context;
555
556 if (Token->Packet == Packet) {
557 return TRUE;
558 }
559
560 return FALSE;
561 }
562
563
564 /**
565 Cancel a single sent datagram.
566
567 @param UdpIo The UDP IO port to cancel the packet from
568 @param Packet The packet to cancel
569
570 @return None
571
572 **/
573 VOID
574 UdpIoCancelSentDatagram (
575 IN UDP_IO_PORT *UdpIo,
576 IN NET_BUF *Packet
577 )
578 {
579 UdpIoCancelDgrams (UdpIo, EFI_ABORTED, UdpIoCancelSingleDgram, Packet);
580 }
581
582
583 /**
584 Recycle the received UDP data.
585
586 @param Context The UDP_RX_TOKEN
587
588 @return None
589
590 **/
591 STATIC
592 VOID
593 UdpIoRecycleDgram (
594 IN VOID *Context
595 )
596 {
597 UDP_RX_TOKEN *Token;
598
599 Token = (UDP_RX_TOKEN *) Context;
600 gBS->SignalEvent (Token->UdpToken.Packet.RxData->RecycleSignal);
601 UdpIoFreeRxToken (Token);
602 }
603
604
605 /**
606 The event handle for UDP receive request. It will build
607 a NET_BUF from the recieved UDP data, then deliver it
608 to the receiver.
609
610 @param Event The UDP receive request event
611 @param Context The UDP RX token.
612
613 @return None
614
615 **/
616 STATIC
617 VOID
618 EFIAPI
619 UdpIoOnDgramRcvd (
620 IN EFI_EVENT Event,
621 IN VOID *Context
622 )
623 {
624 EFI_UDP4_COMPLETION_TOKEN *UdpToken;
625 EFI_UDP4_RECEIVE_DATA *UdpRxData;
626 EFI_UDP4_SESSION_DATA *UdpSession;
627 UDP_RX_TOKEN *Token;
628 UDP_POINTS Points;
629 NET_BUF *Netbuf;
630
631 Token = (UDP_RX_TOKEN *) Context;
632
633 ASSERT ((Token->Signature == UDP_IO_RX_SIGNATURE) &&
634 (Token == Token->UdpIo->RecvRequest));
635
636 //
637 // Clear the receive request first in case that the caller
638 // wants to restart the receive in the callback.
639 //
640 Token->UdpIo->RecvRequest = NULL;
641
642 UdpToken = &Token->UdpToken;
643 UdpRxData = UdpToken->Packet.RxData;
644
645 if (EFI_ERROR (UdpToken->Status) || (UdpRxData == NULL)) {
646 Token->CallBack (NULL, NULL, UdpToken->Status, Token->Context);
647 UdpIoFreeRxToken (Token);
648
649 goto ON_EXIT;
650 }
651
652 //
653 // Build a NET_BUF from the UDP receive data, then deliver it up.
654 //
655 Netbuf = NetbufFromExt (
656 (NET_FRAGMENT *) UdpRxData->FragmentTable,
657 UdpRxData->FragmentCount,
658 0,
659 (UINT32) Token->HeadLen,
660 UdpIoRecycleDgram,
661 Token
662 );
663
664 if (Netbuf == NULL) {
665 gBS->SignalEvent (UdpRxData->RecycleSignal);
666 Token->CallBack (NULL, NULL, EFI_OUT_OF_RESOURCES, Token->Context);
667
668 UdpIoFreeRxToken (Token);
669 goto ON_EXIT;
670 }
671
672 UdpSession = &UdpRxData->UdpSession;
673 Points.LocalAddr = EFI_NTOHL (UdpSession->DestinationAddress);
674 Points.LocalPort = UdpSession->DestinationPort;
675 Points.RemoteAddr = EFI_NTOHL (UdpSession->SourceAddress);
676 Points.RemotePort = UdpSession->SourcePort;
677
678 Token->CallBack (Netbuf, &Points, EFI_SUCCESS, Token->Context);
679
680 ON_EXIT:
681 return;
682 }
683
684
685 /**
686 Issue a receive request to the UDP IO port.
687
688 @param UdpIo The UDP IO port to recieve the packet from.
689 @param CallBack The call back function to execute when receive
690 finished.
691 @param Context The opque context to the call back
692 @param HeadLen The lenght of the application's header
693
694 @retval EFI_ALREADY_STARTED There is already a pending receive request. Only
695 one receive request is supported.
696 @retval EFI_OUT_OF_RESOURCES Failed to allocate some resource.
697 @retval EFI_SUCCESS The receive request is issued successfully.
698
699 **/
700 EFI_STATUS
701 UdpIoRecvDatagram (
702 IN UDP_IO_PORT *UdpIo,
703 IN UDP_IO_CALLBACK CallBack,
704 IN VOID *Context,
705 IN UINT32 HeadLen
706 )
707 {
708 UDP_RX_TOKEN *Token;
709 EFI_STATUS Status;
710
711 if (UdpIo->RecvRequest != NULL) {
712 return EFI_ALREADY_STARTED;
713 }
714
715 Token = UdpIoCreateRxToken (UdpIo, CallBack, Context, HeadLen);
716
717 if (Token == NULL) {
718 return EFI_OUT_OF_RESOURCES;
719 }
720
721 Status = UdpIo->Udp->Receive (UdpIo->Udp, &Token->UdpToken);
722
723 if (EFI_ERROR (Status)) {
724 UdpIoFreeRxToken (Token);
725 return Status;
726 }
727
728 UdpIo->RecvRequest = Token;
729 return EFI_SUCCESS;
730 }