mtftp4rrq.c

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

C
778
字号

STATIC
EFI_STATUS
Mtftp4RrqConfigMcastPort (
  IN UDP_IO_PORT            *McastIo,
  IN VOID                   *Context
  )
/*++

Routine Description:

  Configure a UDP IO port to receive the multicast. 

Arguments:

  McastIo - The UDP IO port to configure
  Context - The opaque parameter to the function which is the MTFTP session. 

Returns:

  EFI_SUCCESS - The udp child is successfully configured.
  Others      - Failed to configure the UDP child.

--*/
{
  MTFTP4_PROTOCOL           *Instance;
  EFI_MTFTP4_CONFIG_DATA    *Config;
  EFI_UDP4_CONFIG_DATA      UdpConfig;
  EFI_IPv4_ADDRESS          Group;
  EFI_STATUS                Status;

  Instance                     = (MTFTP4_PROTOCOL *) Context;
  Config                       = &Instance->Config;

  UdpConfig.AcceptBroadcast    = FALSE;
  UdpConfig.AcceptPromiscuous  = FALSE;
  UdpConfig.AcceptAnyPort      = FALSE;
  UdpConfig.AllowDuplicatePort = FALSE;
  UdpConfig.TypeOfService      = 0;
  UdpConfig.TimeToLive         = 64;
  UdpConfig.DoNotFragment      = FALSE;
  UdpConfig.ReceiveTimeout     = 0;
  UdpConfig.TransmitTimeout    = 0;
  UdpConfig.UseDefaultAddress  = Config->UseDefaultSetting;
  UdpConfig.StationAddress     = Config->StationIp;
  UdpConfig.SubnetMask         = Config->SubnetMask;
  UdpConfig.StationPort        = Instance->McastPort;
  UdpConfig.RemotePort         = 0;
  
  EFI_IP4 (UdpConfig.RemoteAddress) = HTONL (Instance->ServerIp);

  Status = McastIo->Udp->Configure (McastIo->Udp, &UdpConfig);

  if (EFI_ERROR (Status)) {
    return Status;
  }
  
  //
  // join the multicast group
  //
  EFI_IP4 (Group) = HTONL (Instance->McastIp);
  return McastIo->Udp->Groups (McastIo->Udp, TRUE, &Group);
}

EFI_STATUS
Mtftp4RrqHandleOack (
  IN  MTFTP4_PROTOCOL       *Instance,
  IN  EFI_MTFTP4_PACKET     *Packet,
  IN  UINT32                Len,
  IN  BOOLEAN               Multicast,
  OUT BOOLEAN               *Completed
  )
