mirror of
https://git.proxmox.com/git/fwupd
synced 2025-06-11 07:47:57 +00:00
243 lines
8.0 KiB
C
243 lines
8.0 KiB
C
/*
|
|
* SPDX-License-Identifier: LGPL-2.1+
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "fu-redfish-backend.h"
|
|
#include "fu-redfish-common.h"
|
|
#include "fu-redfish-smc-device.h"
|
|
|
|
struct _FuRedfishSmcDevice {
|
|
FuRedfishDevice parent_instance;
|
|
};
|
|
|
|
G_DEFINE_TYPE(FuRedfishSmcDevice, fu_redfish_smc_device, FU_TYPE_REDFISH_DEVICE)
|
|
|
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(curl_mime, curl_mime_free)
|
|
|
|
static const gchar *
|
|
fu_redfish_smc_device_get_task(JsonObject *json_obj)
|
|
{
|
|
JsonObject *tmp_obj;
|
|
JsonArray *tmp_ary;
|
|
const gchar *msgid;
|
|
|
|
if (!json_object_has_member(json_obj, "Accepted"))
|
|
return NULL;
|
|
tmp_obj = json_object_get_object_member(json_obj, "Accepted");
|
|
if (tmp_obj == NULL || !json_object_has_member(tmp_obj, "@Message.ExtendedInfo"))
|
|
return NULL;
|
|
tmp_ary = json_object_get_array_member(tmp_obj, "@Message.ExtendedInfo");
|
|
if (tmp_ary == NULL || json_array_get_length(tmp_ary) != 1)
|
|
return NULL;
|
|
tmp_obj = json_array_get_object_element(tmp_ary, 0);
|
|
if (tmp_obj == NULL)
|
|
return NULL;
|
|
msgid = json_object_get_string_member(tmp_obj, "MessageId");
|
|
if (g_strcmp0(msgid, "SMC.1.0.OemSimpleupdateAcceptedMessage") != 0)
|
|
return NULL;
|
|
tmp_ary = json_object_get_array_member(tmp_obj, "MessageArgs");
|
|
if (tmp_ary == NULL)
|
|
return NULL;
|
|
if (json_array_get_length(tmp_ary) != 1)
|
|
return NULL;
|
|
return json_array_get_string_element(tmp_ary, 0);
|
|
}
|
|
|
|
static GString *
|
|
fu_redfish_smc_device_get_parameters(FuRedfishSmcDevice *self)
|
|
{
|
|
g_autoptr(GString) str = g_string_new(NULL);
|
|
g_autoptr(JsonBuilder) builder = json_builder_new();
|
|
g_autoptr(JsonGenerator) json_generator = json_generator_new();
|
|
g_autoptr(JsonNode) json_root = NULL;
|
|
|
|
/* create header */
|
|
/* https://supermicro.com/manuals/other/RedishRefGuide.pdf */
|
|
json_builder_begin_object(builder);
|
|
json_builder_set_member_name(builder, "Targets");
|
|
json_builder_begin_array(builder);
|
|
json_builder_add_string_value(builder, "/redfish/v1/Systems/1/Bios");
|
|
json_builder_end_array(builder);
|
|
json_builder_set_member_name(builder, "@Redfish.OperationApplyTime");
|
|
json_builder_add_string_value(builder, "OnStartUpdateRequest");
|
|
json_builder_set_member_name(builder, "Oem");
|
|
json_builder_begin_object(builder);
|
|
json_builder_set_member_name(builder, "Supermicro");
|
|
json_builder_begin_object(builder);
|
|
json_builder_set_member_name(builder, "BIOS");
|
|
json_builder_begin_object(builder);
|
|
json_builder_set_member_name(builder, "PreserveME");
|
|
json_builder_add_boolean_value(builder, TRUE);
|
|
json_builder_set_member_name(builder, "PreserveNVRAM");
|
|
json_builder_add_boolean_value(builder, TRUE);
|
|
json_builder_set_member_name(builder, "PreserveSMBIOS");
|
|
json_builder_add_boolean_value(builder, TRUE);
|
|
json_builder_set_member_name(builder, "BackupBIOS");
|
|
json_builder_add_boolean_value(builder, FALSE);
|
|
json_builder_end_object(builder);
|
|
json_builder_end_object(builder);
|
|
json_builder_end_object(builder);
|
|
json_builder_end_object(builder);
|
|
|
|
/* export as a string */
|
|
json_root = json_builder_get_root(builder);
|
|
json_generator_set_pretty(json_generator, TRUE);
|
|
json_generator_set_root(json_generator, json_root);
|
|
json_generator_to_gstring(json_generator, str);
|
|
|
|
return g_steal_pointer(&str);
|
|
}
|
|
|
|
static gboolean
|
|
fu_redfish_smc_device_start_update(FuDevice *device, FuProgress *progress, GError **error)
|
|
{
|
|
FuRedfishBackend *backend = fu_redfish_device_get_backend(FU_REDFISH_DEVICE(device));
|
|
JsonObject *json_obj;
|
|
CURL *curl;
|
|
const gchar *location = NULL;
|
|
g_autoptr(FuRedfishRequest) request = fu_redfish_backend_request_new(backend);
|
|
|
|
curl = fu_redfish_request_get_curl(request);
|
|
(void)curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
|
|
|
|
if (!fu_redfish_request_perform(
|
|
request,
|
|
"/redfish/v1/UpdateService/Actions/UpdateService.StartUpdate",
|
|
FU_REDFISH_REQUEST_PERFORM_FLAG_LOAD_JSON,
|
|
error)) {
|
|
if (g_error_matches(*error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED)) {
|
|
fu_device_add_problem(device, FWUPD_DEVICE_PROBLEM_UPDATE_PENDING);
|
|
}
|
|
return FALSE;
|
|
}
|
|
json_obj = fu_redfish_request_get_json_object(request);
|
|
|
|
location = fu_redfish_smc_device_get_task(json_obj);
|
|
if (location == NULL) {
|
|
g_set_error(error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_INVALID_FILE,
|
|
"no task returned for %s",
|
|
fu_redfish_backend_get_push_uri_path(backend));
|
|
return FALSE;
|
|
}
|
|
return fu_redfish_device_poll_task(FU_REDFISH_DEVICE(device), location, progress, error);
|
|
}
|
|
|
|
static gboolean
|
|
fu_redfish_smc_device_write_firmware(FuDevice *device,
|
|
FuFirmware *firmware,
|
|
FuProgress *progress,
|
|
FwupdInstallFlags flags,
|
|
GError **error)
|
|
{
|
|
FuRedfishSmcDevice *self = FU_REDFISH_SMC_DEVICE(device);
|
|
FuRedfishBackend *backend = fu_redfish_device_get_backend(FU_REDFISH_DEVICE(self));
|
|
CURL *curl;
|
|
JsonObject *json_obj;
|
|
curl_mimepart *part;
|
|
const gchar *location = NULL;
|
|
gboolean ret;
|
|
g_autoptr(curl_mime) mime = NULL;
|
|
g_autoptr(FuRedfishRequest) request = NULL;
|
|
g_autoptr(GBytes) fw = NULL;
|
|
g_autoptr(GString) params = NULL;
|
|
|
|
fu_progress_set_id(progress, G_STRLOC);
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 50, "write");
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_RESTART, 50, "apply");
|
|
|
|
/* get default image */
|
|
fw = fu_firmware_get_bytes(firmware, error);
|
|
if (fw == NULL)
|
|
return FALSE;
|
|
|
|
/* create the multipart for uploading the image request */
|
|
request = fu_redfish_backend_request_new(backend);
|
|
curl = fu_redfish_request_get_curl(request);
|
|
mime = curl_mime_init(curl);
|
|
(void)curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
|
|
|
|
params = fu_redfish_smc_device_get_parameters(self);
|
|
part = curl_mime_addpart(mime);
|
|
curl_mime_name(part, "UpdateParameters");
|
|
(void)curl_mime_type(part, "application/json");
|
|
(void)curl_mime_data(part, params->str, CURL_ZERO_TERMINATED);
|
|
if (g_getenv("FWUPD_REDFISH_VERBOSE") != NULL)
|
|
g_debug("request: %s", params->str);
|
|
|
|
part = curl_mime_addpart(mime);
|
|
curl_mime_name(part, "UpdateFile");
|
|
(void)curl_mime_type(part, "application/octet-stream");
|
|
(void)curl_mime_filedata(part, "firmware.bin");
|
|
(void)curl_mime_data(part, g_bytes_get_data(fw, NULL), g_bytes_get_size(fw));
|
|
|
|
fu_progress_set_status(progress, FWUPD_STATUS_DEVICE_WRITE);
|
|
if (!fu_redfish_request_perform(request,
|
|
fu_redfish_backend_get_push_uri_path(backend),
|
|
FU_REDFISH_REQUEST_PERFORM_FLAG_LOAD_JSON,
|
|
error)) {
|
|
if (g_error_matches(*error, FWUPD_ERROR, FWUPD_ERROR_ALREADY_PENDING)) {
|
|
fu_device_add_problem(device, FWUPD_DEVICE_PROBLEM_UPDATE_PENDING);
|
|
}
|
|
return FALSE;
|
|
}
|
|
if (fu_redfish_request_get_status_code(request) != 202) {
|
|
g_set_error(error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_INVALID_FILE,
|
|
"failed to upload: %li",
|
|
fu_redfish_request_get_status_code(request));
|
|
return FALSE;
|
|
}
|
|
json_obj = fu_redfish_request_get_json_object(request);
|
|
|
|
/* poll the verify task for progress */
|
|
location = fu_redfish_smc_device_get_task(json_obj);
|
|
if (location == NULL) {
|
|
g_set_error(error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_INVALID_FILE,
|
|
"no task returned for %s",
|
|
fu_redfish_backend_get_push_uri_path(backend));
|
|
return FALSE;
|
|
}
|
|
|
|
if (!fu_redfish_device_poll_task(FU_REDFISH_DEVICE(self),
|
|
location,
|
|
fu_progress_get_child(progress),
|
|
error))
|
|
return FALSE;
|
|
fu_progress_step_done(progress);
|
|
|
|
ret = fu_redfish_smc_device_start_update(device, fu_progress_get_child(progress), error);
|
|
fu_progress_step_done(progress);
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
fu_redfish_smc_device_set_progress(FuDevice *self, FuProgress *progress)
|
|
{
|
|
fu_progress_set_id(progress, G_STRLOC);
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_RESTART, 1, "detach");
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_WRITE, 98, "write");
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_RESTART, 1, "attach");
|
|
fu_progress_add_step(progress, FWUPD_STATUS_DEVICE_BUSY, 0, "reload");
|
|
}
|
|
|
|
static void
|
|
fu_redfish_smc_device_init(FuRedfishSmcDevice *self)
|
|
{
|
|
fu_device_set_summary(FU_DEVICE(self), "Redfish Supermicro device");
|
|
}
|
|
|
|
static void
|
|
fu_redfish_smc_device_class_init(FuRedfishSmcDeviceClass *klass)
|
|
{
|
|
FuDeviceClass *klass_device = FU_DEVICE_CLASS(klass);
|
|
klass_device->write_firmware = fu_redfish_smc_device_write_firmware;
|
|
klass_device->set_progress = fu_redfish_smc_device_set_progress;
|
|
}
|