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