Exemplo n.º 1
0
EFI_STATUS
ConvertIpStringToEfiIp (
  IN  CHAR8           *PathName,
  OUT EFI_IP_ADDRESS  *ServerIp
  )
{
  CHAR8     *Str;

  Str = PathName;
  ServerIp->v4.Addr[0] = (UINT8)AsciiStrDecimalToUintn (Str);

  Str = AsciiStrStr (Str, ".");
  if (Str == NULL) {
    return EFI_DEVICE_ERROR;
  }

  ServerIp->v4.Addr[1] = (UINT8)AsciiStrDecimalToUintn (++Str);

  Str = AsciiStrStr (Str, ".");
  if (Str == NULL) {
    return EFI_DEVICE_ERROR;
  }

  ServerIp->v4.Addr[2] = (UINT8)AsciiStrDecimalToUintn (++Str);

  Str = AsciiStrStr (Str, ".");
  if (Str == NULL) {
    return EFI_DEVICE_ERROR;
  }

  ServerIp->v4.Addr[3] = (UINT8)AsciiStrDecimalToUintn (++Str);

  return EFI_SUCCESS;
}
Exemplo n.º 2
0
/**
  Get section entry decimal UINTN value.

  @param[in]  Context         INI Config file context.
  @param[in]  SectionName     Section name.
  @param[in]  EntryName       Section entry name.
  @param[out] Data            Point to the got decimal UINTN value.

  @retval EFI_SUCCESS    Section entry decimal UINTN value is got.
  @retval EFI_NOT_FOUND  Section is not found.
**/
EFI_STATUS
EFIAPI
GetDecimalUintnFromDataFile (
  IN      VOID                          *Context,
  IN      CHAR8                         *SectionName,
  IN      CHAR8                         *EntryName,
  OUT     UINTN                         *Data
  )
{
  CHAR8                                 *Value;
  EFI_STATUS                            Status;

  if (Context == NULL || SectionName == NULL || EntryName == NULL || Data == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  Status = GetStringFromDataFile(
             Context,
             SectionName,
             EntryName,
             &Value
             );
  if (EFI_ERROR(Status)) {
    return EFI_NOT_FOUND;
  }
  ASSERT (Value != NULL);
  if (!IsValidDecimalString(Value, AsciiStrLen(Value))) {
    return EFI_NOT_FOUND;
  }
  *Data = AsciiStrDecimalToUintn(Value);
  return EFI_SUCCESS;
}
Exemplo n.º 3
0
EFI_STATUS
EFIAPI
EblSleepCmd (
  IN UINTN Argc,
  IN CHAR8 **Argv
  )
{
  UINTN Delay;

  Delay = (Argc == 1)? 10 : AsciiStrDecimalToUintn (Argv[1]);

  gBS->Stall (Delay * 1000000);

  return EFI_SUCCESS;
}
Exemplo n.º 4
0
/**
  Get the value of the content length if there is a "Content-Length" header.

  @param[in]    HeaderCount        Number of HTTP header structures in Headers.
  @param[in]    Headers            Array containing list of HTTP headers.
  @param[out]   ContentLength      Pointer to save the value of the content length.

  @retval EFI_SUCCESS              Successfully get the content length.
  @retval EFI_NOT_FOUND            No "Content-Length" header in the Headers.

**/
EFI_STATUS
HttpIoParseContentLengthHeader (
  IN     UINTN                HeaderCount,
  IN     EFI_HTTP_HEADER      *Headers,
     OUT UINTN                *ContentLength
  )
{
  EFI_HTTP_HEADER       *Header;
  
  Header = HttpIoFindHeader (HeaderCount, Headers, "Content-Length");
  if (Header == NULL) {
    return EFI_NOT_FOUND;
  }

  *ContentLength = AsciiStrDecimalToUintn (Header->FieldValue);
  return EFI_SUCCESS;
}
Exemplo n.º 5
0
/**
  Get the port number from a HTTP URL.

  This function will return the port number according to the Url and previous parse result.

  @param[in]    Url                The pointer to a HTTP URL string.
  @param[in]    UrlParser          URL Parse result returned by NetHttpParseUrl().
  @param[out]   Port               Pointer to a buffer to store the port number.

  @retval EFI_SUCCESS              Successfully get the required component.
  @retval EFI_INVALID_PARAMETER    Uri is NULL or Port is NULL or UrlParser is invalid.
  @retval EFI_NOT_FOUND            No port number in the URL.
  @retval EFI_OUT_OF_RESOURCES     Could not allocate needed resources.
  
**/
EFI_STATUS
EFIAPI
HttpUrlGetPort (
  IN      CHAR8              *Url,
  IN      VOID               *UrlParser,
     OUT  UINT16             *Port
  )
{
  CHAR8         *PortString;
  EFI_STATUS    Status;
  UINT32        ResultLength;
  HTTP_URL_PARSER      *Parser;

  if (Url == NULL || UrlParser == NULL || Port == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  Parser = (HTTP_URL_PARSER*) UrlParser;

  if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_PORT)) == 0) {
    return EFI_INVALID_PARAMETER;
  }

  PortString = AllocatePool (Parser->FieldData[HTTP_URI_FIELD_PORT].Length + 1);
  if (PortString == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }

  Status = UriPercentDecode (
             Url + Parser->FieldData[HTTP_URI_FIELD_PORT].Offset,
             Parser->FieldData[HTTP_URI_FIELD_PORT].Length,
             PortString,
             &ResultLength
             );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  PortString[ResultLength] = '\0';
  *Port = (UINT16) AsciiStrDecimalToUintn (Url + Parser->FieldData[HTTP_URI_FIELD_PORT].Offset);

  return  EFI_SUCCESS;
}
Exemplo n.º 6
0
/**
Internal work function to extract a device number from a string skipping
text. Easy way to extract numbers from strings like blk7:.

@param  Str   String to extract device number form

@return -1    Device string is not valid
@return       Device #

**/
UINTN
EblConvertDevStringToNumber (
  IN  CHAR8   *Str
  )
{
  UINTN   Max;
  UINTN   Index;


  // Find the first digit
  Max = AsciiStrLen (Str);
  for  (Index = 0; !((*Str >= '0') && (*Str <= '9')) && (Index < Max); Index++) {
    Str++;
  }
  if (Index == Max) {
    return (UINTN)-1;
  }

  return AsciiStrDecimalToUintn (Str);
}
Exemplo n.º 7
0
/**
  Pause until a key is pressed and abort the remaining commands on the command
  line. If no key is pressed continue processing the command line. This command
  allows the user to stop an operation from happening and return control to the
  command prompt.

  Argv[0] - "pause"
  Argv[1] - timeout value is decimal seconds

  @param  Argc   Number of command arguments in Argv
  @param  Argv   Array of strings that represent the parsed command line.
                 Argv[0] is the command name

  @return EFI_SUCCESS  Timeout expired with no input
  @return EFI_TIMEOUT  Stop processing other commands on the same command line

**/
EFI_STATUS
EFIAPI
EblPauseCmd (
  IN UINTN  Argc,
  IN CHAR8  **Argv
  )
{
  EFI_STATUS      Status;
  UINTN           Delay;
  EFI_INPUT_KEY   Key;

  Delay = (Argc == 1)? 10 : AsciiStrDecimalToUintn (Argv[1]);

  AsciiPrint ("Hit any key to break. You have %3d seconds", Delay);
  Status = EblGetCharKey (&Key, Delay, EblPauseCallback);
  AsciiPrint ("\n");

  // If we timeout then the pause succeeded thus return success
  // If we get a key return timeout to stop other command on this cmd line
  return (Status == EFI_SUCCESS) ? EFI_TIMEOUT : EFI_SUCCESS;;
}
Exemplo n.º 8
0
/** The atoi function converts the initial portion of the string pointed to by
    nptr to int representation.  Except for the behavior on error, it is
    equivalent to:
      - (int)strtol(nptr, (char **)NULL, 10)

  @return   The atoi function returns the converted value.
**/
int
atoi(const char *nptr)
{
  int       Retval;
  BOOLEAN   Negative = FALSE;

  while(isspace((const unsigned char)*nptr)) ++nptr; // Skip leading spaces

  if(*nptr == '+') {
    Negative = FALSE;
    ++nptr;
  }
  else if(*nptr == '-') {
    Negative = TRUE;
    ++nptr;
  }
  Retval = (int)AsciiStrDecimalToUintn(nptr);
  if(Negative) {
    Retval = -Retval;
  }
  return Retval;
}
Exemplo n.º 9
0
/**
  See if command contains .# where # is a number. Return # as the Width
  or 1 as the default Width for commands.

  Example hexdump.4 returns a width of 4.

  @param  Argv   Argv[0] is the command name

  @return Width of command

**/
UINTN
WidthFromCommandName (
  IN CHAR8  *Argv,
  IN UINTN  Default
  )
{
  CHAR8         *Str;
  UINTN         Width;

  //Hexdump.2 HexDump.4 mean use a different width
  Str = AsciiStrStr (Argv, ".");
  if (Str != NULL) {
    Width = AsciiStrDecimalToUintn (Str + 1);
    if (Width == 0) {
      Width = Default;
    }
  } else {
    // Default answer
    return Default;
  }

  return Width;
}
Exemplo n.º 10
0
/**
  This function checks the received iSCSI Login Response during the security
  negotiation stage.

  @param[in] Conn             The iSCSI connection.

  @retval EFI_SUCCESS          The Login Response passed the CHAP validation.
  @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
  @retval EFI_PROTOCOL_ERROR   Some kind of protocol error happend.
  @retval Others               Other errors as indicated.
**/
EFI_STATUS
IScsiCHAPOnRspReceived (
  IN ISCSI_CONNECTION  *Conn
  )
{
  EFI_STATUS                Status;
  ISCSI_SESSION             *Session;
  ISCSI_CHAP_AUTH_DATA      *AuthData;
  CHAR8                     *Value;
  UINT8                     *Data;
  UINT32                    Len;
  LIST_ENTRY                *KeyValueList;
  UINTN                     Algorithm;
  CHAR8                     *Identifier;
  CHAR8                     *Challenge;
  CHAR8                     *Name;
  CHAR8                     *Response;
  UINT8                     TargetRsp[ISCSI_CHAP_RSP_LEN];
  UINT32                    RspLen;

  ASSERT (Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION);
  ASSERT (Conn->RspQue.BufNum != 0);

  Session     = Conn->Session;
  AuthData    = &Session->AuthData;

  Len         = Conn->RspQue.BufSize;
  Data        = AllocatePool (Len);
  if (Data == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }
  //
  // Copy the data in case the data spans over multiple PDUs.
  //
  NetbufQueCopy (&Conn->RspQue, 0, Len, Data);

  //
  // Build the key-value list from the data segment of the Login Response.
  //
  KeyValueList = IScsiBuildKeyValueList ((CHAR8 *) Data, Len);
  if (KeyValueList == NULL) {
    FreePool (Data);
    return EFI_OUT_OF_RESOURCES;
  }

  Status = EFI_PROTOCOL_ERROR;

  switch (Conn->CHAPStep) {
  case ISCSI_CHAP_INITIAL:
    //
    // The first Login Response.
    //
    Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_TARGET_PORTAL_GROUP_TAG);
    if (Value == NULL) {
      goto ON_EXIT;
    }

    Session->TargetPortalGroupTag = (UINT16) AsciiStrDecimalToUintn (Value);

    Value                         = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_AUTH_METHOD);
    if (Value == NULL) {
      goto ON_EXIT;
    }
    //
    // Initiator mandates CHAP authentication but target replies without "CHAP" or
    // initiator suggets "None" but target replies with some kind of auth method.
    //
    if (AsciiStrCmp (Value, ISCSI_AUTH_METHOD_CHAP) == 0) {
      if (AuthData->AuthConfig.CHAPType == ISCSI_CHAP_NONE) {
        goto ON_EXIT;
      }
    } else {
      if (AuthData->AuthConfig.CHAPType != ISCSI_CHAP_NONE) {
        goto ON_EXIT;
      }
    }
    //
    // Transit to CHAP step one.
    //
    Conn->CHAPStep  = ISCSI_CHAP_STEP_ONE;
    Status          = EFI_SUCCESS;
    break;

  case ISCSI_CHAP_STEP_TWO:
    //
    // The Target replies with CHAP_A=<A> CHAP_I=<I> CHAP_C=<C>
    //
    Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_ALGORITHM);
    if (Value == NULL) {
      goto ON_EXIT;
    }

    Algorithm = AsciiStrDecimalToUintn (Value);
    if (Algorithm != ISCSI_CHAP_ALGORITHM_MD5) {
      //
      // Unsupported algorithm is chosen by target.
      //
      goto ON_EXIT;
    }

    Identifier = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_IDENTIFIER);
    if (Identifier == NULL) {
      goto ON_EXIT;
    }

    Challenge = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_CHALLENGE);
    if (Challenge == NULL) {
      goto ON_EXIT;
    }
    //
    // Process the CHAP identifier and CHAP Challenge from Target
    // Calculate Response value
    //
    AuthData->InIdentifier      = (UINT32) AsciiStrDecimalToUintn (Identifier);
    AuthData->InChallengeLength = ISCSI_CHAP_AUTH_MAX_LEN;
    IScsiHexToBin ((UINT8 *) AuthData->InChallenge, &AuthData->InChallengeLength, Challenge);
    Status = IScsiCHAPCalculateResponse (
              AuthData->InIdentifier,
              AuthData->AuthConfig.CHAPSecret,
              (UINT32) AsciiStrLen (AuthData->AuthConfig.CHAPSecret),
              AuthData->InChallenge,
              AuthData->InChallengeLength,
              AuthData->CHAPResponse
              );

    //
    // Transit to next step.
    //
    Conn->CHAPStep = ISCSI_CHAP_STEP_THREE;
    break;

  case ISCSI_CHAP_STEP_THREE:
    //
    // one way CHAP authentication and the target would like to
    // authenticate us.
    //
    Status = EFI_SUCCESS;
    break;

  case ISCSI_CHAP_STEP_FOUR:
    ASSERT (AuthData->AuthConfig.CHAPType == ISCSI_CHAP_MUTUAL);
    //
    // The forth step, CHAP_N=<N> CHAP_R=<R> is received from Target.
    //
    Name = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_NAME);
    if (Name == NULL) {
      goto ON_EXIT;
    }

    Response = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_RESPONSE);
    if (Response == NULL) {
      goto ON_EXIT;
    }

    RspLen = ISCSI_CHAP_RSP_LEN;
    IScsiHexToBin (TargetRsp, &RspLen, Response);

    //
    // Check the CHAP Response replied by Target.
    //
    Status = IScsiCHAPAuthTarget (AuthData, TargetRsp);
    break;

  default:
    break;
  }

