From a6ff41640187a218e3bd2d27df0c660ebde36595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Walstr=C3=B6m?= Date: Wed, 7 Feb 2024 18:23:49 +0100 Subject: [PATCH] confd: Add support for ietf-hardware Add supports to enable disable USB port --- src/confd/src/Makefile.am | 3 +- src/confd/src/core.c | 3 + src/confd/src/core.h | 3 + src/confd/src/ietf-hardware.c | 261 ++++++++++++++++++++++++++++++++++ 4 files changed, 269 insertions(+), 1 deletion(-) create mode 100644 src/confd/src/ietf-hardware.c diff --git a/src/confd/src/Makefile.am b/src/confd/src/Makefile.am index c11ccf51..cdf8a986 100644 --- a/src/confd/src/Makefile.am +++ b/src/confd/src/Makefile.am @@ -33,7 +33,8 @@ confd_plugin_la_SOURCES = \ infix-dhcp.c \ infix-services.c \ infix-factory.c \ - infix-system-software.c + infix-system-software.c \ + ietf-hardware.c rauc_installer_sources = \ rauc-installer.c rauc-installer.h diff --git a/src/confd/src/core.c b/src/confd/src/core.c index a9a6bbbf..68c05d5b 100644 --- a/src/confd/src/core.c +++ b/src/confd/src/core.c @@ -126,6 +126,9 @@ int sr_plugin_init_cb(sr_session_ctx_t *session, void **priv) if (rc) goto err; rc = infix_services_init(&confd); + if (rc) + goto err; + rc = ietf_hardware_init(&confd); if (rc) goto err; diff --git a/src/confd/src/core.h b/src/confd/src/core.h index d866aa52..f6d5a44e 100644 --- a/src/confd/src/core.h +++ b/src/confd/src/core.h @@ -147,4 +147,7 @@ int infix_system_sw_init(struct confd *confd); /* infix-services.c */ int infix_services_init(struct confd *confd); +/* ietf-hardware.c */ +int ietf_hardware_init(struct confd *confd); + #endif /* CONFD_CORE_H_ */ diff --git a/src/confd/src/ietf-hardware.c b/src/confd/src/ietf-hardware.c new file mode 100644 index 00000000..42c05ec2 --- /dev/null +++ b/src/confd/src/ietf-hardware.c @@ -0,0 +1,261 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "core.h" + +#define XPATH_BASE_ "/ietf-hardware:hardware" + +static int dir_cb(const char *fpath, const struct stat *sb, + int typeflag, struct FTW *ftwbuf) +{ + char *filename; + if (typeflag == FTW_DP) + return 0; + + filename = basename((char *)fpath); + if (!strcmp(filename, "authorized_default") || !strcmp(filename, "authorized")) { + if (writedf(1, "w", "%s", fpath)) { + ERROR("Failed to authorize %s", fpath); + return FTW_STOP; + } + } + return 0; +} + +static bool usb_authorize(struct json_t *root, const char *name, int enabled) +{ + json_t *usb_port, *usb_ports; + int index; + + usb_ports = json_object_get(root, "usb-ports"); + if (!usb_ports) /* No Infix controlled USB ports is ok */ + return 0; + + json_array_foreach(usb_ports, index, usb_port) { + struct json_t *jname, *jpath; + const char *path; + jname = json_object_get(usb_port, "name"); + if (!jname || !json_is_string(jname)) { + ERROR("Did not find USB hardware port (name) for %s", name); + continue; + } + if (!strcmp(name, json_string_value(jname))) { + jpath = json_object_get(usb_port, "path"); + if (!jpath || !json_is_string(jpath)) { + ERROR("Did not find USB hardware port (path) for %s", name); + continue; + } + path = json_string_value(jpath); + if (!enabled) { + if (fexist(path)) { + if (writedf(0, "w", "%s", path)) { + ERROR("Failed to unauthorize %s", path); + return 1; + } + } + } else { + char *rpath, *path_dup, *dir; + path_dup = strdup(path); + if (!path_dup) { + ERROR("Failed to allocate memory."); + return 1; + } + dir = dirname((char *)path_dup); + rpath = realpath(dir, NULL); + if (rpath) { + nftw(rpath, dir_cb, 0, FTW_DEPTH | FTW_PHYS); + free(rpath); + } + free(path_dup); + } + } + } + return 0; +} + +static char *component_xpath(const char *xpath) +{ + char *path, *ptr; + + if (!xpath) + return NULL; + + path = strdup(xpath); + if (!path) + return NULL; + + if (!(ptr = strstr(path, "]/"))) { + free(path); + return NULL; + } + ptr[1] = 0; + + return path; +} + +static int hardware_cand_infer_class(json_t *root, sr_session_ctx_t *session, const char *path) +{ + sr_val_t inferred = { .type = SR_STRING_T }; + struct json_t *usb_ports, *usb_port; + sr_error_t err = SR_ERR_OK; + char *name, *class; + char *xpath; + int index; + + xpath = component_xpath(path); + if (!xpath) + return SR_ERR_SYS; + + class = srx_get_str(session, "%s/class", xpath); + if (class) { + free(class); + goto out_free_xpath; + } + + name = srx_get_str(session, "%s/name", xpath); + if (!name) { + err = SR_ERR_INTERNAL; + goto out_free_xpath; + } + usb_ports = json_object_get(root, "usb-ports"); + if (!usb_ports) + goto out_free_name; /* No USB-ports is OK */ + + json_array_foreach(usb_ports, index, usb_port) { + struct json_t *n = json_object_get(usb_port, "name"); + if (!n || !json_is_string(n)) { + ERROR("Did not find hardware port for %s", name); + continue; + } + if (!strcmp(name, json_string_value(n))) { + inferred.data.string_val = "infix-hardware:usb"; + err = srx_set_item(session, &inferred, 0, + "%s/class", xpath); + break; + } + } +out_free_name: + free(name); +out_free_xpath: + free(xpath); + return err; +} +static int hardware_cand(sr_session_ctx_t *session, uint32_t sub_id, const char *module, + const char *xpath, sr_event_t event, unsigned request_id, void *priv) +{ + sr_change_iter_t *iter; + sr_change_oper_t op; + sr_val_t *old, *new; + sr_error_t err = SR_ERR_OK; + struct confd *confd = (struct confd *)priv; + + switch (event) { + case SR_EV_UPDATE: + case SR_EV_CHANGE: + break; + default: + return SR_ERR_OK; + } + err = sr_dup_changes_iter(session, "/ietf-hardware:hardware/component//*", &iter); + if (err) + return err; + while (sr_get_change_next(session, iter, &op, &old, &new) == SR_ERR_OK) { + switch (op) { + case SR_OP_CREATED: + case SR_OP_MODIFIED: + break; + default: + continue; + } + err = hardware_cand_infer_class(confd->root, session, new->xpath); + if (err) + break; + } + sr_free_change_iter(iter); + return err; +} + +static int change_hardware(sr_session_ctx_t *session, uint32_t sub_id, const char *module, + const char *xpath, sr_event_t event, unsigned request_id, void *priv) +{ + struct lyd_node *diff, *difs = NULL, *dif = NULL, *cifs = NULL, *cif = NULL; + sr_data_t *cfg; + int rc = SR_ERR_OK; + struct confd *confd = (struct confd *)priv; + + if (event != SR_EV_DONE) + return SR_ERR_OK; + + rc = sr_get_data(session, XPATH_BASE_ "//.", 0, 0, 0, &cfg); + if (rc) + goto err; + + rc = srx_get_diff(session, &diff); + if (rc) + goto err_release_data; + + cifs = lydx_get_descendant(cfg->tree, "hardware", "component", NULL); + difs = lydx_get_descendant(diff, "hardware", "component", NULL); + + LYX_LIST_FOR_EACH(difs, dif, "component") { + enum lydx_op op; + struct lyd_node *state; + const char *admin_state; + const char *class, *name; + + op = lydx_get_op(dif); + name = lydx_get_cattr(dif, "name"); + if (op == LYDX_OP_DELETE) { + if (usb_authorize(confd->root, name, 0)) { + rc = SR_ERR_INTERNAL; + goto err_release_diff; + } + continue; + } + + LYX_LIST_FOR_EACH(cifs, cif, "component") { + if (strcmp(name, lydx_get_cattr(cif, "name"))) + continue; + + class = lydx_get_cattr(cif, "class"); + if (strcmp(class, "infix-hardware:usb")) { + continue; + } + state = lydx_get_child(dif, "state"); + admin_state = lydx_get_cattr(state, "admin-state"); + if (usb_authorize(confd->root, name, !strcmp(admin_state, "unlocked"))) { + rc = SR_ERR_INTERNAL; + goto err_release_diff; + } + } + } + +err_release_diff: + lyd_free_tree(diff); +err_release_data: + sr_release_data(cfg); +err: + return rc; +} +int ietf_hardware_init(struct confd *confd) +{ + int rc = 0; + + REGISTER_CHANGE(confd->session, "ietf-hardware", XPATH_BASE_, 0, change_hardware, confd, &confd->sub); + REGISTER_CHANGE(confd->cand, "ietf-hardware", XPATH_BASE_, + SR_SUBSCR_UPDATE, hardware_cand, confd, &confd->sub); + + return SR_ERR_OK; +fail: + ERROR("Init hardware failed: %s", sr_strerror(rc)); + return rc; +}