udp4impl.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 2,114 行 · 第 1/4 页

C
2,114
字号
/*++

Copyright (c) 2006, Intel Corporation                                                         
All rights reserved. This program and the accompanying materials                          
are licensed and made available under the terms and conditions of the BSD License         
which accompanies this distribution.  The full text of the license may be found at        
http://opensource.org/licenses/bsd-license.php                                            
                                                                                          
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 

Module Name:

  Udp4Impl.c

Abstract:

  The implementation of the Udp4 protocol.

--*/

#include "Udp4Impl.h"

UINT16  mUdp4RandomPort;

STATIC
VOID
EFIAPI
Udp4CheckTimeout (
  IN EFI_EVENT  Event,
  IN VOID       *Context
  );

STATIC
BOOLEAN
Udp4FindInstanceByPort (
  IN NET_LIST_ENTRY    *InstanceList,
  IN EFI_IPv4_ADDRESS  *Address,
  IN UINT16            Port
  );

STATIC
VOID
Udp4DgramSent (
  IN EFI_STATUS  Status,
  IN VOID        *Context,
  IN VOID        *Sender,
  IN VOID        *NotifyData
  );

STATIC
VOID
Udp4DgramRcvd (
  IN EFI_STATUS            Status,
  IN ICMP_ERROR            IcmpError,
  IN EFI_NET_SESSION_DATA  *NetSession,
  IN NET_BUF               *Packet,
  IN VOID                  *Context
  );

STATIC
EFI_STATUS
Udp4CancelTokens (
  IN NET_MAP       *Map,
  IN NET_MAP_ITEM  *Item,
  IN VOID          *Arg OPTIONAL
  );

STATIC
BOOLEAN
Udp4MatchDgram (
  IN UDP4_INSTANCE_DATA     *Instance,
  IN EFI_UDP4_SESSION_DATA  *Udp4Session
  );

STATIC
VOID
EFIAPI
Udp4RecycleRxDataWrap (
  IN EFI_EVENT  Event,
  IN VOID       *Context
  );

STATIC
UDP4_RXDATA_WRAP *
Udp4WrapRxData (
  IN UDP4_INSTANCE_DATA     *Instance,
  IN NET_BUF                *Packet,
  IN EFI_UDP4_RECEIVE_DATA  *RxData
  );

STATIC
UINTN
Udp4EnqueueDgram (
  IN UDP4_SERVICE_DATA      *Udp4Service,
  IN NET_BUF                *Packet,
  IN EFI_UDP4_RECEIVE_DATA  *RxData
  );

STATIC
VOID
Udp4DeliverDgram (
  IN UDP4_SERVICE_DATA  *Udp4Service
  );

STATIC
VOID
Udp4Demultiplex (
  IN UDP4_SERVICE_DATA     *Udp4Service,
  IN EFI_NET_SESSION_DATA  *NetSession,
  IN NET_BUF               *Packet
  );

STATIC
VOID
Udp4IcmpHandler (
  IN UDP4_SERVICE_DATA     *Udp4Service,
  IN ICMP_ERROR            IcmpError,
  IN EFI_NET_SESSION_DATA  *NetSession,
  IN NET_BUF               *Packet
  );

STATIC
VOID
Udp4SendPortUnreach (
  IN IP_IO                 *IpIo,
  IN EFI_NET_SESSION_DATA  *NetSession,
  IN VOID                  *Udp4Header
  );

EFI_STATUS
Udp4CreateService (
  IN UDP4_SERVICE_DATA  *Udp4Service,
  IN EFI_HANDLE         ImageHandle,
  IN EFI_HANDLE         ControllerHandle
  )