ON_EXIT:

  IScsiFreeKeyValueList (KeyValueList);

  FreePool (Data);

  return Status;
}
Exemplo n.º 11
0
Arquivo: Tftp.c Projeto: rsalveti/edk2
/**
  Worker function that gets the size in numbers of bytes of a file from a TFTP
  server before to download the file.

  @param[in]   Mtftp4    MTFTP4 protocol interface
  @param[in]   FilePath  Path of the file, ASCII encoded
  @param[out]  FileSize  Address where to store the file size in number of
                         bytes.

  @retval  EFI_SUCCESS      The size of the file was returned.
  @retval  EFI_UNSUPPORTED  The server does not support the "tsize" option.
  @retval  Others           Error when retrieving the information from the server
                            (see EFI_MTFTP4_PROTOCOL.GetInfo() status codes)
                            or error when parsing the response of the server.
**/
STATIC
EFI_STATUS
GetFileSize (
  IN   EFI_MTFTP4_PROTOCOL  *Mtftp4,
  IN   CONST CHAR8          *FilePath,
  OUT  UINTN                *FileSize
  )
{
  EFI_STATUS         Status;
  EFI_MTFTP4_OPTION  ReqOpt[1];
  EFI_MTFTP4_PACKET  *Packet;
  UINT32             PktLen;
  EFI_MTFTP4_OPTION  *TableOfOptions;
  EFI_MTFTP4_OPTION  *Option;
  UINT32             OptCnt;
  UINT8              OptBuf[128];

  ReqOpt[0].OptionStr = (UINT8*)"tsize";
  OptBuf[0] = '0';
  OptBuf[1] = 0;
  ReqOpt[0].ValueStr = OptBuf;

  Status = Mtftp4->GetInfo (
             Mtftp4,
             NULL,
             (UINT8*)FilePath,
             NULL,
             1,
             ReqOpt,
             &PktLen,
             &Packet
             );

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

  Status = Mtftp4->ParseOptions (
                     Mtftp4,
                     PktLen,
                     Packet,
                     (UINT32 *) &OptCnt,
                     &TableOfOptions
                     );
  if (EFI_ERROR (Status)) {
    goto Error;
  }

  Option = TableOfOptions;
  while (OptCnt != 0) {
    if (AsciiStrnCmp ((CHAR8 *)Option->OptionStr, "tsize", 5) == 0) {
      *FileSize = AsciiStrDecimalToUintn ((CHAR8 *)Option->ValueStr);
      break;
    }
    OptCnt--;
    Option++;
  }
  FreePool (TableOfOptions);

  if (OptCnt == 0) {
    Status = EFI_UNSUPPORTED;
  }

Error :

  return Status;
}
Exemplo n.º 12
0
/**
  The work function of EfiHttpResponse().

  @param[in]  Wrap                Pointer to HTTP token's wrap data.

  @retval EFI_SUCCESS             Allocation succeeded.
  @retval EFI_OUT_OF_RESOURCES    Failed to complete the opration due to lack of resources.
  @retval EFI_NOT_READY           Can't find a corresponding TxToken.

**/
EFI_STATUS
HttpResponseWorker (
  IN  HTTP_TOKEN_WRAP           *Wrap
  )
{
  EFI_STATUS                    Status;
  EFI_HTTP_MESSAGE              *HttpMsg;
  EFI_TCP4_IO_TOKEN             *RxToken;
  EFI_TCP4_PROTOCOL             *Tcp4;
  CHAR8                         *EndofHeader;
  CHAR8                         *HttpHeaders;
  UINTN                         SizeofHeaders;
  CHAR8                         *Buffer;
  UINTN                         BufferSize;
  UINTN                         StatusCode;
  CHAR8                         *Tmp;
  CHAR8                         *HeaderTmp;
  CHAR8                         *StatusCodeStr;
  UINTN                         BodyLen;
  HTTP_PROTOCOL                 *HttpInstance;
  EFI_HTTP_TOKEN                *Token;
  NET_MAP_ITEM                  *Item;
  HTTP_TOKEN_WRAP               *ValueInItem;
  UINTN                         HdrLen;

  if (Wrap == NULL || Wrap->HttpInstance == NULL) {
    return EFI_INVALID_PARAMETER;
  }
  
  HttpInstance = Wrap->HttpInstance;
  Token = Wrap->HttpToken;

  HttpMsg = Token->Message;

  Tcp4 = HttpInstance->Tcp4;
  ASSERT (Tcp4 != NULL);
  HttpMsg->Headers = NULL;
  HttpHeaders   = NULL;
  SizeofHeaders = 0;
  Buffer        = NULL;
  BufferSize    = 0;
  EndofHeader   = NULL;
 
  if (HttpMsg->Data.Response != NULL) {
    //
    // Need receive the HTTP headers, prepare buffer.
    //
    Status = HttpCreateTcp4RxEventForHeader (HttpInstance);
    if (EFI_ERROR (Status)) {
      goto Error;
    }

    //
    // Check whether we have cached header from previous call.
    //
    if ((HttpInstance->CacheBody != NULL) && (HttpInstance->NextMsg != NULL)) {
      //
      // The data is stored at [NextMsg, CacheBody + CacheLen].
      //
      HdrLen = HttpInstance->CacheBody + HttpInstance->CacheLen - HttpInstance->NextMsg;
      HttpHeaders = AllocateZeroPool (HdrLen);
      if (HttpHeaders == NULL) {
        Status = EFI_OUT_OF_RESOURCES;
        goto Error;
      }

      CopyMem (HttpHeaders, HttpInstance->NextMsg, HdrLen);
      FreePool (HttpInstance->CacheBody);
      HttpInstance->CacheBody   = NULL;
      HttpInstance->NextMsg     = NULL;
      HttpInstance->CacheOffset = 0;
      SizeofHeaders = HdrLen;
      BufferSize = HttpInstance->CacheLen;

      //
      // Check whether we cached the whole HTTP headers.
      //
      EndofHeader = AsciiStrStr (HttpHeaders, HTTP_END_OF_HDR_STR); 
    }
    
    RxToken = &HttpInstance->RxToken;
    RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);
    if (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {
      Status = EFI_OUT_OF_RESOURCES;
      goto Error;
    }

    //
    // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.
    //
    while (EndofHeader == NULL) {   
      HttpInstance->IsRxDone = FALSE;
      RxToken->Packet.RxData->DataLength = DEF_BUF_LEN;
      RxToken->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;
      Status = Tcp4->Receive (Tcp4, RxToken);
      if (EFI_ERROR (Status)) {
        DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));
        goto Error;
      }
      
      while (!HttpInstance->IsRxDone) {
       Tcp4->Poll (Tcp4);
      }    

      Status = RxToken->CompletionToken.Status;
      if (EFI_ERROR (Status)) {
        goto Error;
      }

      //
      // Append the response string.
      //
      BufferSize = SizeofHeaders + RxToken->Packet.RxData->FragmentTable[0].FragmentLength;
      Buffer = AllocateZeroPool (BufferSize);
      if (Buffer == NULL) {
        Status = EFI_OUT_OF_RESOURCES;
        goto Error;
      }

      if (HttpHeaders != NULL) {
        CopyMem (Buffer, HttpHeaders, SizeofHeaders);
        FreePool (HttpHeaders);
      }

      CopyMem (
        Buffer + SizeofHeaders,
        RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer,
        RxToken->Packet.RxData->FragmentTable[0].FragmentLength
        );
      HttpHeaders   = Buffer;
      SizeofHeaders = BufferSize;

      //
      // Check whether we received end of HTTP headers.
      //
      EndofHeader = AsciiStrStr (HttpHeaders, HTTP_END_OF_HDR_STR); 
    };

    //
    // Skip the CRLF after the HTTP headers.
    //
    EndofHeader = EndofHeader + AsciiStrLen (HTTP_END_OF_HDR_STR);

    //
    // Cache the part of body.
    //
    BodyLen = BufferSize - (EndofHeader - HttpHeaders);
    if (BodyLen > 0) {
      if (HttpInstance->CacheBody != NULL) {
        FreePool (HttpInstance->CacheBody);
      }

      HttpInstance->CacheBody = AllocateZeroPool (BodyLen);
      if (HttpInstance->CacheBody == NULL) {
        Status = EFI_OUT_OF_RESOURCES;
        goto Error;
      }

      CopyMem (HttpInstance->CacheBody, EndofHeader, BodyLen);
      HttpInstance->CacheLen = BodyLen;
    }

    FreePool (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer);
    RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;

    //
    // Search for Status Code.
    //
    StatusCodeStr = HttpHeaders + AsciiStrLen (HTTP_VERSION_STR) + 1;
    if (StatusCodeStr == NULL) {
      goto Error;
    }

    StatusCode = AsciiStrDecimalToUintn (StatusCodeStr);

    //
    // Remove the first line of HTTP message, e.g. "HTTP/1.1 200 OK\r\n".
    //
    Tmp = AsciiStrStr (HttpHeaders, HTTP_CRLF_STR);
    if (Tmp == NULL) {
      goto Error;
    }

    Tmp = Tmp + AsciiStrLen (HTTP_CRLF_STR);
    SizeofHeaders = SizeofHeaders - (Tmp - HttpHeaders);
    HeaderTmp = AllocateZeroPool (SizeofHeaders);
    if (HeaderTmp == NULL) {
      goto Error;
    }

    CopyMem (HeaderTmp, Tmp, SizeofHeaders);
    FreePool (HttpHeaders);
    HttpHeaders = HeaderTmp;
    //
    // Parse the HTTP header into array of key/value pairs.
    //
    Status = HttpUtilitiesParse (HttpHeaders, SizeofHeaders, &HttpMsg->Headers, &HttpMsg->HeaderCount);
    if (EFI_ERROR (Status)) {
      goto Error;
    }

    FreePool (HttpHeaders);
    HttpHeaders = NULL;
    
    HttpMsg->Data.Response->StatusCode = HttpMappingToStatusCode (StatusCode);

    //
    // Init message-body parser by header information.  
    //
    Status = EFI_NOT_READY;
    ValueInItem = NULL;
    NetMapRemoveHead (&HttpInstance->TxTokens, (VOID**) &ValueInItem);
    if (ValueInItem == NULL)  {
      goto Error;
    }

    //
    // The first TxToken not transmitted yet, insert back and return error.
    //
    if (!ValueInItem->TcpWrap.IsTxDone) {
      goto Error2;
    }

    Status = HttpInitMsgParser (
               ValueInItem->TcpWrap.Method,
               HttpMsg->Data.Response->StatusCode,
               HttpMsg->HeaderCount,
               HttpMsg->Headers,
               HttpBodyParserCallback,
               (VOID *) ValueInItem,
               &HttpInstance->MsgParser
               );
    if (EFI_ERROR (Status)) {       
      goto Error2;
    }

    //
    // Check whether we received a complete HTTP message.
    //
    if (HttpInstance->CacheBody != NULL) {
      Status = HttpParseMessageBody (HttpInstance->MsgParser, HttpInstance->CacheLen, HttpInstance->CacheBody);
      if (EFI_ERROR (Status)) {
        goto Error2;
      }

      if (HttpIsMessageComplete (HttpInstance->MsgParser)) {
        //
        // Free the MsgParse since we already have a full HTTP message.
        //
        HttpFreeMsgParser (HttpInstance->MsgParser);
        HttpInstance->MsgParser = NULL;
      }
    }

    if ((HttpMsg->Body == NULL) || (HttpMsg->BodyLength == 0)) {    
      Status = EFI_SUCCESS;
      goto Exit;
    }
  }  

  //
  // Receive the response body.
  //
  BodyLen = 0;

  //
  // First check whether we cached some data.
  //
  if (HttpInstance->CacheBody != NULL) {
    //
    // Calculate the length of the cached data.
    //
    if (HttpInstance->NextMsg != NULL) {
      //
      // We have a cached HTTP message which includes a part of HTTP header of next message.
      //
      BodyLen = HttpInstance->NextMsg - (HttpInstance->CacheBody + HttpInstance->CacheOffset);      
    } else {
      BodyLen = HttpInstance->CacheLen - HttpInstance->CacheOffset;
    }

    if (BodyLen > 0) {
      //
      // We have some cached data. Just copy the data and return.
      //
      if (HttpMsg->BodyLength < BodyLen) {
        CopyMem (HttpMsg->Body, HttpInstance->CacheBody + HttpInstance->CacheOffset, HttpMsg->BodyLength);
        HttpInstance->CacheOffset = HttpInstance->CacheOffset + HttpMsg->BodyLength;
      } else {
        //
        // Copy all cached data out.
        //
        CopyMem (HttpMsg->Body, HttpInstance->CacheBody + HttpInstance->CacheOffset, BodyLen);
        HttpInstance->CacheOffset = BodyLen + HttpInstance->CacheOffset;
        HttpMsg->BodyLength = BodyLen;

        if (HttpInstance->NextMsg == NULL) {
          //
          // There is no HTTP header of next message. Just free the cache buffer.
          //
          FreePool (HttpInstance->CacheBody);
          HttpInstance->CacheBody   = NULL;
          HttpInstance->NextMsg     = NULL;
          HttpInstance->CacheOffset = 0;
        }
      }
      //
      // Return since we aready received required data.
      //
      Status = EFI_SUCCESS;
      goto Exit;
    } 

    if (BodyLen == 0 && HttpInstance->MsgParser == NULL) {
      //
      // We received a complete HTTP message, and we don't have more data to return to caller.
      //
      HttpMsg->BodyLength = 0;
      Status = EFI_SUCCESS;
      goto Exit;      
    }    
  }

  ASSERT (HttpInstance->MsgParser != NULL);

  //
  // We still need receive more data when there is no cache data and MsgParser is not NULL;
  //
  RxToken = &Wrap->TcpWrap.RxToken;

  RxToken->Packet.RxData->DataLength = (UINT32) HttpMsg->BodyLength;
  RxToken->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32) HttpMsg->BodyLength;
  RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *) HttpMsg->Body;

  RxToken->CompletionToken.Status = EFI_NOT_READY;
  Status = Tcp4->Receive (Tcp4, RxToken);
  if (EFI_ERROR (Status)) {
    DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));
    goto Error;
  }

  return Status;

