Esempio n. 1
0
/**
  Process the ICMPv6 error packet, and deliver the packet to upper layer.

  @param[in]  IpSb               The IP service that received the packet.
  @param[in]  Head               The IP head of the ICMPv6 error packet.
  @param[in]  Packet             The content of the ICMPv6 error with the IP head
                                 removed.

  @retval EFI_SUCCESS            The ICMPv6 error processed successfully.
  @retval EFI_INVALID_PARAMETER  The packet is invalid.
  @retval Others                 Failed to process the packet.

**/
EFI_STATUS
Ip6ProcessIcmpError (
  IN IP6_SERVICE            *IpSb,
  IN EFI_IP6_HEADER         *Head,
  IN NET_BUF                *Packet
  )
{
  IP6_ICMP_ERROR_HEAD       Icmp;

  //
  // Check the validity of the packet
  //
  if (Packet->TotalSize < sizeof (Icmp)) {
    goto DROP;
  }

  NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
  if (Icmp.Head.Type == ICMP_V6_PACKET_TOO_BIG) {
    return Ip6ProcessPacketTooBig (IpSb, Head, Packet);
  }

  //
  // Notify the upper-layer process that an ICMPv6 eror message is received.
  //
  IP6_GET_CLIP_INFO (Packet)->Status = EFI_ICMP_ERROR;
  return Ip6Demultiplex (IpSb, Head, Packet);

DROP:
  NetbufFree (Packet);
  Packet = NULL;
  return EFI_INVALID_PARAMETER;
}
Esempio n. 2
0
/**
  Process the ICMPv6 informational messages. If it is an ICMPv6 echo
  request, answer it. If it is a MLD message, trigger MLD routines to
  process it. If it is a ND message, trigger ND routines to process it.
  Otherwise, deliver it to upper layer.

  @param[in]  IpSb               The IP service that receivd the packet.
  @param[in]  Head               The IP head of the ICMPv6 informational packet.
  @param[in]  Packet             The content of the ICMPv6 informational packet
                                 with IP head removed.

  @retval EFI_INVALID_PARAMETER  The packet is invalid.
  @retval EFI_SUCCESS            The ICMPv6 informational message processed.
  @retval Others                 Failed to process ICMPv6 informational message.

**/
EFI_STATUS
Ip6ProcessIcmpInformation (
  IN IP6_SERVICE            *IpSb,
  IN EFI_IP6_HEADER         *Head,
  IN NET_BUF                *Packet
  )
{
  IP6_ICMP_INFORMATION_HEAD Icmp;
  EFI_STATUS                Status;

  NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
  NET_CHECK_SIGNATURE (Packet, NET_BUF_SIGNATURE);
  ASSERT (Head != NULL);

  NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
  Status = EFI_INVALID_PARAMETER;

  switch (Icmp.Head.Type) {
  case ICMP_V6_ECHO_REQUEST:
    //
    // If ICMPv6 echo, reply it
    //
    if (Icmp.Head.Code == 0) {
      Status = Ip6IcmpReplyEcho (IpSb, Head, Packet);
    }
    break;
  case ICMP_V6_LISTENER_QUERY:
    Status = Ip6ProcessMldQuery (IpSb, Head, Packet);
    break;
  case ICMP_V6_LISTENER_REPORT:
  case ICMP_V6_LISTENER_REPORT_2:
    Status = Ip6ProcessMldReport (IpSb, Head, Packet);
    break;
  case ICMP_V6_NEIGHBOR_SOLICIT:
    Status = Ip6ProcessNeighborSolicit (IpSb, Head, Packet);
    break;
  case ICMP_V6_NEIGHBOR_ADVERTISE:
    Status = Ip6ProcessNeighborAdvertise (IpSb, Head, Packet);
    break;
  case ICMP_V6_ROUTER_ADVERTISE:
    Status = Ip6ProcessRouterAdvertise (IpSb, Head, Packet);
    break;
  case ICMP_V6_REDIRECT:
    Status = Ip6ProcessRedirect (IpSb, Head, Packet);
    break;
  case ICMP_V6_ECHO_REPLY:
    Status = Ip6Demultiplex (IpSb, Head, Packet);
    break;
  default:
    Status = EFI_INVALID_PARAMETER;
    break;
  }

  return Status;
}
Esempio n. 3
0
/**
  Process Packet Too Big message sent by a router in response to a packet that
  it cannot forward because the packet is larger than the MTU of outgoing link.
  Since this driver already uses IPv6 minimum link MTU as the maximum packet size,
  if Packet Too Big message is still received, do not reduce the packet size, but
  rather include a Fragment header in the subsequent packets.

  @param[in]  IpSb               The IP service that received the packet.
  @param[in]  Head               The IP head of the ICMPv6 error packet.
  @param[in]  Packet             The content of the ICMPv6 error with the IP head
                                 removed.

  @retval EFI_SUCCESS            The ICMPv6 error processed successfully.
  @retval EFI_OUT_OF_RESOURCES   Failed to finish the operation due to lack of
                                 resource.
  @retval EFI_NOT_FOUND          The packet too big message is not sent to us.

**/
EFI_STATUS
Ip6ProcessPacketTooBig (
  IN IP6_SERVICE            *IpSb,
  IN EFI_IP6_HEADER         *Head,
  IN NET_BUF                *Packet
  )
{
  IP6_ICMP_ERROR_HEAD       Icmp;
  UINT32                    Mtu;
  IP6_ROUTE_ENTRY           *RouteEntry;
  EFI_IPv6_ADDRESS          *DestAddress;

  NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
  Mtu         = NTOHL (Icmp.Fourth);
  DestAddress = &Icmp.IpHead.DestinationAddress;

  if (Mtu < IP6_MIN_LINK_MTU) {
    //
    // Normally the multicast address is considered to be on-link and not recorded
    // in route table. Here it is added into the table since the MTU information
    // need be recorded.
    //
    if (IP6_IS_MULTICAST (DestAddress)) {
      RouteEntry = Ip6CreateRouteEntry (DestAddress, 128, NULL);
      if (RouteEntry == NULL) {
        NetbufFree (Packet);
        return EFI_OUT_OF_RESOURCES;
      }

      RouteEntry->Flag = IP6_DIRECT_ROUTE | IP6_PACKET_TOO_BIG;
      InsertHeadList (&IpSb->RouteTable->RouteArea[128], &RouteEntry->Link);
      IpSb->RouteTable->TotalNum++;
    } else {
      RouteEntry = Ip6FindRouteEntry (IpSb->RouteTable, DestAddress, NULL);
      if (RouteEntry == NULL) {
        NetbufFree (Packet);
        return EFI_NOT_FOUND;
      }

      RouteEntry->Flag = RouteEntry->Flag | IP6_PACKET_TOO_BIG;

      Ip6FreeRouteEntry (RouteEntry);
    }
  }

  NetbufFree (Packet);
  return EFI_SUCCESS;
}
Esempio n. 4
0
/**
  Handle the ICMPv6 packet. First validate the message format,
  then, according to the message types, process it as an informational packet or
  an error packet.

  @param[in]  IpSb               The IP service that received the packet.
  @param[in]  Head               The IP head of the ICMPv6 packet.
  @param[in]  Packet             The content of the ICMPv6 packet with IP head
                                 removed.

  @retval EFI_INVALID_PARAMETER  The packet is malformated.
  @retval EFI_SUCCESS            The ICMPv6 message successfully processed.
  @retval Others                 Failed to handle the ICMPv6 packet.

**/
EFI_STATUS
Ip6IcmpHandle (
  IN IP6_SERVICE            *IpSb,
  IN EFI_IP6_HEADER         *Head,
  IN NET_BUF                *Packet
  )
{
  IP6_ICMP_HEAD             Icmp;
  UINT16                    PseudoCheckSum;
  UINT16                    CheckSum;

  //
  // Check the validity of the incoming packet.
  //
  if (Packet->TotalSize < sizeof (Icmp)) {
    goto DROP;
  }

  NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);

  //
  // Make sure checksum is valid.
  //
  PseudoCheckSum = NetIp6PseudoHeadChecksum (
                     &Head->SourceAddress,
                     &Head->DestinationAddress,
                     IP6_ICMP,
                     Packet->TotalSize
                     );
  CheckSum = (UINT16) ~NetAddChecksum (PseudoCheckSum, NetbufChecksum (Packet));
  if (CheckSum != 0) {
    goto DROP;
  }

  //
  // According to the packet type, call corresponding process
  //
  if (Icmp.Type <= ICMP_V6_ERROR_MAX) {
    return Ip6ProcessIcmpError (IpSb, Head, Packet);
  } else {
    return Ip6ProcessIcmpInformation (IpSb, Head, Packet);
  }