/*++

Routine Description:

  Create the Udp service context data.

Arguments:

  Udp4Service      - Pointer to the UDP4_SERVICE_DATA.
  ImageHandle      - The image handle of this udp4 driver.
  ControllerHandle - The controller handle this udp4 driver binds on.

Returns:

  EFI_SUCCESS          - The udp4 service context data is created and initialized.
  EFI_OUT_OF_RESOURCES - Cannot allocate memory.

--*/
{
  EFI_STATUS       Status;
  IP_IO_OPEN_DATA  OpenData;

  Udp4Service->Signature        = UDP4_SERVICE_DATA_SIGNATURE;
  Udp4Service->ServiceBinding   = mUdp4ServiceBinding;
  Udp4Service->ImageHandle      = ImageHandle;
  Udp4Service->ControllerHandle = ControllerHandle;
  Udp4Service->ChildrenNumber   = 0;

  NetListInit (&Udp4Service->ChildrenList);

  //
  // Create the IpIo for this service context.
  //
  Udp4Service->IpIo = IpIoCreate (ImageHandle, ControllerHandle);
  if (Udp4Service->IpIo == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }

  //
  // Set the OpenData used to open the IpIo.
  //
  OpenData.IpConfigData                 = mIpIoDefaultIpConfigData;
  OpenData.IpConfigData.AcceptBroadcast = TRUE;
  OpenData.RcvdContext                  = (VOID *) Udp4Service;
  OpenData.SndContext                   = NULL;
  OpenData.PktRcvdNotify                = Udp4DgramRcvd;
  OpenData.PktSentNotify                = Udp4DgramSent;

  //
  // Configure and start the IpIo.
  //
  Status = IpIoOpen (Udp4Service->IpIo, &OpenData);
  if (EFI_ERROR (Status)) {
    goto RELEASE_IPIO;
  }

  //
  // Create the event for Udp timeout checking.
  //
  Status = gBS->CreateEvent (
                  EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL,
                  NET_TPL_FAST_TIMER,
                  Udp4CheckTimeout,
                  Udp4Service,
                  &Udp4Service->TimeoutEvent
                  );
  if (EFI_ERROR (Status)) {
    goto RELEASE_IPIO;
  }

  //
  // Start the timeout timer event.
  //
  Status = gBS->SetTimer (
                  Udp4Service->TimeoutEvent,
                  TimerPeriodic,
                  UDP4_TIMEOUT_INTERVAL
                  );
  if (EFI_ERROR (Status)) {
    goto RELEASE_ALL;
  }

  Udp4Service->MacString = NULL;

  return EFI_SUCCESS;

RELEASE_ALL:

  gBS->CloseEvent (Udp4Service->TimeoutEvent);

RELEASE_IPIO:

  IpIoDestroy (Udp4Service->IpIo);

  return Status;
}

VOID
Udp4CleanService (
  IN UDP4_SERVICE_DATA  *Udp4Service
  )
/*++

Routine Description:

  Clean the Udp service context data.

Arguments:

  Udp4Service - Pointer to the UDP4_SERVICE_DATA.

Returns:

  None.

--*/
{
  //
  // Cancel the TimeoutEvent timer.
  //
  gBS->SetTimer (Udp4Service->TimeoutEvent, TimerCancel, 0);

  //
  // Close the TimeoutEvent timer.
  //
  gBS->CloseEvent (Udp4Service->TimeoutEvent);

  //
  // Destroy the IpIo.
  //
  IpIoDestroy (Udp4Service->IpIo);
}

STATIC
VOID
EFIAPI
Udp4CheckTimeout (
  IN EFI_EVENT  Event,
  IN VOID       *Context
  )
/*++

Routine Description:

  This function checks and timeouts the I/O datagrams holding by the corresponding
  service context.

Arguments:

  Event  - The event this function registered to.
  Conext - The context data registered during the creation of the Event.

Returns:

  None.

--*/
{
  UDP4_SERVICE_DATA   *Udp4Service;
  NET_LIST_ENTRY      *Entry;
  UDP4_INSTANCE_DATA  *Instance;
  NET_LIST_ENTRY      *WrapEntry;
  NET_LIST_ENTRY      *NextEntry;
  UDP4_RXDATA_WRAP    *Wrap;

  Udp4Service = (UDP4_SERVICE_DATA *) Context;
  NET_CHECK_SIGNATURE (Udp4Service, UDP4_SERVICE_DATA_SIGNATURE);

  NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) {
    //
    // Iterate all the instances belonging to this service context.
    //
    Instance = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link);
    NET_CHECK_SIGNATURE (Instance, UDP4_INSTANCE_DATA_SIGNATURE);

    if (!Instance->Configured || (Instance->ConfigData.ReceiveTimeout == 0)) {
      //
      // Skip this instance if it's not configured or no receive timeout.
      //
      continue;
    }

    NET_LIST_FOR_EACH_SAFE (WrapEntry, NextEntry, &Instance->RcvdDgramQue) {
      //
      // Iterate all the rxdatas belonging to this udp instance.
      //
      Wrap = NET_LIST_USER_STRUCT (Entry, UDP4_RXDATA_WRAP, Link);

      if (Wrap->TimeoutTick <= UDP4_TIMEOUT_INTERVAL / 1000) {
        //
        // Remove this RxData if it timeouts.
        //
        Udp4RecycleRxDataWrap (NULL, (VOID *) Wrap);
      } else {
        Wrap->TimeoutTick -= UDP4_TIMEOUT_INTERVAL / 1000;
      }
    }
  }
}

VOID
Udp4InitInstance (
  IN UDP4_SERVICE_DATA   *Udp4Service,
  IN UDP4_INSTANCE_DATA  *Instance
  )
