]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.c
refine the code and add more security check.
[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 It locates the UDP service binding prototype on the Controller parameter
561 uses the UDP service binding prototype to create a UDP child (also known as
562 a UDP instance) configures the UDP child by calling Configure function prototype.
563 Any failures in creating or configuring the UDP child return NULL for failure.
564
565 @param[in] Controller The controller that has the UDP service binding.
566 protocol installed.
567 @param[in] ImageHandle The image handle for the driver.
568 @param[in] Configure The function to configure the created UDP child.
569 @param[in] UdpVersion The UDP protocol version, UDP4 or UDP6.
570 @param[in] Context The opaque parameter for the Configure funtion.
571
572 @return Newly-created UDP_IO or NULL if failed.
573
574 **/
575 UDP_IO *
576 EFIAPI
577 UdpIoCreateIo (
578 IN EFI_HANDLE Controller,
579 IN EFI_HANDLE ImageHandle,
580 IN UDP_IO_CONFIG Configure,
581 IN UINT8 UdpVersion,
582 IN VOID *Context
583 )
584 {
585 UDP_IO *UdpIo;
586 EFI_STATUS Status;
587
588 ASSERT (Configure != NULL);
589 ASSERT ((UdpVersion == UDP_IO_UDP4_VERSION) || (UdpVersion == UDP_IO_UDP6_VERSION));
590
591 UdpIo = AllocatePool (sizeof (UDP_IO));
592
593 if (UdpIo == NULL) {
594 return NULL;
595 }
596
597 UdpIo->UdpVersion = UdpVersion;
598 UdpIo->Signature = UDP_IO_SIGNATURE;
599 InitializeListHead (&UdpIo->Link);
600 UdpIo->RefCnt = 1;
601
602 UdpIo->Controller = Controller;
603 UdpIo->Image = ImageHandle;
604
605 InitializeListHead (&UdpIo->SentDatagram);
606 UdpIo->RecvRequest = NULL;
607 UdpIo->UdpHandle = NULL;
608
609 if (UdpVersion == UDP_IO_UDP4_VERSION) {
610 //
611 // Create a UDP child then open and configure it
612 //
613 Status = NetLibCreateServiceChild (
614 Controller,
615 ImageHandle,
616 &gEfiUdp4ServiceBindingProtocolGuid,
617 &UdpIo->UdpHandle
618 );
619
620 if (EFI_ERROR (Status)) {
621 goto FREE_MEM;
622 }
623
624 Status = gBS->OpenProtocol (
625 UdpIo->UdpHandle,
626 &gEfiUdp4ProtocolGuid,
627 (VOID **) &UdpIo->Protocol.Udp4,
628 ImageHandle,
629 Controller,
630 EFI_OPEN_PROTOCOL_BY_DRIVER
631 );
632
633 if (EFI_ERROR (Status)) {
634 goto FREE_CHILD;
635 }
636
637 if (EFI_ERROR (Configure (UdpIo, Context))) {
638 goto CLOSE_PROTOCOL;
639 }
640
641 Status = UdpIo->Protocol.Udp4->GetModeData (
642 UdpIo->Protocol.Udp4,
643 NULL,
644 NULL,
645 NULL,
646 &UdpIo->SnpMode
647 );
648
649 if (EFI_ERROR (Status)) {
650 goto CLOSE_PROTOCOL;
651 }
652
653 } else {
654
655 Status = NetLibCreateServiceChild (
656 Controller,
657 ImageHandle,
658 &gEfiUdp6ServiceBindingProtocolGuid,
659 &UdpIo->UdpHandle
660 );
661
662 if (EFI_ERROR (Status)) {
663 goto FREE_MEM;
664 }
665
666 Status = gBS->OpenProtocol (
667 UdpIo->UdpHandle,
668 &gEfiUdp6ProtocolGuid,
669 (VOID **) &UdpIo->Protocol.Udp6,
670 ImageHandle,
671 Controller,
672 EFI_OPEN_PROTOCOL_BY_DRIVER
673 );
674
675 if (EFI_ERROR (Status)) {
676 goto FREE_CHILD;
677 }
678
679 if (EFI_ERROR (Configure (UdpIo, Context))) {
680 goto CLOSE_PROTOCOL;
681 }
682
683 Status = UdpIo->Protocol.Udp6->GetModeData (
684 UdpIo->Protocol.Udp6,
685 NULL,
686 NULL,
687 NULL,
688 &UdpIo->SnpMode
689 );
690
691 if (EFI_ERROR (Status)) {
692 goto CLOSE_PROTOCOL;
693 }
694 }
695
696 return UdpIo;
697
698 CLOSE_PROTOCOL:
699 if (UdpVersion == UDP_IO_UDP4_VERSION) {
700 gBS->CloseProtocol (UdpIo->UdpHandle, &gEfiUdp4ProtocolGuid, ImageHandle, Controller);
701 } else {
702 gBS->CloseProtocol (UdpIo->UdpHandle, &gEfiUdp6ProtocolGuid, ImageHandle, Controller);
703 }
704
705 FREE_CHILD:
706 if (UdpVersion == UDP_IO_UDP4_VERSION) {
707 NetLibDestroyServiceChild (
708 Controller,
709 ImageHandle,
710 &gEfiUdp4ServiceBindingProtocolGuid,
711 UdpIo->UdpHandle
712 );
713 } else {
714 NetLibDestroyServiceChild (
715 Controller,
716 ImageHandle,
717 &gEfiUdp6ServiceBindingProtocolGuid,
718 UdpIo->UdpHandle
719 );
720 }
721
722 FREE_MEM:
723 FreePool (UdpIo);
724 return NULL;
725 }
726
727 /**
728 Cancel all the sent datagram that pass the selection criteria of ToCancel.
729 If ToCancel is NULL, all the datagrams are cancelled.
730
731 @param[in] UdpIo The UDP_IO to cancel packet.
732 @param[in] IoStatus The IoStatus to return to the packet owners.
733 @param[in] ToCancel The select funtion to test whether to cancel this
734 packet or not.
735 @param[in] Context The opaque parameter to the ToCancel.
736
737 **/
738 VOID
739 EFIAPI
740 UdpIoCancelDgrams (
741 IN UDP_IO *UdpIo,
742 IN EFI_STATUS IoStatus,
743 IN UDP_IO_TO_CANCEL ToCancel, OPTIONAL
744 IN VOID *Context
745 )
746 {
747 LIST_ENTRY *Entry;
748 LIST_ENTRY *Next;
749 UDP_TX_TOKEN *TxToken;
750
751 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
752 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
753
754 NET_LIST_FOR_EACH_SAFE (Entry, Next, &UdpIo->SentDatagram) {
755 TxToken = NET_LIST_USER_STRUCT (Entry, UDP_TX_TOKEN, Link);
756
757 if ((ToCancel == NULL) || (ToCancel (TxToken, Context))) {
758
759 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
760 UdpIo->Protocol.Udp4->Cancel (UdpIo->Protocol.Udp4, &TxToken->Token.Udp4);
761 } else {
762 UdpIo->Protocol.Udp6->Cancel (UdpIo->Protocol.Udp6, &TxToken->Token.Udp6);
763 }
764 }
765 }
766 }
767
768 /**
769 Free the UDP_IO and all its related resources.
770
771 The function will cancel all sent datagram and receive request.
772
773 @param[in] UdpIo The UDP_IO to free.
774
775 @retval EFI_SUCCESS The UDP_IO is freed.
776
777 **/
778 EFI_STATUS
779 EFIAPI
780 UdpIoFreeIo (
781 IN UDP_IO *UdpIo
782 )
783 {
784 UDP_RX_TOKEN *RxToken;
785
786 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
787 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
788
789 //
790 // Cancel all the sent datagram and receive requests. The
791 // callbacks of transmit requests are executed to allow the
792 // caller to release the resource. The callback of receive
793 // request are NOT executed. This is because it is most
794 // likely that the current user of the UDP IO port is closing
795 // itself.
796 //
797 UdpIoCancelDgrams (UdpIo, EFI_ABORTED, NULL, NULL);
798
799 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
800
801 if ((RxToken = UdpIo->RecvRequest) != NULL) {
802 UdpIo->Protocol.Udp4->Cancel (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);
803 }
804
805 //
806 // Close then destory the Udp4 child
807 //
808 gBS->CloseProtocol (
809 UdpIo->UdpHandle,
810 &gEfiUdp4ProtocolGuid,
811 UdpIo->Image,
812 UdpIo->Controller
813 );
814
815 NetLibDestroyServiceChild (
816 UdpIo->Controller,
817 UdpIo->Image,
818 &gEfiUdp4ServiceBindingProtocolGuid,
819 UdpIo->UdpHandle
820 );
821
822 } else {
823
824 if ((RxToken = UdpIo->RecvRequest) != NULL) {
825 UdpIo->Protocol.Udp6->Cancel (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6);
826 }
827
828 //
829 // Close then destory the Udp6 child
830 //
831 gBS->CloseProtocol (
832 UdpIo->UdpHandle,
833 &gEfiUdp6ProtocolGuid,
834 UdpIo->Image,
835 UdpIo->Controller
836 );
837
838 NetLibDestroyServiceChild (
839 UdpIo->Controller,
840 UdpIo->Image,
841 &gEfiUdp6ServiceBindingProtocolGuid,
842 UdpIo->UdpHandle
843 );
844 }
845
846 if (!IsListEmpty(&UdpIo->Link)) {
847 RemoveEntryList (&UdpIo->Link);
848 }
849
850 FreePool (UdpIo);
851 return EFI_SUCCESS;
852 }
853
854
855 /**
856 Clean up the UDP_IO without freeing it. The function is called when
857 user wants to re-use the UDP_IO later.
858
859 It will release all the transmitted datagrams and receive request. It will
860 also configure NULL for the UDP instance.
861
862 @param[in] UdpIo The UDP_IO to clean up.
863
864 **/
865 VOID
866 EFIAPI
867 UdpIoCleanIo (
868 IN UDP_IO *UdpIo
869 )
870 {
871 UDP_RX_TOKEN *RxToken;
872
873 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
874 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
875
876 //
877 // Cancel all the sent datagram and receive requests.
878 //
879 UdpIoCancelDgrams (UdpIo, EFI_ABORTED, NULL, NULL);
880
881 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
882 if ((RxToken = UdpIo->RecvRequest) != NULL) {
883 UdpIo->Protocol.Udp4->Cancel (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);
884 }
885
886 UdpIo->Protocol.Udp4->Configure (UdpIo->Protocol.Udp4, NULL);
887
888 } else {
889 if ((RxToken = UdpIo->RecvRequest) != NULL) {
890 UdpIo->Protocol.Udp6->Cancel (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6);
891 }
892
893 UdpIo->Protocol.Udp6->Configure (UdpIo->Protocol.Udp6, NULL);
894 }
895 }
896
897 /**
898 Send a packet through the UDP_IO.
899
900 The packet will be wrapped in UDP_TX_TOKEN. Function Callback will be called
901 when the packet is sent. The optional parameter EndPoint overrides the default
902 address pair if specified.
903
904 @param[in] UdpIo The UDP_IO to send the packet through.
905 @param[in] Packet The packet to send.
906 @param[in] EndPoint The local and remote access point. Override the
907 default address pair set during configuration.
908 @param[in] Gateway The gateway to use.
909 @param[in] CallBack The function being called when packet is
910 transmitted or failed.
911 @param[in] Context The opaque parameter passed to CallBack.
912
913 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the packet.
914 @retval EFI_SUCCESS The packet is successfully delivered to UDP for
915 transmission.
916
917 **/
918 EFI_STATUS
919 EFIAPI
920 UdpIoSendDatagram (
921 IN UDP_IO *UdpIo,
922 IN NET_BUF *Packet,
923 IN UDP_END_POINT *EndPoint OPTIONAL,
924 IN EFI_IP_ADDRESS *Gateway OPTIONAL,
925 IN UDP_IO_CALLBACK CallBack,
926 IN VOID *Context
927 )
928 {
929 UDP_TX_TOKEN *TxToken;
930 EFI_STATUS Status;
931
932 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
933 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
934
935 TxToken = UdpIoCreateTxToken (UdpIo, Packet, EndPoint, Gateway, CallBack, Context);
936
937 if (TxToken == NULL) {
938 return EFI_OUT_OF_RESOURCES;
939 }
940
941 //
942 // Insert the tx token into SendDatagram list before transmitting it. Remove
943 // it from the list if the returned status is not EFI_SUCCESS.
944 //
945 InsertHeadList (&UdpIo->SentDatagram, &TxToken->Link);
946
947 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
948 Status = UdpIo->Protocol.Udp4->Transmit (UdpIo->Protocol.Udp4, &TxToken->Token.Udp4);
949 } else {
950 Status = UdpIo->Protocol.Udp6->Transmit (UdpIo->Protocol.Udp6, &TxToken->Token.Udp6);
951 }
952
953 if (EFI_ERROR (Status)) {
954 RemoveEntryList (&TxToken->Link);
955 UdpIoFreeTxToken (TxToken);
956 return Status;
957 }
958
959 return EFI_SUCCESS;
960 }
961
962
963 /**
964 The select function to cancel a single sent datagram.
965
966 @param[in] Token The UDP_TX_TOKEN to test against
967 @param[in] Context The NET_BUF of the sent datagram
968
969 @retval TRUE The packet is to be cancelled.
970 @retval FALSE The packet is not to be cancelled.
971 **/
972 BOOLEAN
973 UdpIoCancelSingleDgram (
974 IN UDP_TX_TOKEN *Token,
975 IN VOID *Context
976 )
977 {
978 NET_BUF *Packet;
979
980 Packet = (NET_BUF *) Context;
981
982 if (Token->Packet == Packet) {
983 return TRUE;
984 }
985
986 return FALSE;
987 }
988
989 /**
990 Cancel a single sent datagram.
991
992 @param[in] UdpIo The UDP_IO to cancel the packet from
993 @param[in] Packet The packet to cancel
994
995 **/
996 VOID
997 EFIAPI
998 UdpIoCancelSentDatagram (
999 IN UDP_IO *UdpIo,
1000 IN NET_BUF *Packet
1001 )
1002 {
1003 UdpIoCancelDgrams (UdpIo, EFI_ABORTED, UdpIoCancelSingleDgram, Packet);
1004 }
1005
1006 /**
1007 Issue a receive request to the UDP_IO.
1008
1009 This function is called when upper-layer needs packet from UDP for processing.
1010 Only one receive request is acceptable at a time so a common usage model is
1011 to invoke this function inside its Callback function when the former packet
1012 is processed.
1013
1014 @param[in] UdpIo The UDP_IO to receive the packet from.
1015 @param[in] CallBack The call back function to execute when the packet
1016 is received.
1017 @param[in] Context The opaque context passed to Callback.
1018 @param[in] HeadLen The length of the upper-layer's protocol header.
1019
1020 @retval EFI_ALREADY_STARTED There is already a pending receive request. Only
1021 one receive request is supported at a time.
1022 @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.
1023 @retval EFI_SUCCESS The receive request is issued successfully.
1024 @retval EFI_UNSUPPORTED The UDP version in UDP_IO is not supported.
1025
1026 **/
1027 EFI_STATUS
1028 EFIAPI
1029 UdpIoRecvDatagram (
1030 IN UDP_IO *UdpIo,
1031 IN UDP_IO_CALLBACK CallBack,
1032 IN VOID *Context,
1033 IN UINT32 HeadLen
1034 )
1035 {
1036 UDP_RX_TOKEN *RxToken;
1037 EFI_STATUS Status;
1038
1039 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
1040 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
1041
1042 if (UdpIo->RecvRequest != NULL) {
1043 return EFI_ALREADY_STARTED;
1044 }
1045
1046 RxToken = UdpIoCreateRxToken (UdpIo, CallBack, Context, HeadLen);
1047
1048 if (RxToken == NULL) {
1049 return EFI_OUT_OF_RESOURCES;
1050 }
1051
1052 UdpIo->RecvRequest = RxToken;
1053 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
1054 Status = UdpIo->Protocol.Udp4->Receive (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);
1055 } else {
1056 Status = UdpIo->Protocol.Udp6->Receive (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6);
1057 }
1058
1059 if (EFI_ERROR (Status)) {
1060 UdpIo->RecvRequest = NULL;
1061 UdpIoFreeRxToken (RxToken);
1062 }
1063
1064 return Status;
1065 }