Esempio n. 1
0
/**
  Start the MTFTP session for upload.
  
  It will first init some states, then send the WRQ request packet, 
  and start receiving the packet.

  @param  Instance              The MTFTP session
  @param  Operation             Redundant parameter, which is always
                                EFI_MTFTP4_OPCODE_WRQ here.

  @retval EFI_SUCCESS           The upload process has been started.
  @retval Others                Failed to start the upload.

**/
EFI_STATUS
Mtftp4WrqStart (
  IN MTFTP4_PROTOCOL        *Instance,
  IN UINT16                 Operation
  )
{
  EFI_STATUS                Status;

  //
  // The valid block number range are [0, 0xffff]. For example:
  // the client sends an WRQ request to the server, the server
  // ACK with an ACK0 to let client start transfer the first
  // packet.
  //
  Status = Mtftp4InitBlockRange (&Instance->Blocks, 0, 0xffff);

  if (EFI_ERROR (Status)) {
    return Status;
  }

  Status = Mtftp4SendRequest (Instance);

  if (EFI_ERROR (Status)) {
    return Status;
  }

  return UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4WrqInput, Instance, 0);
}
Esempio n. 2
0
/**
  Start the MTFTP session to download. 
  
  It will first initialize some of the internal states then build and send a RRQ 
  reqeuest packet, at last, it will start receive for the downloading.

  @param  Instance              The Mtftp session
  @param  Operation             The MTFTP opcode, it may be a EFI_MTFTP4_OPCODE_RRQ
                                or EFI_MTFTP4_OPCODE_DIR.

  @retval EFI_SUCCESS           The mtftp download session is started.
  @retval Others                Failed to start downloading.

**/
EFI_STATUS
Mtftp4RrqStart (
  IN MTFTP4_PROTOCOL        *Instance,
  IN UINT16                 Operation
  )
{
  EFI_STATUS                Status;

  //
  // The valid block number range are [1, 0xffff]. For example:
  // the client sends an RRQ request to the server, the server
  // transfers the DATA1 block. If option negoitation is ongoing,
  // the server will send back an OACK, then client will send ACK0.
  //
  Status = Mtftp4InitBlockRange (&Instance->Blocks, 1, 0xffff);

  if (EFI_ERROR (Status)) {
    return Status;
  }

  Status = Mtftp4SendRequest (Instance);

  if (EFI_ERROR (Status)) {
    return Status;
  }

  return UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4RrqInput, Instance, 0);
}
Esempio n. 3
0
/**
  The input process routine for MTFTP upload.

  @param  UdpPacket             The received MTFTP packet.
  @param  EndPoint              The local/remote access point
  @param  IoStatus              The result of the packet receiving
  @param  Context               Opaque parameter for the callback, which is the
                                MTFTP session.
**/
VOID
EFIAPI
Mtftp4WrqInput (
  IN NET_BUF                *UdpPacket,
  IN UDP_END_POINT          *EndPoint,
  IN EFI_STATUS             IoStatus,
  IN VOID                   *Context
  )
{
  MTFTP4_PROTOCOL           *Instance;
  EFI_MTFTP4_PACKET         *Packet;
  BOOLEAN                   Completed;
  EFI_STATUS                Status;
  UINT32                    Len;
  UINT16                    Opcode;

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

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

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

  ASSERT (UdpPacket != NULL);

  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.
  //
  if (EndPoint->RemotePort != Instance->ConnectedPort) {
    if (Instance->ConnectedPort != 0) {
      goto ON_EXIT;
    } else {
      Instance->ConnectedPort = EndPoint->RemotePort;
    }
  }

  //
  // Copy the MTFTP packet to a continuous buffer if it isn't already so.
  //
  Len = UdpPacket->TotalSize;

  if (UdpPacket->BlockOpNum > 1) {
    Packet = AllocatePool (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);
    ASSERT (Packet != 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,
          (UINT8 *) "User aborted the transfer"
          );
      }

      Status = EFI_ABORTED;
      goto ON_EXIT;
    }
  }

  switch (Opcode) {
  case EFI_MTFTP4_OPCODE_ACK:
    if (Len != MTFTP4_OPCODE_LEN + MTFTP4_BLKNO_LEN) {
      goto ON_EXIT;
    }

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

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

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

  case EFI_MTFTP4_OPCODE_ERROR:
    Status = EFI_TFTP_ERROR;
    break;
    
  default:
    break;
  }

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

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

  if (!EFI_ERROR (Status) && !Completed) {
    Status = UdpIoRecvDatagram (Instance->UnicastPort, Mtftp4WrqInput, Instance, 0);
  }

  //
  // Status may have been updated by UdpIoRecvDatagram
  //
  if (EFI_ERROR (Status) || Completed) {
    Mtftp4CleanOperation (Instance, Status);
  }
}
Esempio n. 4
0
/**
  Function to process the OACK. 
  
  It will first validate the OACK packet, then update the various negotiated parameters.

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

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

**/
EFI_STATUS
Mtftp4RrqHandleOack (
  IN OUT MTFTP4_PROTOCOL       *Instance,
  IN     EFI_MTFTP4_PACKET     *Packet,
  IN     UINT32                Len,
  IN     BOOLEAN               Multicast,
     OUT BOOLEAN               *Completed
  )
{
  MTFTP4_OPTION             Reply;
  EFI_STATUS                Status;
  INTN                      Expected;
  EFI_UDP4_PROTOCOL         *Udp4;

  *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
  //
  ZeroMem (&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,
        (UINT8 *) "Mal-formated OACK packet"
        );
    }

    return EFI_TFTP_ERROR;
  }

  if ((Reply.Exist & MTFTP4_MCAST_EXIST) != 0) {

    //
    // 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,
          (UINT8 *) "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;
      if (Instance->McastUdpPort == NULL) {
        Instance->McastUdpPort = UdpIoCreateIo (
                                   Instance->Service->Controller,
                                   Instance->Service->Image,
                                   Mtftp4RrqConfigMcastPort,
                                   UDP_IO_UDP4_VERSION,
                                   Instance
                                   );
        if (Instance->McastUdpPort != NULL) {
          Status = gBS->OpenProtocol (
                          Instance->McastUdpPort->UdpHandle,
                          &gEfiUdp4ProtocolGuid,
                          (VOID **) &Udp4,
                          Instance->Service->Image,
                          Instance->Handle,
                          EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
                          );
          if (EFI_ERROR (Status)) {
            UdpIoFreeIo (Instance->McastUdpPort);
            Instance->McastUdpPort = NULL;
            return EFI_DEVICE_ERROR;
          }
        }
      }


      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,
          (UINT8 *) "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));
}
Esempio n. 5
0
/**
  The packet process callback for Mtftp6 download.

  @param[in]  UdpPacket             The pointer to the packet received.
  @param[in]  UdpEpt                The pointer to the Udp6 access point.
  @param[in]  IoStatus              The status from Udp6 instance.
  @param[in]  Context               The pointer to the context.

**/
VOID
EFIAPI
Mtftp6RrqInput (
  IN NET_BUF                *UdpPacket,
  IN UDP_END_POINT          *UdpEpt,
  IN EFI_STATUS             IoStatus,
  IN VOID                   *Context
  )
{
  MTFTP6_INSTANCE           *Instance;
  EFI_MTFTP6_PACKET         *Packet;
  BOOLEAN                   IsCompleted;
  BOOLEAN                   IsMcast;
  EFI_STATUS                Status;
  UINT16                    Opcode;
  UINT32                    TotalNum;
  UINT32                    Len;

  Instance = (MTFTP6_INSTANCE *) Context;

  NET_CHECK_SIGNATURE (Instance, MTFTP6_INSTANCE_SIGNATURE);

  Status      = EFI_SUCCESS;
  Packet      = NULL;
  IsCompleted = FALSE;
  IsMcast     = FALSE;
  TotalNum    = 0;

  //
  // Return error status if Udp6 instance failed to receive.
  //
  if (EFI_ERROR (IoStatus)) {
    Status = IoStatus;
    goto ON_EXIT;
  }

  ASSERT (UdpPacket != NULL);

  if (UdpPacket->TotalSize < MTFTP6_OPCODE_LEN) {
    goto ON_EXIT;
  }

  //
  // Find the port this packet is from to restart receive correctly.
  //
  if (CompareMem (
        Ip6Swap128 (&UdpEpt->LocalAddr.v6),
        &Instance->McastIp,
        sizeof (EFI_IPv6_ADDRESS)
        ) == 0) {
    IsMcast = TRUE;
  } else {
    IsMcast = FALSE;
  }

  //
  // 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 (UdpEpt->RemotePort != Instance->ServerDataPort) {
    if (Instance->ServerDataPort != 0) {
      goto ON_EXIT;
    } else {
      //
      // For the subsequent exchange of requests, reconfigure the udpio as
      // (serverip, serverport, localip, localport).
      // Ususally, the client set serverport as 0 to receive and reset it
      // once the first packet arrives to send ack.
      //
      Instance->ServerDataPort = UdpEpt->RemotePort;
    }
  }

  //
  // Copy the MTFTP packet to a continuous buffer if it isn't already so.
  //
  Len      = UdpPacket->TotalSize;
  TotalNum = UdpPacket->BlockOpNum;

  if (TotalNum > 1) {
    Packet = AllocateZeroPool (Len);

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

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

  } else {
    Packet = (EFI_MTFTP6_PACKET *) NetbufGetByte (UdpPacket, 0, NULL);
    ASSERT (Packet != NULL);
  }

  Opcode = NTOHS (Packet->OpCode);

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

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

    if (EFI_ERROR (Status)) {
      //
      // Send an error message to the server to inform it
      //
      if (Opcode != EFI_MTFTP6_OPCODE_ERROR) {
        //
        // Free the received packet before send new packet in ReceiveNotify,
        // since the udpio might need to be reconfigured.
        //
        NetbufFree (UdpPacket);
        UdpPacket = NULL;
        //
        // Send the Mtftp6 error message if user aborted the current session.
        //
        Mtftp6SendError (
          Instance,
          EFI_MTFTP6_ERRORCODE_REQUEST_DENIED,
          (UINT8 *) "User aborted the transfer"
          );
      }

      Status = EFI_ABORTED;
      goto ON_EXIT;
    }
  }

  //
  // Switch the process routines by the operation code.
  //
  switch (Opcode) {
  case EFI_MTFTP6_OPCODE_DATA:
    if ((Len > (UINT32) (MTFTP6_DATA_HEAD_LEN + Instance->BlkSize)) || (Len < (UINT32) MTFTP6_DATA_HEAD_LEN)) {
      goto ON_EXIT;
    }
    //
    // Handle the data packet of Rrq.
    //
    Status = Mtftp6RrqHandleData (
               Instance,
               Packet,
               Len,
               &UdpPacket,
               &IsCompleted
               );
    break;

  case EFI_MTFTP6_OPCODE_OACK:
    if (IsMcast || Len <= MTFTP6_OPCODE_LEN) {
      goto ON_EXIT;
    }
    //
    // Handle the Oack packet of Rrq.
    //
    Status = Mtftp6RrqHandleOack (
               Instance,
               Packet,
               Len,
               &UdpPacket,
               &IsCompleted
               );
    break;

  default:
    //
    // Drop and return eror if received error message.
    //
    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 && TotalNum > 1) {
    FreePool (Packet);
  }
  if (UdpPacket != NULL) {
    NetbufFree (UdpPacket);
  }
  if (!EFI_ERROR (Status) && !IsCompleted) {
    if (IsMcast) {
      Status = UdpIoRecvDatagram (
                 Instance->McastUdpIo,
                 Mtftp6RrqInput,
                 Instance,
                 0
                 );
    } else {
      Status = UdpIoRecvDatagram (
                 Instance->UdpIo,
                 Mtftp6RrqInput,
                 Instance,
                 0
                 );
    }
  }
  //
  // Clean up the current session if failed to continue.
  //
  if (EFI_ERROR (Status) || IsCompleted) {
    Mtftp6OperationClean (Instance, Status);
  }
}
Esempio n. 6
0
/**
  Process the OACK packet for Rrq.

  @param[in]  Instance              The pointer to the Mtftp6 instance.
  @param[in]  Packet                The pointer to the received packet.
  @param[in]  Len                   The length of the packet.
  @param[out] UdpPacket             The net buf of received packet.
  @param[out] IsCompleted           If TRUE, the download has been completed.
                                    Otherwise, the download has not been completed.

  @retval EFI_DEVICE_ERROR      Failed to create/start a multicast Udp6 child.
  @retval EFI_TFTP_ERROR        An error happened during the process.
  @retval EFI_SUCCESS           The OACK packet successfully processed.

**/
EFI_STATUS
Mtftp6RrqHandleOack (
  IN  MTFTP6_INSTANCE       *Instance,
  IN  EFI_MTFTP6_PACKET     *Packet,
  IN  UINT32                Len,
  OUT NET_BUF               **UdpPacket,
  OUT BOOLEAN               *IsCompleted
  )
{
  EFI_MTFTP6_OPTION         *Options;
  UINT32                    Count;
  MTFTP6_EXT_OPTION_INFO    ExtInfo;
  EFI_STATUS                Status;
  INTN                      Expected;

  *IsCompleted = FALSE;

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

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

  ZeroMem (&ExtInfo, sizeof (MTFTP6_EXT_OPTION_INFO));

  //
  // Parse the options in the packet.
  //
  Status = Mtftp6ParseStart (Packet, Len, &Count, &Options);

  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Parse the extensive options in the packet.
  //
  Status = Mtftp6ParseExtensionOption (Options, Count, FALSE, &ExtInfo);

  if (EFI_ERROR (Status) || !Mtftp6RrqOackValid (Instance, &ExtInfo, &Instance->ExtInfo)) {
    //
    // Don't send an ERROR packet if the error is EFI_OUT_OF_RESOURCES.
    //
    if (Status != EFI_OUT_OF_RESOURCES) {
      //
      // Free the received packet before send new packet in ReceiveNotify,
      // since the udpio might need to be reconfigured.
      //
      NetbufFree (*UdpPacket);
      *UdpPacket = NULL;
      //
      // Send the Mtftp6 error message if invalid packet.
      //
      Mtftp6SendError (
        Instance,
        EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION,
        (UINT8 *) "Mal-formated OACK packet"
        );
    }

    return EFI_TFTP_ERROR;
  }

  if ((ExtInfo.BitMap & MTFTP6_OPT_MCAST_BIT) != 0) {

    //
    // 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->IsMaster = ExtInfo.IsMaster;

    if (NetIp6IsUnspecifiedAddr (&Instance->McastIp)) {
      if (NetIp6IsUnspecifiedAddr (&ExtInfo.McastIp) || ExtInfo.McastPort == 0) {
        //
        // Free the received packet before send new packet in ReceiveNotify,
        // since the udpio might need to be reconfigured.
        //
        NetbufFree (*UdpPacket);
        *UdpPacket = NULL;
        //
        // Send the Mtftp6 error message if invalid multi-cast setting.
        //
        Mtftp6SendError (
          Instance,
          EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION,
          (UINT8 *) "Illegal multicast setting"
          );

        return EFI_TFTP_ERROR;
      }

      //
      // Create a UDP child then start receive the multicast from it.
      //
      CopyMem (
        &Instance->McastIp,
        &ExtInfo.McastIp,
        sizeof (EFI_IP_ADDRESS)
        );

      Instance->McastPort  = ExtInfo.McastPort;
      Instance->McastUdpIo = UdpIoCreateIo (
                               Instance->Service->Controller,
                               Instance->Service->Image,
                               Mtftp6RrqConfigMcastUdpIo,
                               UDP_IO_UDP6_VERSION,
                               Instance
                               );

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

      Status = UdpIoRecvDatagram (
                 Instance->McastUdpIo,
                 Mtftp6RrqInput,
                 Instance,
                 0
                 );

      if (EFI_ERROR (Status)) {
        //
        // Free the received packet before send new packet in ReceiveNotify,
        // since the udpio might need to be reconfigured.
        //
        NetbufFree (*UdpPacket);
        *UdpPacket = NULL;
        //
        // Send the Mtftp6 error message if failed to create Udp6Io to receive.
        //
        Mtftp6SendError (
          Instance,
          EFI_MTFTP6_ERRORCODE_ACCESS_VIOLATION,
          (UINT8 *) "Failed to create socket to receive multicast packet"
          );

        return Status;
      }

      //
      // Update the parameters used.
      //
      if (ExtInfo.BlkSize != 0) {
        Instance->BlkSize = ExtInfo.BlkSize;
      }

      if (ExtInfo.Timeout != 0) {
        Instance->Timeout = ExtInfo.Timeout;
      }
    }

  } else {

    Instance->IsMaster = TRUE;

    if (ExtInfo.BlkSize != 0) {
      Instance->BlkSize = ExtInfo.BlkSize;
    }

    if (ExtInfo.Timeout != 0) {
      Instance->Timeout = ExtInfo.Timeout;
    }
  }

  //
  // Free the received packet before send new packet in ReceiveNotify,
  // since the udpio might need to be reconfigured.
  //
  NetbufFree (*UdpPacket);
  *UdpPacket = NULL;
  //
  // Send an ACK to (Expected - 1) which is 0 for unicast download,
  // or tell the server we want to receive the Expected block.
  //
  return Mtftp6RrqSendAck (Instance, (UINT16) (Expected - 1));
}
Esempio n. 7
0
/**
  Starts the DHCPv6 standard S.A.R.R. process.

  The Start() function starts the DHCPv6 standard process. This function can
  be called only when the state of Dhcp6 instance is in the Dhcp6Init state.
  If the DHCP process completes successfully, the state of the Dhcp6 instance
  will be transferred through Dhcp6Selecting and Dhcp6Requesting to the
  Dhcp6Bound state.
  Refer to rfc-3315 for precise state transitions during this process. At the
  time when each event occurs in this process, the callback function that was set
  by EFI_DHCP6_PROTOCOL.Configure() will be called, and the user can take this
  opportunity to control the process.

  @param[in]  This              The pointer to Dhcp6 protocol.

  @retval EFI_SUCCESS           The DHCPv6 standard process has started, or it has
                                completed when CompletionEvent is NULL.
  @retval EFI_ACCESS_DENIED     The EFI DHCPv6 Child instance hasn't been configured.
  @retval EFI_INVALID_PARAMETER This is NULL.
  @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
  @retval EFI_TIMEOUT           The DHCPv6 configuration process failed because no
                                response was received from the server within the
                                specified timeout value.
  @retval EFI_ABORTED           The user aborted the DHCPv6 process.
  @retval EFI_ALREADY_STARTED   Some other Dhcp6 instance already started the DHCPv6
                                standard process.
  @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
  @retval EFI_NO_MEDIA          There was a media error.

**/
EFI_STATUS
EFIAPI
EfiDhcp6Start (
  IN EFI_DHCP6_PROTOCOL        *This
  )
{
  EFI_STATUS                   Status;
  EFI_TPL                      OldTpl;
  DHCP6_INSTANCE               *Instance;
  DHCP6_SERVICE                *Service;

  if (This == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  Instance = DHCP6_INSTANCE_FROM_THIS (This);
  Service  = Instance->Service;

  //
  // The instance hasn't been configured.
  //
  if (Instance->Config == NULL) {
    return EFI_ACCESS_DENIED;
  }

  ASSERT (Instance->IaCb.Ia != NULL);

  //
  // The instance has already been started.
  //
  if (Instance->IaCb.Ia->State != Dhcp6Init) {
    return EFI_ALREADY_STARTED;
  }

  OldTpl           = gBS->RaiseTPL (TPL_CALLBACK);
  Instance->UdpSts = EFI_ALREADY_STARTED;

  //
  // Need to clear initial time to make sure that elapsed-time
  // is set to 0 for first Solicit.
  //
  Instance->StartTime = 0;

  //
  // Send the solicit message to start S.A.R.R process.
  //
  Status = Dhcp6SendSolicitMsg (Instance);

  if (EFI_ERROR (Status)) {
    goto ON_ERROR;
  }

  //
  // Register receive callback for the stateful exchange process.
  //
  Status = UdpIoRecvDatagram(
             Service->UdpIo,
             Dhcp6ReceivePacket,
             Service,
             0
             );

  if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
    goto ON_ERROR;
  }

  gBS->RestoreTPL (OldTpl);

  //
  // Poll udp out of the net tpl if synchronous call.
  //
  if (Instance->Config->IaInfoEvent == NULL) {

    while (Instance->UdpSts == EFI_ALREADY_STARTED) {
      Service->UdpIo->Protocol.Udp6->Poll (Service->UdpIo->Protocol.Udp6);
    }
    return Instance->UdpSts;
  }

  return EFI_SUCCESS;

ON_ERROR:

  gBS->RestoreTPL (OldTpl);
  return Status;
}
/**
  Starts the DHCPv6 standard S.A.R.R. process.

  The Start() function starts the DHCPv6 standard process. This function can
  be called only when the state of Dhcp6 instance is in the Dhcp6Init state.
  If the DHCP process completes successfully, the state of the Dhcp6 instance
  will be transferred through Dhcp6Selecting and Dhcp6Requesting to the
  Dhcp6Bound state.
  Refer to rfc-3315 for precise state transitions during this process. At the
  time when each event occurs in this process, the callback function that was set
  by EFI_DHCP6_PROTOCOL.Configure() will be called, and the user can take this
  opportunity to control the process.

  @param[in]  This              The pointer to Dhcp6 protocol.

  @retval EFI_SUCCESS           The DHCPv6 standard process has started, or it has
                                completed when CompletionEvent is NULL.
  @retval EFI_ACCESS_DENIED     The EFI DHCPv6 Child instance hasn't been configured.
  @retval EFI_INVALID_PARAMETER This is NULL.
  @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
  @retval EFI_TIMEOUT           The DHCPv6 configuration process failed because no
                                response was received from the server within the
                                specified timeout value.
  @retval EFI_ABORTED           The user aborted the DHCPv6 process.
  @retval EFI_ALREADY_STARTED   Some other Dhcp6 instance already started the DHCPv6
                                standard process.
  @retval EFI_DEVICE_ERROR      An unexpected system or network error occurred.
  @retval EFI_NO_MEDIA          There was a media error.

**/
EFI_STATUS
EFIAPI
EfiDhcp6Start (
  IN EFI_DHCP6_PROTOCOL        *This
  )
{
  EFI_STATUS                   Status;
  EFI_TPL                      OldTpl;
  DHCP6_INSTANCE               *Instance;
  DHCP6_SERVICE                *Service;
  EFI_STATUS                   MediaStatus;

  if (This == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  Instance = DHCP6_INSTANCE_FROM_THIS (This);
  Service  = Instance->Service;

  //
  // The instance hasn't been configured.
  //
  if (Instance->Config == NULL) {
    return EFI_ACCESS_DENIED;
  }

  ASSERT (Instance->IaCb.Ia != NULL);

  //
  // The instance has already been started.
  //
  if (Instance->IaCb.Ia->State != Dhcp6Init) {
    return EFI_ALREADY_STARTED;
  }

  OldTpl           = gBS->RaiseTPL (TPL_CALLBACK);

  //
  // Check Media Satus.
  //
  MediaStatus = EFI_SUCCESS;
  NetLibDetectMediaWaitTimeout (Service->Controller, DHCP_CHECK_MEDIA_WAITING_TIME, &MediaStatus);
  if (MediaStatus != EFI_SUCCESS) {
    Status = EFI_NO_MEDIA;
    goto ON_ERROR;
  }

  Instance->UdpSts = EFI_ALREADY_STARTED;

  //
  // Send the solicit message to start S.A.R.R process.
  //
  Status = Dhcp6SendSolicitMsg (Instance);

  if (EFI_ERROR (Status)) {
    goto ON_ERROR;
  }

  //
  // Register receive callback for the stateful exchange process.
  //
  Status = UdpIoRecvDatagram(
             Service->UdpIo,
             Dhcp6ReceivePacket,
             Service,
             0
             );

  if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
    goto ON_ERROR;
  }

  gBS->RestoreTPL (OldTpl);

  //
  // Poll udp out of the net tpl if synchronous call.
  //
  if (Instance->Config->IaInfoEvent == NULL) {

    while (Instance->UdpSts == EFI_ALREADY_STARTED) {
      Service->UdpIo->Protocol.Udp6->Poll (Service->UdpIo->Protocol.Udp6);
    }
    return Instance->UdpSts;
  }

  return EFI_SUCCESS;

ON_ERROR:

  gBS->RestoreTPL (OldTpl);
  return Status;
}