Use Firmware upgrade events

This commit is contained in:
Suvendhu Hansa 2023-12-07 08:05:17 +00:00 committed by Vivek Kumar Dutta
parent 1a00d15820
commit cc3bb93280
4 changed files with 148 additions and 61 deletions

View file

@ -163,36 +163,14 @@ int dmubus_call_set(char *obj, char *method, struct ubus_arg u_args[], int u_arg
return rc;
}
struct dmubus_event_data {
struct uloop_timeout tm;
struct ubus_event_handler ev;
struct blob_attr *ev_msg;
};
static void dmubus_receive_event(struct ubus_context *ctx, struct ubus_event_handler *ev,
const char *type, struct blob_attr *msg)
{
struct dmubus_event_data *data;
if (!msg || !ev)
return;
data = container_of(ev, struct dmubus_event_data, ev);
if (validate_blob_message(data->ev_msg, msg) == true) {
uloop_end();
}
return;
}
static void dmubus_listen_timeout(struct uloop_timeout *timeout)
{
uloop_end();
}
/*********************************************************************//**
/*******************************************************************************
**
** dmubus_register_event_blocking
** dmubus_wait_for_event
**
** This API is to wait for the specified event to arrive on ubus or the timeout
** whichever is earlier
@ -200,23 +178,27 @@ static void dmubus_listen_timeout(struct uloop_timeout *timeout)
** NOTE: since this is a blocking call so it should only be called from DM_ASYNC
** operations.
**
** \param event - event to be listened on ubus
** \param event - wait for this <event> to arrive on ubus
** \param timeout - max time (seconds) to wait for the event
** \param type - event type for which the process need to wait
** \param ev_data - data to be passed to the callback method
** \param ev_callback - callback method to be invoked on arrival of the event
**
** E.G: event: wifi.radio, type: {"radio":"wl1","action":"scan_finished"}
** E.G: event: sysupgrade, type: {"status":"Downloading","bank_id":"2"}
**
**************************************************************************/
void dmubus_register_event_blocking(char *event, int timeout, struct blob_attr *type)
*******************************************************************************/
void dmubus_wait_for_event(const char *event, int timeout, void *ev_data, CB_FUNC_PTR ev_callback)
{
if (DM_STRLEN(event) == 0)
return;
struct ubus_context *ctx = ubus_connect(NULL);
if (!ctx)
return;
struct dmubus_event_data data = {
.tm.cb = dmubus_listen_timeout,
.ev.cb = dmubus_receive_event,
.ev_msg = type,
.ev.cb = ev_callback,
.ev_data = ev_data
};
uloop_init();

View file

@ -18,6 +18,17 @@
#include <libubus.h>
#include "dmapi.h"
struct dmubus_event_data {
struct uloop_timeout tm;
struct ubus_event_handler ev;
void *ev_data;
};
typedef void (*CB_FUNC_PTR)(struct ubus_context *ctx, struct ubus_event_handler *ev,
const char *type, struct blob_attr *msg);
void dmubus_wait_for_event(const char *event, int timeout, void *ev_data, CB_FUNC_PTR ev_callback);
int dmubus_call(char *obj, char *method, struct ubus_arg u_args[], int u_args_size, json_object **req_res);
int dmubus_call_blocking(char *obj, char *method, struct ubus_arg u_args[], int u_args_size, json_object **req_res);
int dmubus_call_set(char *obj, char *method, struct ubus_arg u_args[], int u_args_size);
@ -25,8 +36,6 @@ int dmubus_call_set(char *obj, char *method, struct ubus_arg u_args[], int u_arg
int dmubus_call_blob(char *obj, char *method, void *value, json_object **resp);
int dmubus_call_blob_set(char *obj, char *method, void *value);
void dmubus_register_event_blocking(char *event, int timeout, struct blob_attr *type);
void dmubus_free();
bool dmubus_object_method_exists(const char *obj);

View file

@ -89,20 +89,17 @@ static bool get_response_code_status(const char *url, int response_code)
}
static void send_transfer_complete_event(const char *command, const char *obj_path, const char *transfer_url,
long res_code, time_t start_t, time_t complete_t,const char *commandKey, const char *transfer_type)
char *fault_string, time_t start_t, time_t complete_t,const char *commandKey, const char *transfer_type)
{
char start_time[32] = {0};
char complete_time[32] = {0};
char fault_string[128] = {0};
unsigned fault_code = 0;
strftime(start_time, sizeof(start_time), "%Y-%m-%dT%H:%M:%SZ", gmtime(&start_t));
strftime(complete_time, sizeof(complete_time), "%Y-%m-%dT%H:%M:%SZ", gmtime(&complete_t));
if (!get_response_code_status(transfer_url, res_code)) {
if (DM_STRLEN(fault_string) != 0)
fault_code = USP_FAULT_GENERAL_FAILURE;
snprintf(fault_string, sizeof(fault_string), "%s operation is failed, fault code (%ld)", transfer_type, res_code);
}
struct json_object *obj = json_object_new_object();
@ -328,28 +325,31 @@ int bbf_config_backup(const char *url, const char *username, const char *passwor
char *config_name, const char *command, const char *obj_path)
{
int res = 0;
char fault_msg[128] = {0};
time_t complete_time = 0;
time_t start_time = time(NULL);
// Export config file to backup file
if (dmuci_export_package(config_name, CONFIG_BACKUP)) {
snprintf(fault_msg, sizeof(fault_msg), "Failed to export the configurations");
res = -1;
goto end;
}
// Upload the config file
time_t start_time = time(NULL);
long res_code = upload_file(CONFIG_BACKUP, url, username, password);
time_t complete_time = time(NULL);
// Send Transfer Complete Event
send_transfer_complete_event(command, obj_path, url, res_code, start_time, complete_time,NULL,"Upload");
complete_time = time(NULL);
// Check if the upload operation was successful
if (!get_response_code_status(url, res_code)) {
res = -1;
goto end;
snprintf(fault_msg, sizeof(fault_msg), "Upload operation is failed, fault code (%ld)", res_code);
}
end:
// Send the transfer complete event
send_transfer_complete_event(command, obj_path, url, fault_msg, start_time, complete_time, NULL, "Upload");
// Remove temporary file
if (file_exists(CONFIG_BACKUP) && remove(CONFIG_BACKUP))
res = -1;
@ -361,20 +361,21 @@ int bbf_upload_log(const char *url, const char *username, const char *password,
char *config_name, const char *command, const char *obj_path)
{
int res = 0;
char fault_msg[128] = {0};
// Upload the config file
// Upload the config file
time_t start_time = time(NULL);
long res_code = upload_file(config_name, url, username, password);
time_t complete_time = time(NULL);
// Send Transfer Complete Event
send_transfer_complete_event(command, obj_path, url, res_code, start_time, complete_time,NULL, "Upload");
// Check if the upload operation was successful
if (!get_response_code_status(url, res_code)) {
snprintf(fault_msg, sizeof(fault_msg), "Upload operation is failed, fault code (%ld)", res_code);
res = -1;
}
// Send the transfer complete event
send_transfer_complete_event(command, obj_path, url, fault_msg, start_time, complete_time, NULL, "Upload");
return res;
}
int bbf_config_restore(const char *url, const char *username, const char *password,
@ -383,38 +384,45 @@ int bbf_config_restore(const char *url, const char *username, const char *passwo
{
char config_restore[256] = "/tmp/bbf_config_restore";
int res = 0;
char fault_msg[128] = {0};
time_t complete_time = 0;
time_t start_time = time(NULL);
// Check the file system size if there is sufficient space for downloading the config file
if (!validate_file_system_size(file_size)) {
snprintf(fault_msg, sizeof(fault_msg), "Available memory space is less than required for the operation");
res = -1;
goto end;
}
// Download the firmware image
time_t start_time = time(NULL);
long res_code = download_file(config_restore, url, username, password);
time_t complete_time = time(NULL);
// Send Transfer Complete Event
send_transfer_complete_event(command, obj_path, url, res_code, start_time, complete_time, NULL, "Download");
complete_time = time(NULL);
// Check if the download operation was successful
if (!get_response_code_status(url, res_code)) {
snprintf(fault_msg, sizeof(fault_msg), "Upload operation is failed, fault code (%ld)", res_code);
res = -1;
goto end;
}
// Validate the CheckSum value according to its algorithm
if (!validate_checksum_value(config_restore, checksum_algorithm, checksum)) {
snprintf(fault_msg, sizeof(fault_msg), "Checksum of the downloaded file is mismatched");
res = -1;
goto end;
}
// Apply config file
if (dmuci_import(NULL, config_restore))
if (dmuci_import(NULL, config_restore)) {
snprintf(fault_msg, sizeof(fault_msg), "Failed to import the configurations");
res = -1;
}
end:
// Send the transfer complete event
send_transfer_complete_event(command, obj_path, url, fault_msg, start_time, complete_time, NULL, "Download");
// Remove temporary file
if (file_exists(config_restore) && strncmp(url, FILE_URI, strlen(FILE_URI)) && remove(config_restore))
res = -1;
@ -422,6 +430,52 @@ end:
return res;
}
struct sysupgrade_ev_data {
const char *bank_id;
bool status;
};
static void dmubus_receive_sysupgrade(struct ubus_context *ctx, struct ubus_event_handler *ev,
const char *type, struct blob_attr *msg)
{
struct dmubus_event_data *data;
struct blob_attr *msg_attr;
if (!msg || !ev)
return;
data = container_of(ev, struct dmubus_event_data, ev);
if (data == NULL)
return;
struct sysupgrade_ev_data *ev_data = (struct sysupgrade_ev_data *)data->ev_data;
if (ev_data == NULL)
return;
size_t msg_len = (size_t)blobmsg_data_len(msg);
__blob_for_each_attr(msg_attr, blobmsg_data(msg), msg_len) {
if (DM_STRCMP("bank_id", blobmsg_name(msg_attr)) == 0) {
char *attr_val = (char *)blobmsg_data(msg_attr);
if (DM_STRCMP(attr_val, ev_data->bank_id) != 0)
return;
}
if (DM_STRCMP("status", blobmsg_name(msg_attr)) == 0) {
char *attr_val = (char *)blobmsg_data(msg_attr);
if (DM_STRCMP(attr_val, "Downloading") == 0)
return;
else if (DM_STRCMP(attr_val, "Available") == 0)
ev_data->status = true;
else
ev_data->status = false;
}
}
uloop_end();
return;
}
int bbf_fw_image_download(const char *url, const char *auto_activate, const char *username, const char *password,
const char *file_size, const char *checksum_algorithm, const char *checksum,
const char *bank_id, const char *command, const char *obj_path, const char *commandKey)
@ -430,15 +484,20 @@ int bbf_fw_image_download(const char *url, const char *auto_activate, const char
json_object *json_obj = NULL;
bool activate = false, valid = false;
int res = 0;
char fault_msg[128] = {0};
time_t complete_time = 0;
time_t start_time = time(NULL);
// Check the file system size if there is sufficient space for downloading the firmware image
if (!validate_file_system_size(file_size)) {
res = -1;
snprintf(fault_msg, sizeof(fault_msg), "Available memory space is lower than required for downloading");
goto end;
}
res = mkstemp(fw_image_path);
if (res == -1) {
snprintf(fault_msg, sizeof(fault_msg), "Operation failed due to some internal failure");
goto end;
} else {
close(res); // close the fd, as only filename required
@ -446,12 +505,12 @@ int bbf_fw_image_download(const char *url, const char *auto_activate, const char
}
// Download the firmware image
time_t start_time = time(NULL);
long res_code = download_file(fw_image_path, url, username, password);
time_t complete_time = time(NULL);
complete_time = time(NULL);
// Check if the download operation was successful
if (!get_response_code_status(url, res_code)) {
snprintf(fault_msg, sizeof(fault_msg), "Download operation is failed, fault code (%ld)", res_code);
res = -1;
goto end;
}
@ -459,6 +518,7 @@ int bbf_fw_image_download(const char *url, const char *auto_activate, const char
// Validate the CheckSum value according to its algorithm
if (!validate_checksum_value(fw_image_path, checksum_algorithm, checksum)) {
res = -1;
snprintf(fault_msg, sizeof(fault_msg), "Checksum of the file is not matched with the specified value");
goto end;
}
@ -468,6 +528,7 @@ int bbf_fw_image_download(const char *url, const char *auto_activate, const char
dmubus_call_blocking("system", "validate_firmware_image", UBUS_ARGS{{"path", fw_image_path, String}}, 1, &json_obj);
if (json_obj == NULL) {
res = -1;
snprintf(fault_msg, sizeof(fault_msg), "Failed in validation of the file");
goto end;
}
@ -476,7 +537,7 @@ int bbf_fw_image_download(const char *url, const char *auto_activate, const char
json_object_put(json_obj);
json_obj = NULL;
if (valid == false) {
send_transfer_complete_event(command, obj_path, url, res_code, start_time, complete_time, commandKey, "Download");
snprintf(fault_msg, sizeof(fault_msg), "File is not a valid firmware image");
res = -1;
goto end;
}
@ -485,15 +546,28 @@ int bbf_fw_image_download(const char *url, const char *auto_activate, const char
dmubus_call_blocking("fwbank", "upgrade", UBUS_ARGS{{"path", fw_image_path, String}, {"auto_activate", act, Boolean}, {"bank", bank_id, Integer}}, 3, &json_obj);
if (json_obj == NULL) {
res = 1;
snprintf(fault_msg, sizeof(fault_msg), "Internal error occurred when applying the firmware");
goto end;
}
sleep(60); // Wait for the image to become available
struct sysupgrade_ev_data ev_data = {
.bank_id = bank_id,
.status = false,
};
dmubus_wait_for_event("sysupgrade", 120, &ev_data, dmubus_receive_sysupgrade);
if (ev_data.status == false) {
res = 1;
snprintf(fault_msg, sizeof(fault_msg), "Failed to apply the downloaded image file");
goto end;
}
// Send the transfer complete after image applied
send_transfer_complete_event(command, obj_path, url, res_code, start_time, complete_time, commandKey, "Download");
// Reboot the device if auto activation is true
if (activate) {
// Send the transfer complete after image applied
send_transfer_complete_event(command, obj_path, url, fault_msg, start_time, complete_time, commandKey, "Download");
sleep(5); // added additional buffer for TransferComplete! event
if (dmubus_call_set("system", "reboot", UBUS_ARGS{0}, 0) != 0)
res = -1;
@ -501,6 +575,9 @@ int bbf_fw_image_download(const char *url, const char *auto_activate, const char
}
end:
// Send the transfer complete event
send_transfer_complete_event(command, obj_path, url, fault_msg, start_time, complete_time, commandKey, "Download");
// Remove temporary file if ubus upgrade failed and file exists
if (!json_obj && file_exists(fw_image_path) && strncmp(url, FILE_URI, strlen(FILE_URI))) {
remove(fw_image_path);

View file

@ -3506,6 +3506,25 @@ static int get_operate_args_WiFi_NeighboringWiFiDiagnostic(char *refparam, struc
return 0;
}
static void dmubus_receive_wifi_radio(struct ubus_context *ctx, struct ubus_event_handler *ev,
const char *type, struct blob_attr *msg)
{
struct dmubus_event_data *data;
if (!msg || !ev)
return;
data = container_of(ev, struct dmubus_event_data, ev);
if (data == NULL)
return;
if (validate_blob_message(data->ev_data, msg) == true) {
uloop_end();
}
return;
}
static int operate_WiFi_NeighboringWiFiDiagnostic(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
json_object *res = NULL;
@ -3547,7 +3566,7 @@ static int operate_WiFi_NeighboringWiFiDiagnostic(char *refparam, struct dmctx *
dmubus_call_set(object, "scan", UBUS_ARGS{0}, 0);
dmubus_register_event_blocking("wifi.radio", 30, bb.head);
dmubus_wait_for_event("wifi.radio", 30, bb.head, dmubus_receive_wifi_radio);
blob_buf_free(&bb);
dmubus_call(object, "scanresults", UBUS_ARGS{0}, 0, &scan_res);