/*++

Routine Description:

  Function to process the OACK. It will first validate the OACK 
  packet, then update the various negotiated parameters.

Arguments:

  Instance  - The download MTFTP session
  Packet    - The packet received
  Len       - The packet length
  Multicast - Whether this packet is received as a multicast 
  Completed - Returns whether the download has completed. NOT used 
              by this function.

Returns:

  EFI_DEVICE_ERROR - Failed to create/start a multicast UDP child
  EFI_TFTP_ERROR   - Some error happened during the process
  EFI_SUCCESS      - The OACK is successfully processed.

--*/
{
  MTFTP4_OPTION             Reply;
  EFI_STATUS                Status;
  INTN                      Expected;

  *Completed = FALSE;

  //
  // If already started the master download, don't change the 
  // setting. Master download always succeeds. 
  //
  Expected = Mtftp4GetNextBlockNum (&Instance->Blocks);
  ASSERT (Expected != -1);

  if (Instance->Master && (Expected != 1)) {
    return EFI_SUCCESS;
  }

  //
  // Parse and validate the options from server
  //
  NetZeroMem (&Reply, sizeof (MTFTP4_OPTION));

  Status = Mtftp4ParseOptionOack (Packet, Len, &Reply);

  if (EFI_ERROR (Status) || 
      !Mtftp4RrqOackValid (Instance, &Reply, &Instance->RequestOption)) {
    //
    // Don't send an ERROR packet if the error is EFI_OUT_OF_RESOURCES.
    //
    if (Status != EFI_OUT_OF_RESOURCES) {
      Mtftp4SendError (
        Instance, 
        EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,
        "Mal-formated OACK packet"
        );
    }

    return EFI_TFTP_ERROR;
  }

  if (Reply.Exist & MTFTP4_MCAST_EXIST) {
    
    //
    // Save the multicast info. Always update the Master, only update the 
    // multicast IP address, block size, timeoute at the first time. If IP
    // address is updated, create a UDP child to receive the multicast.
    //
    Instance->Master = Reply.Master;

    if (Instance->McastIp == 0) {
      if ((Reply.McastIp == 0) || (Reply.McastPort == 0)) {
        Mtftp4SendError (
          Instance, 
          EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION,
          "Illegal multicast setting"
          );
        
        return EFI_TFTP_ERROR;
      }
      
      //
      // Create a UDP child then start receive the multicast from it.
      //
      Instance->McastIp      = Reply.McastIp;
      Instance->McastPort    = Reply.McastPort;
      Instance->McastUdpPort = UdpIoCreatePort (
                                 Instance->Service->Controller,
                                 Instance->Service->Image,
                                 Mtftp4RrqConfigMcastPort,
                                 Instance
                                 );

      if (Instance->McastUdpPort == NULL) {
        return EFI_DEVICE_ERROR;
      }

      Status = UdpIoRecvDatagram (Instance->McastUdpPort, Mtftp4RrqInput, Instance, 0);

      if (EFI_ERROR (Status)) {
        Mtftp4SendError (
          Instance, 
          EFI_MTFTP4_ERRORCODE_ACCESS_VIOLATION,
          "Failed to create socket to receive multicast packet"
          );
        
        return Status;
      }
    
      //
      // Update the parameters used.
      //
      if (Reply.BlkSize != 0) {
        Instance->BlkSize = Reply.BlkSize;
      }
      
      if (Reply.Timeout != 0) {
        Instance->Timeout = Reply.Timeout;
      }  
    }    
    
  } else {
    Instance->Master = TRUE;
    
    if (Reply.BlkSize != 0) {
      Instance->BlkSize = Reply.BlkSize;
    }

    if (Reply.Timeout != 0) {
      Instance->Timeout = Reply.Timeout;
    }
  }
  
  //
  // Send an ACK to (Expected - 1) which is 0 for unicast download,
  // or tell the server we want to receive the Expected block.
  //
  return Mtftp4RrqSendAck (Instance, (UINT16) (Expected - 1));
}

VOID
Mtftp4RrqInput (
  IN NET_BUF                *UdpPacket,
  IN UDP_POINTS             *Points,
  IN EFI_STATUS             IoStatus,
  IN VOID                   *Context
  )
