mirror of
https://dev.iopsys.eu/bbf/bbfdm.git
synced 2025-12-10 07:44:39 +01:00
Device.DeviceInfo.FirmwareImage: add support for Download() and Activate() commands
This commit is contained in:
parent
d1b7bab383
commit
a82500080a
8 changed files with 577 additions and 75 deletions
|
|
@ -159,6 +159,8 @@ libbbfdm_la_LIBADD = \
|
|||
$(LBLOBMSG_LIBS) \
|
||||
$(LIBDLOPEN_LIBS) \
|
||||
$(LIBCURL_LIBS) \
|
||||
$(LIBOPENSSL_LIBS) \
|
||||
$(LIBCRYPTO_LIBS) \
|
||||
-lbbf_api
|
||||
|
||||
libbbfdm_la_CFLAGS+=-I../
|
||||
|
|
|
|||
|
|
@ -100,6 +100,9 @@ AC_SUBST([LIBDLOPEN_LIBS])
|
|||
LIBCURL_LIBS='-lcurl'
|
||||
AC_SUBST([LIBCURL_LIBS])
|
||||
|
||||
LIBCRYPTO_LIBS='-lcrypto'
|
||||
AC_SUBST([LIBCRYPTO_LIBS])
|
||||
|
||||
AM_COND_IF([LOPENSSL], [
|
||||
LIBOPENSSL_LIBS='-lssl'
|
||||
AC_SUBST([LIBOPENSSL_LIBS])
|
||||
|
|
|
|||
479
dmdiagnostics.c
479
dmdiagnostics.c
|
|
@ -9,6 +9,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <openssl/sha.h>
|
||||
#include <curl/curl.h>
|
||||
#include <libtrace.h>
|
||||
#include "dmentry.h"
|
||||
|
|
@ -16,6 +17,7 @@
|
|||
|
||||
static int read_next;
|
||||
static struct diagnostic_stats diag_stats = {0};
|
||||
static const int READ_BUF_SIZE = { 1024 * 16 };
|
||||
|
||||
char *get_diagnostics_option(char *sec_name, char *option)
|
||||
{
|
||||
|
|
@ -68,34 +70,91 @@ void set_diagnostics_interface_option(struct dmctx *ctx, char *sec_name, char *v
|
|||
}
|
||||
}
|
||||
|
||||
static int download_file(const char *file_path, const char *url, const char *username, const char *password)
|
||||
static bool get_response_code_status(const char *url, int response_code)
|
||||
{
|
||||
int res_code = 0;
|
||||
if ((strncmp(url, HTTP_URI, strlen(HTTP_URI)) == 0 && response_code != 200) ||
|
||||
(strncmp(url, FTP_URI, strlen(FTP_URI)) == 0 && response_code != 226) ||
|
||||
(strncmp(url, FILE_URI, strlen(FILE_URI)) == 0 && response_code != 0) ||
|
||||
(strncmp(url, HTTP_URI, strlen(HTTP_URI)) && strncmp(url, FTP_URI, strlen(FTP_URI)) && strncmp(url, FILE_URI, strlen(FILE_URI)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CURL *curl = curl_easy_init();
|
||||
if (curl) {
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||
curl_easy_setopt(curl, CURLOPT_USERNAME, username);
|
||||
curl_easy_setopt(curl, CURLOPT_PASSWORD, password);
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT, CURL_TIMEOUT);
|
||||
return true;
|
||||
}
|
||||
|
||||
FILE *fp = fopen(file_path, "wb");
|
||||
if (fp) {
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
|
||||
curl_easy_perform(curl);
|
||||
fclose(fp);
|
||||
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 *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", localtime(&start_t));
|
||||
strftime(complete_time, sizeof(complete_time), "%Y-%m-%dT%H:%M:%SZ", localtime(&complete_t));
|
||||
|
||||
if (!get_response_code_status(transfer_url, res_code)) {
|
||||
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();
|
||||
|
||||
json_object_object_add(obj, "Command", json_object_new_string(command));
|
||||
json_object_object_add(obj, "CommandKey", json_object_new_string(""));
|
||||
json_object_object_add(obj, "Requestor", json_object_new_string(""));
|
||||
json_object_object_add(obj, "TransferType", json_object_new_string(transfer_type));
|
||||
json_object_object_add(obj, "Affected", json_object_new_string(obj_path));
|
||||
json_object_object_add(obj, "TransferURL", json_object_new_string(transfer_url));
|
||||
json_object_object_add(obj, "StartTime", json_object_new_string(start_time));
|
||||
json_object_object_add(obj, "CompleteTime", json_object_new_string(complete_time));
|
||||
json_object_object_add(obj, "FaultCode", json_object_new_uint64(fault_code));
|
||||
json_object_object_add(obj, "FaultString", json_object_new_string(fault_string));
|
||||
|
||||
dmubus_call_set("usp.raw", "notify_event", UBUS_ARGS{{"name", "Device.LocalAgent.TransferComplete!", String}, {"input", json_object_to_json_string(obj), Table}}, 2);
|
||||
|
||||
json_object_put(obj);
|
||||
}
|
||||
|
||||
static long download_file(char *file_path, const char *url, const char *username, const char *password)
|
||||
{
|
||||
long res_code = 0;
|
||||
|
||||
if (strncmp(url, FILE_URI, strlen(FILE_URI)) == 0) {
|
||||
|
||||
const char *curr_path = (!strncmp(url, FILE_LOCALHOST_URI, strlen(FILE_LOCALHOST_URI))) ? url + strlen(FILE_LOCALHOST_URI) : url + strlen(FILE_URI);
|
||||
|
||||
if (!file_exists(curr_path))
|
||||
return -1;
|
||||
|
||||
DM_STRNCPY(file_path, curr_path, 256);
|
||||
} else {
|
||||
|
||||
CURL *curl = curl_easy_init();
|
||||
if (curl) {
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||
curl_easy_setopt(curl, CURLOPT_USERNAME, username);
|
||||
curl_easy_setopt(curl, CURLOPT_PASSWORD, password);
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT, CURL_TIMEOUT);
|
||||
|
||||
FILE *fp = fopen(file_path, "wb");
|
||||
if (fp) {
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
|
||||
curl_easy_perform(curl);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &res_code);
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &res_code);
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
return res_code;
|
||||
}
|
||||
|
||||
static int upload_file(const char *file_path, const char *url, const char *username, const char *password)
|
||||
static long upload_file(const char *file_path, const char *url, const char *username, const char *password)
|
||||
{
|
||||
int res_code = 0;
|
||||
long res_code = 0;
|
||||
|
||||
CURL *curl = curl_easy_init();
|
||||
if (curl) {
|
||||
|
|
@ -119,7 +178,222 @@ static int upload_file(const char *file_path, const char *url, const char *usern
|
|||
return res_code;
|
||||
}
|
||||
|
||||
int bbf_config_backup(const char *url, const char *username, const char *password, char *config_name)
|
||||
const bool validate_file_system_size(const char *file_size)
|
||||
{
|
||||
if (file_size && *file_size) {
|
||||
unsigned long f_size = strtoul(file_size, NULL, 10);
|
||||
unsigned long fs_available_size = file_system_size("/tmp", FS_SIZE_AVAILABLE);
|
||||
|
||||
if (fs_available_size < f_size)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const bool validate_sha1sum_value(const char *file_path, const char *checksum)
|
||||
{
|
||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||
unsigned char buffer[READ_BUF_SIZE];
|
||||
char sha1_res[1 + SHA_DIGEST_LENGTH * 2];
|
||||
bool res = false;
|
||||
int bytes = 0;
|
||||
SHA_CTX ctx;
|
||||
|
||||
FILE *file = fopen(file_path, "rb");
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
if (!SHA1_Init(&ctx))
|
||||
goto end;
|
||||
|
||||
while ((bytes = fread (buffer, 1, sizeof(buffer), file))) {
|
||||
if (!SHA1_Update(&ctx, buffer, bytes))
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!SHA1_Final(hash, &ctx))
|
||||
goto end;
|
||||
|
||||
for (int i = 0; i < SHA_DIGEST_LENGTH; i++)
|
||||
snprintf(&sha1_res[i * 2], sizeof(sha1_res) - (i * 2), "%02x", hash[i]);
|
||||
|
||||
if (strcmp(sha1_res, checksum) == 0)
|
||||
res = true;
|
||||
|
||||
end:
|
||||
fclose(file);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
const bool validate_sha224sum_value(const char *file_path, const char *checksum)
|
||||
{
|
||||
unsigned char hash[SHA224_DIGEST_LENGTH];
|
||||
unsigned char buffer[READ_BUF_SIZE];
|
||||
char sha224_res[1 + SHA224_DIGEST_LENGTH * 2];
|
||||
bool res = false;
|
||||
int bytes = 0;
|
||||
SHA256_CTX ctx;
|
||||
|
||||
FILE *file = fopen(file_path, "rb");
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
if (!SHA224_Init(&ctx))
|
||||
goto end;
|
||||
|
||||
while ((bytes = fread (buffer, 1, sizeof(buffer), file))) {
|
||||
if (!SHA224_Update(&ctx, buffer, bytes))
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!SHA224_Final(hash, &ctx))
|
||||
goto end;
|
||||
|
||||
for (int i = 0; i < SHA224_DIGEST_LENGTH; i++)
|
||||
snprintf(&sha224_res[i * 2], sizeof(sha224_res) - (i * 2), "%02x", hash[i]);
|
||||
|
||||
if (strcmp(sha224_res, checksum) == 0)
|
||||
res = true;
|
||||
|
||||
end:
|
||||
fclose(file);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
const bool validate_sha256sum_value(const char *file_path, const char *checksum)
|
||||
{
|
||||
unsigned char hash[SHA256_DIGEST_LENGTH];
|
||||
unsigned char buffer[READ_BUF_SIZE];
|
||||
char sha256_res[1 + SHA256_DIGEST_LENGTH * 2];
|
||||
bool res = false;
|
||||
int bytes = 0;
|
||||
SHA256_CTX ctx;
|
||||
|
||||
FILE *file = fopen(file_path, "rb");
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
if (!SHA256_Init(&ctx))
|
||||
goto end;
|
||||
|
||||
while ((bytes = fread (buffer, 1, sizeof(buffer), file))) {
|
||||
if (!SHA256_Update(&ctx, buffer, bytes))
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!SHA256_Final(hash, &ctx))
|
||||
goto end;
|
||||
|
||||
for (int i = 0; i < SHA256_DIGEST_LENGTH; i++)
|
||||
snprintf(&sha256_res[i * 2], sizeof(sha256_res) - (i * 2), "%02x", hash[i]);
|
||||
|
||||
if (strcmp(sha256_res, checksum) == 0)
|
||||
res = true;
|
||||
|
||||
end:
|
||||
fclose(file);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
const bool validate_sha384sum_value(const char *file_path, const char *checksum)
|
||||
{
|
||||
unsigned char hash[SHA384_DIGEST_LENGTH];
|
||||
unsigned char buffer[READ_BUF_SIZE];
|
||||
char sha384_res[1 + SHA384_DIGEST_LENGTH * 2];
|
||||
bool res = false;
|
||||
int bytes = 0;
|
||||
SHA512_CTX ctx;
|
||||
|
||||
FILE *file = fopen(file_path, "rb");
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
if (!SHA384_Init(&ctx))
|
||||
goto end;
|
||||
|
||||
while ((bytes = fread (buffer, 1, sizeof(buffer), file))) {
|
||||
if (!SHA384_Update(&ctx, buffer, bytes))
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!SHA384_Final(hash, &ctx))
|
||||
goto end;
|
||||
|
||||
for (int i = 0; i < SHA384_DIGEST_LENGTH; i++)
|
||||
snprintf(&sha384_res[i * 2], sizeof(sha384_res) - (i * 2), "%02x", hash[i]);
|
||||
|
||||
if (strcmp(sha384_res, checksum) == 0)
|
||||
res = true;
|
||||
|
||||
end:
|
||||
fclose(file);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
const bool validate_sha512sum_value(const char *file_path, const char *checksum)
|
||||
{
|
||||
unsigned char hash[SHA512_DIGEST_LENGTH];
|
||||
unsigned char buffer[READ_BUF_SIZE];
|
||||
char sha512_res[1 + SHA512_DIGEST_LENGTH * 2];
|
||||
bool res = false;
|
||||
int bytes = 0;
|
||||
SHA512_CTX ctx;
|
||||
|
||||
FILE *file = fopen(file_path, "rb");
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
if (!SHA512_Init(&ctx))
|
||||
goto end;
|
||||
|
||||
while ((bytes = fread (buffer, 1, sizeof(buffer), file))) {
|
||||
if (!SHA512_Update(&ctx, buffer, bytes))
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!SHA512_Final(hash, &ctx))
|
||||
goto end;
|
||||
|
||||
for (int i = 0; i < SHA512_DIGEST_LENGTH; i++)
|
||||
snprintf(&sha512_res[i * 2], sizeof(sha512_res) - (i * 2), "%02x", hash[i]);
|
||||
|
||||
if (strcmp(sha512_res, checksum) == 0)
|
||||
res = true;
|
||||
|
||||
end:
|
||||
fclose(file);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
const bool validate_checksum_value(const char *file_path, const char *checksum_algorithm, const char *checksum)
|
||||
{
|
||||
if (checksum && *checksum) {
|
||||
|
||||
if (strcmp(checksum_algorithm, "SHA-1") == 0)
|
||||
return validate_sha1sum_value(file_path, checksum);
|
||||
else if (strcmp(checksum_algorithm, "SHA-224") == 0)
|
||||
return validate_sha224sum_value(file_path, checksum);
|
||||
else if (strcmp(checksum_algorithm, "SHA-256") == 0)
|
||||
return validate_sha256sum_value(file_path, checksum);
|
||||
else if (strcmp(checksum_algorithm, "SHA-384") == 0)
|
||||
return validate_sha384sum_value(file_path, checksum);
|
||||
else if (strcmp(checksum_algorithm, "SHA-512") == 0)
|
||||
return validate_sha512sum_value(file_path, checksum);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int bbf_config_backup(const char *url, const char *username, const char *password,
|
||||
char *config_name, const char *command, const char *obj_path)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
|
|
@ -129,57 +403,166 @@ int bbf_config_backup(const char *url, const char *username, const char *passwor
|
|||
goto end;
|
||||
}
|
||||
|
||||
// Upload config file
|
||||
int res_code = upload_file(CONFIG_BACKUP, url, username, password);
|
||||
if ((strncmp(url, HTTP_PROTO, strlen(HTTP_PROTO)) == 0 && res_code != 200) ||
|
||||
(strncmp(url, FTP_PROTO, strlen(FTP_PROTO)) == 0 && res_code != 226) ||
|
||||
(strncmp(url, HTTP_PROTO, strlen(HTTP_PROTO)) && strncmp(url, FTP_PROTO, strlen(FTP_PROTO))))
|
||||
// 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, "Upload");
|
||||
|
||||
// Check if the upload operation was successful
|
||||
if (!get_response_code_status(url, res_code)) {
|
||||
res = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
// Remove temporary file
|
||||
if (remove(CONFIG_BACKUP))
|
||||
if (file_exists(CONFIG_BACKUP) && remove(CONFIG_BACKUP))
|
||||
res = -1;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int bbf_config_restore(const char *url, const char *username, const char *password, const char *size)
|
||||
int bbf_config_restore(const char *url, const char *username, const char *password,
|
||||
const char *file_size, const char *checksum_algorithm, const char *checksum,
|
||||
const char *command, const char *obj_path)
|
||||
{
|
||||
char config_restore[256] = "/tmp/bbf_config_restore";
|
||||
int res = 0;
|
||||
|
||||
// Check file size
|
||||
if (size && *size) {
|
||||
unsigned long file_size = strtoul(size, NULL, 10);
|
||||
unsigned long fs_available_size = file_system_size("/tmp", FS_SIZE_AVAILABLE);
|
||||
|
||||
if (fs_available_size < file_size) {
|
||||
res = -1;
|
||||
goto end;
|
||||
}
|
||||
// Check the file system size if there is sufficient space for downloading the config file
|
||||
if (!validate_file_system_size(file_size)) {
|
||||
res = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
// Download config file
|
||||
int res_code = download_file(CONFIG_RESTORE, url, username, password);
|
||||
if ((strncmp(url, HTTP_PROTO, strlen(HTTP_PROTO)) == 0 && res_code != 200) ||
|
||||
(strncmp(url, FTP_PROTO, strlen(FTP_PROTO)) == 0 && res_code != 226) ||
|
||||
(strncmp(url, HTTP_PROTO, strlen(HTTP_PROTO)) && strncmp(url, FTP_PROTO, strlen(FTP_PROTO)))) {
|
||||
// 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, "Download");
|
||||
|
||||
// Check if the download operation was successful
|
||||
if (!get_response_code_status(url, res_code)) {
|
||||
res = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
// Validate the CheckSum value according to its algorithm
|
||||
if (!validate_checksum_value(config_restore, checksum_algorithm, checksum)) {
|
||||
res = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
// Apply config file
|
||||
if (dmuci_import(NULL, CONFIG_RESTORE))
|
||||
if (dmuci_import(NULL, config_restore))
|
||||
res = -1;
|
||||
|
||||
end:
|
||||
// Remove temporary file
|
||||
if (remove(CONFIG_RESTORE))
|
||||
if (file_exists(config_restore) && strncmp(url, FILE_URI, strlen(FILE_URI)) && remove(config_restore))
|
||||
res = -1;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
char fw_image_path[256] = "/tmp/firmware.bin";
|
||||
json_object *json_obj = NULL;
|
||||
bool activate = false;
|
||||
int res = 0;
|
||||
|
||||
// Check the file system size if there is sufficient space for downloading the firmware image
|
||||
if (!validate_file_system_size(file_size)) {
|
||||
res = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// Send Transfer Complete Event
|
||||
send_transfer_complete_event(command, obj_path, url, res_code, start_time, complete_time, "Download");
|
||||
|
||||
// Check if the download operation was successful
|
||||
if (!get_response_code_status(url, res_code)) {
|
||||
res = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
// Validate the CheckSum value according to its algorithm
|
||||
if (!validate_checksum_value(fw_image_path, checksum_algorithm, checksum)) {
|
||||
res = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
// Apply Firmware Image
|
||||
dmubus_call("fwbank", "upgrade", UBUS_ARGS{{"path", fw_image_path, String}, {"auto_activate", auto_activate, Boolean}, {"bank", bank_id, Integer}}, 3, &json_obj);
|
||||
|
||||
if (!json_obj) {
|
||||
res = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
// Reboot the device if auto activation is true
|
||||
string_to_bool((char *)auto_activate, &activate);
|
||||
if (activate) {
|
||||
sleep(30); // Wait for the image to become available
|
||||
if (dmubus_call_set("system", "reboot", UBUS_ARGS{}, 0) != 0)
|
||||
res = -1;
|
||||
}
|
||||
|
||||
end:
|
||||
// Remove temporary file
|
||||
if (!json_obj && file_exists(fw_image_path) && strncmp(url, FILE_URI, strlen(FILE_URI)) && remove(fw_image_path))
|
||||
res = -1;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void launch_activate_iamge_cb(struct uloop_timeout *t)
|
||||
{
|
||||
dmubus_call_set("system", "reboot", UBUS_ARGS{}, 0);
|
||||
}
|
||||
|
||||
static void activate_fw_images(struct activate_image *active_img)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < MAX_TIME_WINDOW && *active_img->start_time; i++, active_img++) {
|
||||
active_img->activate_timer.cb = launch_activate_iamge_cb;
|
||||
uloop_timeout_set(&active_img->activate_timer, atoi(active_img->start_time) * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
int bbf_fw_image_activate(const char *bank_id, struct activate_image *active_img)
|
||||
{
|
||||
json_object *json_obj = NULL;
|
||||
|
||||
dmubus_call("fwbank", "set_bootbank", UBUS_ARGS{{"bank", bank_id, Integer}}, 1, &json_obj);
|
||||
char *status = dmjson_get_value(json_obj, 1, "success");
|
||||
if (strcmp(status, "true") != 0)
|
||||
return -1;
|
||||
|
||||
if (*active_img->start_time) {
|
||||
activate_fw_images(active_img);
|
||||
} else {
|
||||
if (dmubus_call_set("system", "reboot", UBUS_ARGS{}, 0) != 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void libtrace_cleanup(libtrace_t *trace, libtrace_packet_t *packet)
|
||||
{
|
||||
if (trace)
|
||||
|
|
@ -578,8 +961,8 @@ int start_upload_download_diagnostic(int diagnostic_type)
|
|||
}
|
||||
|
||||
if ((url[0] == '\0') ||
|
||||
(strncmp(url, HTTP_PROTO, strlen(HTTP_PROTO)) != 0 &&
|
||||
strncmp(url, FTP_PROTO, strlen(FTP_PROTO)) != 0 &&
|
||||
(strncmp(url, HTTP_URI, strlen(HTTP_URI)) != 0 &&
|
||||
strncmp(url, FTP_URI, strlen(FTP_URI)) != 0 &&
|
||||
strstr(url,"@") != NULL))
|
||||
return -1;
|
||||
|
||||
|
|
@ -600,9 +983,9 @@ int start_upload_download_diagnostic(int diagnostic_type)
|
|||
status = get_diagnostics_option("download", "DiagnosticState");
|
||||
if (status && strcmp(status, "Complete") == 0) {
|
||||
memset(&diag_stats, 0, sizeof(diag_stats));
|
||||
if (strncmp(url, HTTP_PROTO, strlen(HTTP_PROTO)) == 0)
|
||||
if (strncmp(url, HTTP_URI, strlen(HTTP_URI)) == 0)
|
||||
extract_stats(DOWNLOAD_DUMP_FILE, DIAGNOSTIC_HTTP, DOWNLOAD_DIAGNOSTIC);
|
||||
if (strncmp(url, FTP_PROTO, strlen(FTP_PROTO)) == 0)
|
||||
if (strncmp(url, FTP_URI, strlen(FTP_URI)) == 0)
|
||||
extract_stats(DOWNLOAD_DUMP_FILE, DIAGNOSTIC_FTP, DOWNLOAD_DIAGNOSTIC);
|
||||
} else if (status && strncmp(status, "Error_", strlen("Error_")) == 0)
|
||||
return -1;
|
||||
|
|
@ -619,9 +1002,9 @@ int start_upload_download_diagnostic(int diagnostic_type)
|
|||
status = get_diagnostics_option("upload", "DiagnosticState");
|
||||
if (status && strcmp(status, "Complete") == 0) {
|
||||
memset(&diag_stats, 0, sizeof(diag_stats));
|
||||
if (strncmp(url, HTTP_PROTO, strlen(HTTP_PROTO)) == 0)
|
||||
if (strncmp(url, HTTP_URI, strlen(HTTP_URI)) == 0)
|
||||
extract_stats(UPLOAD_DUMP_FILE, DIAGNOSTIC_HTTP, UPLOAD_DIAGNOSTIC);
|
||||
if (strncmp(url, FTP_PROTO, strlen(FTP_PROTO)) == 0)
|
||||
if (strncmp(url, FTP_URI, strlen(FTP_URI)) == 0)
|
||||
extract_stats(UPLOAD_DUMP_FILE, DIAGNOSTIC_FTP, UPLOAD_DIAGNOSTIC);
|
||||
} else if (status && strncmp(status, "Error_", strlen("Error_")) == 0)
|
||||
return -1;
|
||||
|
|
|
|||
|
|
@ -13,9 +13,12 @@
|
|||
#define __DMDIAGNOSTICS_H__
|
||||
|
||||
#include <libbbf_api/dmcommon.h>
|
||||
#include <libubox/uloop.h>
|
||||
|
||||
#define HTTP_PROTO "http://"
|
||||
#define FTP_PROTO "ftp://"
|
||||
#define HTTP_URI "http"
|
||||
#define FTP_URI "ftp"
|
||||
#define FILE_URI "file://"
|
||||
#define FILE_LOCALHOST_URI "file://localhost"
|
||||
#define default_date_format "AAAA-MM-JJTHH:MM:SS.000000Z"
|
||||
#define default_date_size sizeof(default_date_format) + 1
|
||||
#define FTP_SIZE_RESPONSE "213"
|
||||
|
|
@ -23,10 +26,10 @@
|
|||
#define FTP_TRANSFERT_COMPLETE "226 Transfer"
|
||||
#define FTP_RETR_REQUEST "RETR"
|
||||
#define FTP_STOR_REQUEST "STOR"
|
||||
#define CURL_TIMEOUT 10
|
||||
#define CURL_TIMEOUT 100
|
||||
#define DMMAP_DIAGNOSTIGS "dmmap_diagnostics"
|
||||
#define CONFIG_RESTORE "/tmp/bbf_config_restore"
|
||||
#define CONFIG_BACKUP "/tmp/bbf_config_backup"
|
||||
#define MAX_TIME_WINDOW 5
|
||||
|
||||
struct diagnostic_stats
|
||||
{
|
||||
|
|
@ -45,6 +48,12 @@ struct diagnostic_stats
|
|||
uint32_t ftp_syn;
|
||||
};
|
||||
|
||||
struct activate_image
|
||||
{
|
||||
struct uloop_timeout activate_timer;
|
||||
char *start_time;
|
||||
};
|
||||
|
||||
enum diagnostic_protocol {
|
||||
DIAGNOSTIC_HTTP = 1,
|
||||
DIAGNOSTIC_FTP
|
||||
|
|
@ -61,7 +70,14 @@ void set_diagnostics_option(char *sec_name, char *option, char *value);
|
|||
void init_diagnostics_operation(char *sec_name, char *operation_path);
|
||||
void set_diagnostics_interface_option(struct dmctx *ctx, char *sec_name, char *value);
|
||||
int start_upload_download_diagnostic(int diagnostic_type);
|
||||
int bbf_config_backup(const char *url, const char *username, const char *password, char *config_name);
|
||||
int bbf_config_restore(const char *url, const char *username, const char *password, const char *size);
|
||||
int bbf_config_backup(const char *url, const char *username, const char *password,
|
||||
char *config_name, const char *command, const char *obj_path);
|
||||
int bbf_config_restore(const char *url, const char *username, const char *password,
|
||||
const char *file_size, const char *checksum_algorithm, const char *checksum,
|
||||
const char *command, const char *obj_path);
|
||||
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);
|
||||
int bbf_fw_image_activate(const char *bank_id, struct activate_image *active_img);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
120
dmoperate.c
120
dmoperate.c
|
|
@ -20,6 +20,14 @@
|
|||
static uint8_t wifi_neighbor_count = 0;
|
||||
struct op_cmd *dynamic_operate = NULL;
|
||||
|
||||
static const char *fw_image_activate_in[] = {
|
||||
"TimeWindow.1.Start",
|
||||
"TimeWindow.2.Start",
|
||||
"TimeWindow.3.Start",
|
||||
"TimeWindow.4.Start",
|
||||
"TimeWindow.5.Start",
|
||||
};
|
||||
|
||||
static void bbf_init(struct dmctx *dm_ctx, char *path)
|
||||
{
|
||||
unsigned int instance = INSTANCE_MODE_NUMBER;
|
||||
|
|
@ -219,6 +227,12 @@ static opr_ret_t dhcp_client_renew(struct dmctx *dmctx, char *path, json_object
|
|||
static opr_ret_t vendor_conf_backup(struct dmctx *dmctx, char *path, json_object *input)
|
||||
{
|
||||
struct file_server fserver = {0};
|
||||
char obj_path[256] = {'\0'};
|
||||
char command[32] = {'\0'};
|
||||
|
||||
char *ret = strrchr(path, '.');
|
||||
strncpy(obj_path, path, ret - path +1);
|
||||
DM_STRNCPY(command, ret+1, sizeof(command));
|
||||
|
||||
char *vcf_name = get_param_val_from_op_cmd(path, "Name");
|
||||
if (!vcf_name)
|
||||
|
|
@ -231,7 +245,7 @@ static opr_ret_t vendor_conf_backup(struct dmctx *dmctx, char *path, json_object
|
|||
fserver.user = dmjson_get_value(input, 1, "Username");
|
||||
fserver.pass = dmjson_get_value(input, 1, "Password");
|
||||
|
||||
int res = bbf_config_backup(fserver.url, fserver.user, fserver.pass, vcf_name);
|
||||
int res = bbf_config_backup(fserver.url, fserver.user, fserver.pass, vcf_name, command, obj_path);
|
||||
dmfree(vcf_name);
|
||||
|
||||
return res ? FAIL : SUCCESS;
|
||||
|
|
@ -240,7 +254,12 @@ static opr_ret_t vendor_conf_backup(struct dmctx *dmctx, char *path, json_object
|
|||
static opr_ret_t vendor_conf_restore(struct dmctx *dmctx, char *path, json_object *input)
|
||||
{
|
||||
struct file_server fserver = {0};
|
||||
char *file_size = NULL;
|
||||
char obj_path[256] = {'\0'};
|
||||
char command[32] = {'\0'};
|
||||
|
||||
char *ret = strrchr(path, '.');
|
||||
strncpy(obj_path, path, ret - path +1);
|
||||
DM_STRNCPY(command, ret+1, sizeof(command));
|
||||
|
||||
fserver.url = dmjson_get_value(input, 1, "URL");
|
||||
if (fserver.url[0] == '\0')
|
||||
|
|
@ -248,9 +267,11 @@ static opr_ret_t vendor_conf_restore(struct dmctx *dmctx, char *path, json_objec
|
|||
|
||||
fserver.user = dmjson_get_value(input, 1, "Username");
|
||||
fserver.pass = dmjson_get_value(input, 1, "Password");
|
||||
file_size = dmjson_get_value(input, 1, "FileSize");
|
||||
fserver.file_size = dmjson_get_value(input, 1, "FileSize");
|
||||
fserver.checksum_algorithm = dmjson_get_value(input, 1, "CheckSumAlgorithm");
|
||||
fserver.checksum = dmjson_get_value(input, 1, "CheckSum");
|
||||
|
||||
int res = bbf_config_restore(fserver.url, fserver.user, fserver.pass, file_size);
|
||||
int res = bbf_config_restore(fserver.url, fserver.user, fserver.pass, fserver.file_size, fserver.checksum_algorithm, fserver.checksum, command, obj_path);
|
||||
|
||||
return res ? FAIL : SUCCESS;
|
||||
}
|
||||
|
|
@ -744,11 +765,11 @@ static opr_ret_t swmodules_install_du(struct dmctx *dmctx, char *path, json_obje
|
|||
return FAIL;
|
||||
|
||||
dmubus_call("swmodules", "du_install", UBUS_ARGS{
|
||||
{"url", du_install.url},
|
||||
{"uuid", du_install.uuid},
|
||||
{"username", du_install.username},
|
||||
{"password", du_install.password},
|
||||
{"environment", exec_env}},
|
||||
{"url", du_install.url, String},
|
||||
{"uuid", du_install.uuid, String},
|
||||
{"username", du_install.username, String},
|
||||
{"password", du_install.password, String},
|
||||
{"environment", exec_env, String}},
|
||||
5,
|
||||
&res);
|
||||
|
||||
|
|
@ -776,10 +797,10 @@ static opr_ret_t swmodules_update_du(struct dmctx *dmctx, char *path, json_objec
|
|||
return FAIL;
|
||||
|
||||
dmubus_call("swmodules", "du_update", UBUS_ARGS{
|
||||
{"uuid", du_uuid},
|
||||
{"url", du_update.url},
|
||||
{"username", du_update.username},
|
||||
{"password", du_update.password}},
|
||||
{"uuid", du_uuid, String},
|
||||
{"url", du_update.url, String},
|
||||
{"username", du_update.username, String},
|
||||
{"password", du_update.password, String}},
|
||||
4,
|
||||
&res);
|
||||
|
||||
|
|
@ -810,8 +831,8 @@ static opr_ret_t swmodules_uninstall_du(struct dmctx *dmctx, char *path, json_ob
|
|||
return FAIL;
|
||||
|
||||
dmubus_call("swmodules", "du_uninstall", UBUS_ARGS{
|
||||
{"name", du_name},
|
||||
{"environment", env}},
|
||||
{"name", du_name, String},
|
||||
{"environment", env, String}},
|
||||
2,
|
||||
&res);
|
||||
|
||||
|
|
@ -826,12 +847,65 @@ static opr_ret_t swmodules_uninstall_du(struct dmctx *dmctx, char *path, json_ob
|
|||
|
||||
static opr_ret_t firmware_image_download(struct dmctx *dmctx, char *path, json_object *input)
|
||||
{
|
||||
return SUCCESS;
|
||||
char obj_path[256] = {'\0'};
|
||||
char command[32] = {'\0'};
|
||||
char *bank_id = NULL;
|
||||
char *linker = NULL;
|
||||
|
||||
char *ret = strrchr(path, '.');
|
||||
strncpy(obj_path, path, ret - path +1);
|
||||
DM_STRNCPY(command, ret+1, sizeof(command));
|
||||
|
||||
adm_entry_get_linker_value(dmctx, obj_path, &linker);
|
||||
if (linker && *linker) {
|
||||
bank_id = strchr(linker, ':');
|
||||
if (!bank_id)
|
||||
return FAIL;
|
||||
} else {
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
char *url = dmjson_get_value(input, 1, "URL");
|
||||
char *auto_activate = dmjson_get_value(input, 1, "AutoActivate");
|
||||
if (url[0] == '\0' || auto_activate[0] == '\0')
|
||||
return UBUS_INVALID_ARGUMENTS;
|
||||
|
||||
char *username = dmjson_get_value(input, 1, "Username");
|
||||
char *password = dmjson_get_value(input, 1, "Password");
|
||||
char *file_size = dmjson_get_value(input, 1, "FileSize");
|
||||
char *checksum_algorithm = dmjson_get_value(input, 1, "CheckSumAlgorithm");
|
||||
char *checksum = dmjson_get_value(input, 1, "CheckSum");
|
||||
|
||||
int res = bbf_fw_image_download(url, auto_activate, username, password, file_size, checksum_algorithm, checksum, bank_id+1, command, obj_path);
|
||||
|
||||
return res ? FAIL : SUCCESS;
|
||||
}
|
||||
|
||||
static opr_ret_t firmware_image_activate(struct dmctx *dmctx, char *path, json_object *input)
|
||||
{
|
||||
return SUCCESS;
|
||||
struct activate_image active_images[MAX_TIME_WINDOW] = {0};
|
||||
char fwimage_path[256] = {'\0'};
|
||||
char *bank_id = NULL;
|
||||
char *linker = NULL;
|
||||
|
||||
char *ret = strrchr(path, '.');
|
||||
strncpy(fwimage_path, path, ret - path +1);
|
||||
|
||||
adm_entry_get_linker_value(dmctx, fwimage_path, &linker);
|
||||
if (linker && *linker) {
|
||||
bank_id = strchr(linker, ':');
|
||||
if (!bank_id)
|
||||
return FAIL;
|
||||
} else {
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(fw_image_activate_in); i++)
|
||||
active_images[i].start_time = dmjson_get_value(input, 1, fw_image_activate_in[i]);
|
||||
|
||||
int res = bbf_fw_image_activate(bank_id+1, active_images);
|
||||
|
||||
return res ? FAIL : SUCCESS;
|
||||
}
|
||||
|
||||
static int get_index_of_available_dynamic_operate(struct op_cmd *operate)
|
||||
|
|
@ -934,7 +1008,17 @@ static const struct op_cmd operate_helper[] = {
|
|||
}
|
||||
},
|
||||
{
|
||||
"Device.DeviceInfo.FirmwareImage.*.Activate", firmware_image_activate, "async"
|
||||
"Device.DeviceInfo.FirmwareImage.*.Activate", firmware_image_activate, "async",
|
||||
{
|
||||
.in = (const char *[]) {
|
||||
"TimeWindow.{i}.Start",
|
||||
"TimeWindow.{i}.End",
|
||||
"TimeWindow.{i}.Mode",
|
||||
"TimeWindow.{i}.UserMessage",
|
||||
"TimeWindow.{i}.MaxRetries",
|
||||
NULL
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Device.WiFi.NeighboringWiFiDiagnostic", fetch_neighboring_wifi_diagnostic, "async",
|
||||
|
|
|
|||
|
|
@ -34,6 +34,9 @@ struct file_server {
|
|||
char *url;
|
||||
char *user;
|
||||
char *pass;
|
||||
char *file_size;
|
||||
char *checksum_algorithm;
|
||||
char *checksum;
|
||||
};
|
||||
|
||||
struct neighboring_wiFi_diagnostic {
|
||||
|
|
|
|||
|
|
@ -88,10 +88,19 @@ static int __dm_ubus_call(const char *obj, const char *method, const struct ubus
|
|||
|
||||
blob_buf_init(&b, 0);
|
||||
for (i = 0; i < u_args_size; i++) {
|
||||
if (u_args[i].type != Integer)
|
||||
blobmsg_add_string(&b, u_args[i].key, u_args[i].val);
|
||||
else
|
||||
if (u_args[i].type == Integer) {
|
||||
blobmsg_add_u32(&b, u_args[i].key, atoi(u_args[i].val));
|
||||
} else if (u_args[i].type == Boolean) {
|
||||
bool val = false;
|
||||
string_to_bool((char *)u_args[i].val, &val);
|
||||
blobmsg_add_u8(&b, u_args[i].key, val);
|
||||
} else if (u_args[i].type == Table) {
|
||||
json_object *obj = json_tokener_parse(u_args[i].val);
|
||||
blobmsg_add_json_element(&b, u_args[i].key, obj);
|
||||
json_object_put(obj);
|
||||
} else {
|
||||
blobmsg_add_string(&b, u_args[i].key, u_args[i].val);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ubus_lookup_id(ubus_ctx, obj, &id))
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@
|
|||
enum ubus_arg_type {
|
||||
String,
|
||||
Integer,
|
||||
Boolean,
|
||||
Table
|
||||
};
|
||||
|
||||
struct ubus_arg {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue