Home | History | Annotate | Download | only in Udp4Dxe
      1 /** @file
      2 
      3 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
      4 Copyright (c) 2006 - 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
      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 
     15 #include "Udp4Impl.h"
     16 
     17 EFI_UDP4_PROTOCOL  mUdp4Protocol = {
     18   Udp4GetModeData,
     19   Udp4Configure,
     20   Udp4Groups,
     21   Udp4Routes,
     22   Udp4Transmit,
     23   Udp4Receive,
     24   Udp4Cancel,
     25   Udp4Poll
     26 };
     27 
     28 
     29 /**
     30   Reads the current operational settings.
     31 
     32   The GetModeData() function copies the current operational settings of this EFI
     33   UDPv4 Protocol instance into user-supplied buffers. This function is used
     34   optionally to retrieve the operational mode data of underlying networks or
     35   drivers.
     36 
     37   @param[in]  This              Pointer to the EFI_UDP4_PROTOCOL instance.
     38   @param[out] Udp4ConfigData    Pointer to the buffer to receive the current configuration data.
     39   @param[out] Ip4ModeData       Pointer to the EFI IPv4 Protocol mode data structure.
     40   @param[out] MnpConfigData     Pointer to the managed network configuration data structure.
     41   @param[out] SnpModeData       Pointer to the simple network mode data structure.
     42 
     43   @retval EFI_SUCCESS           The mode data was read.
     44   @retval EFI_NOT_STARTED       When Udp4ConfigData is queried, no configuration data is
     45                                 available because this instance has not been started.
     46   @retval EFI_INVALID_PARAMETER This is NULL.
     47 
     48 **/
     49 EFI_STATUS
     50 EFIAPI
     51 Udp4GetModeData (
     52   IN  EFI_UDP4_PROTOCOL                *This,
     53   OUT EFI_UDP4_CONFIG_DATA             *Udp4ConfigData OPTIONAL,
     54   OUT EFI_IP4_MODE_DATA                *Ip4ModeData    OPTIONAL,
     55   OUT EFI_MANAGED_NETWORK_CONFIG_DATA  *MnpConfigData  OPTIONAL,
     56   OUT EFI_SIMPLE_NETWORK_MODE          *SnpModeData    OPTIONAL
     57   )
     58 {
     59   UDP4_INSTANCE_DATA  *Instance;
     60   EFI_IP4_PROTOCOL    *Ip;
     61   EFI_TPL             OldTpl;
     62   EFI_STATUS          Status;
     63 
     64   if (This == NULL) {
     65     return EFI_INVALID_PARAMETER;
     66   }
     67 
     68   Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);
     69 
     70   if (!Instance->Configured && (Udp4ConfigData != NULL)) {
     71     return EFI_NOT_STARTED;
     72   }
     73 
     74   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
     75 
     76   if (Udp4ConfigData != NULL) {
     77     //
     78     // Set the Udp4ConfigData.
     79     //
     80     CopyMem (Udp4ConfigData, &Instance->ConfigData, sizeof (*Udp4ConfigData));
     81   }
     82 
     83   Ip = Instance->IpInfo->Ip.Ip4;
     84 
     85   //
     86   // Get the underlying Ip4ModeData, MnpConfigData and SnpModeData.
     87   //
     88   Status = Ip->GetModeData (Ip, Ip4ModeData, MnpConfigData, SnpModeData);
     89 
     90   gBS->RestoreTPL (OldTpl);
     91 
     92   return Status;
     93 }
     94 
     95 
     96 /**
     97   Initializes, changes, or resets the operational parameters for this instance of the EFI UDPv4
     98   Protocol.
     99 
    100   The Configure() function is used to do the following:
    101   * Initialize and start this instance of the EFI UDPv4 Protocol.
    102   * Change the filtering rules and operational parameters.
    103   * Reset this instance of the EFI UDPv4 Protocol.
    104   Until these parameters are initialized, no network traffic can be sent or
    105   received by this instance. This instance can be also reset by calling Configure()
    106   with UdpConfigData set to NULL. Once reset, the receiving queue and transmitting
    107   queue are flushed and no traffic is allowed through this instance.
    108   With different parameters in UdpConfigData, Configure() can be used to bind
    109   this instance to specified port.
    110 
    111   @param[in]  This              Pointer to the EFI_UDP4_PROTOCOL instance.
    112   @param[in]  UdpConfigData     Pointer to the buffer to receive the current configuration data.
    113 
    114   @retval EFI_SUCCESS           The configuration settings were set, changed, or reset successfully.
    115   @retval EFI_NO_MAPPING        When using a default address, configuration (DHCP, BOOTP,
    116                                 RARP, etc.) is not finished yet.
    117   @retval EFI_INVALID_PARAMETER One or more following conditions are TRUE:
    118   @retval EFI_ALREADY_STARTED   The EFI UDPv4 Protocol instance is already started/configured
    119                                 and must be stopped/reset before it can be reconfigured.
    120   @retval EFI_ACCESS_DENIED     UdpConfigData. AllowDuplicatePort is FALSE
    121                                 and UdpConfigData.StationPort is already used by
    122                                 other instance.
    123   @retval EFI_OUT_OF_RESOURCES  The EFI UDPv4 Protocol driver cannot allocate memory for this
    124                                 EFI UDPv4 Protocol instance.
    125   @retval EFI_DEVICE_ERROR      An unexpected network or system error occurred and this instance
    126                                  was not opened.
    127 
    128 **/
    129 EFI_STATUS
    130 EFIAPI
    131 Udp4Configure (
    132   IN EFI_UDP4_PROTOCOL     *This,
    133   IN EFI_UDP4_CONFIG_DATA  *UdpConfigData OPTIONAL
    134   )
    135 {
    136   EFI_STATUS           Status;
    137   UDP4_INSTANCE_DATA   *Instance;
    138   UDP4_SERVICE_DATA    *Udp4Service;
    139   EFI_TPL              OldTpl;
    140   IP4_ADDR             StationAddress;
    141   IP4_ADDR             SubnetMask;
    142   IP4_ADDR             RemoteAddress;
    143   EFI_IP4_CONFIG_DATA  Ip4ConfigData;
    144   IP4_ADDR             LocalAddr;
    145   IP4_ADDR             RemoteAddr;
    146 
    147   if (This == NULL) {
    148     return EFI_INVALID_PARAMETER;
    149   }
    150 
    151   Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);
    152 
    153   if (!Instance->Configured && (UdpConfigData == NULL)) {
    154     return EFI_SUCCESS;
    155   }
    156 
    157   Udp4Service = Instance->Udp4Service;
    158   Status      = EFI_SUCCESS;
    159 
    160   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    161 
    162   if (UdpConfigData != NULL) {
    163 
    164     CopyMem (&StationAddress, &UdpConfigData->StationAddress, sizeof (IP4_ADDR));
    165     CopyMem (&SubnetMask, &UdpConfigData->SubnetMask, sizeof (IP4_ADDR));
    166     CopyMem (&RemoteAddress, &UdpConfigData->RemoteAddress, sizeof (IP4_ADDR));
    167 
    168     StationAddress = NTOHL (StationAddress);
    169     SubnetMask     = NTOHL (SubnetMask);
    170     RemoteAddress  = NTOHL (RemoteAddress);
    171 
    172 
    173     if (!UdpConfigData->UseDefaultAddress &&
    174         (!IP4_IS_VALID_NETMASK (SubnetMask) ||
    175          !((StationAddress == 0) || NetIp4IsUnicast (StationAddress, SubnetMask)) ||
    176          IP4_IS_LOCAL_BROADCAST (RemoteAddress))) {
    177       //
    178       // Don't use default address, and subnet mask is invalid or StationAddress is not
    179       // a valid unicast IPv4 address or RemoteAddress is not a valid unicast IPv4 address
    180       // if it is not 0.
    181       //
    182       Status = EFI_INVALID_PARAMETER;
    183       goto ON_EXIT;
    184     }
    185 
    186     if (Instance->Configured) {
    187       //
    188       // The instance is already configured, try to do the re-configuration.
    189       //
    190       if (!Udp4IsReconfigurable (&Instance->ConfigData, UdpConfigData)) {
    191         //
    192         // If the new configuration data wants to change some unreconfigurable
    193         // settings, return EFI_ALREADY_STARTED.
    194         //
    195         Status = EFI_ALREADY_STARTED;
    196         goto ON_EXIT;
    197       }
    198 
    199       //
    200       // Save the reconfigurable parameters.
    201       //
    202       Instance->ConfigData.TypeOfService   = UdpConfigData->TypeOfService;
    203       Instance->ConfigData.TimeToLive      = UdpConfigData->TimeToLive;
    204       Instance->ConfigData.DoNotFragment   = UdpConfigData->DoNotFragment;
    205       Instance->ConfigData.ReceiveTimeout  = UdpConfigData->ReceiveTimeout;
    206       Instance->ConfigData.TransmitTimeout = UdpConfigData->TransmitTimeout;
    207     } else {
    208       //
    209       // Construct the Ip configuration data from the UdpConfigData.
    210       //
    211       Udp4BuildIp4ConfigData (UdpConfigData, &Ip4ConfigData);
    212 
    213       //
    214       // Configure the Ip instance wrapped in the IpInfo.
    215       //
    216       Status = IpIoConfigIp (Instance->IpInfo, &Ip4ConfigData);
    217       if (EFI_ERROR (Status)) {
    218         if (Status == EFI_NO_MAPPING) {
    219           Instance->IsNoMapping = TRUE;
    220         }
    221 
    222         goto ON_EXIT;
    223       }
    224 
    225       Instance->IsNoMapping = FALSE;
    226 
    227       //
    228       // Save the configuration data.
    229       //
    230       CopyMem (&Instance->ConfigData, UdpConfigData, sizeof (Instance->ConfigData));
    231       IP4_COPY_ADDRESS (&Instance->ConfigData.StationAddress, &Ip4ConfigData.StationAddress);
    232       IP4_COPY_ADDRESS (&Instance->ConfigData.SubnetMask, &Ip4ConfigData.SubnetMask);
    233 
    234       //
    235       // Try to allocate the required port resource.
    236       //
    237       Status = Udp4Bind (&Udp4Service->ChildrenList, &Instance->ConfigData);
    238       if (EFI_ERROR (Status)) {
    239         //
    240         // Reset the ip instance if bind fails.
    241         //
    242         IpIoConfigIp (Instance->IpInfo, NULL);
    243         goto ON_EXIT;
    244       }
    245 
    246       //
    247       // Pre calculate the checksum for the pseudo head, ignore the UDP length first.
    248       //
    249       CopyMem (&LocalAddr, &Instance->ConfigData.StationAddress, sizeof (IP4_ADDR));
    250       CopyMem (&RemoteAddr, &Instance->ConfigData.RemoteAddress, sizeof (IP4_ADDR));
    251       Instance->HeadSum = NetPseudoHeadChecksum (
    252                             LocalAddr,
    253                             RemoteAddr,
    254                             EFI_IP_PROTO_UDP,
    255                             0
    256                             );
    257 
    258       Instance->Configured = TRUE;
    259     }
    260   } else {
    261     //
    262     // UdpConfigData is NULL, reset the instance.
    263     //
    264     Instance->Configured  = FALSE;
    265     Instance->IsNoMapping = FALSE;
    266 
    267     //
    268     // Reset the Ip instance wrapped in the IpInfo.
    269     //
    270     IpIoConfigIp (Instance->IpInfo, NULL);
    271 
    272     //
    273     // Cancel all the user tokens.
    274     //
    275     Instance->Udp4Proto.Cancel (&Instance->Udp4Proto, NULL);
    276 
    277     //
    278     // Remove the buffered RxData for this instance.
    279     //
    280     Udp4FlushRcvdDgram (Instance);
    281 
    282     ASSERT (IsListEmpty (&Instance->DeliveredDgramQue));
    283   }
    284 
    285 ON_EXIT:
    286 
    287   gBS->RestoreTPL (OldTpl);
    288 
    289   return Status;
    290 }
    291 
    292 
    293 /**
    294   Joins and leaves multicast groups.
    295 
    296   The Groups() function is used to enable and disable the multicast group
    297   filtering. If the JoinFlag is FALSE and the MulticastAddress is NULL, then all
    298   currently joined groups are left.
    299 
    300   @param[in]  This              Pointer to the EFI_UDP4_PROTOCOL instance.
    301   @param[in]  JoinFlag          Set to TRUE to join a multicast group. Set to FALSE to leave one
    302                                 or all multicast groups.
    303   @param[in]  MulticastAddress  Pointer to multicast group address to join or leave.
    304 
    305   @retval EFI_SUCCESS           The operation completed successfully.
    306   @retval EFI_NOT_STARTED       The EFI UDPv4 Protocol instance has not been started.
    307   @retval EFI_NO_MAPPING        When using a default address, configuration (DHCP, BOOTP,
    308                                 RARP, etc.) is not finished yet.
    309   @retval EFI_OUT_OF_RESOURCES  Could not allocate resources to join the group.
    310   @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
    311                                 - This is NULL.
    312                                 - JoinFlag is TRUE and MulticastAddress is NULL.
    313                                 - JoinFlag is TRUE and *MulticastAddress is not
    314                                   a valid multicast address.
    315   @retval EFI_ALREADY_STARTED   The group address is already in the group table (when
    316                                 JoinFlag is TRUE).
    317   @retval EFI_NOT_FOUND         The group address is not in the group table (when JoinFlag is
    318                                 FALSE).
    319   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
    320 
    321 **/
    322 EFI_STATUS
    323 EFIAPI
    324 Udp4Groups (
    325   IN EFI_UDP4_PROTOCOL  *This,
    326   IN BOOLEAN            JoinFlag,
    327   IN EFI_IPv4_ADDRESS   *MulticastAddress OPTIONAL
    328   )
    329 {
    330   EFI_STATUS          Status;
    331   UDP4_INSTANCE_DATA  *Instance;
    332   EFI_IP4_PROTOCOL    *Ip;
    333   EFI_TPL             OldTpl;
    334   IP4_ADDR            McastIp;
    335 
    336   if ((This == NULL) || (JoinFlag && (MulticastAddress == NULL))) {
    337     return EFI_INVALID_PARAMETER;
    338   }
    339 
    340   McastIp = 0;
    341   if (JoinFlag) {
    342     CopyMem (&McastIp, MulticastAddress, sizeof (IP4_ADDR));
    343 
    344     if (!IP4_IS_MULTICAST (NTOHL (McastIp))) {
    345       return EFI_INVALID_PARAMETER;
    346     }
    347   }
    348 
    349   Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);
    350 
    351   if (Instance->IsNoMapping) {
    352     return EFI_NO_MAPPING;
    353   }
    354 
    355   if (!Instance->Configured) {
    356     return EFI_NOT_STARTED;
    357   }
    358 
    359   Ip = Instance->IpInfo->Ip.Ip4;
    360 
    361   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    362 
    363   //
    364   // Invoke the Ip instance the Udp4 instance consumes to do the group operation.
    365   //
    366   Status = Ip->Groups (Ip, JoinFlag, MulticastAddress);
    367 
    368   if (EFI_ERROR (Status)) {
    369     goto ON_EXIT;
    370   }
    371 
    372   //
    373   // Keep a local copy of the configured multicast IPs because IpIo receives
    374   // datagrams from the 0 station address IP instance and then UDP delivers to
    375   // the matched instance. This copy of multicast IPs is used to avoid receive
    376   // the mutlicast datagrams destined to multicast IPs the other instances configured.
    377   //
    378   if (JoinFlag) {
    379 
    380     NetMapInsertTail (&Instance->McastIps, (VOID *) (UINTN) McastIp, NULL);
    381   } else {
    382 
    383     NetMapIterate (&Instance->McastIps, Udp4LeaveGroup, MulticastAddress);
    384   }
    385 
    386 ON_EXIT:
    387 
    388   gBS->RestoreTPL (OldTpl);
    389 
    390   return Status;
    391 }
    392 
    393 
    394 /**
    395   Adds and deletes routing table entries.
    396 
    397   The Routes() function adds a route to or deletes a route from the routing table.
    398   Routes are determined by comparing the SubnetAddress with the destination IP
    399   address and arithmetically AND-ing it with the SubnetMask. The gateway address
    400   must be on the same subnet as the configured station address.
    401   The default route is added with SubnetAddress and SubnetMask both set to 0.0.0.0.
    402   The default route matches all destination IP addresses that do not match any
    403   other routes.
    404   A zero GatewayAddress is a nonroute. Packets are sent to the destination IP
    405   address if it can be found in the Address Resolution Protocol (ARP) cache or
    406   on the local subnet. One automatic nonroute entry will be inserted into the
    407   routing table for outgoing packets that are addressed to a local subnet
    408   (gateway address of 0.0.0.0).
    409   Each instance of the EFI UDPv4 Protocol has its own independent routing table.
    410   Instances of the EFI UDPv4 Protocol that use the default IP address will also
    411   have copies of the routing table provided by the EFI_IP4_CONFIG_PROTOCOL. These
    412   copies will be updated automatically whenever the IP driver reconfigures its
    413   instances; as a result, the previous modification to these copies will be lost.
    414 
    415   @param[in]  This              Pointer to the EFI_UDP4_PROTOCOL instance.
    416   @param[in]  DeleteRoute       Set to TRUE to delete this route from the routing table.
    417                                 Set to FALSE to add this route to the routing table.
    418   @param[in]  SubnetAddress     The destination network address that needs to be routed.
    419   @param[in]  SubnetMask        The subnet mask of SubnetAddress.
    420   @param[in]  GatewayAddress    The gateway IP address for this route.
    421 
    422   @retval EFI_SUCCESS           The operation completed successfully.
    423   @retval EFI_NOT_STARTED       The EFI UDPv4 Protocol instance has not been started.
    424   @retval EFI_NO_MAPPING        When using a default address, configuration (DHCP, BOOTP,
    425                                 - RARP, etc.) is not finished yet.
    426   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
    427   @retval EFI_OUT_OF_RESOURCES  Could not add the entry to the routing table.
    428   @retval EFI_NOT_FOUND         This route is not in the routing table.
    429   @retval EFI_ACCESS_DENIED     The route is already defined in the routing table.
    430 
    431 **/
    432 EFI_STATUS
    433 EFIAPI
    434 Udp4Routes (
    435   IN EFI_UDP4_PROTOCOL  *This,
    436   IN BOOLEAN            DeleteRoute,
    437   IN EFI_IPv4_ADDRESS   *SubnetAddress,
    438   IN EFI_IPv4_ADDRESS   *SubnetMask,
    439   IN EFI_IPv4_ADDRESS   *GatewayAddress
    440   )
    441 {
    442   UDP4_INSTANCE_DATA  *Instance;
    443   EFI_IP4_PROTOCOL    *Ip;
    444 
    445   if (This == NULL) {
    446     return EFI_INVALID_PARAMETER;
    447   }
    448 
    449   Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);
    450 
    451   if (Instance->IsNoMapping) {
    452     return EFI_NO_MAPPING;
    453   }
    454 
    455   if (!Instance->Configured) {
    456     return EFI_NOT_STARTED;
    457   }
    458 
    459   Ip = Instance->IpInfo->Ip.Ip4;
    460 
    461   //
    462   // Invoke the Ip instance the Udp4 instance consumes to do the actual operation.
    463   //
    464   return Ip->Routes (Ip, DeleteRoute, SubnetAddress, SubnetMask, GatewayAddress);
    465 }
    466 
    467 
    468 /**
    469   Queues outgoing data packets into the transmit queue.
    470 
    471   The Transmit() function places a sending request to this instance of the EFI
    472   UDPv4 Protocol, alongside the transmit data that was filled by the user. Whenever
    473   the packet in the token is sent out or some errors occur, the Token.Event will
    474   be signaled and Token.Status is updated. Providing a proper notification function
    475   and context for the event will enable the user to receive the notification and
    476   transmitting status.
    477 
    478   @param[in]  This              Pointer to the EFI_UDP4_PROTOCOL instance.
    479   @param[in]  Token             Pointer to the completion token that will be placed into the
    480                                 transmit queue.
    481 
    482   @retval EFI_SUCCESS           The data has been queued for transmission.
    483   @retval EFI_NOT_STARTED       This EFI UDPv4 Protocol instance has not been started.
    484   @retval EFI_NO_MAPPING        When using a default address, configuration (DHCP, BOOTP,
    485                                 RARP, etc.) is not finished yet.
    486   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
    487   @retval EFI_ACCESS_DENIED     The transmit completion token with the same
    488                                 Token.Event was already in the transmit queue.
    489   @retval EFI_NOT_READY         The completion token could not be queued because the
    490                                 transmit queue is full.
    491   @retval EFI_OUT_OF_RESOURCES  Could not queue the transmit data.
    492   @retval EFI_NOT_FOUND         There is no route to the destination network or address.
    493   @retval EFI_BAD_BUFFER_SIZE   The data length is greater than the maximum UDP packet
    494                                 size. Or the length of the IP header + UDP header + data
    495                                 length is greater than MTU if DoNotFragment is TRUE.
    496 
    497 **/
    498 EFI_STATUS
    499 EFIAPI
    500 Udp4Transmit (
    501   IN EFI_UDP4_PROTOCOL          *This,
    502   IN EFI_UDP4_COMPLETION_TOKEN  *Token
    503   )
    504 {
    505   EFI_STATUS              Status;
    506   UDP4_INSTANCE_DATA      *Instance;
    507   EFI_TPL                 OldTpl;
    508   NET_BUF                 *Packet;
    509   EFI_UDP_HEADER         *Udp4Header;
    510   EFI_UDP4_CONFIG_DATA    *ConfigData;
    511   IP4_ADDR                Source;
    512   IP4_ADDR                Destination;
    513   EFI_UDP4_TRANSMIT_DATA  *TxData;
    514   EFI_UDP4_SESSION_DATA   *UdpSessionData;
    515   UDP4_SERVICE_DATA       *Udp4Service;
    516   IP_IO_OVERRIDE          Override;
    517   UINT16                  HeadSum;
    518   EFI_IP_ADDRESS          IpDestAddr;
    519 
    520   if ((This == NULL) || (Token == NULL)) {
    521     return EFI_INVALID_PARAMETER;
    522   }
    523 
    524   Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);
    525 
    526   if (Instance->IsNoMapping) {
    527     return EFI_NO_MAPPING;
    528   }
    529 
    530   if (!Instance->Configured) {
    531     return EFI_NOT_STARTED;
    532   }
    533 
    534   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    535 
    536   //
    537   // Validate the Token, if the token is invalid return the error code.
    538   //
    539   Status = Udp4ValidateTxToken (Instance, Token);
    540   if (EFI_ERROR (Status)) {
    541     goto ON_EXIT;
    542   }
    543 
    544   if (EFI_ERROR (NetMapIterate (&Instance->TxTokens, Udp4TokenExist, Token)) ||
    545     EFI_ERROR (NetMapIterate (&Instance->RxTokens, Udp4TokenExist, Token))) {
    546     //
    547     // Try to find a duplicate token in the two token maps, if found, return
    548     // EFI_ACCESS_DENIED.
    549     //
    550     Status = EFI_ACCESS_DENIED;
    551     goto ON_EXIT;
    552   }
    553 
    554   TxData = Token->Packet.TxData;
    555 
    556   //
    557   // Create a net buffer to hold the user buffer and the udp header.
    558   //
    559   Packet = NetbufFromExt (
    560              (NET_FRAGMENT *)TxData->FragmentTable,
    561              TxData->FragmentCount,
    562              UDP4_HEADER_SIZE,
    563              0,
    564              Udp4NetVectorExtFree,
    565              NULL
    566              );
    567   if (Packet == NULL) {
    568     Status = EFI_OUT_OF_RESOURCES;
    569     goto ON_EXIT;
    570   }
    571 
    572   //
    573   // Store the IpIo in ProtoData.
    574   //
    575   Udp4Service = Instance->Udp4Service;
    576   *((UINTN *) &Packet->ProtoData[0]) = (UINTN) (Udp4Service->IpIo);
    577 
    578   Udp4Header = (EFI_UDP_HEADER *) NetbufAllocSpace (Packet, UDP4_HEADER_SIZE, TRUE);
    579   ASSERT (Udp4Header != NULL);
    580 
    581   ConfigData = &Instance->ConfigData;
    582 
    583   //
    584   // Fill the udp header.
    585   //
    586   Udp4Header->SrcPort      = HTONS (ConfigData->StationPort);
    587   Udp4Header->DstPort      = HTONS (ConfigData->RemotePort);
    588   Udp4Header->Length       = HTONS ((UINT16) Packet->TotalSize);
    589   Udp4Header->Checksum     = 0;
    590 
    591   UdpSessionData = TxData->UdpSessionData;
    592   IP4_COPY_ADDRESS (&Override.Ip4OverrideData.SourceAddress, &ConfigData->StationAddress);
    593 
    594   if (UdpSessionData != NULL) {
    595     //
    596     // Set the SourceAddress, SrcPort and Destination according to the specified
    597     // UdpSessionData.
    598     //
    599     if (!EFI_IP4_EQUAL (&UdpSessionData->SourceAddress, &mZeroIp4Addr)) {
    600       IP4_COPY_ADDRESS (&Override.Ip4OverrideData.SourceAddress, &UdpSessionData->SourceAddress);
    601     }
    602 
    603     if (UdpSessionData->SourcePort != 0) {
    604       Udp4Header->SrcPort = HTONS (UdpSessionData->SourcePort);
    605     }
    606 
    607     if (UdpSessionData->DestinationPort != 0) {
    608       Udp4Header->DstPort = HTONS (UdpSessionData->DestinationPort);
    609     }
    610 
    611     CopyMem (&Source, &Override.Ip4OverrideData.SourceAddress, sizeof (IP4_ADDR));
    612     CopyMem (&Destination, &UdpSessionData->DestinationAddress, sizeof (IP4_ADDR));
    613 
    614     //
    615     // calculate the pseudo head checksum using the overridden parameters.
    616     //
    617     HeadSum = NetPseudoHeadChecksum (
    618                 Source,
    619                 Destination,
    620                 EFI_IP_PROTO_UDP,
    621                 0
    622                 );
    623   } else {
    624     //
    625     // UdpSessionData is NULL, use the address and port information previously configured.
    626     //
    627     CopyMem (&Destination, &ConfigData->RemoteAddress, sizeof (IP4_ADDR));
    628 
    629     HeadSum = Instance->HeadSum;
    630   }
    631 
    632   //
    633   // calculate the checksum.
    634   //
    635   Udp4Header->Checksum = Udp4Checksum (Packet, HeadSum);
    636   if (Udp4Header->Checksum == 0) {
    637     //
    638     // If the calculated checksum is 0, fill the Checksum field with all ones.
    639     //
    640     Udp4Header->Checksum = 0xffff;
    641   }
    642 
    643   //
    644   // Fill the IpIo Override data.
    645   //
    646   if (TxData->GatewayAddress != NULL) {
    647     IP4_COPY_ADDRESS (&Override.Ip4OverrideData.GatewayAddress, TxData->GatewayAddress);
    648   } else {
    649     ZeroMem (&Override.Ip4OverrideData.GatewayAddress, sizeof (EFI_IPv4_ADDRESS));
    650   }
    651 
    652   Override.Ip4OverrideData.Protocol                 = EFI_IP_PROTO_UDP;
    653   Override.Ip4OverrideData.TypeOfService            = ConfigData->TypeOfService;
    654   Override.Ip4OverrideData.TimeToLive               = ConfigData->TimeToLive;
    655   Override.Ip4OverrideData.DoNotFragment            = ConfigData->DoNotFragment;
    656 
    657   //
    658   // Save the token into the TxToken map.
    659   //
    660   Status = NetMapInsertTail (&Instance->TxTokens, Token, Packet);
    661   if (EFI_ERROR (Status)) {
    662     goto FREE_PACKET;
    663   }
    664 
    665   //
    666   // Send out this datagram through IpIo.
    667   //
    668   IpDestAddr.Addr[0] = Destination;
    669   Status = IpIoSend (
    670              Udp4Service->IpIo,
    671              Packet,
    672              Instance->IpInfo,
    673              Instance,
    674              Token,
    675              &IpDestAddr,
    676              &Override
    677              );
    678   if (EFI_ERROR (Status)) {
    679     //
    680     // Remove this token from the TxTokens.
    681     //
    682     Udp4RemoveToken (&Instance->TxTokens, Token);
    683   }
    684 
    685 FREE_PACKET:
    686 
    687   NetbufFree (Packet);
    688 
    689 ON_EXIT:
    690 
    691   gBS->RestoreTPL (OldTpl);
    692 
    693   return Status;
    694 }
    695 
    696 
    697 /**
    698   Places an asynchronous receive request into the receiving queue.
    699 
    700   The Receive() function places a completion token into the receive packet queue.
    701   This function is always asynchronous.
    702   The caller must fill in the Token.Event field in the completion token, and this
    703   field cannot be NULL. When the receive operation completes, the EFI UDPv4 Protocol
    704   driver updates the Token.Status and Token.Packet.RxData fields and the Token.Event
    705   is signaled. Providing a proper notification function and context for the event
    706   will enable the user to receive the notification and receiving status. That
    707   notification function is guaranteed to not be re-entered.
    708 
    709   @param[in]  This              Pointer to the EFI_UDP4_PROTOCOL instance.
    710   @param[in]  Token             Pointer to a token that is associated with
    711                                 the receive data descriptor.
    712 
    713   @retval EFI_SUCCESS           The receive completion token was cached.
    714   @retval EFI_NOT_STARTED       This EFI UDPv4 Protocol instance has not been started.
    715   @retval EFI_NO_MAPPING        When using a default address, configuration (DHCP, BOOTP, RARP, etc.)
    716                                 is not finished yet.
    717   @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
    718   @retval EFI_OUT_OF_RESOURCES  The receive completion token could not be queued due to a lack of system
    719                                 resources (usually memory).
    720   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
    721   @retval EFI_ACCESS_DENIED     A receive completion token with the same Token.Event was already in
    722                                 the receive queue.
    723   @retval EFI_NOT_READY         The receive request could not be queued because the receive queue is full.
    724 
    725 **/
    726 EFI_STATUS
    727 EFIAPI
    728 Udp4Receive (
    729   IN EFI_UDP4_PROTOCOL          *This,
    730   IN EFI_UDP4_COMPLETION_TOKEN  *Token
    731   )
    732 {
    733   EFI_STATUS          Status;
    734   UDP4_INSTANCE_DATA  *Instance;
    735   EFI_TPL             OldTpl;
    736 
    737   if ((This == NULL) || (Token == NULL) || (Token->Event == NULL)) {
    738     return EFI_INVALID_PARAMETER;
    739   }
    740 
    741   Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);
    742 
    743   if (Instance->IsNoMapping) {
    744     return EFI_NO_MAPPING;
    745   }
    746 
    747   if (!Instance->Configured) {
    748     return EFI_NOT_STARTED;
    749   }
    750 
    751   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    752 
    753   if (EFI_ERROR (NetMapIterate (&Instance->RxTokens, Udp4TokenExist, Token))||
    754     EFI_ERROR (NetMapIterate (&Instance->TxTokens, Udp4TokenExist, Token))) {
    755     //
    756     // Return EFI_ACCESS_DENIED if the specified token is already in the TxTokens or
    757     // RxTokens map.
    758     //
    759     Status = EFI_ACCESS_DENIED;
    760     goto ON_EXIT;
    761   }
    762 
    763   Token->Packet.RxData = NULL;
    764 
    765   //
    766   // Save the token into the RxTokens map.
    767   //
    768   Status = NetMapInsertTail (&Instance->RxTokens, Token, NULL);
    769   if (EFI_ERROR (Status)) {
    770     Status = EFI_NOT_READY;
    771     goto ON_EXIT;
    772   }
    773 
    774   //
    775   // If there is an icmp error, report it.
    776   //
    777   Udp4ReportIcmpError (Instance);
    778 
    779   //
    780   // Try to deliver the received datagrams.
    781   //
    782   Udp4InstanceDeliverDgram (Instance);
    783 
    784   //
    785   // Dispatch the DPC queued by the NotifyFunction of Token->Event.
    786   //
    787   DispatchDpc ();
    788 
    789 ON_EXIT:
    790 
    791   gBS->RestoreTPL (OldTpl);
    792 
    793   return Status;
    794 }
    795 
    796 
    797 /**
    798   Aborts an asynchronous transmit or receive request.
    799 
    800   The Cancel() function is used to abort a pending transmit or receive request.
    801   If the token is in the transmit or receive request queues, after calling this
    802   function, Token.Status will be set to EFI_ABORTED and then Token.Event will be
    803   signaled. If the token is not in one of the queues, which usually means that
    804   the asynchronous operation has completed, this function will not signal the
    805   token and EFI_NOT_FOUND is returned.
    806 
    807   @param[in]  This  Pointer to the EFI_UDP4_PROTOCOL instance.
    808   @param[in]  Token Pointer to a token that has been issued by
    809                     EFI_UDP4_PROTOCOL.Transmit() or
    810                     EFI_UDP4_PROTOCOL.Receive().If NULL, all pending
    811                     tokens are aborted.
    812 
    813   @retval  EFI_SUCCESS           The asynchronous I/O request was aborted and Token.Event
    814                                  was signaled. When Token is NULL, all pending requests are
    815                                  aborted and their events are signaled.
    816   @retval  EFI_INVALID_PARAMETER This is NULL.
    817   @retval  EFI_NOT_STARTED       This instance has not been started.
    818   @retval  EFI_NO_MAPPING        When using the default address, configuration (DHCP, BOOTP,
    819                                  RARP, etc.) is not finished yet.
    820   @retval  EFI_NOT_FOUND         When Token is not NULL, the asynchronous I/O request was
    821                                  not found in the transmit or receive queue. It has either completed
    822                                  or was not issued by Transmit() and Receive().
    823 
    824 **/
    825 EFI_STATUS
    826 EFIAPI
    827 Udp4Cancel (
    828   IN EFI_UDP4_PROTOCOL          *This,
    829   IN EFI_UDP4_COMPLETION_TOKEN  *Token OPTIONAL
    830   )
    831 {
    832   EFI_STATUS          Status;
    833   UDP4_INSTANCE_DATA  *Instance;
    834   EFI_TPL             OldTpl;
    835 
    836   if (This == NULL) {
    837     return EFI_INVALID_PARAMETER;
    838   }
    839 
    840   Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);
    841 
    842   if (Instance->IsNoMapping) {
    843     return EFI_NO_MAPPING;
    844   }
    845 
    846   if (!Instance->Configured) {
    847     return EFI_NOT_STARTED;
    848   }
    849 
    850   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    851 
    852   //
    853   // Cancle the tokens specified by Token for this instance.
    854   //
    855   Status = Udp4InstanceCancelToken (Instance, Token);
    856 
    857   //
    858   // Dispatch the DPC queued by the NotifyFunction of the cancelled token's events.
    859   //
    860   DispatchDpc ();
    861 
    862   gBS->RestoreTPL (OldTpl);
    863 
    864   return Status;
    865 }
    866 
    867 
    868 /**
    869   Polls for incoming data packets and processes outgoing data packets.
    870 
    871   The Poll() function can be used by network drivers and applications to increase
    872   the rate that data packets are moved between the communications device and the
    873   transmit and receive queues.
    874   In some systems, the periodic timer event in the managed network driver may not
    875   poll the underlying communications device fast enough to transmit and/or receive
    876   all data packets without missing incoming packets or dropping outgoing packets.
    877   Drivers and applications that are experiencing packet loss should try calling
    878   the Poll() function more often.
    879 
    880   @param[in]  This  Pointer to the EFI_UDP4_PROTOCOL instance.
    881 
    882   @retval EFI_SUCCESS           Incoming or outgoing data was processed.
    883   @retval EFI_INVALID_PARAMETER This is NULL.
    884   @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
    885   @retval EFI_TIMEOUT           Data was dropped out of the transmit and/or receive queue.
    886 
    887 **/
    888 EFI_STATUS
    889 EFIAPI
    890 Udp4Poll (
    891   IN EFI_UDP4_PROTOCOL  *This
    892   )
    893 {
    894   UDP4_INSTANCE_DATA  *Instance;
    895   EFI_IP4_PROTOCOL    *Ip;
    896 
    897   if (This == NULL) {
    898     return EFI_INVALID_PARAMETER;
    899   }
    900 
    901   Instance = UDP4_INSTANCE_DATA_FROM_THIS (This);
    902   Ip       = Instance->IpInfo->Ip.Ip4;
    903 
    904   //
    905   // Invode the Ip instance consumed by the udp instance to do the poll operation.
    906   //
    907   return Ip->Poll (Ip);
    908 }
    909