/*++

Routine Description:

  The packet process callback for MTFTP download.

Arguments:

  UdpPacket - The packet received
  Points    - The local/remote access point of the packet
  IoStatus  - The status of the receiving
  Context   - Opaque parameter, which is the MTFTP session

Returns:

  None

--*/
{
  MTFTP4_PROTOCOL           *Instance;
  EFI_MTFTP4_PACKET         *Packet;
  BOOLEAN                   Completed;
  BOOLEAN                   Multicast;
  EFI_STATUS                Status;
  UINT16                    Opcode;
  UINT32                    Len;

  Instance  = (MTFTP4_PROTOCOL *) Context;
  NET_CHECK_SIGNATURE (Instance, MTFTP4_PROTOCOL_SIGNATURE);

  Status    = EFI_SUCCESS;
  Packet    = NULL;
  Completed = FALSE;
  Multicast = FALSE;

  if (EFI_ERROR (IoStatus)) {
    Status = IoStatus;
    goto ON_EXIT;
  }

  ASSERT (UdpPacket != NULL);

  //
  // Find the port this packet is from to restart receive correctly.
  //
  Multicast = (BOOLEAN) (Points->LocalAddr == Instance->McastIp);

  if (UdpPacket->TotalSize < MTFTP4_OPCODE_LEN) {
    goto ON_EXIT;
  }
  
  //
  // Client send initial request to server's listening port. Server
  // will select a UDP port to communicate with the client. The server
  // is required to use the same port as RemotePort to multicast the
  // data.
  //
  if (Points->RemotePort != Instance->ConnectedPort) {
    if (Instance->ConnectedPort != 0) {
      goto ON_EXIT;
    } else {
      Instance->ConnectedPort = Points->RemotePort;
    }
  }
  
  //
  // Copy the MTFTP packet to a continuous buffer if it isn't already so.
  //
  Len = UdpPacket->TotalSize;

  if (UdpPacket->BlockOpNum > 1) {
    Packet = NetAllocatePool (Len);

    if (Packet == NULL) {
      Status = EFI_OUT_OF_RESOURCES;
      goto ON_EXIT;
    }

    NetbufCopy (UdpPacket, 0, Len, (UINT8 *) Packet);

  } else {
    Packet = (EFI_MTFTP4_PACKET *) NetbufGetByte (UdpPacket, 0, NULL);
  }

  Opcode = NTOHS (Packet->OpCode);

  //
  // Call the user's CheckPacket if provided. Abort the transmission
  // if CheckPacket returns an EFI_ERROR code.
  //
  if ((Instance->Token->CheckPacket != NULL) &&
      ((Opcode == EFI_MTFTP4_OPCODE_OACK) || (Opcode == EFI_MTFTP4_OPCODE_ERROR))) {

    Status = Instance->Token->CheckPacket (
                                &Instance->Mtftp4,
                                Instance->Token,
                                (UINT16) Len,
                                Packet
                                );

    if (EFI_ERROR (Status)) {
      //
      // Send an error message to the server to inform it
      //
      if (Opcode != EFI_MTFTP4_OPCODE_ERROR) {
        Mtftp4SendError (
          Instance, 
          EFI_MTFTP4_ERRORCODE_REQUEST_DENIED,
          "User aborted the transfer"
          );
      }

      Status = EFI_ABORTED;
      goto ON_EXIT;
    }
  }

  switch (Opcode) {
  case EFI_MTFTP4_OPCODE_DATA:
    if ((Len > (UINT32) (MTFTP4_DATA_HEAD_LEN + Instance->BlkSize)) || 
        (Len < (UINT32) MTFTP4_DATA_HEAD_LEN)) {
      goto ON_EXIT;
    }

    Status = Mtftp4RrqHandleData (Instance, Packet, Len, Multicast, &Completed);
    break;

  case EFI_MTFTP4_OPCODE_OACK:
    if (Multicast || (Len <= MTFTP4_OPCODE_LEN)) {
      goto ON_EXIT;
    }

    Status = Mtftp4RrqHandleOack (Instance, Packet, Len, Multicast, &Completed);
    break;

  case EFI_MTFTP4_OPCODE_ERROR:
    Status = EFI_TFTP_ERROR;
    break;
  }

ON_EXIT:
  
  //
  // Free the resources, then if !EFI_ERROR (Status), restart the
  // receive, otherwise end the session.
  //
  if ((Packet != NULL) && (UdpPacket->BlockOpNum > 1)) {
    NetFreePool (Packet);
  }

  if (UdpPacket != NULL) {
    NetbufFree (UdpPacket);
  }

  if (!EFI_ERROR (Status) && !Completed) {
    if (Multicast) {
      Status = UdpIoRecvDatagram (Instance->McastUdpPort, Mtftp4RrqInput, Instance, 0);
    } else {
      Status = UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4RrqInput, Instance, 0);
    }
  }

  if (EFI_ERROR (Status) || Completed) {
    Mtftp4CleanOperation (Instance, Status);
  }
}

⌨️ 快捷键说明

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