dhcp4option.c

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

C
967
字号
DhcpGetOptionLen (
  IN UINT8                  Tag,
  IN UINT8                  Len,
  IN UINT8                  *Data,
  IN VOID                   *Context
  )
/*++

Routine Description:

  Call back function to DhcpiterateOptions to compute each option's
  length. It just adds the data length of all the occurances of this 
  Tag. Context is an array of 256 DHCP_OPTION_COUNT.

Arguments:

  Tag     - The current option to check
  Len     - The length of the option data
  Data    - The option data
  Context - The context, which is a array of 256 DHCP_OPTION_COUNT.

Returns:

  EFI_SUCCESS - It always returns EFI_SUCCESS.

--*/
{
  DHCP_OPTION_COUNT         *OpCount;

  OpCount             = (DHCP_OPTION_COUNT *) Context;
  OpCount[Tag].Offset = OpCount[Tag].Offset + Len;

  return EFI_SUCCESS;
}

STATIC
EFI_STATUS
DhcpFillOption (
  IN UINT8                  Tag,
  IN UINT8                  Len,
  IN UINT8                  *Data,
  IN VOID                   *Context
  )
/*++

Routine Description:

  Call back function to DhcpiterateOptions to consolidate each option's
  data. There are maybe several occurance of the same option.

Arguments:

  Tag     - The option to consolidate its data
  Len     - The length of option data
  Data    - The data of the option's current occurance
  Context - The context, which is DHCP_OPTION_CONTEXT. This array is 
            just a wrap to pass THREE parameters. 

Returns:

  EFI_SUCCESS - It always returns EFI_SUCCESS

--*/
{
  DHCP_OPTION_CONTEXT       *OptContext;
  DHCP_OPTION_COUNT         *OptCount;
  DHCP_OPTION               *Options;
  UINT8                     *Buf;
  UINT8                     Index;

  OptContext  = (DHCP_OPTION_CONTEXT *) Context;

  OptCount    = OptContext->OpCount;
  Index       = OptCount[Tag].Index;
  Options     = OptContext->Options;
  Buf         = OptContext->Buf;

  if (Options[Index].Data == NULL) {
    Options[Index].Tag  = Tag;
    Options[Index].Data = Buf + OptCount[Tag].Offset;
  }

  NetCopyMem (Buf + OptCount[Tag].Offset, Data, Len);

  OptCount[Tag].Offset  = OptCount[Tag].Offset + Len;
  Options[Index].Len    = Options[Index].Len + Len;
  return EFI_SUCCESS;
}

EFI_STATUS
DhcpParseOption (
  IN  EFI_DHCP4_PACKET      *Packet,
  OUT INTN                  *Count,
  OUT DHCP_OPTION           **OptionPoint
  )
/*++

Routine Description:

  Parse the options of a DHCP packet. It supports RFC 3396: Encoding 
  Long Options in DHCP. That is, it will combine all the option value 
  of all the occurances of each option. 

  A little bit of implemenation:
  It adopts the "Key indexed counting" algorithm. First, it allocates
  an array of 256 DHCP_OPTION_COUNTs because DHCP option tag is encoded
  as a UINT8. It then iterates the DHCP packet to get data length of
  each option by calling DhcpIterOptions with DhcpGetOptionLen. Now, it
  knows the number of present options and their length. It allocates a
  array of DHCP_OPTION and a continous buffer after the array to put 
  all the options' data. Each option's data is pointed to by the Data 
  field in DHCP_OPTION structure. At last, it call DhcpIterateOptions 
  with DhcpFillOption to fill each option's data to its position in the
  buffer.
  
Arguments:

  Packet      - The DHCP packet to parse the options
  Count       - The number of valid dhcp options present in the packet
  OptionPoint - The array that contains the DHCP options. Caller should free it.

Returns:

  EFI_OUT_OF_RESOURCES  - Failed to allocate memory to parse the packet.
  EFI_INVALID_PARAMETER - The options are mal-formated
  EFI_SUCCESS           - The options are parsed into OptionPoint

--*/
{
  DHCP_OPTION_CONTEXT       Context;
  DHCP_OPTION               *Options;
  DHCP_OPTION_COUNT         *OptCount;
  EFI_STATUS                Status;
  UINT16                    TotalLen;
  INTN                      OptNum;
  INTN                      Index;

  ASSERT ((Count != NULL) && (OptionPoint != NULL));

  //
  // First compute how many options and how long each option is
  // with the "Key indexed counting" algorithms.
  //
  OptCount = NetAllocateZeroPool (DHCP_MAX_OPTIONS * sizeof (DHCP_OPTION_COUNT));

  if (OptCount == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }

  Status = DhcpIterateOptions (Packet, DhcpGetOptionLen, OptCount);

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

  //
  // Before the loop, Offset is the length of the option. After loop,
  // OptCount[Index].Offset specifies the offset into the continuous
  // option value buffer to put the data.
  //
  TotalLen  = 0;
  OptNum    = 0;
  
  for (Index = 0; Index < DHCP_MAX_OPTIONS; Index++) {
    if (OptCount[Index].Offset != 0) {
      OptCount[Index].Index   = (UINT8) OptNum;

      TotalLen                = TotalLen + OptCount[Index].Offset;
      OptCount[Index].Offset  = TotalLen - OptCount[Index].Offset;

      OptNum++;
    }
  }

  *Count        = OptNum;
  *OptionPoint  = NULL;

  if (OptNum == 0) {
    goto ON_EXIT;
  }

  //
  // Allocate a buffer to hold the DHCP options, and after that, a 
  // continuous buffer to put all the options' data.
  //
  Options = NetAllocateZeroPool (OptNum * sizeof (DHCP_OPTION) + TotalLen);

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

  Context.OpCount = OptCount;
  Context.Options = Options;
  Context.Buf     = (UINT8 *) (Options + OptNum);

  Status          = DhcpIterateOptions (Packet, DhcpFillOption, &Context);

  if (EFI_ERROR (Status)) {
    NetFreePool (Options);
    goto ON_EXIT;
  }

  *OptionPoint = Options;

ON_EXIT:
  NetFreePool (OptCount);
  return Status;
}