Exit:
  Item = NetMapFindKey (&Wrap->HttpInstance->RxTokens, Wrap->HttpToken);
  if (Item != NULL) {
    NetMapRemoveItem (&Wrap->HttpInstance->RxTokens, Item, NULL);
  }
  Token->Status = Status;
  gBS->SignalEvent (Token->Event);
  FreePool (Wrap);
  return Status;

Error2:
  NetMapInsertHead (&HttpInstance->TxTokens, ValueInItem->HttpToken, ValueInItem);

Error:
  if (Wrap != NULL) {
    if (Wrap->TcpWrap.RxToken.CompletionToken.Event != NULL) {
      gBS->CloseEvent (Wrap->TcpWrap.RxToken.CompletionToken.Event);
    }
    RxToken = &Wrap->TcpWrap.RxToken;
    if (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
      FreePool (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer);
      RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
    }
    FreePool (Wrap);
  }

  if (HttpInstance->RxToken.CompletionToken.Event != NULL) {
    gBS->CloseEvent (HttpInstance->RxToken.CompletionToken.Event);
    HttpInstance->RxToken.CompletionToken.Event = NULL;
  }

  RxToken = &HttpInstance->RxToken;
  if (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
    FreePool (RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer);
    RxToken->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
  }
  
  if (HttpHeaders != NULL) {
    FreePool (HttpHeaders);
  }

  if (HttpMsg->Headers != NULL) {
    FreePool (HttpMsg->Headers);
  }

  if (HttpInstance->CacheBody != NULL) {
    FreePool (HttpInstance->CacheBody);
    HttpInstance->CacheBody = NULL;
  }

  Token->Status = Status;
  gBS->SignalEvent (Token->Event);

  return Status;  

}
Exemplo n.º 13
0
Arquivo: HttpImpl.c Projeto: obek/edk2
/**
  The work function of EfiHttpResponse().

  @param[in]  Wrap                Pointer to HTTP token's wrap data.

  @retval EFI_SUCCESS             Allocation succeeded.
  @retval EFI_OUT_OF_RESOURCES    Failed to complete the opration due to lack of resources.
  @retval EFI_NOT_READY           Can't find a corresponding Tx4Token/Tx6Token or 
                                  the EFI_HTTP_UTILITIES_PROTOCOL is not available.

**/
EFI_STATUS
HttpResponseWorker (
  IN  HTTP_TOKEN_WRAP           *Wrap
  )
{
  EFI_STATUS                    Status;
  EFI_HTTP_MESSAGE              *HttpMsg;
  CHAR8                         *EndofHeader;
  CHAR8                         *HttpHeaders;
  UINTN                         SizeofHeaders;
  UINTN                         BufferSize;
  UINTN                         StatusCode;
  CHAR8                         *Tmp;
  CHAR8                         *HeaderTmp;
  CHAR8                         *StatusCodeStr;
  UINTN                         BodyLen;
  HTTP_PROTOCOL                 *HttpInstance;
  EFI_HTTP_TOKEN                *Token;
  NET_MAP_ITEM                  *Item;
  HTTP_TOKEN_WRAP               *ValueInItem;
  UINTN                         HdrLen;

  if (Wrap == NULL || Wrap->HttpInstance == NULL) {
    return EFI_INVALID_PARAMETER;
  }
  
  HttpInstance = Wrap->HttpInstance;
  Token = Wrap->HttpToken;
  HttpMsg = Token->Message;

  HttpInstance->EndofHeader = NULL;
  HttpInstance->HttpHeaders = NULL;
  HttpMsg->Headers          = NULL;
  HttpHeaders               = NULL;
  SizeofHeaders             = 0;
  BufferSize                = 0;
  EndofHeader               = NULL;
 
  if (HttpMsg->Data.Response != NULL) {
    //
    // Need receive the HTTP headers, prepare buffer.
    //
    Status = HttpCreateTcpRxEventForHeader (HttpInstance);
    if (EFI_ERROR (Status)) {
      goto Error;
    }

    //
    // Check whether we have cached header from previous call.
    //
    if ((HttpInstance->CacheBody != NULL) && (HttpInstance->NextMsg != NULL)) {
      //
      // The data is stored at [NextMsg, CacheBody + CacheLen].
      //
      HdrLen = HttpInstance->CacheBody + HttpInstance->CacheLen - HttpInstance->NextMsg;
      HttpHeaders = AllocateZeroPool (HdrLen);
      if (HttpHeaders == NULL) {
        Status = EFI_OUT_OF_RESOURCES;
        goto Error;
      }

      CopyMem (HttpHeaders, HttpInstance->NextMsg, HdrLen);
      FreePool (HttpInstance->CacheBody);
      HttpInstance->CacheBody   = NULL;
      HttpInstance->NextMsg     = NULL;
      HttpInstance->CacheOffset = 0;
      SizeofHeaders = HdrLen;
      BufferSize = HttpInstance->CacheLen;

      //
      // Check whether we cached the whole HTTP headers.
      //
      EndofHeader = AsciiStrStr (HttpHeaders, HTTP_END_OF_HDR_STR); 
    }   

    HttpInstance->EndofHeader = &EndofHeader;
    HttpInstance->HttpHeaders = &HttpHeaders;

    Status = HttpTcpReceiveHeader (HttpInstance, &SizeofHeaders, &BufferSize);
    if (EFI_ERROR (Status)) {
      goto Error;
    }

    ASSERT (HttpHeaders != NULL);

    //
    // Cache the part of body.
    //
    BodyLen = BufferSize - (EndofHeader - HttpHeaders);
    if (BodyLen > 0) {
      if (HttpInstance->CacheBody != NULL) {
        FreePool (HttpInstance->CacheBody);
      }

      HttpInstance->CacheBody = AllocateZeroPool (BodyLen);
      if (HttpInstance->CacheBody == NULL) {
        Status = EFI_OUT_OF_RESOURCES;
        goto Error;
      }

      CopyMem (HttpInstance->CacheBody, EndofHeader, BodyLen);
      HttpInstance->CacheLen = BodyLen;
    }

    //
    // Search for Status Code.
    //
    StatusCodeStr = HttpHeaders + AsciiStrLen (HTTP_VERSION_STR) + 1;
    if (StatusCodeStr == NULL) {
      goto Error;
    }

    StatusCode = AsciiStrDecimalToUintn (StatusCodeStr);

    //
    // Remove the first line of HTTP message, e.g. "HTTP/1.1 200 OK\r\n".
    //
    Tmp = AsciiStrStr (HttpHeaders, HTTP_CRLF_STR);
    if (Tmp == NULL) {
      goto Error;
    }

    Tmp = Tmp + AsciiStrLen (HTTP_CRLF_STR);
    SizeofHeaders = SizeofHeaders - (Tmp - HttpHeaders);
    HeaderTmp = AllocateZeroPool (SizeofHeaders);
    if (HeaderTmp == NULL) {
      goto Error;
    }

    CopyMem (HeaderTmp, Tmp, SizeofHeaders);
    FreePool (HttpHeaders);
    HttpHeaders = HeaderTmp;

    //
    // Check whether the EFI_HTTP_UTILITIES_PROTOCOL is available.
    //
    if (mHttpUtilities == NULL) {
      Status = EFI_NOT_READY;
      goto Error;
    }
    
    //
    // Parse the HTTP header into array of key/value pairs.
    //
    Status = mHttpUtilities->Parse (
                               mHttpUtilities, 
                               HttpHeaders, 
                               SizeofHeaders, 
                               &HttpMsg->Headers, 
                               &HttpMsg->HeaderCount
                               );
    if (EFI_ERROR (Status)) {
      goto Error;
    }

    FreePool (HttpHeaders);
    HttpHeaders = NULL;
    
    HttpMsg->Data.Response->StatusCode = HttpMappingToStatusCode (StatusCode);
    HttpInstance->StatusCode = StatusCode;
    //
    // Init message-body parser by header information.  
    //
    Status = EFI_NOT_READY;
    ValueInItem = NULL;
    NetMapRemoveHead (&HttpInstance->TxTokens, (VOID**) &ValueInItem);
    if (ValueInItem == NULL)  {
      goto Error;
    }

    //
    // The first Tx Token not transmitted yet, insert back and return error.
    //
    if (!ValueInItem->TcpWrap.IsTxDone) {
      goto Error2;
    }

    Status = HttpInitMsgParser (
               ValueInItem->TcpWrap.Method,
               HttpMsg->Data.Response->StatusCode,
               HttpMsg->HeaderCount,
               HttpMsg->Headers,
               HttpBodyParserCallback,
               (VOID *) ValueInItem,
               &HttpInstance->MsgParser
               );
    if (EFI_ERROR (Status)) {       
      goto Error2;
    }

    //
    // Check whether we received a complete HTTP message.
    //
    if (HttpInstance->CacheBody != NULL) {
      Status = HttpParseMessageBody (HttpInstance->MsgParser, HttpInstance->CacheLen, HttpInstance->CacheBody);
      if (EFI_ERROR (Status)) {
        goto Error2;
      }

      if (HttpIsMessageComplete (HttpInstance->MsgParser)) {
        //
        // Free the MsgParse since we already have a full HTTP message.
        //
        HttpFreeMsgParser (HttpInstance->MsgParser);
        HttpInstance->MsgParser = NULL;
      }
    }

    if ((HttpMsg->Body == NULL) || (HttpMsg->BodyLength == 0)) {    
      Status = EFI_SUCCESS;
      goto Exit;
    }
  }  

  //
  // Receive the response body.
  //
  BodyLen = 0;

  //
  // First check whether we cached some data.
  //
  if (HttpInstance->CacheBody != NULL) {
    //
    // Calculate the length of the cached data.
    //
    if (HttpInstance->NextMsg != NULL) {
      //
      // We have a cached HTTP message which includes a part of HTTP header of next message.
      //
      BodyLen = HttpInstance->NextMsg - (HttpInstance->CacheBody + HttpInstance->CacheOffset);      
    } else {
      BodyLen = HttpInstance->CacheLen - HttpInstance->CacheOffset;
    }

    if (BodyLen > 0) {
      //
      // We have some cached data. Just copy the data and return.
      //
      if (HttpMsg->BodyLength < BodyLen) {
        CopyMem (HttpMsg->Body, HttpInstance->CacheBody + HttpInstance->CacheOffset, HttpMsg->BodyLength);
        HttpInstance->CacheOffset = HttpInstance->CacheOffset + HttpMsg->BodyLength;
      } else {
        //
        // Copy all cached data out.
        //
        CopyMem (HttpMsg->Body, HttpInstance->CacheBody + HttpInstance->CacheOffset, BodyLen);
        HttpInstance->CacheOffset = BodyLen + HttpInstance->CacheOffset;
        HttpMsg->BodyLength = BodyLen;

        if (HttpInstance->NextMsg == NULL) {
          //
          // There is no HTTP header of next message. Just free the cache buffer.
          //
          FreePool (HttpInstance->CacheBody);
          HttpInstance->CacheBody   = NULL;
          HttpInstance->NextMsg     = NULL;
          HttpInstance->CacheOffset = 0;
        }
      }
      //
      // Return since we aready received required data.
      //
      Status = EFI_SUCCESS;
      goto Exit;
    } 

    if (BodyLen == 0 && HttpInstance->MsgParser == NULL) {
      //
      // We received a complete HTTP message, and we don't have more data to return to caller.
      //
      HttpMsg->BodyLength = 0;
      Status = EFI_SUCCESS;
      goto Exit;      
    }    
  }

  ASSERT (HttpInstance->MsgParser != NULL);

  //
  // We still need receive more data when there is no cache data and MsgParser is not NULL;
  //
  Status = HttpTcpReceiveBody (Wrap, HttpMsg);
  if (EFI_ERROR (Status)) {
    goto Error;
  }

  return Status;

Exit:
  Item = NetMapFindKey (&Wrap->HttpInstance->RxTokens, Wrap->HttpToken);
  if (Item != NULL) {
    NetMapRemoveItem (&Wrap->HttpInstance->RxTokens, Item, NULL);
  }

  if (HttpInstance->StatusCode >= HTTP_ERROR_OR_NOT_SUPPORT_STATUS_CODE) {
    Token->Status = EFI_HTTP_ERROR;
  } else {
    Token->Status = Status;
  }

  gBS->SignalEvent (Token->Event);
  HttpCloseTcpRxEvent (Wrap);
  FreePool (Wrap);
  return Status;

Error2:
  NetMapInsertHead (&HttpInstance->TxTokens, ValueInItem->HttpToken, ValueInItem);

Error:
  HttpTcpTokenCleanup (Wrap);
  
  if (HttpHeaders != NULL) {
    FreePool (HttpHeaders);
  }

  if (HttpMsg->Headers != NULL) {
    FreePool (HttpMsg->Headers);
  }

  if (HttpInstance->CacheBody != NULL) {
    FreePool (HttpInstance->CacheBody);
    HttpInstance->CacheBody = NULL;
  }

  if (HttpInstance->StatusCode >= HTTP_ERROR_OR_NOT_SUPPORT_STATUS_CODE) {
    Token->Status = EFI_HTTP_ERROR;
  } else {
    Token->Status = Status;
  }

  gBS->SignalEvent (Token->Event);

  return Status;  

}
Exemplo n.º 14
0
/**
  Extract the Root Path option and get the required target information.

  @param[in]        RootPath         The RootPath.
  @param[in]        Length           Length of the RootPath option payload.
  @param[in, out]   ConfigData       The iSCSI attempt configuration data read
                                     from a nonvolatile device.

  @retval EFI_SUCCESS           All required information is extracted from the RootPath option.
  @retval EFI_NOT_FOUND         The RootPath is not an iSCSI RootPath.
  @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory.
  @retval EFI_INVALID_PARAMETER The RootPath is malformatted.

**/
EFI_STATUS
IScsiDhcpExtractRootPath (
  IN      CHAR8                        *RootPath,
  IN      UINT8                        Length,
  IN OUT  ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData
  )
{
  EFI_STATUS                  Status;
  UINT8                       IScsiRootPathIdLen;
  CHAR8                       *TmpStr;
  ISCSI_ROOT_PATH_FIELD       Fields[RP_FIELD_IDX_MAX];
  ISCSI_ROOT_PATH_FIELD       *Field;
  UINT32                      FieldIndex;
  UINT8                       Index;
  ISCSI_SESSION_CONFIG_NVDATA *ConfigNvData;
  EFI_IP_ADDRESS              Ip;
  UINT8                       IpMode;

  ConfigNvData = &ConfigData->SessionConfigData;

  //
  // "iscsi:"<servername>":"<protocol>":"<port>":"<LUN>":"<targetname>
  //
  IScsiRootPathIdLen = (UINT8) AsciiStrLen (ISCSI_ROOT_PATH_ID);

  if ((Length <= IScsiRootPathIdLen) || (CompareMem (RootPath, ISCSI_ROOT_PATH_ID, IScsiRootPathIdLen) != 0)) {
    return EFI_NOT_FOUND;
  }
  //
  // Skip the iSCSI RootPath ID "iscsi:".
  //
  RootPath += IScsiRootPathIdLen;
  Length  = (UINT8) (Length - IScsiRootPathIdLen);

  TmpStr  = (CHAR8 *) AllocatePool (Length + 1);
  if (TmpStr == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }

  CopyMem (TmpStr, RootPath, Length);
  TmpStr[Length]  = '\0';

  Index           = 0;
  FieldIndex      = RP_FIELD_IDX_SERVERNAME;
  ZeroMem (&Fields[0], sizeof (Fields));

  //
  // Extract the fields in the Root Path option string.
  //
  for (FieldIndex = RP_FIELD_IDX_SERVERNAME; (FieldIndex < RP_FIELD_IDX_MAX) && (Index < Length); FieldIndex++) {
    if (TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) {
      Fields[FieldIndex].Str = &TmpStr[Index];
    }

    while ((TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) && (Index < Length)) {
      Index++;
    }

    if (TmpStr[Index] == ISCSI_ROOT_PATH_FIELD_DELIMITER) {
      if (FieldIndex != RP_FIELD_IDX_TARGETNAME) {
        TmpStr[Index] = '\0';
        Index++;
      }

      if (Fields[FieldIndex].Str != NULL) {
        Fields[FieldIndex].Len = (UINT8) AsciiStrLen (Fields[FieldIndex].Str);
      }
    }
  }

  if (FieldIndex != RP_FIELD_IDX_MAX) {
    Status = EFI_INVALID_PARAMETER;
    goto ON_EXIT;
  }

  if ((Fields[RP_FIELD_IDX_SERVERNAME].Str == NULL) ||
      (Fields[RP_FIELD_IDX_TARGETNAME].Str == NULL) ||
      (Fields[RP_FIELD_IDX_PROTOCOL].Len > 1)
      ) {

    Status = EFI_INVALID_PARAMETER;
    goto ON_EXIT;
  }
  //
  // Get the IP address of the target.
  //
  Field   = &Fields[RP_FIELD_IDX_SERVERNAME];

  if (ConfigNvData->IpMode < IP_MODE_AUTOCONFIG) {
    IpMode = ConfigNvData->IpMode;
  } else {
    IpMode = ConfigData->AutoConfigureMode;
  }

  Status = IScsiAsciiStrToIp (Field->Str, IpMode, &Ip);
  CopyMem (&ConfigNvData->TargetIp, &Ip, sizeof (EFI_IP_ADDRESS));

  if (EFI_ERROR (Status)) {
    goto ON_EXIT;
  }
  //
  // Check the protocol type.
  //
  Field = &Fields[RP_FIELD_IDX_PROTOCOL];
  if ((Field->Str != NULL) && ((*(Field->Str) - '0') != EFI_IP_PROTO_TCP)) {
    Status = EFI_INVALID_PARAMETER;
    goto ON_EXIT;
  }
  //
  // Get the port of the iSCSI target.
  //
  Field = &Fields[RP_FIELD_IDX_PORT];
  if (Field->Str != NULL) {
    ConfigNvData->TargetPort = (UINT16) AsciiStrDecimalToUintn (Field->Str);
  } else {
    ConfigNvData->TargetPort = ISCSI_WELL_KNOWN_PORT;
  }
  //
  // Get the LUN.
  //
  Field = &Fields[RP_FIELD_IDX_LUN];
  if (Field->Str != NULL) {
    Status = IScsiAsciiStrToLun (Field->Str, ConfigNvData->BootLun);
    if (EFI_ERROR (Status)) {
      goto ON_EXIT;
    }
  } else {
    ZeroMem (ConfigNvData->BootLun, sizeof (ConfigNvData->BootLun));
  }
  //
  // Get the target iSCSI Name.
  //
  Field = &Fields[RP_FIELD_IDX_TARGETNAME];

  if (AsciiStrLen (Field->Str) > ISCSI_NAME_MAX_SIZE - 1) {
    Status = EFI_INVALID_PARAMETER;
    goto ON_EXIT;
  }
  //
  // Validate the iSCSI name.
  //
  Status = IScsiNormalizeName (Field->Str, AsciiStrLen (Field->Str));
  if (EFI_ERROR (Status)) {
    goto ON_EXIT;
  }

  AsciiStrCpyS (ConfigNvData->TargetName, ISCSI_NAME_MAX_SIZE, Field->Str);

ON_EXIT:

  FreePool (TmpStr);

  return Status;
}
Exemplo n.º 15
0
/**
  The work function of EfiHttpResponse().

  @param[in]  Wrap                Pointer to HTTP token's wrap data.

  @retval EFI_SUCCESS             Allocation succeeded.
  @retval EFI_OUT_OF_RESOURCES    Failed to complete the opration due to lack of resources.
  @retval EFI_NOT_READY           Can't find a corresponding Tx4Token/Tx6Token or 
                                  the EFI_HTTP_UTILITIES_PROTOCOL is not available.

**/
EFI_STATUS
HttpResponseWorker (
  IN  HTTP_TOKEN_WRAP           *Wrap
  )
{
  EFI_STATUS                    Status;
  EFI_HTTP_MESSAGE              *HttpMsg;
  CHAR8                         *EndofHeader;
  CHAR8                         *HttpHeaders;
  UINTN                         SizeofHeaders;
  UINTN                         BufferSize;
  UINTN                         StatusCode;
  CHAR8                         *Tmp;
  CHAR8                         *HeaderTmp;
  CHAR8                         *StatusCodeStr;
  UINTN                         BodyLen;
  HTTP_PROTOCOL                 *HttpInstance;
  EFI_HTTP_TOKEN                *Token;
  NET_MAP_ITEM                  *Item;
  HTTP_TOKEN_WRAP               *ValueInItem;
  UINTN                         HdrLen;

  if (Wrap == NULL || Wrap->HttpInstance == NULL) {
    return EFI_INVALID_PARAMETER;
  }
  
  HttpInstance = Wrap->HttpInstance;
  Token = Wrap->HttpToken;
  HttpMsg = Token->Message;

  HttpInstance->EndofHeader = NULL;
  HttpInstance->HttpHeaders = NULL;
  HttpMsg->Headers          = NULL;
  HttpHeaders               = NULL;
  SizeofHeaders             = 0;
  BufferSize                = 0;
  EndofHeader               = NULL;
 
  if (HttpMsg->Data.Response != NULL) {
    //
    // Need receive the HTTP headers, prepare buffer.
    //
    Status = HttpCreateTcpRxEventForHeader (HttpInstance);
    if (EFI_ERROR (Status)) {
      goto Error;
    }

    //
    // Check whether we have cached header from previous call.
    //
    if ((HttpInstance->CacheBody != NULL) && (HttpInstance->NextMsg != NULL)) {
      //
      // The data is stored at [NextMsg, CacheBody + CacheLen].
      //
      HdrLen = HttpInstance->CacheBody + HttpInstance->CacheLen - HttpInstance->NextMsg;
      HttpHeaders = AllocateZeroPool (HdrLen);
      if (HttpHeaders == NULL) {
        Status = EFI_OUT_OF_RESOURCES;
        goto Error;
      }

      CopyMem (HttpHeaders, HttpInstance->NextMsg, HdrLen);
      FreePool (HttpInstance->CacheBody);
      HttpInstance->CacheBody   = NULL;
      HttpInstance->NextMsg     = NULL;
      HttpInstance->CacheOffset = 0;
      SizeofHeaders = HdrLen;
      BufferSize = HttpInstance->CacheLen;

      //
      // Check whether we cached the whole HTTP headers.
      //
      EndofHeader = AsciiStrStr (HttpHeaders, HTTP_END_OF_HDR_STR); 
    }   

    HttpInstance->EndofHeader = &EndofHeader;
    HttpInstance->HttpHeaders = &HttpHeaders;


    if (HttpInstance->TimeoutEvent == NULL) {
      //
      // Create TimeoutEvent for response
      //
      Status = gBS->CreateEvent (
                      EVT_TIMER,
                      TPL_CALLBACK,
                      NULL,
                      NULL,
                      &HttpInstance->TimeoutEvent
                      );
      if (EFI_ERROR (Status)) {
        goto Error;
      }
    }

    //
    // Start the timer, and wait Timeout seconds to receive the header packet.
    //
    Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_RESPONSE_TIMEOUT * TICKS_PER_SECOND);
    if (EFI_ERROR (Status)) {
      goto Error;
    }

    Status = HttpTcpReceiveHeader (HttpInstance, &SizeofHeaders, &BufferSize, HttpInstance->TimeoutEvent);

    gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);

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

    ASSERT (HttpHeaders != NULL);

    //
    // Cache the part of body.
    //
    BodyLen = BufferSize - (EndofHeader - HttpHeaders);
    if (BodyLen > 0) {
      if (HttpInstance->CacheBody != NULL) {
        FreePool (HttpInstance->CacheBody);
      }

      HttpInstance->CacheBody = AllocateZeroPool (BodyLen);
      if (HttpInstance->CacheBody == NULL) {
        Status = EFI_OUT_OF_RESOURCES;
        goto Error;
      }

      CopyMem (HttpInstance->CacheBody, EndofHeader, BodyLen);
      HttpInstance->CacheLen = BodyLen;
    }

    //
    // Search for Status Code.
    //
    StatusCodeStr = HttpHeaders + AsciiStrLen (HTTP_VERSION_STR) + 1;
    if (StatusCodeStr == NULL) {
      goto Error;
    }

    StatusCode = AsciiStrDecimalToUintn (StatusCodeStr);

    //
    // Remove the first line of HTTP message, e.g. "HTTP/1.1 200 OK\r\n".
    //
    Tmp = AsciiStrStr (HttpHeaders, HTTP_CRLF_STR);
    if (Tmp == NULL) {
      goto Error;
    }

    //
    // We could have response with just a HTTP message and no headers. For Example,
    // "100 Continue". In such cases, we would not want to unnecessarily call a Parse
    // method. A "\r\n" following Tmp string again would indicate an end. Compare and
    // set SizeofHeaders to 0.
    //
    Tmp = Tmp + AsciiStrLen (HTTP_CRLF_STR);
    if (CompareMem (Tmp, HTTP_CRLF_STR, AsciiStrLen (HTTP_CRLF_STR)) == 0) {
      SizeofHeaders = 0;
    } else {
      SizeofHeaders = SizeofHeaders - (Tmp - HttpHeaders);
    }

    HttpMsg->Data.Response->StatusCode = HttpMappingToStatusCode (StatusCode);
    HttpInstance->StatusCode = StatusCode;

    Status = EFI_NOT_READY;
    ValueInItem = NULL;

    //
    // In cases of PUT/POST, after an initial request-response pair, we would do a
    // continuous request without a response call. So, we would not do an insert of
    // TxToken. After we have sent the complete file, we will call a response to get
    // a final response from server. In such a case, we would not have any TxTokens.
    // Hence, check that case before doing a NetMapRemoveHead.
    //
    if (!NetMapIsEmpty (&HttpInstance->TxTokens)) {
      NetMapRemoveHead (&HttpInstance->TxTokens, (VOID**) &ValueInItem);
      if (ValueInItem == NULL)  {
        goto Error;
      }

      //
      // The first Tx Token not transmitted yet, insert back and return error.
      //
      if (!ValueInItem->TcpWrap.IsTxDone) {
        goto Error2;
      }
    }

    if (SizeofHeaders != 0) {
      HeaderTmp = AllocateZeroPool (SizeofHeaders);
      if (HeaderTmp == NULL) {
        goto Error;
      }

      CopyMem (HeaderTmp, Tmp, SizeofHeaders);
      FreePool (HttpHeaders);
      HttpHeaders = HeaderTmp;

      //
      // Check whether the EFI_HTTP_UTILITIES_PROTOCOL is available.
      //
      if (mHttpUtilities == NULL) {
        Status = EFI_NOT_READY;
        goto Error;
      }

      //
      // Parse the HTTP header into array of key/value pairs.
      //
      Status = mHttpUtilities->Parse (
                                 mHttpUtilities,
                                 HttpHeaders,
                                 SizeofHeaders,
                                 &HttpMsg->Headers,
                                 &HttpMsg->HeaderCount
                                 );
      if (EFI_ERROR (Status)) {
        goto Error;
      }

      FreePool (HttpHeaders);
      HttpHeaders = NULL;


      //
      // Init message-body parser by header information.
      //
      Status = HttpInitMsgParser (
                 HttpInstance->Method,
                 HttpMsg->Data.Response->StatusCode,
                 HttpMsg->HeaderCount,
                 HttpMsg->Headers,
                 HttpBodyParserCallback,
                 (VOID *) ValueInItem,
                 &HttpInstance->MsgParser
                 );
      if (EFI_ERROR (Status)) {
        goto Error2;
      }

      //
      // Check whether we received a complete HTTP message.
      //
      if (HttpInstance->CacheBody != NULL) {
        Status = HttpParseMessageBody (HttpInstance->MsgParser, HttpInstance->CacheLen, HttpInstance->CacheBody);
        if (EFI_ERROR (Status)) {
          goto Error2;
        }

        if (HttpIsMessageComplete (HttpInstance->MsgParser)) {
          //
          // Free the MsgParse since we already have a full HTTP message.
          //
          HttpFreeMsgParser (HttpInstance->MsgParser);
          HttpInstance->MsgParser = NULL;
        }
      }
    }

    if ((HttpMsg->Body == NULL) || (HttpMsg->BodyLength == 0)) {
      Status = EFI_SUCCESS;
      goto Exit;
    }
  }

  //
  // Receive the response body.
  //
  BodyLen = 0;

  //
  // First check whether we cached some data.
  //
  if (HttpInstance->CacheBody != NULL) {
    //
    // Calculate the length of the cached data.
    //
    if (HttpInstance->NextMsg != NULL) {
      //
      // We have a cached HTTP message which includes a part of HTTP header of next message.
      //
      BodyLen = HttpInstance->NextMsg - (HttpInstance->CacheBody + HttpInstance->CacheOffset);      
    } else {
      BodyLen = HttpInstance->CacheLen - HttpInstance->CacheOffset;
    }

    if (BodyLen > 0) {
      //
      // We have some cached data. Just copy the data and return.
      //
      if (HttpMsg->BodyLength < BodyLen) {
        CopyMem (HttpMsg->Body, HttpInstance->CacheBody + HttpInstance->CacheOffset, HttpMsg->BodyLength);
        HttpInstance->CacheOffset = HttpInstance->CacheOffset + HttpMsg->BodyLength;
      } else {
        //
        // Copy all cached data out.
        //
        CopyMem (HttpMsg->Body, HttpInstance->CacheBody + HttpInstance->CacheOffset, BodyLen);
        HttpInstance->CacheOffset = BodyLen + HttpInstance->CacheOffset;
        HttpMsg->BodyLength = BodyLen;

        if (HttpInstance->NextMsg == NULL) {
          //
          // There is no HTTP header of next message. Just free the cache buffer.
          //
          FreePool (HttpInstance->CacheBody);
          HttpInstance->CacheBody   = NULL;
          HttpInstance->NextMsg     = NULL;
          HttpInstance->CacheOffset = 0;
        }
      }
      //
      // Return since we aready received required data.
      //
      Status = EFI_SUCCESS;
      goto Exit;
    } 

    if (BodyLen == 0 && HttpInstance->MsgParser == NULL) {
      //
      // We received a complete HTTP message, and we don't have more data to return to caller.
      //
      HttpMsg->BodyLength = 0;
      Status = EFI_SUCCESS;
      goto Exit;      
    }    
  }

  ASSERT (HttpInstance->MsgParser != NULL);

  if (HttpInstance->TimeoutEvent == NULL) {
    //
    // Create TimeoutEvent for response
    //
    Status = gBS->CreateEvent (
                    EVT_TIMER,
                    TPL_CALLBACK,
                    NULL,
                    NULL,
                    &HttpInstance->TimeoutEvent
                    );
    if (EFI_ERROR (Status)) {
      goto Error;
    }
  }

  //
  // Start the timer, and wait Timeout seconds to receive the body packet.
  //
  Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_RESPONSE_TIMEOUT * TICKS_PER_SECOND);
  if (EFI_ERROR (Status)) {
    goto Error;
  }

  //
  // We still need receive more data when there is no cache data and MsgParser is not NULL;
  //
  Status = HttpTcpReceiveBody (Wrap, HttpMsg, HttpInstance->TimeoutEvent);

  gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);

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

  FreePool (Wrap);
  return Status;

