]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.c
1. Update the UdpIo to a combined UdpIo to support both v4 and v6 stack.
[mirror_edk2.git] / MdeModulePkg / Library / DxeUdpIoLib / DxeUdpIoLib.c
1 /** @file
2 Help functions to access UDP service, it is used by both the DHCP and MTFTP.
3
4 Copyright (c) 2005 - 2009, 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
9
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.
12 **/
13
14 #include <Uefi.h>
15
16 #include <Protocol/Udp4.h>
17 #include <Protocol/Udp6.h>
18
19 #include <Library/UdpIoLib.h>
20 #include <Library/BaseLib.h>
21 #include <Library/DebugLib.h>
22 #include <Library/UefiBootServicesTableLib.h>
23 #include <Library/MemoryAllocationLib.h>
24 #include <Library/BaseMemoryLib.h>
25 #include <Library/DpcLib.h>
26
27
28 /**
29 Free a UDP_TX_TOKEN. The TX event is closed.
30
31 @param[in] TxToken The UDP_TX_TOKEN to release.
32
33 **/
34 VOID
35 UdpIoFreeTxToken (
36 IN UDP_TX_TOKEN *TxToken
37 )
38 {
39
40 if (TxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
41 gBS->CloseEvent (TxToken->Token.Udp4.Event);
42 } else if (TxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION) {
43 gBS->CloseEvent (TxToken->Token.Udp6.Event);
44 } else {
45 ASSERT (FALSE);
46 }
47
48 FreePool (TxToken);
49 }
50
51 /**
52 Free a UDP_RX_TOKEN. The RX event is closed.
53
54 @param[in] RxToken The UDP_RX_TOKEN to release.
55
56 **/
57 VOID
58 UdpIoFreeRxToken (
59 IN UDP_RX_TOKEN *RxToken
60 )
61 {
62 if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
63 gBS->CloseEvent (RxToken->Token.Udp4.Event);
64 } else if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION) {
65 gBS->CloseEvent (RxToken->Token.Udp6.Event);
66 } else {
67 ASSERT (FALSE);
68 }
69
70 FreePool (RxToken);
71 }
72
73 /**
74 The callback function when the packet is sent by UDP.
75
76 It will remove the packet from the local list then call
77 the packet owner's callback function set by UdpIoSendDatagram.
78
79 @param[in] Context The UDP TX Token.
80
81 **/
82 VOID
83 EFIAPI
84 UdpIoOnDgramSentDpc (
85 IN VOID *Context
86 )
87 {
88 UDP_TX_TOKEN *TxToken;
89
90 TxToken = (UDP_TX_TOKEN *) Context;
91 ASSERT (TxToken->Signature == UDP_IO_TX_SIGNATURE);
92 ASSERT ((TxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
93 (TxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
94
95 RemoveEntryList (&TxToken->Link);
96
97 if (TxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
98 TxToken->CallBack (TxToken->Packet, NULL, TxToken->Token.Udp4.Status, TxToken->Context);
99 } else {
100 TxToken->CallBack (TxToken->Packet, NULL, TxToken->Token.Udp6.Status, TxToken->Context);
101 }
102
103 UdpIoFreeTxToken (TxToken);
104 }
105
106 /**
107 Request UdpIoOnDgramSentDpc as a DPC at TPL_CALLBACK.
108
109 @param[in] Event The event signaled.
110 @param[in] Context The UDP TX Token.
111
112 **/
113 VOID
114 EFIAPI
115 UdpIoOnDgramSent (
116 IN EFI_EVENT Event,
117 IN VOID *Context
118 )
119 {
120 //
121 // Request UdpIoOnDgramSentDpc as a DPC at TPL_CALLBACK
122 //
123 QueueDpc (TPL_CALLBACK, UdpIoOnDgramSentDpc, Context);
124 }
125
126 /**
127 Recycle the received UDP data.
128
129 @param[in] Context The UDP_RX_TOKEN.
130
131 **/
132 VOID
133 UdpIoRecycleDgram (
134 IN VOID *Context
135 )
136 {
137 UDP_RX_TOKEN *RxToken;
138
139 RxToken = (UDP_RX_TOKEN *) Context;
140
141 if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
142 gBS->SignalEvent (RxToken->Token.Udp4.Packet.RxData->RecycleSignal);
143 } else if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION) {
144 gBS->SignalEvent (RxToken->Token.Udp6.Packet.RxData->RecycleSignal);
145 } else {
146 ASSERT (FALSE);
147 }
148
149 UdpIoFreeRxToken (RxToken);
150 }
151
152 /**
153 The event handle for UDP receive request.
154
155 It will build a NET_BUF from the recieved UDP data, then deliver it
156 to the receiver.
157
158 @param[in] Context The UDP RX token.
159
160 **/
161 VOID
162 EFIAPI
163 UdpIoOnDgramRcvdDpc (
164 IN VOID *Context
165 )
166 {
167 EFI_STATUS Status;
168 VOID *Token;
169 VOID *RxData;
170 VOID *Session;
171 UDP_RX_TOKEN *RxToken;
172 UDP_END_POINT EndPoint;
173 NET_BUF *Netbuf;
174
175 RxToken = (UDP_RX_TOKEN *) Context;
176
177 ZeroMem (&EndPoint, sizeof(UDP_END_POINT));
178
179 ASSERT ((RxToken->Signature == UDP_IO_RX_SIGNATURE) &&
180 (RxToken == RxToken->UdpIo->RecvRequest));
181
182 ASSERT ((RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
183 (RxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
184
185 //
186 // Clear the receive request first in case that the caller
187 // wants to restart the receive in the callback.
188 //
189 RxToken->UdpIo->RecvRequest = NULL;
190
191 if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
192 Token = &RxToken->Token.Udp4;
193 RxData = ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Packet.RxData;
194 Status = ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Status;
195 } else {
196 Token = &RxToken->Token.Udp6;
197 RxData = ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Packet.RxData;
198 Status = ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Status;
199 }
200
201 if (EFI_ERROR (Status) || RxData == NULL) {
202 if (Status != EFI_ABORTED) {
203 //
204 // Invoke the CallBack only if the reception is not actively aborted.
205 //
206 RxToken->CallBack (NULL, NULL, Status, RxToken->Context);
207 }
208
209 UdpIoFreeRxToken (RxToken);
210 return;
211 }
212
213 //
214 // Build a NET_BUF from the UDP receive data, then deliver it up.
215 //
216 if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
217
218 Netbuf = NetbufFromExt (
219 (NET_FRAGMENT *)((EFI_UDP4_RECEIVE_DATA *) RxData)->FragmentTable,
220 ((EFI_UDP4_RECEIVE_DATA *) RxData)->FragmentCount,
221 0,
222 (UINT32) RxToken->HeadLen,
223 UdpIoRecycleDgram,
224 RxToken
225 );
226
227 if (Netbuf == NULL) {
228 gBS->SignalEvent (((EFI_UDP4_RECEIVE_DATA *) RxData)->RecycleSignal);
229 RxToken->CallBack (NULL, NULL, EFI_OUT_OF_RESOURCES, RxToken->Context);
230
231 UdpIoFreeRxToken (RxToken);
232 return;
233 }
234
235 Session = &((EFI_UDP4_RECEIVE_DATA *) RxData)->UdpSession;
236 EndPoint.LocalPort = ((EFI_UDP4_SESSION_DATA *) Session)->DestinationPort;
237 EndPoint.RemotePort = ((EFI_UDP4_SESSION_DATA *) Session)->SourcePort;
238
239 CopyMem (
240 &EndPoint.LocalAddr,
241 &((EFI_UDP4_SESSION_DATA *) Session)->DestinationAddress,
242 sizeof (EFI_IPv4_ADDRESS)
243 );
244
245 CopyMem (
246 &EndPoint.RemoteAddr,
247 &((EFI_UDP4_SESSION_DATA *) Session)->SourceAddress,
248 sizeof (EFI_IPv4_ADDRESS)
249 );
250
251 EndPoint.LocalAddr.Addr[0] = NTOHL (EndPoint.LocalAddr.Addr[0]);
252 EndPoint.RemoteAddr.Addr[0] = NTOHL (EndPoint.RemoteAddr.Addr[0]);
253 } else {
254
255 Netbuf = NetbufFromExt (
256 (NET_FRAGMENT *)((EFI_UDP6_RECEIVE_DATA *) RxData)->FragmentTable,
257 ((EFI_UDP6_RECEIVE_DATA *) RxData)->FragmentCount,
258 0,
259 (UINT32) RxToken->HeadLen,
260 UdpIoRecycleDgram,
261 RxToken
262 );
263
264 if (Netbuf == NULL) {
265 gBS->SignalEvent (((EFI_UDP6_RECEIVE_DATA *) RxData)->RecycleSignal);
266 RxToken->CallBack (NULL, NULL, EFI_OUT_OF_RESOURCES, RxToken->Context);
267
268 UdpIoFreeRxToken (RxToken);
269 return;
270 }
271
272 Session = &((EFI_UDP6_RECEIVE_DATA *) RxData)->UdpSession;
273 EndPoint.LocalPort = ((EFI_UDP6_SESSION_DATA *) Session)->DestinationPort;
274 EndPoint.RemotePort = ((EFI_UDP6_SESSION_DATA *) Session)->SourcePort;
275
276 CopyMem (
277 &EndPoint.LocalAddr,
278 &((EFI_UDP6_SESSION_DATA *) Session)->DestinationAddress,
279 sizeof (EFI_IPv6_ADDRESS)
280 );
281
282 CopyMem (
283 &EndPoint.RemoteAddr,
284 &((EFI_UDP6_SESSION_DATA *) Session)->SourceAddress,
285 sizeof (EFI_IPv6_ADDRESS)
286 );
287
288 Ip6Swap128 (&EndPoint.LocalAddr.v6);
289 Ip6Swap128 (&EndPoint.RemoteAddr.v6);
290 }
291
292 RxToken->CallBack (Netbuf, &EndPoint, EFI_SUCCESS, RxToken->Context);
293 }
294
295 /**
296 Request UdpIoOnDgramRcvdDpc() as a DPC at TPL_CALLBACK.
297
298 @param[in] Event The UDP receive request event.
299 @param[in] Context The UDP RX token.
300
301 **/
302 VOID
303 EFIAPI
304 UdpIoOnDgramRcvd (
305 IN EFI_EVENT Event,
306 IN VOID *Context
307 )
308 {
309 //
310 // Request UdpIoOnDgramRcvdDpc as a DPC at TPL_CALLBACK
311 //
312 QueueDpc (TPL_CALLBACK, UdpIoOnDgramRcvdDpc, Context);
313 }
314
315 /**
316 Create a UDP_RX_TOKEN to wrap the request.
317
318 @param[in] UdpIo The UdpIo to receive packets from.
319 @param[in] CallBack The function to call when receive finished.
320 @param[in] Context The opaque parameter to the CallBack.
321 @param[in] HeadLen The head length to reserver for the packet.
322
323 @return The Wrapped request or NULL if failed to allocate resources or some errors happened.
324
325 **/
326 UDP_RX_TOKEN *
327 UdpIoCreateRxToken (
328 IN UDP_IO *UdpIo,
329 IN UDP_IO_CALLBACK CallBack,
330 IN VOID *Context,
331 IN UINT32 HeadLen
332 )
333 {
334 UDP_RX_TOKEN *Token;
335 EFI_STATUS Status;
336
337 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
338 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
339
340 Token = AllocatePool (sizeof (UDP_RX_TOKEN));
341
342 if (Token == NULL) {
343 return NULL;
344 }
345
346 Token->Signature = UDP_IO_RX_SIGNATURE;
347 Token->UdpIo = UdpIo;
348 Token->CallBack = CallBack;
349 Token->Context = Context;
350 Token->HeadLen = HeadLen;
351
352 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
353
354 Token->Token.Udp4.Status = EFI_NOT_READY;
355 Token->Token.Udp4.Packet.RxData = NULL;
356
357 Status = gBS->CreateEvent (
358 EVT_NOTIFY_SIGNAL,
359 TPL_NOTIFY,
360 UdpIoOnDgramRcvd,
361 Token,
362 &Token->Token.Udp4.Event
363 );
364 } else {
365
366 Token->Token.Udp6.Status = EFI_NOT_READY;
367 Token->Token.Udp6.Packet.RxData = NULL;
368
369 Status = gBS->CreateEvent (
370 EVT_NOTIFY_SIGNAL,
371 TPL_NOTIFY,
372 UdpIoOnDgramRcvd,
373 Token,
374 &Token->Token.Udp6.Event
375 );
376 }
377
378
379 if (EFI_ERROR (Status)) {
380 FreePool (Token);
381 return NULL;
382 }
383
384 return Token;
385 }
386
387 /**
388 Wrap a transmit request into a new created UDP_TX_TOKEN.
389
390 @param[in] UdpIo The UdpIo to send packet to.
391 @param[in] Packet The user's packet.
392 @param[in] EndPoint The local and remote access point.
393 @param[in] Gateway The overrided next hop.
394 @param[in] CallBack The function to call when transmission completed.
395 @param[in] Context The opaque parameter to the call back.
396
397 @return The wrapped transmission request or NULL if failed to allocate resources
398 or for some errors.
399
400 **/
401 UDP_TX_TOKEN *
402 UdpIoCreateTxToken (
403 IN UDP_IO *UdpIo,
404 IN NET_BUF *Packet,
405 IN UDP_END_POINT *EndPoint OPTIONAL,
406 IN EFI_IP_ADDRESS *Gateway OPTIONAL,
407 IN UDP_IO_CALLBACK CallBack,
408 IN VOID *Context
409 )
410 {
411 UDP_TX_TOKEN *TxToken;
412 VOID *Token;
413 VOID *Data;
414 EFI_STATUS Status;
415 UINT32 Count;
416 UINTN Size;
417 IP4_ADDR Ip;
418
419 ASSERT (Packet != NULL);
420 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
421 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
422
423 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
424 Size = sizeof (UDP_TX_TOKEN) + sizeof (EFI_UDP4_FRAGMENT_DATA) * (Packet->BlockOpNum - 1);
425 } else {
426 Size = sizeof (UDP_TX_TOKEN) + sizeof (EFI_UDP6_FRAGMENT_DATA) * (Packet->BlockOpNum - 1);
427 }
428
429 TxToken = AllocatePool (Size);
430
431 if (TxToken == NULL) {
432 return NULL;
433 }
434
435 TxToken->Signature = UDP_IO_TX_SIGNATURE;
436 InitializeListHead (&TxToken->Link);
437
438 TxToken->UdpIo = UdpIo;
439 TxToken->CallBack = CallBack;
440 TxToken->Packet = Packet;
441 TxToken->Context = Context;
442
443 Token = &(TxToken->Token);
444 Count = Packet->BlockOpNum;
445
446 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
447
448 ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Status = EFI_NOT_READY;
449
450 Status = gBS->CreateEvent (
451 EVT_NOTIFY_SIGNAL,
452 TPL_NOTIFY,
453 UdpIoOnDgramSent,
454 TxToken,
455 &((EFI_UDP4_COMPLETION_TOKEN *) Token)->Event
456 );
457
458 if (EFI_ERROR (Status)) {
459 FreePool (TxToken);
460 return NULL;
461 }
462
463 Data = &(TxToken->Data.Udp4);
464 ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Packet.TxData = Data;
465
466 ((EFI_UDP4_TRANSMIT_DATA *) Data)->UdpSessionData = NULL;
467 ((EFI_UDP4_TRANSMIT_DATA *) Data)->GatewayAddress = NULL;
468 ((EFI_UDP4_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize;
469
470 NetbufBuildExt (
471 Packet,
472 (NET_FRAGMENT *)((EFI_UDP4_TRANSMIT_DATA *) Data)->FragmentTable,
473 &Count
474 );
475
476 ((EFI_UDP4_TRANSMIT_DATA *) Data)->FragmentCount = Count;
477
478 if (EndPoint != NULL) {
479 Ip = HTONL (EndPoint->LocalAddr.Addr[0]);
480 CopyMem (
481 &TxToken->Session.Udp4.SourceAddress,
482 &Ip,
483 sizeof (EFI_IPv4_ADDRESS)
484 );
485
486 Ip = HTONL (EndPoint->RemoteAddr.Addr[0]);
487 CopyMem (
488 &TxToken->Session.Udp4.DestinationAddress,
489 &Ip,
490 sizeof (EFI_IPv4_ADDRESS)
491 );
492
493 TxToken->Session.Udp4.SourcePort = EndPoint->LocalPort;
494 TxToken->Session.Udp4.DestinationPort = EndPoint->RemotePort;
495 ((EFI_UDP4_TRANSMIT_DATA *) Data)->UdpSessionData = &(TxToken->Session.Udp4);
496 }
497
498 if (Gateway != NULL && (Gateway->Addr[0] != 0)) {
499 Ip = HTONL (Gateway->Addr[0]);
500 CopyMem (&TxToken->Gateway, &Ip, sizeof (EFI_IPv4_ADDRESS));
501 ((EFI_UDP4_TRANSMIT_DATA *) Data)->GatewayAddress = &TxToken->Gateway;
502 }
503
504 } else {
505
506 ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Status = EFI_NOT_READY;
507
508 Status = gBS->CreateEvent (
509 EVT_NOTIFY_SIGNAL,
510 TPL_NOTIFY,
511 UdpIoOnDgramSent,
512 TxToken,
513 &((EFI_UDP6_COMPLETION_TOKEN *) Token)->Event
514 );
515
516 if (EFI_ERROR (Status)) {
517 FreePool (TxToken);
518 return NULL;
519 }
520
521 Data = &(TxToken->Data.Udp6);
522 ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Packet.TxData = Data;
523 ((EFI_UDP6_TRANSMIT_DATA *) Data)->UdpSessionData = NULL;
524 ((EFI_UDP6_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize;
525
526 NetbufBuildExt (
527 Packet,
528 (NET_FRAGMENT *)((EFI_UDP6_TRANSMIT_DATA *) Data)->FragmentTable,
529 &Count
530 );
531
532 ((EFI_UDP6_TRANSMIT_DATA *) Data)->FragmentCount = Count;
533
534 if (EndPoint != NULL) {
535 CopyMem (
536 &TxToken->Session.Udp6.SourceAddress,
537 &EndPoint->LocalAddr.v6,
538 sizeof(EFI_IPv6_ADDRESS)
539 );
540
541 CopyMem (
542 &TxToken->Session.Udp6.DestinationAddress,
543 &EndPoint->RemoteAddr.v6,
544 sizeof(EFI_IPv6_ADDRESS)
545 );
546
547 TxToken->Session.Udp6.SourcePort = EndPoint->LocalPort;
548 TxToken->Session.Udp6.DestinationPort = EndPoint->RemotePort;
549 ((EFI_UDP6_TRANSMIT_DATA *) Data)->UdpSessionData = &(TxToken->Session.Udp6);
550 }
551 }
552
553 return TxToken;
554 }
555
556 /**
557 Creates a UDP_IO to access the UDP service. It creates and configures
558 a UDP child.
559
560 This function:
561 # locates the UDP service binding prototype on the Controller parameter
562 # uses the UDP service binding prototype to create a UDP child (also known as a UDP instance)
563 # configures the UDP child by calling Configure function prototype.
564 Any failures in creating or configuring the UDP child return NULL for failure.
565
566 @param[in] Controller The controller that has the UDP service binding.
567 protocol installed.
568 @param[in] ImageHandle The image handle for the driver.
569 @param[in] Configure The function to configure the created UDP child.
570 @param[in] UdpVersion The UDP protocol version, UDP4 or UDP6.
571 @param[in] Context The opaque parameter for the Configure funtion.
572
573 @return Newly-created UDP_IO or NULL if failed.
574
575 **/
576 UDP_IO *
577 EFIAPI
578 UdpIoCreateIo (
579 IN EFI_HANDLE Controller,
580 IN EFI_HANDLE ImageHandle,
581 IN UDP_IO_CONFIG Configure,
582 IN UINT8 UdpVersion,
583 IN VOID *Context
584 )
585 {
586 UDP_IO *UdpIo;
587 EFI_STATUS Status;
588
589 ASSERT (Configure != NULL);
590 ASSERT ((UdpVersion == UDP_IO_UDP4_VERSION) || (UdpVersion == UDP_IO_UDP6_VERSION));
591
592 UdpIo = AllocatePool (sizeof (UDP_IO));
593
594 if (UdpIo == NULL) {
595 return NULL;
596 }
597
598 UdpIo->UdpVersion = UdpVersion;
599 UdpIo->Signature = UDP_IO_SIGNATURE;
600 InitializeListHead (&UdpIo->Link);
601 UdpIo->RefCnt = 1;
602
603 UdpIo->Controller = Controller;
604 UdpIo->Image = ImageHandle;
605
606 InitializeListHead (&UdpIo->SentDatagram);
607 UdpIo->RecvRequest = NULL;
608 UdpIo->UdpHandle = NULL;
609
610 if (UdpVersion == UDP_IO_UDP4_VERSION) {
611 //
612 // Create a UDP child then open and configure it
613 //
614 Status = NetLibCreateServiceChild (
615 Controller,
616 ImageHandle,
617 &gEfiUdp4ServiceBindingProtocolGuid,
618 &UdpIo->UdpHandle
619 );
620
621 if (EFI_ERROR (Status)) {
622 goto FREE_MEM;
623 }
624
625 Status = gBS->OpenProtocol (
626 UdpIo->UdpHandle,
627 &gEfiUdp4ProtocolGuid,
628 (VOID **) &UdpIo->Protocol.Udp4,
629 ImageHandle,
630 Controller,
631 EFI_OPEN_PROTOCOL_BY_DRIVER
632 );
633
634 if (EFI_ERROR (Status)) {
635 goto FREE_CHILD;
636 }
637
638 if (EFI_ERROR (Configure (UdpIo, Context))) {
639 goto CLOSE_PROTOCOL;
640 }
641
642 Status = UdpIo->Protocol.Udp4->GetModeData (
643 UdpIo->Protocol.Udp4,
644 NULL,
645 NULL,
646 NULL,
647 &UdpIo->SnpMode
648 );
649
650 if (EFI_ERROR (Status)) {
651 goto CLOSE_PROTOCOL;
652 }
653
654 } else {
655
656 Status = NetLibCreateServiceChild (
657 Controller,
658 ImageHandle,
659 &gEfiUdp6ServiceBindingProtocolGuid,
660 &UdpIo->UdpHandle
661 );
662
663 if (EFI_ERROR (Status)) {
664 goto FREE_MEM;
665 }
666
667 Status = gBS->OpenProtocol (
668 UdpIo->UdpHandle,
669 &gEfiUdp6ProtocolGuid,
670 (VOID **) &UdpIo->Protocol.Udp6,
671 ImageHandle,
672 Controller,
673 EFI_OPEN_PROTOCOL_BY_DRIVER
674 );
675
676 if (EFI_ERROR (Status)) {
677 goto FREE_CHILD;
678 }
679
680 if (EFI_ERROR (Configure (UdpIo, Context))) {
681 goto CLOSE_PROTOCOL;
682 }
683
684 Status = UdpIo->Protocol.Udp6->GetModeData (
685 UdpIo->Protocol.Udp6,
686 NULL,
687 NULL,
688 NULL,
689 &UdpIo->SnpMode
690 );
691
692 if (EFI_ERROR (Status)) {
693 goto CLOSE_PROTOCOL;
694 }
695 }
696
697 return UdpIo;
698
699 CLOSE_PROTOCOL:
700 if (UdpVersion == UDP_IO_UDP4_VERSION) {
701 gBS->CloseProtocol (UdpIo->UdpHandle, &gEfiUdp4ProtocolGuid, ImageHandle, Controller);
702 } else {
703 gBS->CloseProtocol (UdpIo->UdpHandle, &gEfiUdp6ProtocolGuid, ImageHandle, Controller);
704 }
705
706 FREE_CHILD:
707 if (UdpVersion == UDP_IO_UDP4_VERSION) {
708 NetLibDestroyServiceChild (
709 Controller,
710 ImageHandle,
711 &gEfiUdp4ServiceBindingProtocolGuid,
712 UdpIo->UdpHandle
713 );
714 } else {
715 NetLibDestroyServiceChild (
716 Controller,
717 ImageHandle,
718 &gEfiUdp6ServiceBindingProtocolGuid,
719 UdpIo->UdpHandle
720 );
721 }
722
723 FREE_MEM:
724 FreePool (UdpIo);
725 return NULL;
726 }
727
728 /**
729 Cancel all the sent datagram that pass the selection criteria of ToCancel.
730 If ToCancel is NULL, all the datagrams are cancelled.
731
732 @param[in] UdpIo The UDP_IO to cancel packet.
733 @param[in] IoStatus The IoStatus to return to the packet owners.
734 @param[in] ToCancel The select funtion to test whether to cancel this
735 packet or not.
736 @param[in] Context The opaque parameter to the ToCancel.
737
738 **/
739 VOID
740 EFIAPI
741 UdpIoCancelDgrams (
742 IN UDP_IO *UdpIo,
743 IN EFI_STATUS IoStatus,
744 IN UDP_IO_TO_CANCEL ToCancel, OPTIONAL
745 IN VOID *Context
746 )
747 {
748 LIST_ENTRY *Entry;
749 LIST_ENTRY *Next;
750 UDP_TX_TOKEN *TxToken;
751
752 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
753 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
754
755 NET_LIST_FOR_EACH_SAFE (Entry, Next, &UdpIo->SentDatagram) {
756 TxToken = NET_LIST_USER_STRUCT (Entry, UDP_TX_TOKEN, Link);
757
758 if ((ToCancel == NULL) || (ToCancel (TxToken, Context))) {
759
760 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
761 UdpIo->Protocol.Udp4->Cancel (UdpIo->Protocol.Udp4, &TxToken->Token.Udp4);
762 } else {
763 UdpIo->Protocol.Udp6->Cancel (UdpIo->Protocol.Udp6, &TxToken->Token.Udp6);
764 }
765 }
766 }
767 }
768
769 /**
770 Free the UDP_IO and all its related resources.
771
772 The function will cancel all sent datagram and receive request.
773
774 @param[in] UdpIo The UDP_IO to free.
775
776 @retval EFI_SUCCESS The UDP_IO is freed.
777
778 **/
779 EFI_STATUS
780 EFIAPI
781 UdpIoFreeIo (
782 IN UDP_IO *UdpIo
783 )
784 {
785 UDP_RX_TOKEN *RxToken;
786
787 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
788 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
789
790 //
791 // Cancel all the sent datagram and receive requests. The
792 // callbacks of transmit requests are executed to allow the
793 // caller to release the resource. The callback of receive
794 // request are NOT executed. This is because it is most
795 // likely that the current user of the UDP IO port is closing
796 // itself.
797 //
798 UdpIoCancelDgrams (UdpIo, EFI_ABORTED, NULL, NULL);
799
800 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
801
802 if ((RxToken = UdpIo->RecvRequest) != NULL) {
803 UdpIo->Protocol.Udp4->Cancel (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);
804 }
805
806 //
807 // Close then destory the Udp4 child
808 //
809 gBS->CloseProtocol (
810 UdpIo->UdpHandle,
811 &gEfiUdp4ProtocolGuid,
812 UdpIo->Image,
813 UdpIo->Controller
814 );
815
816 NetLibDestroyServiceChild (
817 UdpIo->Controller,
818 UdpIo->Image,
819 &gEfiUdp4ServiceBindingProtocolGuid,
820 UdpIo->UdpHandle
821 );
822
823 } else {
824
825 if ((RxToken = UdpIo->RecvRequest) != NULL) {
826 UdpIo->Protocol.Udp6->Cancel (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6);
827 }
828
829 //
830 // Close then destory the Udp6 child
831 //
832 gBS->CloseProtocol (
833 UdpIo->UdpHandle,
834 &gEfiUdp6ProtocolGuid,
835 UdpIo->Image,
836 UdpIo->Controller
837 );
838
839 NetLibDestroyServiceChild (
840 UdpIo->Controller,
841 UdpIo->Image,
842 &gEfiUdp6ServiceBindingProtocolGuid,
843 UdpIo->UdpHandle
844 );
845 }
846
847 if (!IsListEmpty(&UdpIo->Link)) {
848 RemoveEntryList (&UdpIo->Link);
849 }
850
851 FreePool (UdpIo);
852 return EFI_SUCCESS;
853 }
854
855
856 /**
857 Clean up the UDP_IO without freeing it. The function is called when
858 user wants to re-use the UDP_IO later.
859
860 It will release all the transmitted datagrams and receive request. It will
861 also configure NULL for the UDP instance.
862
863 @param[in] UdpIo The UDP_IO to clean up.
864
865 **/
866 VOID
867 EFIAPI
868 UdpIoCleanIo (
869 IN UDP_IO *UdpIo
870 )
871 {
872 UDP_RX_TOKEN *RxToken;
873
874 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
875 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
876
877 //
878 // Cancel all the sent datagram and receive requests.
879 //
880 UdpIoCancelDgrams (UdpIo, EFI_ABORTED, NULL, NULL);
881
882 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
883 if ((RxToken = UdpIo->RecvRequest) != NULL) {
884 UdpIo->Protocol.Udp4->Cancel (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);
885 }
886
887 UdpIo->Protocol.Udp4->Configure (UdpIo->Protocol.Udp4, NULL);
888
889 } else {
890 if ((RxToken = UdpIo->RecvRequest) != NULL) {
891 UdpIo->Protocol.Udp6->Cancel (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6);
892 }
893
894 UdpIo->Protocol.Udp6->Configure (UdpIo->Protocol.Udp6, NULL);
895 }
896 }
897
898 /**
899 Send a packet through the UDP_IO.
900
901 The packet will be wrapped in UDP_TX_TOKEN. Function Callback will be called
902 when the packet is sent. The optional parameter EndPoint overrides the default
903 address pair if specified.
904
905 @param[in] UdpIo The UDP_IO to send the packet through.
906 @param[in] Packet The packet to send.
907 @param[in] EndPoint The local and remote access point. Override the
908 default address pair set during configuration.
909 @param[in] Gateway The gateway to use.
910 @param[in] CallBack The function being called when packet is
911 transmitted or failed.
912 @param[in] Context The opaque parameter passed to CallBack.
913
914 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the packet.
915 @retval EFI_SUCCESS The packet is successfully delivered to UDP for
916 transmission.
917
918 **/
919 EFI_STATUS
920 EFIAPI
921 UdpIoSendDatagram (
922 IN UDP_IO *UdpIo,
923 IN NET_BUF *Packet,
924 IN UDP_END_POINT *EndPoint OPTIONAL,
925 IN EFI_IP_ADDRESS *Gateway OPTIONAL,
926 IN UDP_IO_CALLBACK CallBack,
927 IN VOID *Context
928 )
929 {
930 UDP_TX_TOKEN *TxToken;
931 EFI_STATUS Status;
932
933 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
934 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
935
936 TxToken = UdpIoCreateTxToken (UdpIo, Packet, EndPoint, Gateway, CallBack, Context);
937
938 if (TxToken == NULL) {
939 return EFI_OUT_OF_RESOURCES;
940 }
941
942 //
943 // Insert the tx token into SendDatagram list before transmitting it. Remove
944 // it from the list if the returned status is not EFI_SUCCESS.
945 //
946 InsertHeadList (&UdpIo->SentDatagram, &TxToken->Link);
947
948 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
949 Status = UdpIo->Protocol.Udp4->Transmit (UdpIo->Protocol.Udp4, &TxToken->Token.Udp4);
950 } else {
951 Status = UdpIo->Protocol.Udp6->Transmit (UdpIo->Protocol.Udp6, &TxToken->Token.Udp6);
952 }
953
954 if (EFI_ERROR (Status)) {
955 RemoveEntryList (&TxToken->Link);
956 UdpIoFreeTxToken (TxToken);
957 return Status;
958 }
959
960 return EFI_SUCCESS;
961 }
962
963
964 /**
965 The select function to cancel a single sent datagram.
966
967 @param[in] Token The UDP_TX_TOKEN to test against
968 @param[in] Context The NET_BUF of the sent datagram
969
970 @retval TRUE The packet is to be cancelled.
971 @retval FALSE The packet is not to be cancelled.
972 **/
973 BOOLEAN
974 UdpIoCancelSingleDgram (
975 IN UDP_TX_TOKEN *Token,
976 IN VOID *Context
977 )
978 {
979 NET_BUF *Packet;
980
981 Packet = (NET_BUF *) Context;
982
983 if (Token->Packet == Packet) {
984 return TRUE;
985 }
986
987 return FALSE;
988 }
989
990 /**
991 Cancel a single sent datagram.
992
993 @param[in] UdpIo The UDP_IO to cancel the packet from
994 @param[in] Packet The packet to cancel
995
996 **/
997 VOID
998 EFIAPI
999 UdpIoCancelSentDatagram (
1000 IN UDP_IO *UdpIo,
1001 IN NET_BUF *Packet
1002 )
1003 {
1004 UdpIoCancelDgrams (UdpIo, EFI_ABORTED, UdpIoCancelSingleDgram, Packet);
1005 }
1006
1007 /**
1008 Issue a receive request to the UDP_IO.
1009
1010 This function is called when upper-layer needs packet from UDP for processing.
1011 Only one receive request is acceptable at a time so a common usage model is
1012 to invoke this function inside its Callback function when the former packet
1013 is processed.
1014
1015 @param[in] UdpIo The UDP_IO to receive the packet from.
1016 @param[in] CallBack The call back function to execute when the packet
1017 is received.
1018 @param[in] Context The opaque context passed to Callback.
1019 @param[in] HeadLen The length of the upper-layer's protocol header.
1020
1021 @retval EFI_ALREADY_STARTED There is already a pending receive request. Only
1022 one receive request is supported at a time.
1023 @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.
1024 @retval EFI_SUCCESS The receive request is issued successfully.
1025 @retval EFI_UNSUPPORTED The UDP version in UDP_IO is not supported.
1026
1027 **/
1028 EFI_STATUS
1029 EFIAPI
1030 UdpIoRecvDatagram (
1031 IN UDP_IO *UdpIo,
1032 IN UDP_IO_CALLBACK CallBack,
1033 IN VOID *Context,
1034 IN UINT32 HeadLen
1035 )
1036 {
1037 UDP_RX_TOKEN *RxToken;
1038 EFI_STATUS Status;
1039
1040 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
1041 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
1042
1043 if (UdpIo->RecvRequest != NULL) {
1044 return EFI_ALREADY_STARTED;
1045 }
1046
1047 RxToken = UdpIoCreateRxToken (UdpIo, CallBack, Context, HeadLen);
1048
1049 if (RxToken == NULL) {
1050 return EFI_OUT_OF_RESOURCES;
1051 }
1052
1053 UdpIo->RecvRequest = RxToken;
1054 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
1055 Status = UdpIo->Protocol.Udp4->Receive (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);
1056 } else {
1057 Status = UdpIo->Protocol.Udp6->Receive (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6);
1058 }
1059
1060 if (EFI_ERROR (Status)) {
1061 UdpIo->RecvRequest = NULL;
1062 UdpIoFreeRxToken (RxToken);
1063 }
1064
1065 return Status;
1066 }