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
UdpIoFreeTxToken(IN UDP_TX_TOKEN * TxToken)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
UdpIoFreeRxToken(IN UDP_RX_TOKEN * RxToken)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
UdpIoOnDgramSentDpc(IN VOID * Context)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
UdpIoOnDgramSent(IN EFI_EVENT Event,IN VOID * Context)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
UdpIoRecycleDgram(IN VOID * Context)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
UdpIoOnDgramRcvdDpc(IN VOID * Context)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
UdpIoOnDgramRcvd(IN EFI_EVENT Event,IN VOID * Context)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 *
UdpIoCreateRxToken(IN UDP_IO * UdpIo,IN UDP_IO_CALLBACK CallBack,IN VOID * Context,IN UINT32 HeadLen)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 *
UdpIoCreateTxToken(IN UDP_IO * UdpIo,IN NET_BUF * Packet,IN UDP_END_POINT * EndPoint OPTIONAL,IN EFI_IP_ADDRESS * Gateway OPTIONAL,IN UDP_IO_CALLBACK CallBack,IN VOID * Context)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
UdpIoCreateIo(IN EFI_HANDLE Controller,IN EFI_HANDLE ImageHandle,IN UDP_IO_CONFIG Configure,IN UINT8 UdpVersion,IN VOID * Context)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
UdpIoCancelDgrams(IN UDP_IO * UdpIo,IN EFI_STATUS IoStatus,IN UDP_IO_TO_CANCEL ToCancel,OPTIONAL IN VOID * Context OPTIONAL)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
UdpIoFreeIo(IN UDP_IO * UdpIo)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
UdpIoCleanIo(IN UDP_IO * UdpIo)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
UdpIoSendDatagram(IN UDP_IO * UdpIo,IN NET_BUF * Packet,IN UDP_END_POINT * EndPoint OPTIONAL,IN EFI_IP_ADDRESS * Gateway OPTIONAL,IN UDP_IO_CALLBACK CallBack,IN VOID * Context)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
UdpIoCancelSingleDgram(IN UDP_TX_TOKEN * Token,IN VOID * Context)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
UdpIoCancelSentDatagram(IN UDP_IO * UdpIo,IN NET_BUF * Packet)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
UdpIoRecvDatagram(IN UDP_IO * UdpIo,IN UDP_IO_CALLBACK CallBack,IN VOID * Context,IN UINT32 HeadLen)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 }
1120