Exit:
  Item = NetMapFindKey (&Wrap->HttpInstance->RxTokens, Wrap->HttpToken);
  if (Item != NULL) {
    NetMapRemoveItem (&Wrap->HttpInstance->RxTokens, Item, NULL);
  }

  if (HttpInstance->StatusCode >= HTTP_ERROR_OR_NOT_SUPPORT_STATUS_CODE) {
    Token->Status = EFI_HTTP_ERROR;
  } else {
    Token->Status = Status;
  }

  gBS->SignalEvent (Token->Event);
  HttpCloseTcpRxEvent (Wrap);
  FreePool (Wrap);
  return Status;

Error2:
  NetMapInsertHead (&HttpInstance->TxTokens, ValueInItem->HttpToken, ValueInItem);

Error:
  HttpTcpTokenCleanup (Wrap);
  
  if (HttpHeaders != NULL) {
    FreePool (HttpHeaders);
  }

  if (HttpMsg->Headers != NULL) {
    FreePool (HttpMsg->Headers);
  }

  if (HttpInstance->CacheBody != NULL) {
    FreePool (HttpInstance->CacheBody);
    HttpInstance->CacheBody = NULL;
  }

  if (HttpInstance->StatusCode >= HTTP_ERROR_OR_NOT_SUPPORT_STATUS_CODE) {
    Token->Status = EFI_HTTP_ERROR;
  } else {
    Token->Status = Status;
  }

  gBS->SignalEvent (Token->Event);

  return Status;  

}
Exemplo n.º 16
0
/**
  Parse the NULL terminated ASCII string of multicast option.

  @param[in]  Str           The pointer to the Ascii string of multicast option.
  @param[in]  ExtInfo       The pointer to the option information to be filled.

  @retval EFI_SUCCESS            Parse the multicast option successfully.
  @retval EFI_INVALID_PARAMETER  The string is malformatted.
  @retval EFI_OUT_OF_RESOURCES   Failed to perform the operation due to lack of
                                 resources.

**/
EFI_STATUS
Mtftp6ParseMcastOption (
  IN UINT8                  *Str,
  IN MTFTP6_EXT_OPTION_INFO *ExtInfo
  )
{
  EFI_STATUS                Status;
  UINT32                    Num;
  CHAR8                     *Ip6Str;
  CHAR8                     *TempStr;

  //
  // The multicast option is formated like "addr,port,mc"
  // The server can also omit the ip and port, use ",,1"
  //
  if (*Str == ',') {

    ZeroMem (&ExtInfo->McastIp, sizeof (EFI_IPv6_ADDRESS));
  } else {

    Ip6Str = (CHAR8 *) AllocateCopyPool (AsciiStrSize ((CHAR8 *) Str), Str);
    if (Ip6Str == NULL) {
      return EFI_OUT_OF_RESOURCES;
    }

    //
    // The IPv6 address locates before comma in the input Str.
    //
    TempStr = Ip6Str;
    while ((*TempStr != '\0') && (*TempStr != ',')) {
      TempStr++;
    }

    *TempStr = '\0';

    Status = NetLibAsciiStrToIp6 (Ip6Str, &ExtInfo->McastIp);
    FreePool (Ip6Str);

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

    while ((*Str != '\0') && (*Str != ',')) {
      Str++;
    }
  }

  if (*Str != ',') {
    return EFI_INVALID_PARAMETER;
  }

  Str++;

  //
  // Convert the port setting. the server can send us a port number or
  // empty string. such as the port in ",,1"
  //
  if (*Str == ',') {

    ExtInfo->McastPort = 0;
  } else {

    Num = (UINT32) AsciiStrDecimalToUintn ((CHAR8 *) Str);

    if (Num > 65535) {
      return EFI_INVALID_PARAMETER;
    }

    ExtInfo->McastPort = (UINT16) Num;

    while (NET_IS_DIGIT (*Str)) {
      Str++;
    }
  }

  if (*Str != ',') {
    return EFI_INVALID_PARAMETER;
  }

  Str++;

  //
  // Check the master/slave setting, 1 for master, 0 for slave.
  //
  Num = (UINT32) AsciiStrDecimalToUintn ((CHAR8 *) Str);

  if (Num != 0 && Num != 1) {
    return EFI_INVALID_PARAMETER;
  }

  ExtInfo->IsMaster = (BOOLEAN) (Num == 1);

  while (NET_IS_DIGIT (*Str)) {
    Str++;
  }

  if (*Str != '\0') {
    return EFI_INVALID_PARAMETER;
  }

  return EFI_SUCCESS;
}
Exemplo n.º 17
0
/**
  Parse the MTFTP6 extesion options.

  @param[in]  Options       The pointer to the extension options list.
  @param[in]  Count         The num of the extension options.
  @param[in]  IsRequest     If FALSE, the extension options is included
                            by a request packet.
  @param[in]  ExtInfo       The pointer to the option information to be filled.

  @retval EFI_SUCCESS            Parse the multicast option successfully.
  @retval EFI_INVALID_PARAMETER  There is one option is malformatted at least.
  @retval EFI_UNSUPPORTED        There is one option is not supported at least.

**/
EFI_STATUS
Mtftp6ParseExtensionOption (
  IN EFI_MTFTP6_OPTION        *Options,
  IN UINT32                   Count,
  IN BOOLEAN                  IsRequest,
  IN MTFTP6_EXT_OPTION_INFO   *ExtInfo
  )
{
  EFI_STATUS                  Status;
  EFI_MTFTP6_OPTION           *Opt;
  UINT32                      Index;
  UINT32                      Value;

  ExtInfo->BitMap = 0;

  for (Index = 0; Index < Count; Index++) {

    Opt = Options + Index;

    if (Opt->OptionStr == NULL || Opt->ValueStr == NULL) {
      return EFI_INVALID_PARAMETER;
    }

    if (AsciiStriCmp ((CHAR8 *) Opt->OptionStr, "blksize") == 0) {
      //
      // block size option, valid value is between [8, 65464]
      //
      Value = (UINT32) AsciiStrDecimalToUintn ((CHAR8 *) Opt->ValueStr);

      if ((Value < 8) || (Value > 65464)) {
        return EFI_INVALID_PARAMETER;
      }

      ExtInfo->BlkSize = (UINT16) Value;
      ExtInfo->BitMap |= MTFTP6_OPT_BLKSIZE_BIT;

    } else if (AsciiStriCmp ((CHAR8 *) Opt->OptionStr, "timeout") == 0) {
      //
      // timeout option, valid value is between [1, 255]
      //
      Value = (UINT32) AsciiStrDecimalToUintn ((CHAR8 *) Opt->ValueStr);

      if (Value < 1 || Value > 255) {
        return EFI_INVALID_PARAMETER;
      }

      ExtInfo->Timeout = (UINT8) Value;
      ExtInfo->BitMap |= MTFTP6_OPT_TIMEOUT_BIT;

    } else if (AsciiStriCmp ((CHAR8 *) Opt->OptionStr, "tsize") == 0) {
      //
      // tsize option, the biggest transfer supported is 4GB with block size option
      //
      ExtInfo->Tsize   = (UINT32) AsciiStrDecimalToUintn ((CHAR8 *) Opt->ValueStr);
      ExtInfo->BitMap |= MTFTP6_OPT_TSIZE_BIT;

    } else if (AsciiStriCmp ((CHAR8 *) Opt->OptionStr, "multicast") == 0) {
      //
      // Multicast option, if it is a request, the value must be a zero string,
      // otherwise, it must be like "addr,port,mc" string, mc indicates master.
      //
      if (!IsRequest) {

        Status = Mtftp6ParseMcastOption (Opt->ValueStr, ExtInfo);

        if (EFI_ERROR (Status)) {
          return Status;
        }
      } else if (*(Opt->ValueStr) != '\0') {

        return EFI_INVALID_PARAMETER;
      }

      ExtInfo->BitMap |= MTFTP6_OPT_MCAST_BIT;

    } else if (IsRequest) {
      //
      // If it's a request, unsupported; else if it's a reply, ignore.
      //
      return EFI_UNSUPPORTED;
    }
  }

  return EFI_SUCCESS;
}