mirror of
https://dev.iopsys.eu/bbf/icwmp.git
synced 2025-12-10 07:44:41 +01:00
366 lines
8.4 KiB
C
366 lines
8.4 KiB
C
/*
|
|
* cwmp.c - icwmp Main file
|
|
*
|
|
* Copyright (C) 2021-2022, IOPSYS Software Solutions AB.
|
|
*
|
|
* Author Mohamed Kallel <mohamed.kallel@pivasoftware.com>
|
|
* Author Ahmed Zribi <ahmed.zribi@pivasoftware.com>
|
|
* Author Omar Kallel <omar.kallel@pivasoftware.com>
|
|
*
|
|
* See LICENSE file for license related information.
|
|
*
|
|
*/
|
|
|
|
#include <math.h>
|
|
#include <stdlib.h>
|
|
#include <fcntl.h>
|
|
#include <syslog.h>
|
|
#include <sys/file.h>
|
|
#include <sys/socket.h>
|
|
|
|
#include "common.h"
|
|
#include "ssl_utils.h"
|
|
#include "xml.h"
|
|
#include "notifications.h"
|
|
#include "event.h"
|
|
#include "uci_utils.h"
|
|
#include "log.h"
|
|
#include "session.h"
|
|
#include "diagnostic.h"
|
|
#include "http.h"
|
|
#include "rpc.h"
|
|
#include "config.h"
|
|
#include "backupSession.h"
|
|
#include "ubus_utils.h"
|
|
#include "digauth.h"
|
|
#include "upload.h"
|
|
#include "download.h"
|
|
#include "sched_inform.h"
|
|
#include "datamodel_interface.h"
|
|
#include "cwmp_du_state.h"
|
|
#include "heartbeat.h"
|
|
#include "cwmp_http.h"
|
|
|
|
struct list_head intf_reset_list;
|
|
struct list_head du_uuid_list;
|
|
struct list_head force_inform_list;
|
|
|
|
static bool interface_reset_req(char *param_name, char *value)
|
|
{
|
|
if (param_name == NULL || value == NULL)
|
|
return false;
|
|
|
|
char reg_exp[100] = {0};
|
|
snprintf(reg_exp, sizeof(reg_exp), "^(%s|%s)[0-9]+\\.Reset$", DM_IP_INTERFACE_PATH, DM_PPP_INTERFACE_PATH);
|
|
|
|
if (match_reg_exp(reg_exp, param_name) == false)
|
|
return false;
|
|
|
|
if (CWMP_STRCMP(value, "1") != 0 && CWMP_STRCMP(value, "true") != 0)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void set_interface_reset_request(char *param_name, char *value)
|
|
{
|
|
char *inst_path = NULL;
|
|
|
|
if (param_name == NULL || value == NULL)
|
|
return;
|
|
|
|
if (CWMP_OK != instantiate_param_name(param_name, &inst_path))
|
|
return;
|
|
|
|
if (!CWMP_STRLEN(inst_path))
|
|
return;
|
|
|
|
if (interface_reset_req(inst_path, value) == false) {
|
|
FREE(inst_path);
|
|
return;
|
|
}
|
|
|
|
// Store the interface path to handle after session end
|
|
int len = 0;
|
|
char *pos = strrchr(inst_path, '.');
|
|
if (pos == NULL) {
|
|
FREE(inst_path);
|
|
return;
|
|
}
|
|
|
|
len = pos - inst_path + 2;
|
|
if (len <= 0) {
|
|
FREE(inst_path);
|
|
return;
|
|
}
|
|
|
|
intf_reset_node *node = (intf_reset_node *)malloc(sizeof(intf_reset_node));
|
|
if (node == NULL) {
|
|
CWMP_LOG(ERROR, "Out of memory");
|
|
FREE(inst_path);
|
|
return;
|
|
}
|
|
|
|
CWMP_MEMSET(node, 0, sizeof(intf_reset_node));
|
|
snprintf(node->path, len, "%s", inst_path);
|
|
INIT_LIST_HEAD(&node->list);
|
|
list_add_tail(&node->list, &intf_reset_list);
|
|
FREE(inst_path);
|
|
}
|
|
|
|
static int create_cwmp_temporary_files(void)
|
|
{
|
|
if (!file_exists(VARSTATE_CONFIG"/icwmp")) {
|
|
creat(VARSTATE_CONFIG"/icwmp", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
|
}
|
|
|
|
set_uci_path_value(VARSTATE_CONFIG, "icwmp.acs", "acs");
|
|
set_uci_path_value(VARSTATE_CONFIG, "icwmp.cpe", "cpe");
|
|
|
|
if (!file_exists(CWMP_NOTIFICATIONS_PACKAGE)) {
|
|
creat(CWMP_NOTIFICATIONS_PACKAGE, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
|
}
|
|
|
|
set_uci_path_value("/etc/icwmpd", "cwmp_notifications.notifications", "notifications");
|
|
|
|
if (!folder_exists("/var/run/icwmpd")) {
|
|
if (mkdir("/var/run/icwmpd", S_IRWXU | S_IRWXG | S_IRWXO) == -1) {
|
|
CWMP_LOG(INFO, "Not able to create the folder /var/run/icwmpd");
|
|
return CWMP_GEN_ERR;
|
|
}
|
|
}
|
|
|
|
return CWMP_OK;
|
|
}
|
|
|
|
static void wait_for_time_sync(void)
|
|
{
|
|
struct cwmp_dm_parameter cwmp_dm_param = {0};
|
|
|
|
int loop_count = (cwmp_ctx.conf.clock_sync_timeout / 2);
|
|
|
|
if (loop_count == 0) {
|
|
CWMP_LOG(INFO, "Wait for time sync is disabled, cwmp.cpe.clock_sync_timeout=%d", cwmp_ctx.conf.clock_sync_timeout);
|
|
return;
|
|
}
|
|
|
|
while (loop_count) {
|
|
memset(&cwmp_dm_param, 0, sizeof(struct cwmp_dm_parameter));
|
|
|
|
if (!cwmp_get_parameter_value("Device.Time.Status", &cwmp_dm_param)) {
|
|
CWMP_LOG(ERROR, "Failed to get Device.Time.Status ...");
|
|
return;
|
|
}
|
|
|
|
if (CWMP_STRCMP(cwmp_dm_param.value, "Disabled") == 0) {
|
|
CWMP_LOG(INFO, "Time.Status is Disabled, no need to wait");
|
|
return;
|
|
}
|
|
|
|
if (CWMP_STRCMP(cwmp_dm_param.value, "Synchronized") != 0) {
|
|
loop_count--;
|
|
CWMP_LOG(INFO, "Clock status [%s], checking again %d", cwmp_dm_param.value, loop_count);
|
|
sleep(2);
|
|
continue;
|
|
}
|
|
|
|
CWMP_LOG(INFO, "Clock is synchronized, ready to send inform");
|
|
return;
|
|
}
|
|
|
|
CWMP_LOG(ERROR, "Clock not Synchronized in %d sec, last status %s", cwmp_ctx.conf.clock_sync_timeout, cwmp_dm_param.value);
|
|
return;
|
|
}
|
|
|
|
static int cwmp_init(void)
|
|
{
|
|
openlog("cwmp", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
|
|
|
|
cwmp_ctx.curr_delay_reboot = -1;
|
|
cwmp_ctx.curr_schedule_reboot = 0;
|
|
|
|
get_preinit_config();
|
|
|
|
CWMP_LOG(INFO, "STARTING ICWMP with PID :%d", getpid());
|
|
|
|
/* Only One instance should run*/
|
|
// cppcheck-suppress cert-MSC24-C
|
|
cwmp_ctx.pid_file = fopen("/var/run/icwmpd.pid", "w+");
|
|
fcntl(fileno(cwmp_ctx.pid_file), F_SETFD, fcntl(fileno(cwmp_ctx.pid_file), F_GETFD) | FD_CLOEXEC);
|
|
int rc = flock(fileno(cwmp_ctx.pid_file), LOCK_EX | LOCK_NB);
|
|
if (rc) {
|
|
if (EWOULDBLOCK != errno) {
|
|
const char *piderr = "PID file creation failed: Quit the daemon!";
|
|
fprintf(stderr, "%s\n", piderr);
|
|
CWMP_LOG(ERROR, "%s", piderr);
|
|
exit(EXIT_FAILURE);
|
|
} else
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
|
|
if (cwmp_ctx.pid_file)
|
|
fclose(cwmp_ctx.pid_file);
|
|
|
|
CWMP_LOG(DEBUG, "Loading icwmpd configuration");
|
|
cwmp_config_load();
|
|
CWMP_LOG(DEBUG, "Successfully load icwmpd configuration");
|
|
|
|
wait_for_time_sync();
|
|
|
|
cwmp_ctx.prev_periodic_enable = cwmp_ctx.conf.periodic_enable;
|
|
cwmp_ctx.prev_periodic_interval = cwmp_ctx.conf.period;
|
|
cwmp_ctx.prev_periodic_time = cwmp_ctx.conf.time;
|
|
cwmp_ctx.prev_heartbeat_enable = cwmp_ctx.conf.heart_beat_enable;
|
|
cwmp_ctx.prev_heartbeat_interval = cwmp_ctx.conf.heartbeat_interval;
|
|
cwmp_ctx.prev_heartbeat_time = cwmp_ctx.conf.heart_time;
|
|
|
|
if (cwmp_stop == true)
|
|
return CWMP_GEN_ERR;
|
|
|
|
cwmp_get_deviceid();
|
|
|
|
/* Load default force inform parameters */
|
|
CWMP_MEMSET(&force_inform_list, 0, sizeof(struct list_head));
|
|
INIT_LIST_HEAD(&force_inform_list);
|
|
load_default_forced_inform();
|
|
|
|
/* Load custom notify and force inform parameters */
|
|
load_forced_inform_json();
|
|
load_custom_notify_json();
|
|
set_default_forced_active_parameters_notifications();
|
|
init_list_param_notify();
|
|
|
|
create_cwmp_session_structure();
|
|
get_nonce_key();
|
|
|
|
CWMP_MEMSET(&intf_reset_list, 0, sizeof(struct list_head));
|
|
INIT_LIST_HEAD(&intf_reset_list);
|
|
|
|
CWMP_MEMSET(&du_uuid_list, 0, sizeof(struct list_head));
|
|
INIT_LIST_HEAD(&du_uuid_list);
|
|
|
|
cwmp_ctx.start_time = time(NULL);
|
|
|
|
return CWMP_OK;
|
|
}
|
|
|
|
static void cwmp_free()
|
|
{
|
|
http_server_stop();
|
|
FREE(nonce_key);
|
|
clean_list_param_notify();
|
|
bkp_tree_clean();
|
|
icwmp_uloop_ubus_exit();
|
|
icwmp_cleanmem();
|
|
rpc_exit();
|
|
clean_cwmp_session_structure();
|
|
icwmp_free_critical_services();
|
|
CWMP_LOG(INFO, "EXIT ICWMP");
|
|
closelog();
|
|
}
|
|
|
|
void cwmp_exit()
|
|
{
|
|
cwmp_stop = true;
|
|
|
|
if (cwmp_ctx.session->session_status.last_status == SESSION_RUNNING)
|
|
http_set_timeout();
|
|
|
|
uloop_timeout_cancel(&retry_session_timer);
|
|
uloop_timeout_cancel(&periodic_session_timer);
|
|
uloop_timeout_cancel(&session_timer);
|
|
uloop_timeout_cancel(&heartbeat_session_timer);
|
|
clean_autonomous_complpolicy();
|
|
clean_interface_update();
|
|
#ifdef ICWMP_ENABLE_SMM_SUPPORT
|
|
clean_du_uuid_list();
|
|
#endif
|
|
clean_force_inform_list();
|
|
FREE(cwmp_ctx.ev);
|
|
FREE(cwmp_ctx.intf_ev);
|
|
uloop_end();
|
|
shutdown(cwmp_ctx.cr_socket_desc, SHUT_RDWR);
|
|
FREE(global_session_event);
|
|
|
|
/* Free all memory allocation */
|
|
cwmp_free();
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int error = 0;
|
|
|
|
CWMP_MEMSET(&cwmp_ctx, 0, sizeof(struct cwmp));
|
|
|
|
error = icwmp_connect_ubus();
|
|
if (error)
|
|
return error;
|
|
|
|
error = wait_for_bbf_object();
|
|
if (error) {
|
|
icwmp_free_ubus();
|
|
return error;
|
|
}
|
|
|
|
if ((error = global_env_init(argc, argv, &(cwmp_ctx.env)))) {
|
|
icwmp_free_ubus();
|
|
return error;
|
|
}
|
|
|
|
if ((error = create_cwmp_temporary_files())) {
|
|
icwmp_free_ubus();
|
|
return error;
|
|
}
|
|
|
|
if ((error = cwmp_init())) {
|
|
icwmp_free_ubus();
|
|
return error;
|
|
}
|
|
|
|
if ((error = cwmp_init_backup_session(NULL, ALL))) {
|
|
icwmp_free_ubus();
|
|
return error;
|
|
}
|
|
|
|
if ((error = cwmp_root_cause_events())) {
|
|
icwmp_free_ubus();
|
|
return error;
|
|
}
|
|
|
|
icwmp_http_server_init();
|
|
|
|
uloop_init();
|
|
|
|
if ((error = icwmp_uloop_ubus_register())) {
|
|
icwmp_free_ubus();
|
|
return error;
|
|
}
|
|
|
|
if ((error = initiate_autonomous_complpolicy())) {
|
|
icwmp_uloop_ubus_exit();
|
|
return error;
|
|
}
|
|
|
|
if ((error = initiate_interface_update())) {
|
|
icwmp_uloop_ubus_exit();
|
|
return error;
|
|
}
|
|
|
|
trigger_cwmp_session_timer();
|
|
|
|
intiate_heartbeat_procedures();
|
|
|
|
initiate_cwmp_periodic_session_feature();
|
|
|
|
http_server_start();
|
|
|
|
apply_allowed_cr_ip_port();
|
|
cwmp_ctx.cr_ip_port_change = false;
|
|
|
|
uloop_run();
|
|
uloop_done();
|
|
|
|
cwmp_exit();
|
|
|
|
return CWMP_OK;
|
|
}
|