• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Help functions to access UDP service, it is used by both the DHCP and MTFTP.
3 
4 Copyright (c) 2005 - 2016, 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
UdpIoFreeTxToken(IN UDP_TX_TOKEN * TxToken)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
UdpIoFreeRxToken(IN UDP_RX_TOKEN * RxToken)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
UdpIoOnDgramSentDpc(IN VOID * Context)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
UdpIoOnDgramSent(IN EFI_EVENT Event,IN VOID * Context)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
UdpIoRecycleDgram(IN VOID * Context)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
UdpIoOnDgramRcvdDpc(IN VOID * Context)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
UdpIoOnDgramRcvd(IN EFI_EVENT Event,IN VOID * Context)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 *
UdpIoCreateRxToken(IN UDP_IO * UdpIo,IN UDP_IO_CALLBACK CallBack,IN VOID * Context,IN UINT32 HeadLen)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   @param[in]  UdpIo                 The UdpIo to send packet to.
414   @param[in]  Packet                The user's packet.
415   @param[in]  EndPoint              The local and remote access point.
416   @param[in]  Gateway               The overrided next hop.
417   @param[in]  CallBack              The function to call when transmission completed.
418   @param[in]  Context               The opaque parameter to the call back.
419 
420   @return The wrapped transmission request or NULL if failed to allocate resources
421           or for some errors.
422 
423 **/
424 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)425 UdpIoCreateTxToken (
426   IN UDP_IO                 *UdpIo,
427   IN NET_BUF                *Packet,
428   IN UDP_END_POINT          *EndPoint OPTIONAL,
429   IN EFI_IP_ADDRESS         *Gateway  OPTIONAL,
430   IN UDP_IO_CALLBACK        CallBack,
431   IN VOID                   *Context
432   )
433 {
434   UDP_TX_TOKEN              *TxToken;
435   VOID                      *Token;
436   VOID                      *Data;
437   EFI_STATUS                Status;
438   UINT32                    Count;
439   UINTN                     Size;
440   IP4_ADDR                  Ip;
441 
442   ASSERT (Packet != NULL);
443   ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
444           (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
445 
446   if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
447     Size = sizeof (UDP_TX_TOKEN) + sizeof (EFI_UDP4_FRAGMENT_DATA) * (Packet->BlockOpNum - 1);
448   } else {
449     Size = sizeof (UDP_TX_TOKEN) + sizeof (EFI_UDP6_FRAGMENT_DATA) * (Packet->BlockOpNum - 1);
450   }
451 
452   TxToken = AllocatePool (Size);
453 
454   if (TxToken == NULL) {
455     return NULL;
456   }
457 
458   TxToken->Signature = UDP_IO_TX_SIGNATURE;
459   InitializeListHead (&TxToken->Link);
460 
461   TxToken->UdpIo     = UdpIo;
462   TxToken->CallBack  = CallBack;
463   TxToken->Packet    = Packet;
464   TxToken->Context   = Context;
465 
466   Token              = &(TxToken->Token);
467   Count              = Packet->BlockOpNum;
468 
469   if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
470 
471     ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Status = EFI_NOT_READY;
472 
473     Status = gBS->CreateEvent (
474                     EVT_NOTIFY_SIGNAL,
475                     TPL_NOTIFY,
476                     UdpIoOnDgramSent,
477                     TxToken,
478                     &((EFI_UDP4_COMPLETION_TOKEN *) Token)->Event
479                     );
480 
481     if (EFI_ERROR (Status)) {
482       FreePool (TxToken);
483       return NULL;
484     }
485 
486     Data = &(TxToken->Data.Udp4);
487     ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Packet.TxData = Data;
488 
489     ((EFI_UDP4_TRANSMIT_DATA *) Data)->UdpSessionData    = NULL;
490     ((EFI_UDP4_TRANSMIT_DATA *) Data)->GatewayAddress    = NULL;
491     ((EFI_UDP4_TRANSMIT_DATA *) Data)->DataLength        = Packet->TotalSize;
492 
493     NetbufBuildExt (
494       Packet,
495       (NET_FRAGMENT *)((EFI_UDP4_TRANSMIT_DATA *) Data)->FragmentTable,
496       &Count
497       );
498 
499     ((EFI_UDP4_TRANSMIT_DATA *) Data)->FragmentCount     = Count;
500 
501     if (EndPoint != NULL) {
502       Ip = HTONL (EndPoint->LocalAddr.Addr[0]);
503       CopyMem (
504         &TxToken->Session.Udp4.SourceAddress,
505         &Ip,
506         sizeof (EFI_IPv4_ADDRESS)
507         );
508 
509       Ip = HTONL (EndPoint->RemoteAddr.Addr[0]);
510       CopyMem (
511         &TxToken->Session.Udp4.DestinationAddress,
512         &Ip,
513         sizeof (EFI_IPv4_ADDRESS)
514         );
515 
516       TxToken->Session.Udp4.SourcePort                   = EndPoint->LocalPort;
517       TxToken->Session.Udp4.DestinationPort              = EndPoint->RemotePort;
518       ((EFI_UDP4_TRANSMIT_DATA *) Data)->UdpSessionData  = &(TxToken->Session.Udp4);
519     }
520 
521     if (Gateway != NULL && (Gateway->Addr[0] != 0)) {
522       Ip = HTONL (Gateway->Addr[0]);
523       CopyMem (&TxToken->Gateway, &Ip, sizeof (EFI_IPv4_ADDRESS));
524       ((EFI_UDP4_TRANSMIT_DATA *) Data)->GatewayAddress = &TxToken->Gateway;
525     }
526 
527   } else {
528 
529     ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Status = EFI_NOT_READY;
530 
531     Status = gBS->CreateEvent (
532                     EVT_NOTIFY_SIGNAL,
533                     TPL_NOTIFY,
534                     UdpIoOnDgramSent,
535                     TxToken,
536                     &((EFI_UDP6_COMPLETION_TOKEN *) Token)->Event
537                     );
538 
539     if (EFI_ERROR (Status)) {
540       FreePool (TxToken);
541       return NULL;
542     }
543 
544     Data = &(TxToken->Data.Udp6);
545     ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Packet.TxData  = Data;
546     ((EFI_UDP6_TRANSMIT_DATA *) Data)->UdpSessionData     = NULL;
547     ((EFI_UDP6_TRANSMIT_DATA *) Data)->DataLength         = Packet->TotalSize;
548 
549     NetbufBuildExt (
550       Packet,
551       (NET_FRAGMENT *)((EFI_UDP6_TRANSMIT_DATA *) Data)->FragmentTable,
552       &Count
553       );
554 
555     ((EFI_UDP6_TRANSMIT_DATA *) Data)->FragmentCount      = Count;
556 
557     if (EndPoint != NULL) {
558       CopyMem (
559         &TxToken->Session.Udp6.SourceAddress,
560         &EndPoint->LocalAddr.v6,
561         sizeof(EFI_IPv6_ADDRESS)
562         );
563 
564       CopyMem (
565         &TxToken->Session.Udp6.DestinationAddress,
566         &EndPoint->RemoteAddr.v6,
567         sizeof(EFI_IPv6_ADDRESS)
568         );
569 
570       TxToken->Session.Udp6.SourcePort                   = EndPoint->LocalPort;
571       TxToken->Session.Udp6.DestinationPort              = EndPoint->RemotePort;
572       ((EFI_UDP6_TRANSMIT_DATA *) Data)->UdpSessionData  = &(TxToken->Session.Udp6);
573     }
574   }
575 
576   return TxToken;
577 }
578 
579 /**
580   Creates a UDP_IO to access the UDP service. It creates and configures
581   a UDP child.
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   If ToCancel is NULL, all the datagrams are cancelled.
753 
754   @param[in]  UdpIo                 The UDP_IO to cancel packet.
755   @param[in]  IoStatus              The IoStatus to return to the packet owners.
756   @param[in]  ToCancel              The select funtion to test whether to cancel this
757                                     packet or not.
758   @param[in]  Context               The opaque parameter to the ToCancel.
759 
760 **/
761 VOID
762 EFIAPI
UdpIoCancelDgrams(IN UDP_IO * UdpIo,IN EFI_STATUS IoStatus,IN UDP_IO_TO_CANCEL ToCancel,OPTIONAL IN VOID * Context)763 UdpIoCancelDgrams (
764   IN UDP_IO                 *UdpIo,
765   IN EFI_STATUS             IoStatus,
766   IN UDP_IO_TO_CANCEL       ToCancel,        OPTIONAL
767   IN VOID                   *Context
768   )
769 {
770   LIST_ENTRY                *Entry;
771   LIST_ENTRY                *Next;
772   UDP_TX_TOKEN              *TxToken;
773 
774   ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
775           (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
776 
777   NET_LIST_FOR_EACH_SAFE (Entry, Next, &UdpIo->SentDatagram) {
778     TxToken = NET_LIST_USER_STRUCT (Entry, UDP_TX_TOKEN, Link);
779 
780     if ((ToCancel == NULL) || (ToCancel (TxToken, Context))) {
781 
782       if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
783         UdpIo->Protocol.Udp4->Cancel (UdpIo->Protocol.Udp4, &TxToken->Token.Udp4);
784       } else {
785         UdpIo->Protocol.Udp6->Cancel (UdpIo->Protocol.Udp6, &TxToken->Token.Udp6);
786       }
787     }
788   }
789 }
790 
791 /**
792   Free the UDP_IO and all its related resources.
793 
794   The function will cancel all sent datagram and receive request.
795 
796   @param[in]  UdpIo             The UDP_IO to free.
797 
798   @retval EFI_SUCCESS           The UDP_IO is freed.
799 
800 **/
801 EFI_STATUS
802 EFIAPI
UdpIoFreeIo(IN UDP_IO * UdpIo)803 UdpIoFreeIo (
804   IN  UDP_IO           *UdpIo
805   )
806 {
807   UDP_RX_TOKEN         *RxToken;
808 
809   ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
810           (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
811 
812   //
813   // Cancel all the sent datagram and receive requests. The
814   // callbacks of transmit requests are executed to allow the
815   // caller to release the resource. The callback of receive
816   // request are NOT executed. This is because it is most
817   // likely that the current user of the UDP IO port is closing
818   // itself.
819   //
820   UdpIoCancelDgrams (UdpIo, EFI_ABORTED, NULL, NULL);
821 
822   if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
823 
824     if ((RxToken = UdpIo->RecvRequest) != NULL) {
825       UdpIo->Protocol.Udp4->Cancel (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);
826     }
827 
828     //
829     // Close then destroy the Udp4 child
830     //
831     gBS->CloseProtocol (
832            UdpIo->UdpHandle,
833            &gEfiUdp4ProtocolGuid,
834            UdpIo->Image,
835            UdpIo->Controller
836            );
837 
838     NetLibDestroyServiceChild (
839       UdpIo->Controller,
840       UdpIo->Image,
841       &gEfiUdp4ServiceBindingProtocolGuid,
842       UdpIo->UdpHandle
843       );
844 
845   } else {
846 
847     if ((RxToken = UdpIo->RecvRequest) != NULL) {
848       UdpIo->Protocol.Udp6->Cancel (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6);
849     }
850 
851     //
852     // Close then destroy the Udp6 child
853     //
854     gBS->CloseProtocol (
855            UdpIo->UdpHandle,
856            &gEfiUdp6ProtocolGuid,
857            UdpIo->Image,
858            UdpIo->Controller
859            );
860 
861     NetLibDestroyServiceChild (
862       UdpIo->Controller,
863       UdpIo->Image,
864       &gEfiUdp6ServiceBindingProtocolGuid,
865       UdpIo->UdpHandle
866       );
867     }
868 
869   if (!IsListEmpty(&UdpIo->Link)) {
870     RemoveEntryList (&UdpIo->Link);
871   }
872 
873   FreePool (UdpIo);
874   return EFI_SUCCESS;
875 }
876 
877 
878 /**
879   Clean up the UDP_IO without freeing it. The function is called when
880   user wants to re-use the UDP_IO later.
881 
882   It will release all the transmitted datagrams and receive request. It will
883   also configure NULL for the UDP instance.
884 
885   @param[in]  UdpIo                 The UDP_IO to clean up.
886 
887 **/
888 VOID
889 EFIAPI
UdpIoCleanIo(IN UDP_IO * UdpIo)890 UdpIoCleanIo (
891   IN  UDP_IO                *UdpIo
892   )
893 {
894   UDP_RX_TOKEN              *RxToken;
895 
896   ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
897           (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
898 
899   //
900   // Cancel all the sent datagram and receive requests.
901   //
902   UdpIoCancelDgrams (UdpIo, EFI_ABORTED, NULL, NULL);
903 
904   if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
905     if ((RxToken = UdpIo->RecvRequest) != NULL) {
906       UdpIo->Protocol.Udp4->Cancel (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);
907     }
908 
909     UdpIo->Protocol.Udp4->Configure (UdpIo->Protocol.Udp4, NULL);
910 
911   } else {
912     if ((RxToken = UdpIo->RecvRequest) != NULL) {
913       UdpIo->Protocol.Udp6->Cancel (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6);
914     }
915 
916     UdpIo->Protocol.Udp6->Configure (UdpIo->Protocol.Udp6, NULL);
917   }
918 }
919 
920 /**
921   Send a packet through the UDP_IO.
922 
923   The packet will be wrapped in UDP_TX_TOKEN. Function Callback will be called
924   when the packet is sent. The optional parameter EndPoint overrides the default
925   address pair if specified.
926 
927   @param[in]  UdpIo                 The UDP_IO to send the packet through.
928   @param[in]  Packet                The packet to send.
929   @param[in]  EndPoint              The local and remote access point. Override the
930                                     default address pair set during configuration.
931   @param[in]  Gateway               The gateway to use.
932   @param[in]  CallBack              The function being called when packet is
933                                     transmitted or failed.
934   @param[in]  Context               The opaque parameter passed to CallBack.
935 
936   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource for the packet.
937   @retval EFI_SUCCESS           The packet is successfully delivered to UDP  for
938                                 transmission.
939 
940 **/
941 EFI_STATUS
942 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)943 UdpIoSendDatagram (
944   IN  UDP_IO                *UdpIo,
945   IN  NET_BUF               *Packet,
946   IN  UDP_END_POINT         *EndPoint OPTIONAL,
947   IN  EFI_IP_ADDRESS        *Gateway  OPTIONAL,
948   IN  UDP_IO_CALLBACK       CallBack,
949   IN  VOID                  *Context
950   )
951 {
952   UDP_TX_TOKEN              *TxToken;
953   EFI_STATUS                Status;
954 
955   ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
956           (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
957 
958   TxToken = UdpIoCreateTxToken (UdpIo, Packet, EndPoint, Gateway, CallBack, Context);
959 
960   if (TxToken == NULL) {
961     return EFI_OUT_OF_RESOURCES;
962   }
963 
964   //
965   // Insert the tx token into SendDatagram list before transmitting it. Remove
966   // it from the list if the returned status is not EFI_SUCCESS.
967   //
968   InsertHeadList (&UdpIo->SentDatagram, &TxToken->Link);
969 
970   if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
971     Status = UdpIo->Protocol.Udp4->Transmit (UdpIo->Protocol.Udp4, &TxToken->Token.Udp4);
972   } else {
973     Status = UdpIo->Protocol.Udp6->Transmit (UdpIo->Protocol.Udp6, &TxToken->Token.Udp6);
974   }
975 
976   if (EFI_ERROR (Status)) {
977     RemoveEntryList (&TxToken->Link);
978     UdpIoFreeTxToken (TxToken);
979     return Status;
980   }
981 
982   return EFI_SUCCESS;
983 }
984 
985 
986 /**
987   The select function to cancel a single sent datagram.
988 
989   @param[in]  Token                 The UDP_TX_TOKEN to test against
990   @param[in]  Context               The NET_BUF of the sent datagram
991 
992   @retval TRUE              The packet is to be cancelled.
993   @retval FALSE             The packet is not to be cancelled.
994 **/
995 BOOLEAN
996 EFIAPI
UdpIoCancelSingleDgram(IN UDP_TX_TOKEN * Token,IN VOID * Context)997 UdpIoCancelSingleDgram (
998   IN UDP_TX_TOKEN           *Token,
999   IN VOID                   *Context
1000   )
1001 {
1002   NET_BUF                   *Packet;
1003 
1004   Packet = (NET_BUF *) Context;
1005 
1006   if (Token->Packet == Packet) {
1007     return TRUE;
1008   }
1009 
1010   return FALSE;
1011 }
1012 
1013 /**
1014   Cancel a single sent datagram.
1015 
1016   @param[in]  UdpIo                 The UDP_IO to cancel the packet from
1017   @param[in]  Packet                The packet to cancel
1018 
1019 **/
1020 VOID
1021 EFIAPI
UdpIoCancelSentDatagram(IN UDP_IO * UdpIo,IN NET_BUF * Packet)1022 UdpIoCancelSentDatagram (
1023   IN  UDP_IO                *UdpIo,
1024   IN  NET_BUF               *Packet
1025   )
1026 {
1027   UdpIoCancelDgrams (UdpIo, EFI_ABORTED, UdpIoCancelSingleDgram, Packet);
1028 }
1029 
1030 /**
1031   Issue a receive request to the UDP_IO.
1032 
1033   This function is called when upper-layer needs packet from UDP for processing.
1034   Only one receive request is acceptable at a time so a common usage model is
1035   to invoke this function inside its Callback function when the former packet
1036   is processed.
1037 
1038   @param[in]  UdpIo                 The UDP_IO to receive the packet from.
1039   @param[in]  CallBack              The call back function to execute when the packet
1040                                     is received.
1041   @param[in]  Context               The opaque context passed to Callback.
1042   @param[in]  HeadLen               The length of the upper-layer's protocol header.
1043 
1044   @retval EFI_ALREADY_STARTED   There is already a pending receive request. Only
1045                                 one receive request is supported at a time.
1046   @retval EFI_OUT_OF_RESOURCES  Failed to allocate needed resources.
1047   @retval EFI_SUCCESS           The receive request is issued successfully.
1048   @retval EFI_UNSUPPORTED       The UDP version in UDP_IO is not supported.
1049 
1050 **/
1051 EFI_STATUS
1052 EFIAPI
UdpIoRecvDatagram(IN UDP_IO * UdpIo,IN UDP_IO_CALLBACK CallBack,IN VOID * Context,IN UINT32 HeadLen)1053 UdpIoRecvDatagram (
1054   IN  UDP_IO                *UdpIo,
1055   IN  UDP_IO_CALLBACK       CallBack,
1056   IN  VOID                  *Context,
1057   IN  UINT32                HeadLen
1058   )
1059 {
1060   UDP_RX_TOKEN              *RxToken;
1061   EFI_STATUS                Status;
1062 
1063   ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
1064           (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
1065 
1066   if (UdpIo->RecvRequest != NULL) {
1067     return EFI_ALREADY_STARTED;
1068   }
1069 
1070   RxToken = UdpIoCreateRxToken (UdpIo, CallBack, Context, HeadLen);
1071 
1072   if (RxToken == NULL) {
1073     return EFI_OUT_OF_RESOURCES;
1074   }
1075 
1076   UdpIo->RecvRequest = RxToken;
1077   if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
1078     Status = UdpIo->Protocol.Udp4->Receive (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);
1079   } else {
1080     Status = UdpIo->Protocol.Udp6->Receive (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6);
1081   }
1082 
1083   if (EFI_ERROR (Status)) {
1084     UdpIo->RecvRequest = NULL;
1085     UdpIoFreeRxToken (RxToken);
1086   }
1087 
1088   return Status;
1089 }
1090