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