Home | History | Annotate | Download | only in DxeUdpIoLib
      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
     35 UdpIoFreeTxToken (
     36   IN UDP_TX_TOKEN           *TxToken
     37   )
     38 {
     39 
     40   if (TxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
     41     gBS->CloseEvent (TxToken->Token.Udp4.Event);
     42   } else if (TxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION) {
     43     gBS->CloseEvent (TxToken->Token.Udp6.Event);
     44   } else {
     45     ASSERT (FALSE);
     46   }
     47 
     48   FreePool (TxToken);
     49 }
     50 
     51 /**
     52   Free a UDP_RX_TOKEN. The RX event is closed.
     53 
     54   @param[in]  RxToken                 The UDP_RX_TOKEN to release.
     55 
     56 **/
     57 VOID
     58 UdpIoFreeRxToken (
     59   IN UDP_RX_TOKEN           *RxToken
     60   )
     61 {
     62   if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
     63     gBS->CloseEvent (RxToken->Token.Udp4.Event);
     64   } else if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION) {
     65     gBS->CloseEvent (RxToken->Token.Udp6.Event);
     66   } else {
     67     ASSERT (FALSE);
     68   }
     69 
     70   FreePool (RxToken);
     71 }
     72 
     73 /**
     74   The callback function when the packet is sent by UDP.
     75 
     76   It will remove the packet from the local list then call
     77   the packet owner's callback function set by UdpIoSendDatagram.
     78 
     79   @param[in]  Context               The UDP TX Token.
     80 
     81 **/
     82 VOID
     83 EFIAPI
     84 UdpIoOnDgramSentDpc (
     85   IN VOID                   *Context
     86   )
     87 {
     88   UDP_TX_TOKEN              *TxToken;
     89 
     90   TxToken = (UDP_TX_TOKEN *) Context;
     91   ASSERT (TxToken->Signature == UDP_IO_TX_SIGNATURE);
     92   ASSERT ((TxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
     93           (TxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
     94 
     95   RemoveEntryList (&TxToken->Link);
     96 
     97   if (TxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
     98     TxToken->CallBack (TxToken->Packet, NULL, TxToken->Token.Udp4.Status, TxToken->Context);
     99   } else {
    100     TxToken->CallBack (TxToken->Packet, NULL, TxToken->Token.Udp6.Status, TxToken->Context);
    101   }
    102 
    103   UdpIoFreeTxToken (TxToken);
    104 }
    105 
    106 /**
    107   Request UdpIoOnDgramSentDpc as a DPC at TPL_CALLBACK.
    108 
    109   @param[in]  Event                 The event signaled.
    110   @param[in]  Context               The UDP TX Token.
    111 
    112 **/
    113 VOID
    114 EFIAPI
    115 UdpIoOnDgramSent (
    116   IN EFI_EVENT              Event,
    117   IN VOID                   *Context
    118   )
    119 {
    120   //
    121   // Request UdpIoOnDgramSentDpc as a DPC at TPL_CALLBACK
    122   //
    123   QueueDpc (TPL_CALLBACK, UdpIoOnDgramSentDpc, Context);
    124 }
    125 
    126 /**
    127   Recycle the received UDP data.
    128 
    129   @param[in]  Context               The UDP_RX_TOKEN.
    130 
    131 **/
    132 VOID
    133 EFIAPI
    134 UdpIoRecycleDgram (
    135   IN VOID                   *Context
    136   )
    137 {
    138   UDP_RX_TOKEN              *RxToken;
    139 
    140   RxToken = (UDP_RX_TOKEN *) Context;
    141 
    142   if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
    143     gBS->SignalEvent (RxToken->Token.Udp4.Packet.RxData->RecycleSignal);
    144   } else if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION) {
    145     gBS->SignalEvent (RxToken->Token.Udp6.Packet.RxData->RecycleSignal);
    146   } else {
    147     ASSERT (FALSE);
    148   }
    149 
    150   UdpIoFreeRxToken (RxToken);
    151 }
    152 
    153 /**
    154   The event handle for UDP receive request.
    155 
    156   It will build a NET_BUF from the recieved UDP data, then deliver it
    157   to the receiver.
    158 
    159   @param[in]  Context               The UDP RX token.
    160 
    161 **/
    162 VOID
    163 EFIAPI
    164 UdpIoOnDgramRcvdDpc (
    165   IN VOID                   *Context
    166   )
    167 {
    168   EFI_STATUS                Status;
    169   VOID                      *Token;
    170   VOID                      *RxData;
    171   VOID                      *Session;
    172   UDP_RX_TOKEN              *RxToken;
    173   UDP_END_POINT             EndPoint;
    174   NET_BUF                   *Netbuf;
    175 
    176   RxToken = (UDP_RX_TOKEN *) Context;
    177 
    178   ZeroMem (&EndPoint, sizeof(UDP_END_POINT));
    179 
    180   ASSERT ((RxToken->Signature == UDP_IO_RX_SIGNATURE) &&
    181           (RxToken == RxToken->UdpIo->RecvRequest));
    182 
    183   ASSERT ((RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
    184           (RxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
    185 
    186   //
    187   // Clear the receive request first in case that the caller
    188   // wants to restart the receive in the callback.
    189   //
    190   RxToken->UdpIo->RecvRequest = NULL;
    191 
    192   if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
    193     Token  = &RxToken->Token.Udp4;
    194     RxData = ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Packet.RxData;
    195     Status = ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Status;
    196   } else {
    197     Token  = &RxToken->Token.Udp6;
    198     RxData = ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Packet.RxData;
    199     Status = ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Status;
    200   }
    201 
    202   if (EFI_ERROR (Status) || RxData == NULL) {
    203     if (Status != EFI_ABORTED) {
    204       //
    205       // Invoke the CallBack only if the reception is not actively aborted.
    206       //
    207       RxToken->CallBack (NULL, NULL, Status, RxToken->Context);
    208     }
    209 
    210     UdpIoFreeRxToken (RxToken);
    211     return;
    212   }
    213 
    214   //
    215   // Build a NET_BUF from the UDP receive data, then deliver it up.
    216   //
    217   if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
    218     if (((EFI_UDP4_RECEIVE_DATA *) RxData)->DataLength == 0) {
    219       //
    220       // Discard zero length data payload packet.
    221       //
    222       goto Resume;
    223     }
    224 
    225     Netbuf = NetbufFromExt (
    226                (NET_FRAGMENT *)((EFI_UDP4_RECEIVE_DATA *) RxData)->FragmentTable,
    227                ((EFI_UDP4_RECEIVE_DATA *) RxData)->FragmentCount,
    228                0,
    229                (UINT32) RxToken->HeadLen,
    230                UdpIoRecycleDgram,
    231                RxToken
    232                );
    233 
    234     if (Netbuf == NULL) {
    235       gBS->SignalEvent (((EFI_UDP4_RECEIVE_DATA *) RxData)->RecycleSignal);
    236       RxToken->CallBack (NULL, NULL, EFI_OUT_OF_RESOURCES, RxToken->Context);
    237 
    238       UdpIoFreeRxToken (RxToken);
    239       return;
    240     }
    241 
    242     Session             = &((EFI_UDP4_RECEIVE_DATA *) RxData)->UdpSession;
    243     EndPoint.LocalPort  = ((EFI_UDP4_SESSION_DATA *) Session)->DestinationPort;
    244     EndPoint.RemotePort = ((EFI_UDP4_SESSION_DATA *) Session)->SourcePort;
    245 
    246     CopyMem (
    247       &EndPoint.LocalAddr,
    248       &((EFI_UDP4_SESSION_DATA *) Session)->DestinationAddress,
    249       sizeof (EFI_IPv4_ADDRESS)
    250       );
    251 
    252     CopyMem (
    253       &EndPoint.RemoteAddr,
    254       &((EFI_UDP4_SESSION_DATA *) Session)->SourceAddress,
    255       sizeof (EFI_IPv4_ADDRESS)
    256       );
    257 
    258     EndPoint.LocalAddr.Addr[0]  = NTOHL (EndPoint.LocalAddr.Addr[0]);
    259     EndPoint.RemoteAddr.Addr[0] = NTOHL (EndPoint.RemoteAddr.Addr[0]);
    260   } else {
    261     if (((EFI_UDP6_RECEIVE_DATA *) RxData)->DataLength == 0) {
    262       //
    263       // Discard zero length data payload packet.
    264       //
    265       goto Resume;
    266     }
    267 
    268     Netbuf = NetbufFromExt (
    269                (NET_FRAGMENT *)((EFI_UDP6_RECEIVE_DATA *) RxData)->FragmentTable,
    270                ((EFI_UDP6_RECEIVE_DATA *) RxData)->FragmentCount,
    271                0,
    272                (UINT32) RxToken->HeadLen,
    273                UdpIoRecycleDgram,
    274                RxToken
    275                );
    276 
    277     if (Netbuf == NULL) {
    278       gBS->SignalEvent (((EFI_UDP6_RECEIVE_DATA *) RxData)->RecycleSignal);
    279       RxToken->CallBack (NULL, NULL, EFI_OUT_OF_RESOURCES, RxToken->Context);
    280 
    281       UdpIoFreeRxToken (RxToken);
    282       return;
    283     }
    284 
    285     Session             = &((EFI_UDP6_RECEIVE_DATA *) RxData)->UdpSession;
    286     EndPoint.LocalPort  = ((EFI_UDP6_SESSION_DATA *) Session)->DestinationPort;
    287     EndPoint.RemotePort = ((EFI_UDP6_SESSION_DATA *) Session)->SourcePort;
    288 
    289     CopyMem (
    290       &EndPoint.LocalAddr,
    291       &((EFI_UDP6_SESSION_DATA *) Session)->DestinationAddress,
    292       sizeof (EFI_IPv6_ADDRESS)
    293       );
    294 
    295     CopyMem (
    296       &EndPoint.RemoteAddr,
    297       &((EFI_UDP6_SESSION_DATA *) Session)->SourceAddress,
    298       sizeof (EFI_IPv6_ADDRESS)
    299       );
    300 
    301     Ip6Swap128 (&EndPoint.LocalAddr.v6);
    302     Ip6Swap128 (&EndPoint.RemoteAddr.v6);
    303   }
    304 
    305   RxToken->CallBack (Netbuf, &EndPoint, EFI_SUCCESS, RxToken->Context);
    306   return;
    307 
    308 Resume:
    309   if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
    310     gBS->SignalEvent (((EFI_UDP4_RECEIVE_DATA *) RxData)->RecycleSignal);
    311     RxToken->UdpIo->Protocol.Udp4->Receive (RxToken->UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);
    312   } else {
    313     gBS->SignalEvent (((EFI_UDP6_RECEIVE_DATA *) RxData)->RecycleSignal);
    314     RxToken->UdpIo->Protocol.Udp6->Receive (RxToken->UdpIo->Protocol.Udp6, &RxToken->Token.Udp6);
    315   }
    316 }
    317 
    318 /**
    319   Request UdpIoOnDgramRcvdDpc() as a DPC at TPL_CALLBACK.
    320 
    321   @param[in]  Event                 The UDP receive request event.
    322   @param[in]  Context               The UDP RX token.
    323 
    324 **/
    325 VOID
    326 EFIAPI
    327 UdpIoOnDgramRcvd (
    328   IN EFI_EVENT              Event,
    329   IN VOID                   *Context
    330   )
    331 {
    332   //
    333   // Request UdpIoOnDgramRcvdDpc as a DPC at TPL_CALLBACK
    334   //
    335   QueueDpc (TPL_CALLBACK, UdpIoOnDgramRcvdDpc, Context);
    336 }
    337 
    338 /**
    339   Create a UDP_RX_TOKEN to wrap the request.
    340 
    341   @param[in]  UdpIo                 The UdpIo to receive packets from.
    342   @param[in]  CallBack              The function to call when receive finished.
    343   @param[in]  Context               The opaque parameter to the CallBack.
    344   @param[in]  HeadLen               The head length to reserver for the packet.
    345 
    346   @return The Wrapped request or NULL if failed to allocate resources or some errors happened.
    347 
    348 **/
    349 UDP_RX_TOKEN *
    350 UdpIoCreateRxToken (
    351   IN UDP_IO                 *UdpIo,
    352   IN UDP_IO_CALLBACK        CallBack,
    353   IN VOID                   *Context,
    354   IN UINT32                 HeadLen
    355   )
    356 {
    357   UDP_RX_TOKEN              *Token;
    358   EFI_STATUS                Status;
    359 
    360   ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
    361           (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
    362 
    363   Token = AllocatePool (sizeof (UDP_RX_TOKEN));
    364 
    365   if (Token == NULL) {
    366     return NULL;
    367   }
    368 
    369   Token->Signature              = UDP_IO_RX_SIGNATURE;
    370   Token->UdpIo                  = UdpIo;
    371   Token->CallBack               = CallBack;
    372   Token->Context                = Context;
    373   Token->HeadLen                = HeadLen;
    374 
    375   if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
    376 
    377     Token->Token.Udp4.Status        = EFI_NOT_READY;
    378     Token->Token.Udp4.Packet.RxData = NULL;
    379 
    380     Status = gBS->CreateEvent (
    381                     EVT_NOTIFY_SIGNAL,
    382                     TPL_NOTIFY,
    383                     UdpIoOnDgramRcvd,
    384                     Token,
    385                     &Token->Token.Udp4.Event
    386                     );
    387     } else {
    388 
    389     Token->Token.Udp6.Status        = EFI_NOT_READY;
    390     Token->Token.Udp6.Packet.RxData = NULL;
    391 
    392     Status = gBS->CreateEvent (
    393                     EVT_NOTIFY_SIGNAL,
    394                     TPL_NOTIFY,
    395                     UdpIoOnDgramRcvd,
    396                     Token,
    397                     &Token->Token.Udp6.Event
    398                     );
    399   }
    400 
    401 
    402   if (EFI_ERROR (Status)) {
    403     FreePool (Token);
    404     return NULL;
    405   }
    406 
    407   return Token;
    408 }
    409 
    410 /**
    411   Wrap a transmit request into a new created UDP_TX_TOKEN.
    412 
    413   @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 *
    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
    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
    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
    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
    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
    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
    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
   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
   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