pxedhcp4initselect.c

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

C
787
字号
                &This->Data->Discover,
                &offer,
                &offer_verify,
                seconds_timeout
                );

  if (EFI_ERROR (EfiStatus)) {
    if (Private->offer_list) {
      gBS->FreePool (Private->offer_list);
    }

    Private->offers     = 0;
    Private->offer_list = NULL;
    Private->callback   = NULL;

    DebugPrint (("%a:%d:%r\n", __FILE__, __LINE__, EfiStatus));
    return EfiStatus;
  }

  *Offers                     = Private->offers;
  *OfferList                  = Private->offer_list;

  Private->offers             = 0;
  Private->offer_list         = NULL;
  Private->callback           = NULL;

  This->Data->InitCompleted   = TRUE;
  This->Data->SelectCompleted = FALSE;
  This->Data->IsBootp         = FALSE;
  This->Data->IsAck           = FALSE;

  return EFI_SUCCESS;
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
EFI_STATUS
EFIAPI
PxeDhcp4Select (
  IN EFI_PXE_DHCP4_PROTOCOL *This,
  IN UINTN                  seconds_timeout,
  IN DHCP4_PACKET           *Offer
  )
{
  PXE_DHCP4_PRIVATE_DATA  *Private;
  EFI_STATUS              EfiStatus;
  DHCP4_PACKET            request;
  DHCP4_PACKET            acknak;
  EFI_IP_ADDRESS          bcast_ip;
  EFI_IP_ADDRESS          zero_ip;
  EFI_IP_ADDRESS          local_ip;
  DHCP4_OP                *srvid;
  DHCP4_OP                *op;
  UINT32                  dhcp4_magik;
  UINT8                   buf[16];
  BOOLEAN                 is_bootp;

  //
  // Verify parameters.
  //
  if (This == NULL || seconds_timeout < DHCP4_MIN_SECONDS || seconds_timeout > DHCP4_MAX_SECONDS || Offer == NULL) {
    return EFI_INVALID_PARAMETER;
  }
  //
  // Check protocol state.
  //
  if (This->Data == NULL) {
    return EFI_NOT_STARTED;
  }

  if (!This->Data->SetupCompleted) {
    return EFI_NOT_READY;
  }
  //
  // Get pointer to instance data.
  //
  Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This);

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

  if (Private->PxeBc == NULL) {
    return EFI_DEVICE_ERROR;
  }

#if 0
  if (!is_good_discover (&This->Data->Discover)) {
    //
    // %%TBD - check discover packet fields
    //
  }
