/* * event.c: event handler * * Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved. * * Author: Iryna Antsyferova <iryna.antsyferova@iopsys.eu> * * See LICENSE file for license related information. */ #include "libdmtree/dmcommon.h" #include "event.h" #include <unistd.h> #include <netinet/in.h> #define FIREWALL_RULE_DATA_SIP "Device.Services.VoiceService.1.SIP.Network.1.X_RDK_Firewall_Rule_Data" #define FIREWALL_RULE_DATA_SIP_PATTERN "Device\\.Services\\.VoiceService\\.[0-9]+\\.SIP\\.Network\\.[0-9]+\\.X_RDK_Firewall_Rule_Data" #define FIREWALL_RULE_DATA_RTP "Device.Services.VoiceService.1.VoIPProfile.1.RTP.X_RDK_Firewall_Rule_Data" #define FIREWALL_RULE_DATA_RTP_PATTERN "Device\\.Services\\.VoiceService\\.[0-9]+\\.VoIPProfile\\.[0-9]+\\.RTP\\.X_RDK_Firewall_Rule_Data" // 4 IPv6 rules max #define FIREWALL_RULE_STR_LEN_MAX 218 struct rule_node { struct list_head list; char ip[INET6_ADDRSTRLEN]; uint16_t port; }; static struct list_head sip_list, rtp_list; int subs_event_init() { INIT_LIST_HEAD(&sip_list); INIT_LIST_HEAD(&rtp_list); return 0; } void subs_event_uninit() { struct rule_node *iter = NULL, *node = NULL; list_for_each_entry_safe(iter, node, &sip_list, list) { list_del(&iter->list); free(iter); } list_for_each_entry_safe(iter, node, &rtp_list, list) { list_del(&iter->list); free(iter); } } int subs_event_handler(const json_object *jmsg, int param_count, json_object *jreply) { int ret = RETURN_OK; int param_index = 0; hal_subscribe_event_request_t param_request; if (jmsg == NULL || jreply == NULL) { ERR("event handler: Invalid memory"); return RETURN_ERR; } memset(¶m_request, 0, sizeof(param_request)); for (param_index = 0; param_index < param_count; param_index++) { /* Unpack the request parameter */ if (json_hal_get_subscribe_event_request((json_object *)jmsg, param_index, ¶m_request) != RETURN_OK) { INFO("Failed to get subscription data from the server"); return RETURN_ERR; } if (!match(param_request.name, FIREWALL_RULE_DATA_SIP_PATTERN, 0, NULL) && !match(param_request.name, FIREWALL_RULE_DATA_RTP_PATTERN, 0, NULL)) { ret = RETURN_ERR; WARNING("Unexpected event [%s][%d]", param_request.name, (int)param_request.type); } else INFO("Subscribed [%s][%d]", param_request.name, (int)param_request.type); } ret = json_hal_add_result_status(jreply, ret == RETURN_OK ? RESULT_SUCCESS : RESULT_FAILURE); INFO("[%s] Replly msg = %s", __FUNCTION__, json_object_to_json_string_ext(jreply, JSON_C_TO_STRING_PRETTY)); return ret; } static int update_fw_rule_list(bool enable, char *ip, int port, struct list_head *rule_list, bool *changed) { struct rule_node *node = NULL; bool found = false; *changed = false; list_for_each_entry(node, rule_list, list) { if (DM_STRNCMP(node->ip, ip, sizeof(node->ip)) == 0 && node->port == port) { found = true; break; } } if (enable == found) { return 0; } if (!enable && found) { list_del(&node->list); free(node); } if (enable && !found) { node = malloc(sizeof(struct rule_node)); if (!node) { ERR("failed to allocate memory"); return -1; } DM_STRNCPY(node->ip, ip, sizeof(node->ip)); node->port = port; INIT_LIST_HEAD(&node->list); list_add_tail(&node->list, rule_list); } *changed = true; return 0; } /* Expected format of rule : ip,port; Example: 192.168.0.11,5060;192.168.0.12,5060; */ static int create_fw_rule_payload(struct list_head *rule_list, char *buf, int buf_size) { struct rule_node *node = NULL; char *pos = buf, *end = buf + buf_size; list_for_each_entry(node, rule_list, list) { if (pos < end) { pos += snprintf(pos, end - pos, "%s,%d;", node->ip, node->port); } } if (pos == end) { ERR("fw rule string overflow"); return -1; } return 0; } static int pub_fw_rule_event(bool enable, char *ip, int port, struct list_head *rule_list, const char *param_name) { int ret; bool changed = false; char buf[FIREWALL_RULE_STR_LEN_MAX] = {0}; ret = update_fw_rule_list(enable, ip, port, rule_list, &changed); if (ret) { ERR("failed to create fw rule list"); return -1; } if (!changed) { return 0; } ret = create_fw_rule_payload(rule_list, buf, sizeof(buf)); if (ret) { ERR("failed to create fw rule"); return -1; } ret = json_hal_server_publish_event(param_name, buf); if (ret != RETURN_OK) { ERR("failed to send fw event"); return -1; } return 0; } int send_fw_rule_event(bool enable, char *protocol, char *ip, int port) { if (DM_STRCMP(protocol, "sip") == 0) { return pub_fw_rule_event(enable, ip, port, &sip_list, FIREWALL_RULE_DATA_SIP); } if (DM_STRCMP(protocol, "rtp") == 0) { return pub_fw_rule_event(enable, ip, port, &rtp_list, FIREWALL_RULE_DATA_RTP); } DEBUG("wrong protocol: %s", protocol); return -1; } int send_fw_rules_clear_event() { int ret = 0; char fw_rule[] = {0}; struct rule_node *iter, *node; ret = json_hal_server_publish_event(FIREWALL_RULE_DATA_SIP, fw_rule); if (ret != RETURN_OK) { ERR("failed to send fw sip event"); return -1; } ret = json_hal_server_publish_event(FIREWALL_RULE_DATA_RTP, fw_rule); if (ret != RETURN_OK) { ERR("failed to send fw rtp event"); return -1; } list_for_each_entry_safe(iter, node, &sip_list, list) { list_del(&iter->list); free(iter); } list_for_each_entry_safe(iter, node, &rtp_list, list) { list_del(&iter->list); free(iter); } return 0; }