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