#endif
  //
  // Setup useful variables...
  //
  EfiSetMem (&bcast_ip, sizeof (EFI_IP_ADDRESS), 0xFF);

  EfiZeroMem (&zero_ip, sizeof (EFI_IP_ADDRESS));

  EfiZeroMem (&local_ip, sizeof (EFI_IP_ADDRESS));
  local_ip.v4.Addr[0]         = 127;
  local_ip.v4.Addr[3]         = 1;

  This->Data->SelectCompleted = FALSE;
  This->Data->IsBootp         = FALSE;
  This->Data->IsAck           = FALSE;

  EfiStatus = gBS->HandleProtocol (
                    Private->Handle,
                    &gEfiPxeDhcp4CallbackProtocolGuid,
                    (VOID *) &Private->callback
                    );

  if (EFI_ERROR (EfiStatus)) {
    Private->callback = NULL;
  }

  Private->function = EFI_PXE_DHCP4_FUNCTION_SELECT;

  //
  // Verify offer packet fields.
  //
  if (Offer->dhcp4.op != BOOTP_REPLY) {
    Private->callback = NULL;
    return EFI_INVALID_PARAMETER;
  }

  if (Offer->dhcp4.htype != This->Data->Discover.dhcp4.htype) {
    Private->callback = NULL;
    return EFI_INVALID_PARAMETER;
  }

  if (Offer->dhcp4.hlen != This->Data->Discover.dhcp4.hlen) {
    Private->callback = NULL;
    return EFI_INVALID_PARAMETER;
  }

  if (EfiCompareMem (&Offer->dhcp4.xid, &This->Data->Discover.dhcp4.xid, 4)) {
    Private->callback = NULL;
    return EFI_INVALID_PARAMETER;
  }

  if (!EfiCompareMem (&Offer->dhcp4.yiaddr, &bcast_ip, 4)) {
    Private->callback = NULL;
    return EFI_INVALID_PARAMETER;
  }

  if (!EfiCompareMem (&Offer->dhcp4.yiaddr, &zero_ip, 4)) {
    Private->callback = NULL;
    return EFI_INVALID_PARAMETER;
  }

  if (!EfiCompareMem (&Offer->dhcp4.yiaddr, &local_ip, 4)) {
    Private->callback = NULL;
    return EFI_INVALID_PARAMETER;
  }

  if (EfiCompareMem (
        &Offer->dhcp4.chaddr,
        &This->Data->Discover.dhcp4.chaddr,
        16
        )) {
    Private->callback = NULL;
    return EFI_INVALID_PARAMETER;
  }
  //
  // DHCP option checks
  //
  dhcp4_magik = htonl (DHCP4_MAGIK_NUMBER);
  is_bootp    = TRUE;

  if (!EfiCompareMem (&Offer->dhcp4.magik, &dhcp4_magik, 4)) {
    //
    // If present, DHCP message type must be offer.
    //
    EfiStatus = find_opt (Offer, DHCP4_MESSAGE_TYPE, 0, &op);

    if (!EFI_ERROR (EfiStatus)) {
      if (op->len != 1 || op->data[0] != DHCP4_MESSAGE_TYPE_OFFER) {
        Private->callback = NULL;
        return EFI_INVALID_PARAMETER;
      }

      is_bootp = FALSE;
    }
    //
    // If present, DHCP max message size must be valid.
    //
    EfiStatus = find_opt (Offer, DHCP4_MAX_MESSAGE_SIZE, 0, &op);

    if (!EFI_ERROR (EfiStatus)) {
      if (op->len != 2 || ((op->data[0] << 8) | op->data[1]) < DHCP4_DEFAULT_MAX_MESSAGE_SIZE) {
        Private->callback = NULL;
        return EFI_INVALID_PARAMETER;
      }
    }
    //
    // If present, DHCP server identifier must be valid.
    //
    EfiStatus = find_opt (Offer, DHCP4_SERVER_IDENTIFIER, 0, &op);

    if (!EFI_ERROR (EfiStatus)) {
      if (op->len != 4 || !EfiCompareMem (op->data, &bcast_ip, 4) || !EfiCompareMem (op->data, &zero_ip, 4)) {
        Private->callback = NULL;
        return EFI_INVALID_PARAMETER;
      }
    }
    //
    // If present, DHCP subnet mask must be valid.
    //
    EfiStatus = find_opt (
                  Offer,
                  DHCP4_SUBNET_MASK,
                  0,
                  &op
                  );

    if (!EFI_ERROR (EfiStatus)) {
      if (op->len != 4) {
        Private->callback = NULL;
        return EFI_INVALID_PARAMETER;
      }
    }
  }
  //
  // Early out for BOOTP.
  //
  This->Data->IsBootp = is_bootp;
  if (is_bootp) {
    //
    // Copy offer packet to instance data.
    //
    EfiCopyMem (&This->Data->Offer, Offer, sizeof (DHCP4_PACKET));

    //
    // Copy discover to request and offer to acknak.
    //
    EfiCopyMem (
      &This->Data->Request,
      &This->Data->Discover,
      sizeof (DHCP4_PACKET)
      );

    EfiCopyMem (
      &This->Data->AckNak,
      &This->Data->Offer,
      sizeof (DHCP4_PACKET)
      );

    //
    // Set state flags.
    //
    This->Data->SelectCompleted = TRUE;
    This->Data->IsAck           = TRUE;

    Private->callback           = NULL;
    return EFI_SUCCESS;
  }
  //
  // Copy discover packet contents to request packet.
  //
  EfiCopyMem (&request, &This->Data->Discover, sizeof (DHCP4_PACKET));

  This->Data->IsAck = FALSE;

  //
  // Change DHCP message type from discover to request.
  //
  EfiStatus = find_opt (&request, DHCP4_MESSAGE_TYPE, 0, &op);

  if (EFI_ERROR (EfiStatus) && EfiStatus != EFI_NOT_FOUND) {
    Private->callback = NULL;
    return EFI_INVALID_PARAMETER;
  }

  if (EfiStatus == EFI_NOT_FOUND) {
    EfiStatus = find_opt (&request, DHCP4_END, 0, &op);

    if (EFI_ERROR (EfiStatus)) {
      Private->callback = NULL;
      return EFI_INVALID_PARAMETER;
    }

    op->op      = DHCP4_MESSAGE_TYPE;
    op->len     = 1;

    op->data[1] = DHCP4_END;
  }

  op->data[0] = DHCP4_MESSAGE_TYPE_REQUEST;

  //
  // Copy server identifier option from offer to request.
  //
  EfiStatus = find_opt (Offer, DHCP4_SERVER_IDENTIFIER, 0, &srvid);

  if (EFI_ERROR (EfiStatus)) {
    Private->callback = NULL;
    return EFI_INVALID_PARAMETER;
  }

  if (srvid->len != 4) {
    Private->callback = NULL;
    return EFI_INVALID_PARAMETER;
  }

  EfiStatus = add_opt (&request, srvid);

  if (EFI_ERROR (EfiStatus)) {
    DebugPrint (("%a:%d:%r\n", __FILE__, __LINE__, EfiStatus));
    Private->callback = NULL;
    return EfiStatus;
  }
  //
  // Add requested IP address option to request packet.
  //
  op      = (DHCP4_OP *) buf;
  op->op  = DHCP4_REQUESTED_IP_ADDRESS;
  op->len = 4;
  EfiCopyMem (op->data, &Offer->dhcp4.yiaddr, 4);

  EfiStatus = add_opt (&request, op);

  if (EFI_ERROR (EfiStatus)) {
    DebugPrint (("%a:%d:%r\n", __FILE__, __LINE__, EfiStatus));
    Private->callback = NULL;
    return EfiStatus;
  }
  //
  // Transimit DHCP request and wait for DHCP ack...
  //
  EfiSetMem (&bcast_ip, sizeof (EFI_IP_ADDRESS), 0xFF);

  EfiStatus = tx_rx_udp (
                Private,
                &bcast_ip,
                NULL,
                NULL,
                NULL,
                &request,
                &acknak,
                &acknak_verify,
                seconds_timeout
                );

  if (EFI_ERROR (EfiStatus)) {
    DebugPrint (("%a:%d:%r\n", __FILE__, __LINE__, EfiStatus));
    Private->callback = NULL;
    return EfiStatus;
  }
  //
  // Set Data->IsAck and return.
  //
  EfiStatus = find_opt (&acknak, DHCP4_MESSAGE_TYPE, 0, &op);

  if (EFI_ERROR (EfiStatus)) {
    Private->callback = NULL;
    return EFI_DEVICE_ERROR;
  }

  if (op->len != 1) {
    Private->callback = NULL;
    return EFI_DEVICE_ERROR;
  }

  switch (op->data[0]) {
  case DHCP4_MESSAGE_TYPE_ACK:
    This->Data->IsAck = TRUE;
    break;

  case DHCP4_MESSAGE_TYPE_NAK:
    This->Data->IsAck = FALSE;
    break;

  default:
    Private->callback = NULL;
    return EFI_DEVICE_ERROR;
  }
  //
  // Copy packets into instance data...
  //
  EfiCopyMem (&This->Data->Offer, Offer, sizeof (DHCP4_PACKET));
  EfiCopyMem (&This->Data->Request, &request, sizeof (DHCP4_PACKET));
  EfiCopyMem (&This->Data->AckNak, &acknak, sizeof (DHCP4_PACKET));

  This->Data->SelectCompleted = TRUE;

  Private->callback           = NULL;
  return EFI_SUCCESS;
}

/* eof - PxeDhcp4InitSelect.c */

⌨️ 快捷键说明

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