blob: e1d72f3f1c68929721a7ce4a56b918951ffc9f11 [file] [log] [blame]
Vishal Bhoj82c80712015-12-15 21:13:33 +05301/** @file
2 Help functions to access UDP service, it is used by both the DHCP and MTFTP.
3
4Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution. The full text of the license may be found at<BR>
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT 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**/
34VOID
35UdpIoFreeTxToken (
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**/
57VOID
58UdpIoFreeRxToken (
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**/
82VOID
83EFIAPI
84UdpIoOnDgramSentDpc (
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**/
113VOID
114EFIAPI
115UdpIoOnDgramSent (
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**/
132VOID
133EFIAPI
134UdpIoRecycleDgram (
135 IN VOID *Context
136 )
137{
138 UDP_RX_TOKEN *RxToken;
139
140 RxToken = (UDP_RX_TOKEN *) Context;
141
142 if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
143 gBS->SignalEvent (RxToken->Token.Udp4.Packet.RxData->RecycleSignal);
144 } else if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION) {
145 gBS->SignalEvent (RxToken->Token.Udp6.Packet.RxData->RecycleSignal);
146 } else {
147 ASSERT (FALSE);
148 }
149
150 UdpIoFreeRxToken (RxToken);
151}
152
153/**
154 The event handle for UDP receive request.
155
156 It will build a NET_BUF from the recieved UDP data, then deliver it
157 to the receiver.
158
159 @param[in] Context The UDP RX token.
160
161**/
162VOID
163EFIAPI
164UdpIoOnDgramRcvdDpc (
165 IN VOID *Context
166 )
167{
168 EFI_STATUS Status;
169 VOID *Token;
170 VOID *RxData;
171 VOID *Session;
172 UDP_RX_TOKEN *RxToken;
173 UDP_END_POINT EndPoint;
174 NET_BUF *Netbuf;
175
176 RxToken = (UDP_RX_TOKEN *) Context;
177
178 ZeroMem (&EndPoint, sizeof(UDP_END_POINT));
179
180 ASSERT ((RxToken->Signature == UDP_IO_RX_SIGNATURE) &&
181 (RxToken == RxToken->UdpIo->RecvRequest));
182
183 ASSERT ((RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
184 (RxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
185
186 //
187 // Clear the receive request first in case that the caller
188 // wants to restart the receive in the callback.
189 //
190 RxToken->UdpIo->RecvRequest = NULL;
191
192 if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
193 Token = &RxToken->Token.Udp4;
194 RxData = ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Packet.RxData;
195 Status = ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Status;
196 } else {
197 Token = &RxToken->Token.Udp6;
198 RxData = ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Packet.RxData;
199 Status = ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Status;
200 }
201
202 if (EFI_ERROR (Status) || RxData == NULL) {
203 if (Status != EFI_ABORTED) {
204 //
205 // Invoke the CallBack only if the reception is not actively aborted.
206 //
207 RxToken->CallBack (NULL, NULL, Status, RxToken->Context);
208 }
209
210 UdpIoFreeRxToken (RxToken);
211 return;
212 }
213
214 //
215 // Build a NET_BUF from the UDP receive data, then deliver it up.
216 //
217 if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
218
219 Netbuf = NetbufFromExt (
220 (NET_FRAGMENT *)((EFI_UDP4_RECEIVE_DATA *) RxData)->FragmentTable,
221 ((EFI_UDP4_RECEIVE_DATA *) RxData)->FragmentCount,
222 0,
223 (UINT32) RxToken->HeadLen,
224 UdpIoRecycleDgram,
225 RxToken
226 );
227
228 if (Netbuf == NULL) {
229 gBS->SignalEvent (((EFI_UDP4_RECEIVE_DATA *) RxData)->RecycleSignal);
230 RxToken->CallBack (NULL, NULL, EFI_OUT_OF_RESOURCES, RxToken->Context);
231
232 UdpIoFreeRxToken (RxToken);
233 return;
234 }
235
236 Session = &((EFI_UDP4_RECEIVE_DATA *) RxData)->UdpSession;
237 EndPoint.LocalPort = ((EFI_UDP4_SESSION_DATA *) Session)->DestinationPort;
238 EndPoint.RemotePort = ((EFI_UDP4_SESSION_DATA *) Session)->SourcePort;
239
240 CopyMem (
241 &EndPoint.LocalAddr,
242 &((EFI_UDP4_SESSION_DATA *) Session)->DestinationAddress,
243 sizeof (EFI_IPv4_ADDRESS)
244 );
245
246 CopyMem (
247 &EndPoint.RemoteAddr,
248 &((EFI_UDP4_SESSION_DATA *) Session)->SourceAddress,
249 sizeof (EFI_IPv4_ADDRESS)
250 );
251
252 EndPoint.LocalAddr.Addr[0] = NTOHL (EndPoint.LocalAddr.Addr[0]);
253 EndPoint.RemoteAddr.Addr[0] = NTOHL (EndPoint.RemoteAddr.Addr[0]);
254 } else {
255
256 Netbuf = NetbufFromExt (
257 (NET_FRAGMENT *)((EFI_UDP6_RECEIVE_DATA *) RxData)->FragmentTable,
258 ((EFI_UDP6_RECEIVE_DATA *) RxData)->FragmentCount,
259 0,
260 (UINT32) RxToken->HeadLen,
261 UdpIoRecycleDgram,
262 RxToken
263 );
264
265 if (Netbuf == NULL) {
266 gBS->SignalEvent (((EFI_UDP6_RECEIVE_DATA *) RxData)->RecycleSignal);
267 RxToken->CallBack (NULL, NULL, EFI_OUT_OF_RESOURCES, RxToken->Context);
268
269 UdpIoFreeRxToken (RxToken);
270 return;
271 }
272
273 Session = &((EFI_UDP6_RECEIVE_DATA *) RxData)->UdpSession;
274 EndPoint.LocalPort = ((EFI_UDP6_SESSION_DATA *) Session)->DestinationPort;
275 EndPoint.RemotePort = ((EFI_UDP6_SESSION_DATA *) Session)->SourcePort;
276
277 CopyMem (
278 &EndPoint.LocalAddr,
279 &((EFI_UDP6_SESSION_DATA *) Session)->DestinationAddress,
280 sizeof (EFI_IPv6_ADDRESS)
281 );
282
283 CopyMem (
284 &EndPoint.RemoteAddr,
285 &((EFI_UDP6_SESSION_DATA *) Session)->SourceAddress,
286 sizeof (EFI_IPv6_ADDRESS)
287 );
288
289 Ip6Swap128 (&EndPoint.LocalAddr.v6);
290 Ip6Swap128 (&EndPoint.RemoteAddr.v6);
291 }
292
293 RxToken->CallBack (Netbuf, &EndPoint, EFI_SUCCESS, RxToken->Context);
294}
295
296/**
297 Request UdpIoOnDgramRcvdDpc() as a DPC at TPL_CALLBACK.
298
299 @param[in] Event The UDP receive request event.
300 @param[in] Context The UDP RX token.
301
302**/
303VOID
304EFIAPI
305UdpIoOnDgramRcvd (
306 IN EFI_EVENT Event,
307 IN VOID *Context
308 )
309{
310 //
311 // Request UdpIoOnDgramRcvdDpc as a DPC at TPL_CALLBACK
312 //
313 QueueDpc (TPL_CALLBACK, UdpIoOnDgramRcvdDpc, Context);
314}
315
316/**
317 Create a UDP_RX_TOKEN to wrap the request.
318
319 @param[in] UdpIo The UdpIo to receive packets from.
320 @param[in] CallBack The function to call when receive finished.
321 @param[in] Context The opaque parameter to the CallBack.
322 @param[in] HeadLen The head length to reserver for the packet.
323
324 @return The Wrapped request or NULL if failed to allocate resources or some errors happened.
325
326**/
327UDP_RX_TOKEN *
328UdpIoCreateRxToken (
329 IN UDP_IO *UdpIo,
330 IN UDP_IO_CALLBACK CallBack,
331 IN VOID *Context,
332 IN UINT32 HeadLen
333 )
334{
335 UDP_RX_TOKEN *Token;
336 EFI_STATUS Status;
337
338 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
339 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
340
341 Token = AllocatePool (sizeof (UDP_RX_TOKEN));
342
343 if (Token == NULL) {
344 return NULL;
345 }
346
347 Token->Signature = UDP_IO_RX_SIGNATURE;
348 Token->UdpIo = UdpIo;
349 Token->CallBack = CallBack;
350 Token->Context = Context;
351 Token->HeadLen = HeadLen;
352
353 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
354
355 Token->Token.Udp4.Status = EFI_NOT_READY;
356 Token->Token.Udp4.Packet.RxData = NULL;
357
358 Status = gBS->CreateEvent (
359 EVT_NOTIFY_SIGNAL,
360 TPL_NOTIFY,
361 UdpIoOnDgramRcvd,
362 Token,
363 &Token->Token.Udp4.Event
364 );
365 } else {
366
367 Token->Token.Udp6.Status = EFI_NOT_READY;
368 Token->Token.Udp6.Packet.RxData = NULL;
369
370 Status = gBS->CreateEvent (
371 EVT_NOTIFY_SIGNAL,
372 TPL_NOTIFY,
373 UdpIoOnDgramRcvd,
374 Token,
375 &Token->Token.Udp6.Event
376 );
377 }
378
379
380 if (EFI_ERROR (Status)) {
381 FreePool (Token);
382 return NULL;
383 }
384
385 return Token;
386}
387
388/**
389 Wrap a transmit request into a new created UDP_TX_TOKEN.
390
391 @param[in] UdpIo The UdpIo to send packet to.
392 @param[in] Packet The user's packet.
393 @param[in] EndPoint The local and remote access point.
394 @param[in] Gateway The overrided next hop.
395 @param[in] CallBack The function to call when transmission completed.
396 @param[in] Context The opaque parameter to the call back.
397
398 @return The wrapped transmission request or NULL if failed to allocate resources
399 or for some errors.
400
401**/
402UDP_TX_TOKEN *
403UdpIoCreateTxToken (
404 IN UDP_IO *UdpIo,
405 IN NET_BUF *Packet,
406 IN UDP_END_POINT *EndPoint OPTIONAL,
407 IN EFI_IP_ADDRESS *Gateway OPTIONAL,
408 IN UDP_IO_CALLBACK CallBack,
409 IN VOID *Context
410 )
411{
412 UDP_TX_TOKEN *TxToken;
413 VOID *Token;
414 VOID *Data;
415 EFI_STATUS Status;
416 UINT32 Count;
417 UINTN Size;
418 IP4_ADDR Ip;
419
420 ASSERT (Packet != NULL);
421 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
422 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
423
424 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
425 Size = sizeof (UDP_TX_TOKEN) + sizeof (EFI_UDP4_FRAGMENT_DATA) * (Packet->BlockOpNum - 1);
426 } else {
427 Size = sizeof (UDP_TX_TOKEN) + sizeof (EFI_UDP6_FRAGMENT_DATA) * (Packet->BlockOpNum - 1);
428 }
429
430 TxToken = AllocatePool (Size);
431
432 if (TxToken == NULL) {
433 return NULL;
434 }
435
436 TxToken->Signature = UDP_IO_TX_SIGNATURE;
437 InitializeListHead (&TxToken->Link);
438
439 TxToken->UdpIo = UdpIo;
440 TxToken->CallBack = CallBack;
441 TxToken->Packet = Packet;
442 TxToken->Context = Context;
443
444 Token = &(TxToken->Token);
445 Count = Packet->BlockOpNum;
446
447 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
448
449 ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Status = EFI_NOT_READY;
450
451 Status = gBS->CreateEvent (
452 EVT_NOTIFY_SIGNAL,
453 TPL_NOTIFY,
454 UdpIoOnDgramSent,
455 TxToken,
456 &((EFI_UDP4_COMPLETION_TOKEN *) Token)->Event
457 );
458
459 if (EFI_ERROR (Status)) {
460 FreePool (TxToken);
461 return NULL;
462 }
463
464 Data = &(TxToken->Data.Udp4);
465 ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Packet.TxData = Data;
466
467 ((EFI_UDP4_TRANSMIT_DATA *) Data)->UdpSessionData = NULL;
468 ((EFI_UDP4_TRANSMIT_DATA *) Data)->GatewayAddress = NULL;
469 ((EFI_UDP4_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize;
470
471 NetbufBuildExt (
472 Packet,
473 (NET_FRAGMENT *)((EFI_UDP4_TRANSMIT_DATA *) Data)->FragmentTable,
474 &Count
475 );
476
477 ((EFI_UDP4_TRANSMIT_DATA *) Data)->FragmentCount = Count;
478
479 if (EndPoint != NULL) {
480 Ip = HTONL (EndPoint->LocalAddr.Addr[0]);
481 CopyMem (
482 &TxToken->Session.Udp4.SourceAddress,
483 &Ip,
484 sizeof (EFI_IPv4_ADDRESS)
485 );
486
487 Ip = HTONL (EndPoint->RemoteAddr.Addr[0]);
488 CopyMem (
489 &TxToken->Session.Udp4.DestinationAddress,
490 &Ip,
491 sizeof (EFI_IPv4_ADDRESS)
492 );
493
494 TxToken->Session.Udp4.SourcePort = EndPoint->LocalPort;
495 TxToken->Session.Udp4.DestinationPort = EndPoint->RemotePort;
496 ((EFI_UDP4_TRANSMIT_DATA *) Data)->UdpSessionData = &(TxToken->Session.Udp4);
497 }
498
499 if (Gateway != NULL && (Gateway->Addr[0] != 0)) {
500 Ip = HTONL (Gateway->Addr[0]);
501 CopyMem (&TxToken->Gateway, &Ip, sizeof (EFI_IPv4_ADDRESS));
502 ((EFI_UDP4_TRANSMIT_DATA *) Data)->GatewayAddress = &TxToken->Gateway;
503 }
504
505 } else {
506
507 ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Status = EFI_NOT_READY;
508
509 Status = gBS->CreateEvent (
510 EVT_NOTIFY_SIGNAL,
511 TPL_NOTIFY,
512 UdpIoOnDgramSent,
513 TxToken,
514 &((EFI_UDP6_COMPLETION_TOKEN *) Token)->Event
515 );
516
517 if (EFI_ERROR (Status)) {
518 FreePool (TxToken);
519 return NULL;
520 }
521
522 Data = &(TxToken->Data.Udp6);
523 ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Packet.TxData = Data;
524 ((EFI_UDP6_TRANSMIT_DATA *) Data)->UdpSessionData = NULL;
525 ((EFI_UDP6_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize;
526
527 NetbufBuildExt (
528 Packet,
529 (NET_FRAGMENT *)((EFI_UDP6_TRANSMIT_DATA *) Data)->FragmentTable,
530 &Count
531 );
532
533 ((EFI_UDP6_TRANSMIT_DATA *) Data)->FragmentCount = Count;
534
535 if (EndPoint != NULL) {
536 CopyMem (
537 &TxToken->Session.Udp6.SourceAddress,
538 &EndPoint->LocalAddr.v6,
539 sizeof(EFI_IPv6_ADDRESS)
540 );
541
542 CopyMem (
543 &TxToken->Session.Udp6.DestinationAddress,
544 &EndPoint->RemoteAddr.v6,
545 sizeof(EFI_IPv6_ADDRESS)
546 );
547
548 TxToken->Session.Udp6.SourcePort = EndPoint->LocalPort;
549 TxToken->Session.Udp6.DestinationPort = EndPoint->RemotePort;
550 ((EFI_UDP6_TRANSMIT_DATA *) Data)->UdpSessionData = &(TxToken->Session.Udp6);
551 }
552 }
553
554 return TxToken;
555}
556
557/**
558 Creates a UDP_IO to access the UDP service. It creates and configures
559 a UDP child.
560
561 It 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
563 a UDP instance) 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**/
576UDP_IO *
577EFIAPI
578UdpIoCreateIo (
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
699CLOSE_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
706FREE_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
723FREE_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**/
739VOID
740EFIAPI
741UdpIoCancelDgrams (
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**/
779EFI_STATUS
780EFIAPI
781UdpIoFreeIo (
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 destroy 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 destroy 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**/
866VOID
867EFIAPI
868UdpIoCleanIo (
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**/
919EFI_STATUS
920EFIAPI
921UdpIoSendDatagram (
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**/
973BOOLEAN
974EFIAPI
975UdpIoCancelSingleDgram (
976 IN UDP_TX_TOKEN *Token,
977 IN VOID *Context
978 )
979{
980 NET_BUF *Packet;
981
982 Packet = (NET_BUF *) Context;
983
984 if (Token->Packet == Packet) {
985 return TRUE;
986 }
987
988 return FALSE;
989}
990
991/**
992 Cancel a single sent datagram.
993
994 @param[in] UdpIo The UDP_IO to cancel the packet from
995 @param[in] Packet The packet to cancel
996
997**/
998VOID
999EFIAPI
1000UdpIoCancelSentDatagram (
1001 IN UDP_IO *UdpIo,
1002 IN NET_BUF *Packet
1003 )
1004{
1005 UdpIoCancelDgrams (UdpIo, EFI_ABORTED, UdpIoCancelSingleDgram, Packet);
1006}
1007
1008/**
1009 Issue a receive request to the UDP_IO.
1010
1011 This function is called when upper-layer needs packet from UDP for processing.
1012 Only one receive request is acceptable at a time so a common usage model is
1013 to invoke this function inside its Callback function when the former packet
1014 is processed.
1015
1016 @param[in] UdpIo The UDP_IO to receive the packet from.
1017 @param[in] CallBack The call back function to execute when the packet
1018 is received.
1019 @param[in] Context The opaque context passed to Callback.
1020 @param[in] HeadLen The length of the upper-layer's protocol header.
1021
1022 @retval EFI_ALREADY_STARTED There is already a pending receive request. Only
1023 one receive request is supported at a time.
1024 @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.
1025 @retval EFI_SUCCESS The receive request is issued successfully.
1026 @retval EFI_UNSUPPORTED The UDP version in UDP_IO is not supported.
1027
1028**/
1029EFI_STATUS
1030EFIAPI
1031UdpIoRecvDatagram (
1032 IN UDP_IO *UdpIo,
1033 IN UDP_IO_CALLBACK CallBack,
1034 IN VOID *Context,
1035 IN UINT32 HeadLen
1036 )
1037{
1038 UDP_RX_TOKEN *RxToken;
1039 EFI_STATUS Status;
1040
1041 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
1042 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
1043
1044 if (UdpIo->RecvRequest != NULL) {
1045 return EFI_ALREADY_STARTED;
1046 }
1047
1048 RxToken = UdpIoCreateRxToken (UdpIo, CallBack, Context, HeadLen);
1049
1050 if (RxToken == NULL) {
1051 return EFI_OUT_OF_RESOURCES;
1052 }
1053
1054 UdpIo->RecvRequest = RxToken;
1055 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
1056 Status = UdpIo->Protocol.Udp4->Receive (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);
1057 } else {
1058 Status = UdpIo->Protocol.Udp6->Receive (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6);
1059 }
1060
1061 if (EFI_ERROR (Status)) {
1062 UdpIo->RecvRequest = NULL;
1063 UdpIoFreeRxToken (RxToken);
1064 }
1065
1066 return Status;
1067}