]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.c
MdeModulePkg/DxeUdpIoLib: Did some code enhancement for UdpIoLib
[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 - 2018, Intel Corporation. All rights reserved.<BR>
5 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 EFIAPI
134 UdpIoRecycleDgram (
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 **/
162 VOID
163 EFIAPI
164 UdpIoOnDgramRcvdDpc (
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 if (((EFI_UDP4_RECEIVE_DATA *) RxData)->DataLength == 0) {
219 //
220 // Discard zero length data payload packet.
221 //
222 goto Resume;
223 }
224
225 Netbuf = NetbufFromExt (
226 (NET_FRAGMENT *)((EFI_UDP4_RECEIVE_DATA *) RxData)->FragmentTable,
227 ((EFI_UDP4_RECEIVE_DATA *) RxData)->FragmentCount,
228 0,
229 (UINT32) RxToken->HeadLen,
230 UdpIoRecycleDgram,
231 RxToken
232 );
233
234 if (Netbuf == NULL) {
235 gBS->SignalEvent (((EFI_UDP4_RECEIVE_DATA *) RxData)->RecycleSignal);
236 RxToken->CallBack (NULL, NULL, EFI_OUT_OF_RESOURCES, RxToken->Context);
237
238 UdpIoFreeRxToken (RxToken);
239 return;
240 }
241
242 Session = &((EFI_UDP4_RECEIVE_DATA *) RxData)->UdpSession;
243 EndPoint.LocalPort = ((EFI_UDP4_SESSION_DATA *) Session)->DestinationPort;
244 EndPoint.RemotePort = ((EFI_UDP4_SESSION_DATA *) Session)->SourcePort;
245
246 CopyMem (
247 &EndPoint.LocalAddr,
248 &((EFI_UDP4_SESSION_DATA *) Session)->DestinationAddress,
249 sizeof (EFI_IPv4_ADDRESS)
250 );
251
252 CopyMem (
253 &EndPoint.RemoteAddr,
254 &((EFI_UDP4_SESSION_DATA *) Session)->SourceAddress,
255 sizeof (EFI_IPv4_ADDRESS)
256 );
257
258 EndPoint.LocalAddr.Addr[0] = NTOHL (EndPoint.LocalAddr.Addr[0]);
259 EndPoint.RemoteAddr.Addr[0] = NTOHL (EndPoint.RemoteAddr.Addr[0]);
260 } else {
261 if (((EFI_UDP6_RECEIVE_DATA *) RxData)->DataLength == 0) {
262 //
263 // Discard zero length data payload packet.
264 //
265 goto Resume;
266 }
267
268 Netbuf = NetbufFromExt (
269 (NET_FRAGMENT *)((EFI_UDP6_RECEIVE_DATA *) RxData)->FragmentTable,
270 ((EFI_UDP6_RECEIVE_DATA *) RxData)->FragmentCount,
271 0,
272 (UINT32) RxToken->HeadLen,
273 UdpIoRecycleDgram,
274 RxToken
275 );
276
277 if (Netbuf == NULL) {
278 gBS->SignalEvent (((EFI_UDP6_RECEIVE_DATA *) RxData)->RecycleSignal);
279 RxToken->CallBack (NULL, NULL, EFI_OUT_OF_RESOURCES, RxToken->Context);
280
281 UdpIoFreeRxToken (RxToken);
282 return;
283 }
284
285 Session = &((EFI_UDP6_RECEIVE_DATA *) RxData)->UdpSession;
286 EndPoint.LocalPort = ((EFI_UDP6_SESSION_DATA *) Session)->DestinationPort;
287 EndPoint.RemotePort = ((EFI_UDP6_SESSION_DATA *) Session)->SourcePort;
288
289 CopyMem (
290 &EndPoint.LocalAddr,
291 &((EFI_UDP6_SESSION_DATA *) Session)->DestinationAddress,
292 sizeof (EFI_IPv6_ADDRESS)
293 );
294
295 CopyMem (
296 &EndPoint.RemoteAddr,
297 &((EFI_UDP6_SESSION_DATA *) Session)->SourceAddress,
298 sizeof (EFI_IPv6_ADDRESS)
299 );
300
301 Ip6Swap128 (&EndPoint.LocalAddr.v6);
302 Ip6Swap128 (&EndPoint.RemoteAddr.v6);
303 }
304
305 RxToken->CallBack (Netbuf, &EndPoint, EFI_SUCCESS, RxToken->Context);
306 return;
307
308 Resume:
309 if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
310 gBS->SignalEvent (((EFI_UDP4_RECEIVE_DATA *) RxData)->RecycleSignal);
311 RxToken->UdpIo->Protocol.Udp4->Receive (RxToken->UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);
312 } else {
313 gBS->SignalEvent (((EFI_UDP6_RECEIVE_DATA *) RxData)->RecycleSignal);
314 RxToken->UdpIo->Protocol.Udp6->Receive (RxToken->UdpIo->Protocol.Udp6, &RxToken->Token.Udp6);
315 }
316 }
317
318 /**
319 Request UdpIoOnDgramRcvdDpc() as a DPC at TPL_CALLBACK.
320
321 @param[in] Event The UDP receive request event.
322 @param[in] Context The UDP RX token.
323
324 **/
325 VOID
326 EFIAPI
327 UdpIoOnDgramRcvd (
328 IN EFI_EVENT Event,
329 IN VOID *Context
330 )
331 {
332 //
333 // Request UdpIoOnDgramRcvdDpc as a DPC at TPL_CALLBACK
334 //
335 QueueDpc (TPL_CALLBACK, UdpIoOnDgramRcvdDpc, Context);
336 }
337
338 /**
339 Create a UDP_RX_TOKEN to wrap the request.
340
341 @param[in] UdpIo The UdpIo to receive packets from.
342 @param[in] CallBack The function to call when receive finished.
343 @param[in] Context The opaque parameter to the CallBack.
344 @param[in] HeadLen The head length to reserver for the packet.
345
346 @return The Wrapped request or NULL if failed to allocate resources or some errors happened.
347
348 **/
349 UDP_RX_TOKEN *
350 UdpIoCreateRxToken (
351 IN UDP_IO *UdpIo,
352 IN UDP_IO_CALLBACK CallBack,
353 IN VOID *Context,
354 IN UINT32 HeadLen
355 )
356 {
357 UDP_RX_TOKEN *Token;
358 EFI_STATUS Status;
359
360 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
361 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
362
363 Token = AllocatePool (sizeof (UDP_RX_TOKEN));
364
365 if (Token == NULL) {
366 return NULL;
367 }
368
369 Token->Signature = UDP_IO_RX_SIGNATURE;
370 Token->UdpIo = UdpIo;
371 Token->CallBack = CallBack;
372 Token->Context = Context;
373 Token->HeadLen = HeadLen;
374
375 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
376
377 Token->Token.Udp4.Status = EFI_NOT_READY;
378 Token->Token.Udp4.Packet.RxData = NULL;
379
380 Status = gBS->CreateEvent (
381 EVT_NOTIFY_SIGNAL,
382 TPL_NOTIFY,
383 UdpIoOnDgramRcvd,
384 Token,
385 &Token->Token.Udp4.Event
386 );
387 } else {
388
389 Token->Token.Udp6.Status = EFI_NOT_READY;
390 Token->Token.Udp6.Packet.RxData = NULL;
391
392 Status = gBS->CreateEvent (
393 EVT_NOTIFY_SIGNAL,
394 TPL_NOTIFY,
395 UdpIoOnDgramRcvd,
396 Token,
397 &Token->Token.Udp6.Event
398 );
399 }
400
401
402 if (EFI_ERROR (Status)) {
403 FreePool (Token);
404 return NULL;
405 }
406
407 return Token;
408 }
409
410 /**
411 Wrap a transmit request into a new created UDP_TX_TOKEN.
412
413 If Packet is NULL, then ASSERT().
414 If Udp version is not UDP_IO_UDP4_VERSION or UDP_IO_UDP6_VERSION, then ASSERT().
415
416 @param[in] UdpIo The UdpIo to send packet to.
417 @param[in] Packet The user's packet.
418 @param[in] EndPoint The local and remote access point.
419 @param[in] Gateway The overrided next hop.
420 @param[in] CallBack The function to call when transmission completed.
421 @param[in] Context The opaque parameter to the call back.
422
423 @return The wrapped transmission request or NULL if failed to allocate resources
424 or for some errors.
425
426 **/
427 UDP_TX_TOKEN *
428 UdpIoCreateTxToken (
429 IN UDP_IO *UdpIo,
430 IN NET_BUF *Packet,
431 IN UDP_END_POINT *EndPoint OPTIONAL,
432 IN EFI_IP_ADDRESS *Gateway OPTIONAL,
433 IN UDP_IO_CALLBACK CallBack,
434 IN VOID *Context
435 )
436 {
437 UDP_TX_TOKEN *TxToken;
438 VOID *Token;
439 VOID *Data;
440 EFI_STATUS Status;
441 UINT32 Count;
442 UINTN Size;
443 IP4_ADDR Ip;
444
445 ASSERT (Packet != NULL);
446 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
447 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
448
449 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
450 Size = sizeof (UDP_TX_TOKEN) + sizeof (EFI_UDP4_FRAGMENT_DATA) * (Packet->BlockOpNum - 1);
451 } else {
452 Size = sizeof (UDP_TX_TOKEN) + sizeof (EFI_UDP6_FRAGMENT_DATA) * (Packet->BlockOpNum - 1);
453 }
454
455 TxToken = AllocatePool (Size);
456
457 if (TxToken == NULL) {
458 return NULL;
459 }
460
461 TxToken->Signature = UDP_IO_TX_SIGNATURE;
462 InitializeListHead (&TxToken->Link);
463
464 TxToken->UdpIo = UdpIo;
465 TxToken->CallBack = CallBack;
466 TxToken->Packet = Packet;
467 TxToken->Context = Context;
468
469 Token = &(TxToken->Token);
470 Count = Packet->BlockOpNum;
471
472 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
473
474 ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Status = EFI_NOT_READY;
475
476 Status = gBS->CreateEvent (
477 EVT_NOTIFY_SIGNAL,
478 TPL_NOTIFY,
479 UdpIoOnDgramSent,
480 TxToken,
481 &((EFI_UDP4_COMPLETION_TOKEN *) Token)->Event
482 );
483
484 if (EFI_ERROR (Status)) {
485 FreePool (TxToken);
486 return NULL;
487 }
488
489 Data = &(TxToken->Data.Udp4);
490 ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Packet.TxData = Data;
491
492 ((EFI_UDP4_TRANSMIT_DATA *) Data)->UdpSessionData = NULL;
493 ((EFI_UDP4_TRANSMIT_DATA *) Data)->GatewayAddress = NULL;
494 ((EFI_UDP4_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize;
495
496 NetbufBuildExt (
497 Packet,
498 (NET_FRAGMENT *)((EFI_UDP4_TRANSMIT_DATA *) Data)->FragmentTable,
499 &Count
500 );
501
502 ((EFI_UDP4_TRANSMIT_DATA *) Data)->FragmentCount = Count;
503
504 if (EndPoint != NULL) {
505 Ip = HTONL (EndPoint->LocalAddr.Addr[0]);
506 CopyMem (
507 &TxToken->Session.Udp4.SourceAddress,
508 &Ip,
509 sizeof (EFI_IPv4_ADDRESS)
510 );
511
512 Ip = HTONL (EndPoint->RemoteAddr.Addr[0]);
513 CopyMem (
514 &TxToken->Session.Udp4.DestinationAddress,
515 &Ip,
516 sizeof (EFI_IPv4_ADDRESS)
517 );
518
519 TxToken->Session.Udp4.SourcePort = EndPoint->LocalPort;
520 TxToken->Session.Udp4.DestinationPort = EndPoint->RemotePort;
521 ((EFI_UDP4_TRANSMIT_DATA *) Data)->UdpSessionData = &(TxToken->Session.Udp4);
522 }
523
524 if (Gateway != NULL && (Gateway->Addr[0] != 0)) {
525 Ip = HTONL (Gateway->Addr[0]);
526 CopyMem (&TxToken->Gateway, &Ip, sizeof (EFI_IPv4_ADDRESS));
527 ((EFI_UDP4_TRANSMIT_DATA *) Data)->GatewayAddress = &TxToken->Gateway;
528 }
529
530 } else {
531
532 ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Status = EFI_NOT_READY;
533
534 Status = gBS->CreateEvent (
535 EVT_NOTIFY_SIGNAL,
536 TPL_NOTIFY,
537 UdpIoOnDgramSent,
538 TxToken,
539 &((EFI_UDP6_COMPLETION_TOKEN *) Token)->Event
540 );
541
542 if (EFI_ERROR (Status)) {
543 FreePool (TxToken);
544 return NULL;
545 }
546
547 Data = &(TxToken->Data.Udp6);
548 ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Packet.TxData = Data;
549 ((EFI_UDP6_TRANSMIT_DATA *) Data)->UdpSessionData = NULL;
550 ((EFI_UDP6_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize;
551
552 NetbufBuildExt (
553 Packet,
554 (NET_FRAGMENT *)((EFI_UDP6_TRANSMIT_DATA *) Data)->FragmentTable,
555 &Count
556 );
557
558 ((EFI_UDP6_TRANSMIT_DATA *) Data)->FragmentCount = Count;
559
560 if (EndPoint != NULL) {
561 CopyMem (
562 &TxToken->Session.Udp6.SourceAddress,
563 &EndPoint->LocalAddr.v6,
564 sizeof(EFI_IPv6_ADDRESS)
565 );
566
567 CopyMem (
568 &TxToken->Session.Udp6.DestinationAddress,
569 &EndPoint->RemoteAddr.v6,
570 sizeof(EFI_IPv6_ADDRESS)
571 );
572
573 TxToken->Session.Udp6.SourcePort = EndPoint->LocalPort;
574 TxToken->Session.Udp6.DestinationPort = EndPoint->RemotePort;
575 ((EFI_UDP6_TRANSMIT_DATA *) Data)->UdpSessionData = &(TxToken->Session.Udp6);
576 }
577 }
578
579 return TxToken;
580 }
581
582 /**
583 Creates a UDP_IO to access the UDP service. It creates and configures
584 a UDP child.
585
586 If Configure is NULL, then ASSERT().
587 If Udp version is not UDP_IO_UDP4_VERSION or UDP_IO_UDP6_VERSION, then ASSERT().
588
589 It locates the UDP service binding prototype on the Controller parameter
590 uses the UDP service binding prototype to create a UDP child (also known as
591 a UDP instance) configures the UDP child by calling Configure function prototype.
592 Any failures in creating or configuring the UDP child return NULL for failure.
593
594 @param[in] Controller The controller that has the UDP service binding.
595 protocol installed.
596 @param[in] ImageHandle The image handle for the driver.
597 @param[in] Configure The function to configure the created UDP child.
598 @param[in] UdpVersion The UDP protocol version, UDP4 or UDP6.
599 @param[in] Context The opaque parameter for the Configure funtion.
600
601 @return Newly-created UDP_IO or NULL if failed.
602
603 **/
604 UDP_IO *
605 EFIAPI
606 UdpIoCreateIo (
607 IN EFI_HANDLE Controller,
608 IN EFI_HANDLE ImageHandle,
609 IN UDP_IO_CONFIG Configure,
610 IN UINT8 UdpVersion,
611 IN VOID *Context
612 )
613 {
614 UDP_IO *UdpIo;
615 EFI_STATUS Status;
616
617 ASSERT (Configure != NULL);
618 ASSERT ((UdpVersion == UDP_IO_UDP4_VERSION) || (UdpVersion == UDP_IO_UDP6_VERSION));
619
620 UdpIo = AllocatePool (sizeof (UDP_IO));
621
622 if (UdpIo == NULL) {
623 return NULL;
624 }
625
626 UdpIo->UdpVersion = UdpVersion;
627 UdpIo->Signature = UDP_IO_SIGNATURE;
628 InitializeListHead (&UdpIo->Link);
629 UdpIo->RefCnt = 1;
630
631 UdpIo->Controller = Controller;
632 UdpIo->Image = ImageHandle;
633
634 InitializeListHead (&UdpIo->SentDatagram);
635 UdpIo->RecvRequest = NULL;
636 UdpIo->UdpHandle = NULL;
637
638 if (UdpVersion == UDP_IO_UDP4_VERSION) {
639 //
640 // Create a UDP child then open and configure it
641 //
642 Status = NetLibCreateServiceChild (
643 Controller,
644 ImageHandle,
645 &gEfiUdp4ServiceBindingProtocolGuid,
646 &UdpIo->UdpHandle
647 );
648
649 if (EFI_ERROR (Status)) {
650 goto FREE_MEM;
651 }
652
653 Status = gBS->OpenProtocol (
654 UdpIo->UdpHandle,
655 &gEfiUdp4ProtocolGuid,
656 (VOID **) &UdpIo->Protocol.Udp4,
657 ImageHandle,
658 Controller,
659 EFI_OPEN_PROTOCOL_BY_DRIVER
660 );
661
662 if (EFI_ERROR (Status)) {
663 goto FREE_CHILD;
664 }
665
666 if (EFI_ERROR (Configure (UdpIo, Context))) {
667 goto CLOSE_PROTOCOL;
668 }
669
670 Status = UdpIo->Protocol.Udp4->GetModeData (
671 UdpIo->Protocol.Udp4,
672 NULL,
673 NULL,
674 NULL,
675 &UdpIo->SnpMode
676 );
677
678 if (EFI_ERROR (Status)) {
679 goto CLOSE_PROTOCOL;
680 }
681
682 } else {
683
684 Status = NetLibCreateServiceChild (
685 Controller,
686 ImageHandle,
687 &gEfiUdp6ServiceBindingProtocolGuid,
688 &UdpIo->UdpHandle
689 );
690
691 if (EFI_ERROR (Status)) {
692 goto FREE_MEM;
693 }
694
695 Status = gBS->OpenProtocol (
696 UdpIo->UdpHandle,
697 &gEfiUdp6ProtocolGuid,
698 (VOID **) &UdpIo->Protocol.Udp6,
699 ImageHandle,
700 Controller,
701 EFI_OPEN_PROTOCOL_BY_DRIVER
702 );
703
704 if (EFI_ERROR (Status)) {
705 goto FREE_CHILD;
706 }
707
708 if (EFI_ERROR (Configure (UdpIo, Context))) {
709 goto CLOSE_PROTOCOL;
710 }
711
712 Status = UdpIo->Protocol.Udp6->GetModeData (
713 UdpIo->Protocol.Udp6,
714 NULL,
715 NULL,
716 NULL,
717 &UdpIo->SnpMode
718 );
719
720 if (EFI_ERROR (Status)) {
721 goto CLOSE_PROTOCOL;
722 }
723 }
724
725 return UdpIo;
726
727 CLOSE_PROTOCOL:
728 if (UdpVersion == UDP_IO_UDP4_VERSION) {
729 gBS->CloseProtocol (UdpIo->UdpHandle, &gEfiUdp4ProtocolGuid, ImageHandle, Controller);
730 } else {
731 gBS->CloseProtocol (UdpIo->UdpHandle, &gEfiUdp6ProtocolGuid, ImageHandle, Controller);
732 }
733
734 FREE_CHILD:
735 if (UdpVersion == UDP_IO_UDP4_VERSION) {
736 NetLibDestroyServiceChild (
737 Controller,
738 ImageHandle,
739 &gEfiUdp4ServiceBindingProtocolGuid,
740 UdpIo->UdpHandle
741 );
742 } else {
743 NetLibDestroyServiceChild (
744 Controller,
745 ImageHandle,
746 &gEfiUdp6ServiceBindingProtocolGuid,
747 UdpIo->UdpHandle
748 );
749 }
750
751 FREE_MEM:
752 FreePool (UdpIo);
753 return NULL;
754 }
755
756 /**
757 Cancel all the sent datagram that pass the selection criteria of ToCancel.
758
759 If ToCancel is NULL, all the datagrams are cancelled.
760 If Udp version is not UDP_IO_UDP4_VERSION or UDP_IO_UDP6_VERSION, then ASSERT().
761
762 @param[in] UdpIo The UDP_IO to cancel packet.
763 @param[in] IoStatus The IoStatus to return to the packet owners.
764 @param[in] ToCancel The select funtion to test whether to cancel this
765 packet or not.
766 @param[in] Context The opaque parameter to the ToCancel.
767
768 **/
769 VOID
770 EFIAPI
771 UdpIoCancelDgrams (
772 IN UDP_IO *UdpIo,
773 IN EFI_STATUS IoStatus,
774 IN UDP_IO_TO_CANCEL ToCancel, OPTIONAL
775 IN VOID *Context OPTIONAL
776 )
777 {
778 LIST_ENTRY *Entry;
779 LIST_ENTRY *Next;
780 UDP_TX_TOKEN *TxToken;
781
782 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
783 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
784
785 NET_LIST_FOR_EACH_SAFE (Entry, Next, &UdpIo->SentDatagram) {
786 TxToken = NET_LIST_USER_STRUCT (Entry, UDP_TX_TOKEN, Link);
787
788 if ((ToCancel == NULL) || (ToCancel (TxToken, Context))) {
789
790 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
791 UdpIo->Protocol.Udp4->Cancel (UdpIo->Protocol.Udp4, &TxToken->Token.Udp4);
792 } else {
793 UdpIo->Protocol.Udp6->Cancel (UdpIo->Protocol.Udp6, &TxToken->Token.Udp6);
794 }
795 }
796 }
797 }
798
799 /**
800 Free the UDP_IO and all its related resources.
801
802 If Udp version is not UDP_IO_UDP4_VERSION or UDP_IO_UDP6_VERSION, then ASSERT().
803
804 The function will cancel all sent datagram and receive request.
805
806 @param[in] UdpIo The UDP_IO to free.
807
808 @retval EFI_SUCCESS The UDP_IO is freed.
809 @retval Others Failed to free UDP_IO.
810
811 **/
812 EFI_STATUS
813 EFIAPI
814 UdpIoFreeIo (
815 IN UDP_IO *UdpIo
816 )
817 {
818 EFI_STATUS Status;
819 UDP_RX_TOKEN *RxToken;
820
821 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
822 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
823
824 //
825 // Cancel all the sent datagram and receive requests. The
826 // callbacks of transmit requests are executed to allow the
827 // caller to release the resource. The callback of receive
828 // request are NOT executed. This is because it is most
829 // likely that the current user of the UDP IO port is closing
830 // itself.
831 //
832 UdpIoCancelDgrams (UdpIo, EFI_ABORTED, NULL, NULL);
833
834 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
835
836 if ((RxToken = UdpIo->RecvRequest) != NULL) {
837 Status = UdpIo->Protocol.Udp4->Cancel (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);
838 if (EFI_ERROR (Status)) {
839 return Status;
840 }
841 }
842
843 //
844 // Close then destroy the Udp4 child
845 //
846 Status = gBS->CloseProtocol (
847 UdpIo->UdpHandle,
848 &gEfiUdp4ProtocolGuid,
849 UdpIo->Image,
850 UdpIo->Controller
851 );
852 if (EFI_ERROR (Status)) {
853 return Status;
854 }
855
856 Status = NetLibDestroyServiceChild (
857 UdpIo->Controller,
858 UdpIo->Image,
859 &gEfiUdp4ServiceBindingProtocolGuid,
860 UdpIo->UdpHandle
861 );
862 if (EFI_ERROR (Status)) {
863 return Status;
864 }
865
866 } else {
867
868 if ((RxToken = UdpIo->RecvRequest) != NULL) {
869 Status = UdpIo->Protocol.Udp6->Cancel (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6);
870 if (EFI_ERROR (Status)) {
871 return Status;
872 }
873 }
874
875 //
876 // Close then destroy the Udp6 child
877 //
878 Status = gBS->CloseProtocol (
879 UdpIo->UdpHandle,
880 &gEfiUdp6ProtocolGuid,
881 UdpIo->Image,
882 UdpIo->Controller
883 );
884 if (EFI_ERROR (Status)) {
885 return Status;
886 }
887
888 Status = NetLibDestroyServiceChild (
889 UdpIo->Controller,
890 UdpIo->Image,
891 &gEfiUdp6ServiceBindingProtocolGuid,
892 UdpIo->UdpHandle
893 );
894 if (EFI_ERROR (Status)) {
895 return Status;
896 }
897 }
898
899 if (!IsListEmpty(&UdpIo->Link)) {
900 RemoveEntryList (&UdpIo->Link);
901 }
902
903 FreePool (UdpIo);
904 return EFI_SUCCESS;
905 }
906
907
908 /**
909 Clean up the UDP_IO without freeing it. The function is called when
910 user wants to re-use the UDP_IO later.
911
912 If Udp version is not UDP_IO_UDP4_VERSION or UDP_IO_UDP6_VERSION, then ASSERT().
913
914 It will release all the transmitted datagrams and receive request. It will
915 also configure NULL for the UDP instance.
916
917 @param[in] UdpIo The UDP_IO to clean up.
918
919 **/
920 VOID
921 EFIAPI
922 UdpIoCleanIo (
923 IN UDP_IO *UdpIo
924 )
925 {
926 UDP_RX_TOKEN *RxToken;
927
928 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
929 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
930
931 //
932 // Cancel all the sent datagram and receive requests.
933 //
934 UdpIoCancelDgrams (UdpIo, EFI_ABORTED, NULL, NULL);
935
936 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
937 if ((RxToken = UdpIo->RecvRequest) != NULL) {
938 UdpIo->Protocol.Udp4->Cancel (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);
939 }
940
941 UdpIo->Protocol.Udp4->Configure (UdpIo->Protocol.Udp4, NULL);
942
943 } else {
944 if ((RxToken = UdpIo->RecvRequest) != NULL) {
945 UdpIo->Protocol.Udp6->Cancel (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6);
946 }
947
948 UdpIo->Protocol.Udp6->Configure (UdpIo->Protocol.Udp6, NULL);
949 }
950 }
951
952 /**
953 Send a packet through the UDP_IO.
954
955 If Udp version is not UDP_IO_UDP4_VERSION or UDP_IO_UDP6_VERSION, then ASSERT().
956
957 The packet will be wrapped in UDP_TX_TOKEN. Function Callback will be called
958 when the packet is sent. The optional parameter EndPoint overrides the default
959 address pair if specified.
960
961 @param[in] UdpIo The UDP_IO to send the packet through.
962 @param[in] Packet The packet to send.
963 @param[in] EndPoint The local and remote access point. Override the
964 default address pair set during configuration.
965 @param[in] Gateway The gateway to use.
966 @param[in] CallBack The function being called when packet is
967 transmitted or failed.
968 @param[in] Context The opaque parameter passed to CallBack.
969
970 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the packet.
971 @retval EFI_SUCCESS The packet is successfully delivered to UDP for
972 transmission.
973
974 **/
975 EFI_STATUS
976 EFIAPI
977 UdpIoSendDatagram (
978 IN UDP_IO *UdpIo,
979 IN NET_BUF *Packet,
980 IN UDP_END_POINT *EndPoint OPTIONAL,
981 IN EFI_IP_ADDRESS *Gateway OPTIONAL,
982 IN UDP_IO_CALLBACK CallBack,
983 IN VOID *Context
984 )
985 {
986 UDP_TX_TOKEN *TxToken;
987 EFI_STATUS Status;
988
989 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
990 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
991
992 TxToken = UdpIoCreateTxToken (UdpIo, Packet, EndPoint, Gateway, CallBack, Context);
993
994 if (TxToken == NULL) {
995 return EFI_OUT_OF_RESOURCES;
996 }
997
998 //
999 // Insert the tx token into SendDatagram list before transmitting it. Remove
1000 // it from the list if the returned status is not EFI_SUCCESS.
1001 //
1002 InsertHeadList (&UdpIo->SentDatagram, &TxToken->Link);
1003
1004 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
1005 Status = UdpIo->Protocol.Udp4->Transmit (UdpIo->Protocol.Udp4, &TxToken->Token.Udp4);
1006 } else {
1007 Status = UdpIo->Protocol.Udp6->Transmit (UdpIo->Protocol.Udp6, &TxToken->Token.Udp6);
1008 }
1009
1010 if (EFI_ERROR (Status)) {
1011 RemoveEntryList (&TxToken->Link);
1012 UdpIoFreeTxToken (TxToken);
1013 return Status;
1014 }
1015
1016 return EFI_SUCCESS;
1017 }
1018
1019
1020 /**
1021 The select function to cancel a single sent datagram.
1022
1023 @param[in] Token The UDP_TX_TOKEN to test against
1024 @param[in] Context The NET_BUF of the sent datagram
1025
1026 @retval TRUE The packet is to be cancelled.
1027 @retval FALSE The packet is not to be cancelled.
1028 **/
1029 BOOLEAN
1030 EFIAPI
1031 UdpIoCancelSingleDgram (
1032 IN UDP_TX_TOKEN *Token,
1033 IN VOID *Context
1034 )
1035 {
1036 NET_BUF *Packet;
1037
1038 Packet = (NET_BUF *) Context;
1039
1040 if (Token->Packet == Packet) {
1041 return TRUE;
1042 }
1043
1044 return FALSE;
1045 }
1046
1047 /**
1048 Cancel a single sent datagram.
1049
1050 @param[in] UdpIo The UDP_IO to cancel the packet from
1051 @param[in] Packet The packet to cancel
1052
1053 **/
1054 VOID
1055 EFIAPI
1056 UdpIoCancelSentDatagram (
1057 IN UDP_IO *UdpIo,
1058 IN NET_BUF *Packet
1059 )
1060 {
1061 UdpIoCancelDgrams (UdpIo, EFI_ABORTED, UdpIoCancelSingleDgram, Packet);
1062 }
1063
1064 /**
1065 Issue a receive request to the UDP_IO.
1066
1067 If Udp version is not UDP_IO_UDP4_VERSION or UDP_IO_UDP6_VERSION, then ASSERT().
1068
1069 This function is called when upper-layer needs packet from UDP for processing.
1070 Only one receive request is acceptable at a time so a common usage model is
1071 to invoke this function inside its Callback function when the former packet
1072 is processed.
1073
1074 @param[in] UdpIo The UDP_IO to receive the packet from.
1075 @param[in] CallBack The call back function to execute when the packet
1076 is received.
1077 @param[in] Context The opaque context passed to Callback.
1078 @param[in] HeadLen The length of the upper-layer's protocol header.
1079
1080 @retval EFI_ALREADY_STARTED There is already a pending receive request. Only
1081 one receive request is supported at a time.
1082 @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.
1083 @retval EFI_SUCCESS The receive request is issued successfully.
1084 @retval EFI_UNSUPPORTED The UDP version in UDP_IO is not supported.
1085
1086 **/
1087 EFI_STATUS
1088 EFIAPI
1089 UdpIoRecvDatagram (
1090 IN UDP_IO *UdpIo,
1091 IN UDP_IO_CALLBACK CallBack,
1092 IN VOID *Context,
1093 IN UINT32 HeadLen
1094 )
1095 {
1096 UDP_RX_TOKEN *RxToken;
1097 EFI_STATUS Status;
1098
1099 ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
1100 (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
1101
1102 if (UdpIo->RecvRequest != NULL) {
1103 return EFI_ALREADY_STARTED;
1104 }
1105
1106 RxToken = UdpIoCreateRxToken (UdpIo, CallBack, Context, HeadLen);
1107
1108 if (RxToken == NULL) {
1109 return EFI_OUT_OF_RESOURCES;
1110 }
1111
1112 UdpIo->RecvRequest = RxToken;
1113 if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
1114 Status = UdpIo->Protocol.Udp4->Receive (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);
1115 } else {
1116 Status = UdpIo->Protocol.Udp6->Receive (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6);
1117 }
1118
1119 if (EFI_ERROR (Status)) {
1120 UdpIo->RecvRequest = NULL;
1121 UdpIoFreeRxToken (RxToken);
1122 }
1123
1124 return Status;
1125 }