DROP:
  NetbufFree (Packet);
  return EFI_INVALID_PARAMETER;
}
Esempio n. 5
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. 6
0
/**
  Connect one TLS session by finishing the TLS handshake process.

  @param[in]  HttpInstance       The HTTP instance private data.
  @param[in]  Timeout            The time to wait for connection done.

  @retval EFI_SUCCESS            The TLS session is established.
  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
  @retval EFI_ABORTED            TLS session state is incorrect.
  @retval Others                 Other error as indicated.

**/
EFI_STATUS
EFIAPI
TlsConnectSession (
  IN  HTTP_PROTOCOL            *HttpInstance,
  IN  EFI_EVENT                Timeout
  )
{
  EFI_STATUS              Status;
  UINT8                   *BufferOut;
  UINTN                   BufferOutSize;
  NET_BUF                 *PacketOut;
  UINT8                   *DataOut;
  NET_BUF                 *Pdu;
  UINT8                   *BufferIn;
  UINTN                   BufferInSize;
  UINT8                   *GetSessionDataBuffer;
  UINTN                   GetSessionDataBufferSize;

  BufferOut    = NULL;
  PacketOut    = NULL;
  DataOut      = NULL;
  Pdu          = NULL;
  BufferIn     = NULL;

  //
  // Initialize TLS state.
  //
  HttpInstance->TlsSessionState = EfiTlsSessionNotStarted;
  Status = HttpInstance->Tls->SetSessionData (
                                HttpInstance->Tls,
                                EfiTlsSessionState,
                                &(HttpInstance->TlsSessionState),
                                sizeof (EFI_TLS_SESSION_STATE)
                                );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Create ClientHello
  //
  BufferOutSize = DEF_BUF_LEN;
  BufferOut = AllocateZeroPool (BufferOutSize);
  if (BufferOut == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    return Status;
  }

  Status = HttpInstance->Tls->BuildResponsePacket (
                                HttpInstance->Tls,
                                NULL,
                                0,
                                BufferOut,
                                &BufferOutSize
                                );
  if (Status == EFI_BUFFER_TOO_SMALL) {
    FreePool (BufferOut);
    BufferOut = AllocateZeroPool (BufferOutSize);
    if (BufferOut == NULL) {
      Status = EFI_OUT_OF_RESOURCES;
      return Status;
    }

    Status = HttpInstance->Tls->BuildResponsePacket (
                                  HttpInstance->Tls,
                                  NULL,
                                  0,
                                  BufferOut,
                                  &BufferOutSize
                                  );
  }
  if (EFI_ERROR (Status)) {
    FreePool (BufferOut);
    return Status;
  }

  //
  // Transmit ClientHello
  //
  PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
  DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
  if (DataOut == NULL) {
    FreePool (BufferOut);
    return EFI_OUT_OF_RESOURCES;
  }
  
  CopyMem (DataOut, BufferOut, BufferOutSize);
  Status = TlsCommonTransmit (HttpInstance, PacketOut);

  FreePool (BufferOut);
  NetbufFree (PacketOut);

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

  while(HttpInstance->TlsSessionState != EfiTlsSessionDataTransferring && \
    ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
    //
    // Receive one TLS record.
    //
    Status = TlsReceiveOnePdu (HttpInstance, &Pdu, Timeout);
    if (EFI_ERROR (Status)) {
      return Status;
    }

    BufferInSize = Pdu->TotalSize;
    BufferIn = AllocateZeroPool (BufferInSize);
    if (BufferIn == NULL) {
      NetbufFree (Pdu);
      Status = EFI_OUT_OF_RESOURCES;
      return Status;
    }

    NetbufCopy (Pdu, 0, (UINT32)BufferInSize, BufferIn);

    NetbufFree (Pdu);

    //
    // Handle Receive data.
    //
    BufferOutSize = DEF_BUF_LEN;
    BufferOut = AllocateZeroPool (BufferOutSize);
    if (BufferOut == NULL) {
      Status = EFI_OUT_OF_RESOURCES;
      return Status;
    }

    Status = HttpInstance->Tls->BuildResponsePacket (
                                  HttpInstance->Tls,
                                  BufferIn,
                                  BufferInSize,
                                  BufferOut,
                                  &BufferOutSize
                                  );
    if (Status == EFI_BUFFER_TOO_SMALL) {
       FreePool (BufferOut);
       BufferOut = AllocateZeroPool (BufferOutSize);
       if (BufferOut == NULL) {
         FreePool (BufferIn);
         Status = EFI_OUT_OF_RESOURCES;
         return Status;
       }

       Status = HttpInstance->Tls->BuildResponsePacket (
                                     HttpInstance->Tls,
                                     BufferIn,
                                     BufferInSize,
                                     BufferOut,
                                     &BufferOutSize
                                     );
    }

    FreePool (BufferIn);

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

    if (BufferOutSize != 0) {
      //
      // Transmit the response packet.
      //
      PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
      DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
      if (DataOut == NULL) {
        FreePool (BufferOut);
        return EFI_OUT_OF_RESOURCES;
      }
      
      CopyMem (DataOut, BufferOut, BufferOutSize);

      Status = TlsCommonTransmit (HttpInstance, PacketOut);

      NetbufFree (PacketOut);

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

    FreePool (BufferOut);

    //
    // Get the session state, then decide whether need to continue handle received packet.
    //
    GetSessionDataBufferSize = DEF_BUF_LEN;
    GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
    if (GetSessionDataBuffer == NULL) {
      Status = EFI_OUT_OF_RESOURCES;
      return Status;
    }

    Status = HttpInstance->Tls->GetSessionData (
                                  HttpInstance->Tls,
                                  EfiTlsSessionState,
                                  GetSessionDataBuffer,
                                  &GetSessionDataBufferSize
                                  );
    if (Status == EFI_BUFFER_TOO_SMALL) {
       FreePool (GetSessionDataBuffer);
       GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
       if (GetSessionDataBuffer == NULL) {
         Status = EFI_OUT_OF_RESOURCES;
         return Status;
       }

       Status = HttpInstance->Tls->GetSessionData (
                                     HttpInstance->Tls,
                                     EfiTlsSessionState,
                                     GetSessionDataBuffer,
                                     &GetSessionDataBufferSize
                                     );
    }
    if (EFI_ERROR (Status)) {
      FreePool(GetSessionDataBuffer);
      return Status;
    }

    ASSERT(GetSessionDataBufferSize == sizeof (EFI_TLS_SESSION_STATE));
    HttpInstance->TlsSessionState = *(EFI_TLS_SESSION_STATE *) GetSessionDataBuffer;

    FreePool (GetSessionDataBuffer);

    if(HttpInstance->TlsSessionState == EfiTlsSessionError) {
      return EFI_ABORTED;
    }
  }

  if (HttpInstance->TlsSessionState != EfiTlsSessionDataTransferring) {
    Status = EFI_ABORTED;
  }

  return Status;
}
Esempio n. 7
0
/**
  Receive one fragment decrypted from one TLS record.

  @param[in]           HttpInstance    Pointer to HTTP_PROTOCOL structure.
  @param[in, out]      Fragment        The received Fragment.
  @param[in]           Timeout         The time to wait for connection done.

  @retval EFI_SUCCESS          One fragment is received.
  @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
  @retval EFI_ABORTED          Something wrong decryption the message.
  @retval Others               Other errors as indicated.

**/
EFI_STATUS
EFIAPI
HttpsReceive (
  IN     HTTP_PROTOCOL         *HttpInstance,
  IN OUT NET_FRAGMENT          *Fragment,
  IN     EFI_EVENT             Timeout
  )
{
  EFI_STATUS                      Status;
  NET_BUF                         *Pdu;
  TLS_RECORD_HEADER               RecordHeader;
  UINT8                           *BufferIn;
  UINTN                           BufferInSize;
  NET_FRAGMENT                    TempFragment;
  UINT8                           *BufferOut;
  UINTN                           BufferOutSize;
  NET_BUF                         *PacketOut;
  UINT8                           *DataOut;
  UINT8                           *GetSessionDataBuffer;
  UINTN                           GetSessionDataBufferSize;

  Status                   = EFI_SUCCESS;
  Pdu                      = NULL;
  BufferIn                 = NULL;
  BufferInSize             = 0;
  BufferOut                = NULL;
  BufferOutSize            = 0;
  PacketOut                = NULL;
  DataOut                  = NULL;
  GetSessionDataBuffer     = NULL;
  GetSessionDataBufferSize = 0;

  //
  // Receive only one TLS record
  //
  Status = TlsReceiveOnePdu (HttpInstance, &Pdu, Timeout);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  BufferInSize = Pdu->TotalSize;
  BufferIn = AllocateZeroPool (BufferInSize);
  if (BufferIn == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    NetbufFree (Pdu);
    return Status;
  }

  NetbufCopy (Pdu, 0, (UINT32) BufferInSize, BufferIn);

  NetbufFree (Pdu);

  //
  // Handle Receive data.
  //
  RecordHeader = *(TLS_RECORD_HEADER *) BufferIn;

  if ((RecordHeader.ContentType == TlsContentTypeApplicationData) &&
    (RecordHeader.Version.Major == 0x03) &&
    (RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||
    RecordHeader.Version.Minor == TLS11_PROTOCOL_VERSION_MINOR ||
    RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)
  ) {
    //
    // Decrypt Packet.
    //
    Status = TlsProcessMessage (
               HttpInstance,
               BufferIn,
               BufferInSize,
               EfiTlsDecrypt,
               &TempFragment
               );

    FreePool (BufferIn);

    if (EFI_ERROR (Status)) {
      if (Status == EFI_ABORTED) {
        //
        // Something wrong decryption the message.
        // BuildResponsePacket() will be called to generate Error Alert message and send it out.
        //
        BufferOutSize = DEF_BUF_LEN;
        BufferOut = AllocateZeroPool (BufferOutSize);
        if (BufferOut == NULL) {
          Status = EFI_OUT_OF_RESOURCES;
          return Status;
        }

        Status = HttpInstance->Tls->BuildResponsePacket (
                                      HttpInstance->Tls,
                                      NULL,
                                      0,
                                      BufferOut,
                                      &BufferOutSize
                                      );
        if (Status == EFI_BUFFER_TOO_SMALL) {
          FreePool (BufferOut);
          BufferOut = AllocateZeroPool (BufferOutSize);
          if (BufferOut == NULL) {
            Status = EFI_OUT_OF_RESOURCES;
            return Status;
          }

          Status = HttpInstance->Tls->BuildResponsePacket (
                                        HttpInstance->Tls,
                                        NULL,
                                        0,
                                        BufferOut,
                                        &BufferOutSize
                                        );
        }
        if (EFI_ERROR (Status)) {
          FreePool(BufferOut);
          return Status;
        }

        if (BufferOutSize != 0) {
          PacketOut = NetbufAlloc ((UINT32)BufferOutSize);
          DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
          if (DataOut == NULL) {
            FreePool (BufferOut);
            return EFI_OUT_OF_RESOURCES;
          }
          
          CopyMem (DataOut, BufferOut, BufferOutSize);

          Status = TlsCommonTransmit (HttpInstance, PacketOut);

          NetbufFree (PacketOut);
        }

        FreePool(BufferOut);

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

        return EFI_ABORTED;
      }

      return Status;
    }

    //
    // Parsing buffer.
    //
    ASSERT (((TLS_RECORD_HEADER *) (TempFragment.Bulk))->ContentType == TlsContentTypeApplicationData);

    BufferInSize = ((TLS_RECORD_HEADER *) (TempFragment.Bulk))->Length;
    BufferIn = AllocateZeroPool (BufferInSize);
    if (BufferIn == NULL) {
      Status = EFI_OUT_OF_RESOURCES;
      return Status;
    }

    CopyMem (BufferIn, TempFragment.Bulk + sizeof (TLS_RECORD_HEADER), BufferInSize);

    //
    // Free the buffer in TempFragment.
    //
    FreePool (TempFragment.Bulk);

  } else if ((RecordHeader.ContentType == TlsContentTypeAlert) &&
    (RecordHeader.Version.Major == 0x03) &&
    (RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||
    RecordHeader.Version.Minor == TLS11_PROTOCOL_VERSION_MINOR ||
    RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)
    ) {
    BufferOutSize = DEF_BUF_LEN;
    BufferOut = AllocateZeroPool (BufferOutSize);
    if (BufferOut == NULL) {
      FreePool (BufferIn);
      Status = EFI_OUT_OF_RESOURCES;
      return Status;
    }

    Status = HttpInstance->Tls->BuildResponsePacket (
                                  HttpInstance->Tls,
                                  BufferIn,
                                  BufferInSize,
                                  BufferOut,
                                  &BufferOutSize
                                  );
    if (Status == EFI_BUFFER_TOO_SMALL) {
      FreePool (BufferOut);
      BufferOut = AllocateZeroPool (BufferOutSize);
      if (BufferOut == NULL) {
        FreePool (BufferIn);
        Status = EFI_OUT_OF_RESOURCES;
        return Status;
      }

      Status = HttpInstance->Tls->BuildResponsePacket (
                                    HttpInstance->Tls,
                                    BufferIn,
                                    BufferInSize,
                                    BufferOut,
                                    &BufferOutSize
                                    );
    }

    FreePool (BufferIn);

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

    if (BufferOutSize != 0) {
      PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
      DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
      if (DataOut == NULL) {
        FreePool (BufferOut);
        return EFI_OUT_OF_RESOURCES;
      }
      
      CopyMem (DataOut, BufferOut, BufferOutSize);

      Status = TlsCommonTransmit (HttpInstance, PacketOut);

      NetbufFree (PacketOut);
    }

    FreePool (BufferOut);

    //
    // Get the session state.
    //
    GetSessionDataBufferSize = DEF_BUF_LEN;
    GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
    if (GetSessionDataBuffer == NULL) {
      Status = EFI_OUT_OF_RESOURCES;
      return Status;
    }

    Status = HttpInstance->Tls->GetSessionData (
                                  HttpInstance->Tls,
                                  EfiTlsSessionState,
                                  GetSessionDataBuffer,
                                  &GetSessionDataBufferSize
                                  );
    if (Status == EFI_BUFFER_TOO_SMALL) {
       FreePool (GetSessionDataBuffer);
       GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
       if (GetSessionDataBuffer == NULL) {
         Status = EFI_OUT_OF_RESOURCES;
         return Status;
       }

       Status = HttpInstance->Tls->GetSessionData (
                                     HttpInstance->Tls,
                                     EfiTlsSessionState,
                                     GetSessionDataBuffer,
                                     &GetSessionDataBufferSize
                                     );
    }
    if (EFI_ERROR (Status)) {
      FreePool (GetSessionDataBuffer);
      return Status;
    }

    ASSERT(GetSessionDataBufferSize == sizeof (EFI_TLS_SESSION_STATE));
    HttpInstance->TlsSessionState = *(EFI_TLS_SESSION_STATE *) GetSessionDataBuffer;

    FreePool (GetSessionDataBuffer);

    if(HttpInstance->TlsSessionState == EfiTlsSessionError) {
      DEBUG ((EFI_D_ERROR, "TLS Session State Error!\n"));
      return EFI_ABORTED;
    }

    BufferIn = NULL;
    BufferInSize = 0;
  }

  Fragment->Bulk = BufferIn;
  Fragment->Len = (UINT32) BufferInSize;

  return Status;
}
Esempio n. 8
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);
  }
}