diff options
Diffstat (limited to 'src/daemon/client.c')
-rw-r--r-- | src/daemon/client.c | 700 |
1 files changed, 700 insertions, 0 deletions
diff --git a/src/daemon/client.c b/src/daemon/client.c new file mode 100644 index 0000000..d9d907f --- /dev/null +++ b/src/daemon/client.c @@ -0,0 +1,700 @@ +/* -*- mode: c; c-file-style: "openbsd" -*- */ +/* + * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "lldpd.h" +#include "trace.h" + +#include <sys/utsname.h> + +static ssize_t +client_handle_none(struct lldpd *cfg, enum hmsg_type *type, void *input, int input_len, + void **output, int *subscribed) +{ + log_info("rpc", "received noop request from client"); + *type = NONE; + return 0; +} + +/* Return the global configuration */ +static ssize_t +client_handle_get_configuration(struct lldpd *cfg, enum hmsg_type *type, void *input, + int input_len, void **output, int *subscribed) +{ + ssize_t output_len; + log_debug("rpc", "client requested configuration"); + output_len = lldpd_config_serialize(&cfg->g_config, output); + if (output_len <= 0) { + output_len = 0; + *type = NONE; + } + return output_len; +} + +static char * +xstrdup(const char *str) +{ + if (!str) return NULL; + return strdup(str); +} + +/* Change the global configuration */ +static ssize_t +client_handle_set_configuration(struct lldpd *cfg, enum hmsg_type *type, void *input, + int input_len, void **output, int *subscribed) +{ + struct lldpd_config *config; + + log_debug("rpc", "client request a change in configuration"); + /* Get the proposed configuration. */ + if (lldpd_config_unserialize(input, input_len, &config) <= 0) { + *type = NONE; + return 0; + } + +#define CHANGED(w) (config->w != cfg->g_config.w) +#define CHANGED_STR(w) \ + (!(config->w == cfg->g_config.w || \ + (config->w && cfg->g_config.w && !strcmp(config->w, cfg->g_config.w)))) + + /* What needs to be done? Transmit delay? */ + if (CHANGED(c_tx_interval) && config->c_tx_interval != 0) { + if (config->c_tx_interval < 0) { + log_debug("rpc", "client asked for immediate retransmission"); + } else { + log_debug("rpc", "client change transmit interval to %d ms", + config->c_tx_interval); + cfg->g_config.c_tx_interval = config->c_tx_interval; + cfg->g_config.c_ttl = + cfg->g_config.c_tx_interval * cfg->g_config.c_tx_hold; + cfg->g_config.c_ttl = (cfg->g_config.c_ttl + 999) / 1000; + } + levent_send_now(cfg); + } + if (CHANGED(c_tx_hold) && config->c_tx_hold > 0) { + log_debug("rpc", "client change transmit hold to %d", + config->c_tx_hold); + cfg->g_config.c_tx_hold = config->c_tx_hold; + cfg->g_config.c_ttl = + cfg->g_config.c_tx_interval * cfg->g_config.c_tx_hold; + cfg->g_config.c_ttl = (cfg->g_config.c_ttl + 999) / 1000; + } + if (CHANGED(c_max_neighbors) && config->c_max_neighbors > 0) { + log_debug("rpc", "client change maximum neighbors to %d", + config->c_max_neighbors); + cfg->g_config.c_max_neighbors = config->c_max_neighbors; + } + if (CHANGED(c_lldp_portid_type) && + config->c_lldp_portid_type > LLDP_PORTID_SUBTYPE_UNKNOWN && + config->c_lldp_portid_type <= LLDP_PORTID_SUBTYPE_MAX) { + log_debug("rpc", "change lldp portid tlv subtype to %d", + config->c_lldp_portid_type); + cfg->g_config.c_lldp_portid_type = config->c_lldp_portid_type; + levent_update_now(cfg); + } + if (CHANGED(c_lldp_agent_type) && + config->c_lldp_agent_type > LLDP_AGENT_TYPE_UNKNOWN && + config->c_lldp_agent_type <= LLDP_AGENT_TYPE_MAX) { + log_debug("rpc", "change lldp agent type to %d", + config->c_lldp_agent_type); + cfg->g_config.c_lldp_agent_type = config->c_lldp_agent_type; + levent_update_now(cfg); + } + /* Pause/resume */ + if (CHANGED(c_paused)) { + log_debug("rpc", "client asked to %s lldpd", + config->c_paused ? "pause" : "resume"); + cfg->g_config.c_paused = config->c_paused; + levent_send_now(cfg); + } + +#ifdef ENABLE_LLDPMED + if (CHANGED(c_enable_fast_start)) { + cfg->g_config.c_enable_fast_start = config->c_enable_fast_start; + log_debug("rpc", "client asked to %s fast start", + cfg->g_config.c_enable_fast_start ? "enable" : "disable"); + } + if (CHANGED(c_tx_fast_interval) && config->c_tx_fast_interval > 0) { + log_debug("rpc", "change fast interval to %d", + config->c_tx_fast_interval); + cfg->g_config.c_tx_fast_interval = config->c_tx_fast_interval; + } +#endif + if (CHANGED_STR(c_iface_pattern)) { + log_debug("rpc", "change interface pattern to %s", + config->c_iface_pattern ? config->c_iface_pattern : "(NULL)"); + free(cfg->g_config.c_iface_pattern); + cfg->g_config.c_iface_pattern = xstrdup(config->c_iface_pattern); + levent_update_now(cfg); + } + if (CHANGED_STR(c_perm_ifaces)) { + log_debug("rpc", "change permanent interface pattern to %s", + config->c_perm_ifaces ? config->c_perm_ifaces : "(NULL)"); + free(cfg->g_config.c_perm_ifaces); + cfg->g_config.c_perm_ifaces = xstrdup(config->c_perm_ifaces); + levent_update_now(cfg); + } + if (CHANGED_STR(c_mgmt_pattern)) { + log_debug("rpc", "change management pattern to %s", + config->c_mgmt_pattern ? config->c_mgmt_pattern : "(NULL)"); + free(cfg->g_config.c_mgmt_pattern); + cfg->g_config.c_mgmt_pattern = xstrdup(config->c_mgmt_pattern); + levent_update_now(cfg); + } + if (CHANGED_STR(c_cid_string)) { + log_debug("rpc", "change chassis ID string to %s", + config->c_cid_string ? config->c_cid_string : "(NULL)"); + free(cfg->g_config.c_cid_string); + cfg->g_config.c_cid_string = xstrdup(config->c_cid_string); + free(LOCAL_CHASSIS(cfg)->c_id); + LOCAL_CHASSIS(cfg)->c_id = NULL; + lldpd_update_localchassis(cfg); + levent_update_now(cfg); + } + if (CHANGED_STR(c_description)) { + log_debug("rpc", "change chassis description to %s", + config->c_description ? config->c_description : "(NULL)"); + free(cfg->g_config.c_description); + cfg->g_config.c_description = xstrdup(config->c_description); + lldpd_update_localchassis(cfg); + levent_update_now(cfg); + } + if (CHANGED_STR(c_platform)) { + log_debug("rpc", "change platform description to %s", + config->c_platform ? config->c_platform : "(NULL)"); + free(cfg->g_config.c_platform); + cfg->g_config.c_platform = xstrdup(config->c_platform); + lldpd_update_localchassis(cfg); + levent_update_now(cfg); + } + if (CHANGED_STR(c_hostname)) { + log_debug("rpc", "change system name to %s", + config->c_hostname ? config->c_hostname : "(NULL)"); + free(cfg->g_config.c_hostname); + cfg->g_config.c_hostname = xstrdup(config->c_hostname); + lldpd_update_localchassis(cfg); + levent_update_now(cfg); + } + if (CHANGED(c_set_ifdescr)) { + log_debug("rpc", + "%s setting of interface description based on discovered neighbors", + config->c_set_ifdescr ? "enable" : "disable"); + cfg->g_config.c_set_ifdescr = config->c_set_ifdescr; + levent_update_now(cfg); + } + if (CHANGED(c_promisc)) { + log_debug("rpc", "%s promiscuous mode on managed interfaces", + config->c_promisc ? "enable" : "disable"); + cfg->g_config.c_promisc = config->c_promisc; + levent_update_now(cfg); + } + if (CHANGED(c_cap_advertise)) { + log_debug("rpc", "%s chassis capabilities advertisement", + config->c_cap_advertise ? "enable" : "disable"); + cfg->g_config.c_cap_advertise = config->c_cap_advertise; + levent_update_now(cfg); + } + if (CHANGED(c_cap_override)) { + log_debug("rpc", "%s chassis capabilities override", + config->c_cap_override ? "enable" : "disable"); + cfg->g_config.c_cap_override = config->c_cap_override; + levent_update_now(cfg); + } + if (CHANGED(c_mgmt_advertise)) { + log_debug("rpc", "%s management addresses advertisement", + config->c_mgmt_advertise ? "enable" : "disable"); + cfg->g_config.c_mgmt_advertise = config->c_mgmt_advertise; + levent_update_now(cfg); + } + if (CHANGED(c_bond_slave_src_mac_type)) { + if (config->c_bond_slave_src_mac_type > + LLDP_BOND_SLAVE_SRC_MAC_TYPE_UNKNOWN && + config->c_bond_slave_src_mac_type <= + LLDP_BOND_SLAVE_SRC_MAC_TYPE_MAX) { + log_debug("rpc", "change bond src mac type to %d", + config->c_bond_slave_src_mac_type); + cfg->g_config.c_bond_slave_src_mac_type = + config->c_bond_slave_src_mac_type; + } else { + log_info("rpc", "Invalid bond slave src mac type: %d\n", + config->c_bond_slave_src_mac_type); + } + } + + lldpd_config_cleanup(config); + free(config); + + return 0; +} + +/* Return the list of interfaces. + Input: nothing. + Output: list of interface names (lldpd_interface_list) +*/ +static ssize_t +client_handle_get_interfaces(struct lldpd *cfg, enum hmsg_type *type, void *input, + int input_len, void **output, int *subscribed) +{ + struct lldpd_interface *iff, *iff_next; + struct lldpd_hardware *hardware; + ssize_t output_len; + + /* Build the list of interfaces */ + struct lldpd_interface_list ifs; + + log_debug("rpc", "client request the list of interfaces"); + TAILQ_INIT(&ifs); + TAILQ_FOREACH (hardware, &cfg->g_hardware, h_entries) { + if ((iff = (struct lldpd_interface *)malloc( + sizeof(struct lldpd_interface))) == NULL) + fatal("rpc", NULL); + iff->name = hardware->h_ifname; + TAILQ_INSERT_TAIL(&ifs, iff, next); + } + + output_len = lldpd_interface_list_serialize(&ifs, output); + if (output_len <= 0) { + output_len = 0; + *type = NONE; + } + + /* Free the temporary list */ + for (iff = TAILQ_FIRST(&ifs); iff != NULL; iff = iff_next) { + iff_next = TAILQ_NEXT(iff, next); + TAILQ_REMOVE(&ifs, iff, next); + free(iff); + } + + return output_len; +} + +/** + * Set local chassis info + * Input: chassis object + * Output: updated chassis object + */ +static ssize_t +client_handle_set_local_chassis(struct lldpd *cfg, enum hmsg_type *type, void *input, + int input_len, void **output, int *subscribed) +{ + struct lldpd_chassis *chassis = NULL; + struct lldpd_chassis *local_chassis = NULL; +#ifdef ENABLE_LLDPMED + struct utsname un; +#endif + + log_debug("rpc", "client request a change in chassis configuration"); + if (lldpd_chassis_unserialize(input, input_len, &chassis) <= 0) { + *type = NONE; + return 0; + } + + local_chassis = LOCAL_CHASSIS(cfg); + +#ifdef ENABLE_LLDPMED + free(local_chassis->c_med_hw); + local_chassis->c_med_hw = + (!chassis->c_med_hw) ? dmi_hw() : strdup(chassis->c_med_hw); + + // Follows lldpd.c - only set sw if advertising is enabled + if (cfg->g_config.c_advertise_version) { + free(local_chassis->c_med_sw); + + if (!chassis->c_med_sw) { + if (uname(&un) < 0) { + log_warn("rpc", + "Could not get default uname. Will continue anyway."); + local_chassis->c_med_sw = NULL; + } else { + local_chassis->c_med_sw = strdup(un.release); + } + } else { + local_chassis->c_med_sw = strdup(chassis->c_med_sw); + } + } + + free(local_chassis->c_med_fw); + local_chassis->c_med_fw = + (!chassis->c_med_fw) ? dmi_fw() : strdup(chassis->c_med_fw); + + free(local_chassis->c_med_sn); + local_chassis->c_med_sn = + (!chassis->c_med_sn) ? dmi_sn() : strdup(chassis->c_med_sn); + + free(local_chassis->c_med_manuf); + local_chassis->c_med_manuf = + (!chassis->c_med_manuf) ? dmi_manuf() : strdup(chassis->c_med_manuf); + + free(local_chassis->c_med_model); + local_chassis->c_med_model = + (!chassis->c_med_model) ? dmi_model() : strdup(chassis->c_med_model); + + free(local_chassis->c_med_asset); + local_chassis->c_med_asset = + (!chassis->c_med_asset) ? dmi_asset() : strdup(chassis->c_med_asset); +#endif + + if (chassis->c_cap_enabled != local_chassis->c_cap_enabled) { + local_chassis->c_cap_enabled = chassis->c_cap_enabled; + log_debug("rpc", "change capabilities enabled to: %d", + local_chassis->c_cap_enabled); + } + +#ifdef ENABLE_LLDPMED + log_debug("rpc", "change hardware-revision to: %s", local_chassis->c_med_hw); + log_debug("rpc", "change software-revision to: %s", local_chassis->c_med_sw); + log_debug("rpc", "change firmware-revision to: %s", local_chassis->c_med_fw); + log_debug("rpc", "change serial-number to: %s", local_chassis->c_med_sn); + log_debug("rpc", "change manufacturer to: %s", local_chassis->c_med_manuf); + log_debug("rpc", "change model to: %s", local_chassis->c_med_model); + log_debug("rpc", "change asset to: %s", local_chassis->c_med_asset); +#endif + + lldpd_chassis_cleanup(chassis, 1); + + ssize_t output_len = lldpd_chassis_serialize(local_chassis, output); + if (output_len <= 0) { + *type = NONE; + return 0; + } + + return output_len; +} + +/* Return the local chassis. + Input: nothing. + Output: local chassis (lldpd_chassis) +*/ +static ssize_t +client_handle_get_local_chassis(struct lldpd *cfg, enum hmsg_type *type, void *input, + int input_len, void **output, int *subscribed) +{ + struct lldpd_chassis *chassis = LOCAL_CHASSIS(cfg); + ssize_t output_len; + + log_debug("rpc", "client request the local chassis"); + output_len = lldpd_chassis_serialize(chassis, output); + if (output_len <= 0) { + output_len = 0; + *type = NONE; + } + + return output_len; +} + +/* Return all available information related to an interface + Input: name of the interface (serialized) + Output: Information about the interface (lldpd_hardware) +*/ +static ssize_t +client_handle_get_interface(struct lldpd *cfg, enum hmsg_type *type, void *input, + int input_len, void **output, int *subscribed) +{ + char *name; + struct lldpd_hardware *hardware; + void *p; + + /* Get name of the interface */ + if (marshal_unserialize(string, input, input_len, &p) <= 0) { + *type = NONE; + return 0; + } + name = p; + + /* Search appropriate hardware */ + log_debug("rpc", "client request interface %s", name); + TAILQ_FOREACH (hardware, &cfg->g_hardware, h_entries) + if (!strcmp(hardware->h_ifname, name)) { + ssize_t output_len = lldpd_hardware_serialize(hardware, output); + free(name); + if (output_len <= 0) { + *type = NONE; + return 0; + } + return output_len; + } + + log_warnx("rpc", "no interface %s found", name); + free(name); + *type = NONE; + return 0; +} + +/* Return all available information related to an interface + Input: name of the interface (serialized) + Output: Information about the interface (lldpd_hardware) +*/ +static ssize_t +client_handle_get_default_port(struct lldpd *cfg, enum hmsg_type *type, void *input, + int input_len, void **output, int *subscribed) +{ + log_debug("rpc", "client request the default local port"); + ssize_t output_len = lldpd_port_serialize(cfg->g_default_local_port, output); + if (output_len <= 0) { + *type = NONE; + return 0; + } + return output_len; +} + +static int +_client_handle_set_port(struct lldpd *cfg, struct lldpd_port *port, + struct lldpd_port_set *set) +{ +#ifdef ENABLE_LLDPMED + struct lldpd_med_loc *loc = NULL; +#endif + if (set->local_id) { + log_debug("rpc", "requested change to Port ID"); + free(port->p_id); + port->p_id = strdup(set->local_id); + port->p_id_len = strlen(set->local_id); + port->p_id_subtype = LLDP_PORTID_SUBTYPE_LOCAL; + port->p_descr_force = 0; + } + if (set->local_descr) { + log_debug("rpc", "requested change to Port Description"); + free(port->p_descr); + port->p_descr = strdup(set->local_descr); + port->p_descr_force = 1; + } + switch (set->rxtx) { + case LLDPD_RXTX_TXONLY: + log_debug("rpc", "requested TX only mode"); + port->p_disable_rx = 1; + port->p_disable_tx = 0; + break; + case LLDPD_RXTX_RXONLY: + log_debug("rpc", "requested RX only mode"); + port->p_disable_rx = 0; + port->p_disable_tx = 1; + break; + case LLDPD_RXTX_BOTH: + log_debug("rpc", "requested RX/TX mode"); + port->p_disable_rx = port->p_disable_tx = 0; + break; + case LLDPD_RXTX_DISABLED: + log_debug("rpc", "requested disabled mode"); + port->p_disable_rx = port->p_disable_tx = 1; + break; + } + if (set->vlan_tx_enabled > -1) { + port->p_vlan_tx_enabled = set->vlan_tx_enabled; + port->p_vlan_tx_tag = set->vlan_tx_tag; + } +#ifdef ENABLE_LLDPMED + if (set->med_policy && set->med_policy->type > 0) { + log_debug("rpc", "requested change to MED policy"); + if (set->med_policy->type > LLDP_MED_APPTYPE_LAST) { + log_warnx("rpc", "invalid policy provided: %d", + set->med_policy->type); + return -1; + } + memcpy(&port->p_med_policy[set->med_policy->type - 1], set->med_policy, + sizeof(struct lldpd_med_policy)); + port->p_med_cap_enabled |= LLDP_MED_CAP_POLICY; + } + if (set->med_location && set->med_location->format > 0) { + char *newdata = NULL; + log_debug("rpc", "requested change to MED location"); + if (set->med_location->format > LLDP_MED_LOCFORMAT_LAST) { + log_warnx("rpc", "invalid location format provided: %d", + set->med_location->format); + return -1; + } + loc = &port->p_med_location[set->med_location->format - 1]; + free(loc->data); + memcpy(loc, set->med_location, sizeof(struct lldpd_med_loc)); + if (!loc->data || !(newdata = malloc(loc->data_len))) loc->data_len = 0; + if (newdata) memcpy(newdata, loc->data, loc->data_len); + loc->data = newdata; + port->p_med_cap_enabled |= LLDP_MED_CAP_LOCATION; + } + if (set->med_power) { + log_debug("rpc", "requested change to MED power"); + memcpy(&port->p_med_power, set->med_power, + sizeof(struct lldpd_med_power)); + switch (set->med_power->devicetype) { + case LLDP_MED_POW_TYPE_PD: + port->p_med_cap_enabled |= LLDP_MED_CAP_MDI_PD; + port->p_med_cap_enabled &= ~LLDP_MED_CAP_MDI_PSE; + break; + case LLDP_MED_POW_TYPE_PSE: + port->p_med_cap_enabled |= LLDP_MED_CAP_MDI_PSE; + port->p_med_cap_enabled &= ~LLDP_MED_CAP_MDI_PD; + break; + } + } +#endif +#ifdef ENABLE_DOT3 + if (set->dot3_power) { + log_debug("rpc", "requested change to Dot3 power"); + memcpy(&port->p_power, set->dot3_power, + sizeof(struct lldpd_dot3_power)); + } +#endif +#ifdef ENABLE_CUSTOM + if (set->custom_list_clear) { + log_debug("rpc", "requested custom TLVs clear"); + lldpd_custom_list_cleanup(port); + } else { + if (set->custom) { + log_info("rpc", + "custom TLV op %s oui %02x:%02x:%02x subtype %x", + (set->custom_tlv_op == CUSTOM_TLV_REMOVE) ? "remove" : + (set->custom_tlv_op == CUSTOM_TLV_ADD) ? "add" : + "replace", + set->custom->oui[0], set->custom->oui[1], + set->custom->oui[2], set->custom->subtype); + switch (set->custom_tlv_op) { + case CUSTOM_TLV_REMOVE: + lldpd_custom_tlv_cleanup(port, set->custom); + break; + case CUSTOM_TLV_ADD: + lldpd_custom_tlv_add(port, set->custom); + break; + case CUSTOM_TLV_REPLACE: + default: + lldpd_custom_tlv_cleanup(port, set->custom); + lldpd_custom_tlv_add(port, set->custom); + break; + } + } + } +#endif + return 0; +} + +/* Set some port related settings (policy, location, power) + Input: name of the interface, policy/location/power setting to be modified + Output: nothing +*/ +static ssize_t +client_handle_set_port(struct lldpd *cfg, enum hmsg_type *type, void *input, + int input_len, void **output, int *subscribed) +{ + int ret = 0; + struct lldpd_port_set *set = NULL; + struct lldpd_hardware *hardware = NULL; + + if (lldpd_port_set_unserialize(input, input_len, &set) <= 0) { + *type = NONE; + return 0; + } + if (!set->ifname) { + log_warnx("rpc", "no interface provided"); + goto set_port_finished; + } + + /* Search the appropriate hardware */ + if (strlen(set->ifname) == 0) { + log_debug("rpc", "client request change to default port"); + if (_client_handle_set_port(cfg, cfg->g_default_local_port, set) == -1) + goto set_port_finished; + ret = 1; + } else { + log_debug("rpc", "client request change to port %s", set->ifname); + TAILQ_FOREACH (hardware, &cfg->g_hardware, h_entries) { + if (!strcmp(hardware->h_ifname, set->ifname)) { + struct lldpd_port *port = &hardware->h_lport; + if (_client_handle_set_port(cfg, port, set) == -1) + goto set_port_finished; + ret = 1; + break; + } + } + } + + if (ret == 0) + log_warn("rpc", "no interface %s found", set->ifname); + else + levent_update_now(cfg); + +set_port_finished: + if (!ret) *type = NONE; + free(set->ifname); + free(set->local_id); + free(set->local_descr); +#ifdef ENABLE_LLDPMED + free(set->med_policy); + if (set->med_location) free(set->med_location->data); + free(set->med_location); + free(set->med_power); +#endif +#ifdef ENABLE_DOT3 + free(set->dot3_power); +#endif +#ifdef ENABLE_CUSTOM + if (set->custom) { + free(set->custom->oui_info); + free(set->custom); + } +#endif + free(set); + return 0; +} + +/* Register subscribtion to neighbor changes */ +static ssize_t +client_handle_subscribe(struct lldpd *cfg, enum hmsg_type *type, void *input, + int input_len, void **output, int *subscribed) +{ + log_debug("rpc", "client subscribe to changes"); + *subscribed = 1; + return 0; +} + +struct client_handle { + enum hmsg_type type; + const char *name; + ssize_t ( + *handle)(struct lldpd *, enum hmsg_type *, void *, int, void **, int *); +}; + +static struct client_handle client_handles[] = { { NONE, "None", client_handle_none }, + { GET_CONFIG, "Get configuration", client_handle_get_configuration }, + { SET_CONFIG, "Set configuration", client_handle_set_configuration }, + { GET_INTERFACES, "Get interfaces", client_handle_get_interfaces }, + { GET_INTERFACE, "Get interface", client_handle_get_interface }, + { GET_DEFAULT_PORT, "Get default port", client_handle_get_default_port }, + { SET_CHASSIS, "Set local chassis", client_handle_set_local_chassis }, + { GET_CHASSIS, "Get local chassis", client_handle_get_local_chassis }, + { SET_PORT, "Set port", client_handle_set_port }, + { SUBSCRIBE, "Subscribe", client_handle_subscribe }, { 0, NULL } }; + +int +client_handle_client(struct lldpd *cfg, ssize_t (*send)(void *, int, void *, size_t), + void *out, enum hmsg_type type, void *buffer, size_t n, int *subscribed) +{ + struct client_handle *ch; + void *answer; + ssize_t len, sent; + + log_debug("rpc", "handle client request"); + for (ch = client_handles; ch->handle != NULL; ch++) { + if (ch->type == type) { + TRACE(LLDPD_CLIENT_REQUEST(ch->name)); + answer = NULL; + len = ch->handle(cfg, &type, buffer, n, &answer, subscribed); + sent = send(out, type, answer, len); + free(answer); + return sent; + } + } + + log_warnx("rpc", "unknown message request (%d) received", type); + return -1; +} |