/*++

Routine Description:

  This function intializes the new created udp instance.

Arguments:

  Udp4Service - Pointer to the UDP4_SERVICE_DATA.
  Instance    - Pointer to the un-initialized UDP4_INSTANCE_DATA.

Returns:

  None.

--*/
{
  //
  // Set the signature.
  //
  Instance->Signature = UDP4_INSTANCE_DATA_SIGNATURE;

  //
  // Init the lists.
  //
  NetListInit (&Instance->Link);
  NetListInit (&Instance->RcvdDgramQue);
  NetListInit (&Instance->DeliveredDgramQue);

  //
  // Init the NET_MAPs.
  //
  NetMapInit (&Instance->TxTokens);
  NetMapInit (&Instance->RxTokens);
  NetMapInit (&Instance->McastIps);

  //
  // Save the pointer to the UDP4_SERVICE_DATA, and initialize other members.
  //
  Instance->Udp4Service = Udp4Service;
  Instance->Udp4Proto   = mUdp4Protocol;
  Instance->IcmpError   = EFI_SUCCESS;
  Instance->Configured  = FALSE;
  Instance->IsNoMapping = FALSE;
  Instance->Destroyed   = FALSE;
}

VOID
Udp4CleanInstance (
  IN UDP4_INSTANCE_DATA  *Instance
  )
/*++

Routine Description:

  This function cleans the udp instance.

Arguments:

  Instance  - Pointer to the UDP4_INSTANCE_DATA to clean.

Returns:

  None.

--*/
{
  NetMapClean (&Instance->McastIps);
  NetMapClean (&Instance->RxTokens);
  NetMapClean (&Instance->TxTokens);
}

STATIC
BOOLEAN
Udp4FindInstanceByPort (
  IN NET_LIST_ENTRY    *InstanceList,
  IN EFI_IPv4_ADDRESS  *Address,
  IN UINT16            Port
  )
/*++

Routine Description:

  This function finds the udp instance by the specified <Address, Port> pair.

Arguments:

  InstanceList - Pointer to the head of the list linking the udp instances.
  Address      - Pointer to the specified IPv4 address.
  Port         - The udp port number.

Returns:

  Is the specified <Address, Port> pair found or not.

--*/
{
  NET_LIST_ENTRY        *Entry;
  UDP4_INSTANCE_DATA    *Instance;
  EFI_UDP4_CONFIG_DATA  *ConfigData;

  NET_LIST_FOR_EACH (Entry, InstanceList) {
    //
    // Iterate all the udp instances.
    //
    Instance   = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link);
    ConfigData = &Instance->ConfigData;

    if (!Instance->Configured || ConfigData->AcceptAnyPort) {
      //
      // If the instance is not configured or the configdata of the instance indicates
      // this instance accepts any port, skip it.
      //
      continue;
    }

    if (EFI_IP_EQUAL (ConfigData->StationAddress, *Address) &&
      (ConfigData->StationPort == Port)) {
      //
      // if both the address and the port are the same, return TRUE.
      //
      return TRUE;
    }
  }

  //
  // return FALSE when matching fails.
  //
  return FALSE;
}

EFI_STATUS
Udp4Bind (
  IN NET_LIST_ENTRY        *InstanceList,   
  IN EFI_UDP4_CONFIG_DATA  *ConfigData
  )
/*++

Routine Description:

  This function tries to bind the udp instance according to the configured port 
  allocation stragety.

Arguments:

  InstanceList - Pointer to the head of the list linking the udp instances.
  ConfigData   - Pointer to the ConfigData of the instance to be bound.

Returns:

  EFI_SUCCESS          - The bound operation is completed successfully.
  EFI_ACCESS_DENIED    - The <Address, Port> specified by the ConfigData is already used
                         by other instance.
  EFI_OUT_OF_RESOURCES - No available port resources.

--*/
{
  EFI_IPv4_ADDRESS  *StationAddress;
  UINT16            StartPort;
  
  if (ConfigData->AcceptAnyPort) {
    return EFI_SUCCESS;
  }

  StationAddress = &ConfigData->StationAddress;

  if (ConfigData->StationPort != 0) {

    if (!ConfigData->AllowDuplicatePort &&
      Udp4FindInstanceByPort (InstanceList, StationAddress, ConfigData->StationPort)) {
      //
      // Do not allow duplicate port and the port is already used by other instance.
      //
      return EFI_ACCESS_DENIED;
    }
  } else {
    //
    // select a random port for this instance;
    //

    if (ConfigData->AllowDuplicatePort) {
      //
      // Just pick up the random port if the instance allows duplicate port.
      //
      ConfigData->StationPort = mUdp4RandomPort;
    } else {

      StartPort = mUdp4RandomPort;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?