EFI_STATUS
DhcpValidateOptions (
  IN  EFI_DHCP4_PACKET      *Packet,
  OUT DHCP_PARAMETER        **Para       OPTIONAL
  )
/*++

Routine Description:

  Validate the packet's options. If necessary, allocate
  and fill in the interested parameters.

Arguments:

  Packet  - The packet to validate the options
  Para    - The variable to save the DHCP parameters.

Returns:

  EFI_OUT_OF_RESOURCES  - Failed to allocate memory to validate the packet.
  EFI_INVALID_PARAMETER - The options are mal-formated
  EFI_SUCCESS           - The options are parsed into OptionPoint

--*/
{
  DHCP_PARAMETER            Parameter;
  DHCP_OPTION_FORMAT        *Format;
  DHCP_OPTION               *AllOption;
  DHCP_OPTION               *Option;
  EFI_STATUS                Status;
  BOOLEAN                   Updated;
  INTN                      Count;
  INTN                      Index;

  if (Para != NULL) {
    *Para = NULL;
  }

  AllOption = NULL;
  Status    = DhcpParseOption (Packet, &Count, &AllOption);

  if (EFI_ERROR (Status) || (Count == 0)) {
    return Status;
  }

  Updated = FALSE;
  NetZeroMem (&Parameter, sizeof (Parameter));

  for (Index = 0; Index < Count; Index++) {
    Option = &AllOption[Index];

    //
    // Find the format of the option then validate it.
    //
    Format = DhcpFindOptionFormat (Option->Tag);
    
    if (Format == NULL) {
      continue;
    }

    if (!DhcpOptionIsValid (Format, Option->Data, Option->Len)) {
      Status = EFI_INVALID_PARAMETER;
      goto ON_EXIT;
    }
    
    //
    // Get the client interested parameters
    //
    if (Format->Alert && (Para != NULL)) {
      Updated = TRUE;
      Status  = DhcpGetParameter (Option->Tag, Option->Len, Option->Data, &Parameter);

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

  if (Updated && (Para != NULL)) {
    if ((*Para = NetAllocatePool (sizeof (DHCP_PARAMETER))) == NULL) {
      Status = EFI_OUT_OF_RESOURCES;
      goto ON_EXIT;
    }

    **Para = Parameter;
  }

ON_EXIT:
  NetFreePool (AllOption);
  return Status;
}


UINT8 *
DhcpAppendOption (
  IN UINT8                  *Buf,
  IN UINT8                  Tag,
  IN UINT16                 DataLen,
  IN UINT8                  *Data
  )
/*++

Routine Description:

  Append an option to the memory, if the option is longer than
  255 bytes, splits it into several options.

Arguments:

  Buf     - The buffer to append the option to
  Tag     - The option's tag
  DataLen - The length of the option's data
  Data    - The option's data

Returns:

  The position to append the next option

--*/
{
  INTN                      Index;
  INTN                      Len;

  ASSERT (DataLen != 0);

  for (Index = 0; Index < (DataLen + 254) / 255; Index++) {
    Len      = NET_MIN (255, DataLen - Index * 255);

    *(Buf++) = Tag;
    *(Buf++) = (UINT8) Len;
    NetCopyMem (Buf, Data + Index * 255, Len);

    Buf     += Len;
  }

  return Buf;
}

EFI_STATUS
DhcpBuild (
  IN  EFI_DHCP4_PACKET        *SeedPacket,
  IN  UINT32                  DeleteCount,
  IN  UINT8                   *DeleteList     OPTIONAL,
  IN  UINT32                  AppendCount,
  IN  EFI_DHCP4_PACKET_OPTION *AppendList[]   OPTIONAL,
  OUT EFI_DHCP4_PACKET        **NewPacket
  )
/*++

Routine Description:

  Build a new DHCP packet from a seed packet. Options may be deleted or
  appended. The caller should free the NewPacket when finished using it.

Arguments:

  SeedPacket  - The seed packet to start with
  DeleteCount - The number of options to delete
  DeleteList  - The options to delete from the packet 
  AppendCount - The number of options to append
  AppendList  - The options to append to the packet 
  NewPacket   - The new packet, allocated and built by this function.

Returns:

  EFI_OUT_OF_RESOURCES - Failed to allocate memory
  EFI_SUCCESS          - The packet is build.
  
--*/
{
  DHCP_OPTION               *Mark;
  DHCP_OPTION               *SeedOptions;
  EFI_DHCP4_PACKET          *Packet;
  EFI_STATUS                Status;
  INTN                      Count;
  UINT32                    Index;
  UINT32                    Len;
  UINT8                     *Buf;

  //
  // Use an array of DHCP_OPTION to mark the existance
  // and position of each valid options.
  //
  Mark = NetAllocatePool (sizeof (DHCP_OPTION) * DHCP_MAX_OPTIONS);
  
  if (Mark == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }

  for (Index = 0; Index < DHCP_MAX_OPTIONS; Index++) {
    Mark[Index].Tag = (UINT8) Index;
    Mark[Index].Len = 0;
  }
  
  //
  // Get list of the options from the seed packet, then put
  // them to the mark array according to their tags.
  //
  SeedOptions = NULL;
  Status      = DhcpParseOption (SeedPacket, &Count, &SeedOptions);

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

  for (Index = 0; Index < (UINT32) Count; Index++) {
    Mark[SeedOptions[Index].Tag] = SeedOptions[Index];
  }
  
  //
  // Mark the option's length is zero if it is in the DeleteList.
  //
  for (Index = 0; Index < DeleteCount; Index++) {
    Mark[DeleteList[Index]].Len = 0;
  }
  
  //
  // Add or replace the option if it is in the append list.
  //
  for (Index = 0; Index < AppendCount; Index++) {
    Mark[AppendList[Index]->OpCode].Len  = AppendList[Index]->Length;
    Mark[AppendList[Index]->OpCode].Data = AppendList[Index]->Data;
  }
  
  //
  // compute the new packet length. No need to add 1 byte for
  // EOP option since EFI_DHCP4_PACKET includes one extra byte
  // for option. It is necessary to split the option if it is
  // longer than 255 bytes.
  //
  Len = sizeof (EFI_DHCP4_PACKET);

  for (Index = 0; Index < DHCP_MAX_OPTIONS; Index++) {
    if (Mark[Index].Len != 0) {
      Len += ((Mark[Index].Len + 254) / 255) * 2 + Mark[Index].Len;
    }
  }

  Status  = EFI_OUT_OF_RESOURCES;
  Packet  = (EFI_DHCP4_PACKET *) NetAllocatePool (Len);

  if (Packet == NULL) {
    goto ON_ERROR;
  }

  Packet->Size         = Len;
  Packet->Length       = 0;
  Packet->Dhcp4.Header = SeedPacket->Dhcp4.Header;
  Packet->Dhcp4.Magik  = DHCP_OPTION_MAGIC;
  Buf                  = Packet->Dhcp4.Option;

  for (Index = 0; Index < DHCP_MAX_OPTIONS; Index++) {
    if (Mark[Index].Len != 0) {
      Buf = DhcpAppendOption (Buf, Mark[Index].Tag, Mark[Index].Len, Mark[Index].Data);
    }
  }

  *(Buf++)        = DHCP_TAG_EOP;
  Packet->Length  = sizeof (EFI_DHCP4_HEADER) + sizeof (UINT32) 
                      + (UINT32) (Buf - Packet->Dhcp4.Option);

  *NewPacket      = Packet;
  Status          = EFI_SUCCESS;

ON_ERROR:
  if (SeedOptions != NULL) {
    NetFreePool (SeedOptions);
  }

  NetFreePool (Mark);
  return Status;
}

⌨️ 快捷键说明

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