/* -*- mode: c; c-file-style: "openbsd" -*- */ /* * Copyright (c) 2015 Vincent Bernat * * 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 #include #include #include #include "../lldpctl.h" #include "../../log.h" #include "../atom.h" #include "../helpers.h" static struct atom_map bond_slave_src_mac_map = { .key = lldpctl_k_config_bond_slave_src_mac_type, .map = { { LLDP_BOND_SLAVE_SRC_MAC_TYPE_REAL, "real"}, { LLDP_BOND_SLAVE_SRC_MAC_TYPE_ZERO, "zero"}, { LLDP_BOND_SLAVE_SRC_MAC_TYPE_FIXED, "fixed"}, { LLDP_BOND_SLAVE_SRC_MAC_TYPE_LOCALLY_ADMINISTERED, "local" }, { LLDP_BOND_SLAVE_SRC_MAC_TYPE_UNKNOWN, NULL}, }, }; static struct atom_map lldp_portid_map = { .key = lldpctl_k_config_lldp_portid_type, .map = { { LLDP_PORTID_SUBTYPE_IFNAME, "ifname"}, { LLDP_PORTID_SUBTYPE_LLADDR, "macaddress"}, { LLDP_PORTID_SUBTYPE_LOCAL, "local"}, { LLDP_PORTID_SUBTYPE_UNKNOWN, NULL}, }, }; static struct atom_map lldp_agent_map = { .key = lldpctl_k_config_lldp_agent_type, .map = { { LLDP_AGENT_TYPE_NEAREST_BRIDGE, "nearest bridge"}, { LLDP_AGENT_TYPE_NEAREST_NONTPMR_BRIDGE, "nearest non-TPMR bridge"}, { LLDP_AGENT_TYPE_NEAREST_CUSTOMER_BRIDGE, "nearest customer bridge"}, { LLDP_AGENT_TYPE_UNKNOWN, NULL}, }, }; ATOM_MAP_REGISTER(bond_slave_src_mac_map, 1); ATOM_MAP_REGISTER(lldp_portid_map, 2); ATOM_MAP_REGISTER(lldp_agent_map, 3); static int _lldpctl_atom_new_config(lldpctl_atom_t *atom, va_list ap) { struct _lldpctl_atom_config_t *c = (struct _lldpctl_atom_config_t *)atom; c->config = va_arg(ap, struct lldpd_config *); return 1; } static void _lldpctl_atom_free_config(lldpctl_atom_t *atom) { struct _lldpctl_atom_config_t *c = (struct _lldpctl_atom_config_t *)atom; lldpd_config_cleanup(c->config); free(c->config); } static const char * _lldpctl_atom_get_str_config(lldpctl_atom_t *atom, lldpctl_key_t key) { char *res = NULL; struct _lldpctl_atom_config_t *c = (struct _lldpctl_atom_config_t *)atom; switch (key) { case lldpctl_k_config_mgmt_pattern: res = c->config->c_mgmt_pattern; break; case lldpctl_k_config_iface_pattern: res = c->config->c_iface_pattern; break; case lldpctl_k_config_perm_iface_pattern: res = c->config->c_perm_ifaces; break; case lldpctl_k_config_cid_pattern: res = c->config->c_cid_pattern; break; case lldpctl_k_config_cid_string: res = c->config->c_cid_string; break; case lldpctl_k_config_description: res = c->config->c_description; break; case lldpctl_k_config_platform: res = c->config->c_platform; break; case lldpctl_k_config_hostname: res = c->config->c_hostname; break; case lldpctl_k_config_bond_slave_src_mac_type: return map_lookup(bond_slave_src_mac_map.map, c->config->c_bond_slave_src_mac_type); case lldpctl_k_config_lldp_portid_type: return map_lookup(lldp_portid_map.map, c->config->c_lldp_portid_type); case lldpctl_k_config_lldp_agent_type: return map_lookup(lldp_agent_map.map, c->config->c_lldp_agent_type); default: SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; } return res ? res : ""; } static struct _lldpctl_atom_config_t * __lldpctl_atom_set_str_config(struct _lldpctl_atom_config_t *c, char **local, char **global, const char *value) { if (value) { char *aval = NULL; size_t len = strlen(value) + 1; aval = _lldpctl_alloc_in_atom((lldpctl_atom_t *)c, len); if (!aval) return NULL; memcpy(aval, value, len); *local = aval; free(*global); *global = strdup(aval); } else { free(*global); *local = *global = NULL; } return c; } static lldpctl_atom_t * _lldpctl_atom_set_str_config(lldpctl_atom_t *atom, lldpctl_key_t key, const char *value) { struct _lldpctl_atom_config_t *c = (struct _lldpctl_atom_config_t *)atom; struct lldpd_config config; memcpy(&config, c->config, sizeof(struct lldpd_config)); char *canary = NULL; int rc; switch (key) { case lldpctl_k_config_perm_iface_pattern: if (!__lldpctl_atom_set_str_config(c, &config.c_perm_ifaces, &c->config->c_perm_ifaces, value)) return NULL; break; case lldpctl_k_config_iface_pattern: if (!__lldpctl_atom_set_str_config(c, &config.c_iface_pattern, &c->config->c_iface_pattern, value)) return NULL; break; case lldpctl_k_config_mgmt_pattern: if (!__lldpctl_atom_set_str_config(c, &config.c_mgmt_pattern, &c->config->c_mgmt_pattern, value)) return NULL; break; case lldpctl_k_config_cid_string: if (!__lldpctl_atom_set_str_config(c, &config.c_cid_string, &c->config->c_cid_string, value)) return NULL; break; case lldpctl_k_config_description: if (!__lldpctl_atom_set_str_config(c, &config.c_description, &c->config->c_description, value)) return NULL; break; case lldpctl_k_config_platform: if (!__lldpctl_atom_set_str_config(c, &config.c_platform, &c->config->c_platform, value)) return NULL; break; case lldpctl_k_config_hostname: if (!__lldpctl_atom_set_str_config(c, &config.c_hostname, &c->config->c_hostname, value)) return NULL; break; default: SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; } if (asprintf(&canary, "%d%s", key, value ? value : "(NULL)") == -1) { SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM); return NULL; } rc = _lldpctl_do_something(atom->conn, CONN_STATE_SET_CONFIG_SEND, CONN_STATE_SET_CONFIG_RECV, canary, SET_CONFIG, &config, &MARSHAL_INFO(lldpd_config), NULL, NULL); free(canary); if (rc == 0) return atom; #undef SET_STR return NULL; } static long int _lldpctl_atom_get_int_config(lldpctl_atom_t *atom, lldpctl_key_t key) { struct _lldpctl_atom_config_t *c = (struct _lldpctl_atom_config_t *)atom; switch (key) { case lldpctl_k_config_paused: return c->config->c_paused; case lldpctl_k_config_tx_interval: return (c->config->c_tx_interval + 999) / 1000; /* s units */ case lldpctl_k_config_tx_interval_ms: return c->config->c_tx_interval; /* ms units */ case lldpctl_k_config_receiveonly: return c->config->c_receiveonly; case lldpctl_k_config_advertise_version: return c->config->c_advertise_version; case lldpctl_k_config_ifdescr_update: return c->config->c_set_ifdescr; case lldpctl_k_config_iface_promisc: return c->config->c_promisc; case lldpctl_k_config_chassis_cap_advertise: return c->config->c_cap_advertise; case lldpctl_k_config_chassis_cap_override: return c->config->c_cap_override; case lldpctl_k_config_chassis_mgmt_advertise: return c->config->c_mgmt_advertise; #ifdef ENABLE_LLDPMED case lldpctl_k_config_lldpmed_noinventory: return c->config->c_noinventory; case lldpctl_k_config_fast_start_enabled: return c->config->c_enable_fast_start; case lldpctl_k_config_fast_start_interval: return c->config->c_tx_fast_interval; #endif case lldpctl_k_config_tx_hold: return c->config->c_tx_hold; case lldpctl_k_config_max_neighbors: return c->config->c_max_neighbors; default: return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); } } static lldpctl_atom_t * _lldpctl_atom_set_int_config(lldpctl_atom_t *atom, lldpctl_key_t key, long int value) { int rc; char *canary = NULL; struct _lldpctl_atom_config_t *c = (struct _lldpctl_atom_config_t *)atom; struct lldpd_config config; memcpy(&config, c->config, sizeof(struct lldpd_config)); switch (key) { case lldpctl_k_config_paused: config.c_paused = c->config->c_paused = value; break; case lldpctl_k_config_tx_interval: config.c_tx_interval = value * 1000; if (value > 0) c->config->c_tx_interval = value * 1000; break; case lldpctl_k_config_tx_interval_ms: config.c_tx_interval = value; if (value > 0) c->config->c_tx_interval = value; break; case lldpctl_k_config_ifdescr_update: config.c_set_ifdescr = c->config->c_set_ifdescr = value; break; case lldpctl_k_config_iface_promisc: config.c_promisc = c->config->c_promisc = value; break; case lldpctl_k_config_chassis_cap_advertise: config.c_cap_advertise = c->config->c_cap_advertise = value; break; case lldpctl_k_config_chassis_cap_override: config.c_cap_override = c->config->c_cap_override = value; break; case lldpctl_k_config_chassis_mgmt_advertise: config.c_mgmt_advertise = c->config->c_mgmt_advertise = value; break; #ifdef ENABLE_LLDPMED case lldpctl_k_config_fast_start_enabled: config.c_enable_fast_start = c->config->c_enable_fast_start = value; break; case lldpctl_k_config_fast_start_interval: config.c_tx_fast_interval = c->config->c_tx_fast_interval = value; break; #endif case lldpctl_k_config_tx_hold: config.c_tx_hold = value; if (value > 0) c->config->c_tx_hold = value; break; case lldpctl_k_config_max_neighbors: config.c_max_neighbors = value; if (value > 0) c->config->c_max_neighbors = value; break; case lldpctl_k_config_bond_slave_src_mac_type: config.c_bond_slave_src_mac_type = value; c->config->c_bond_slave_src_mac_type = value; break; case lldpctl_k_config_lldp_portid_type: config.c_lldp_portid_type = value; c->config->c_lldp_portid_type = value; break; case lldpctl_k_config_lldp_agent_type: config.c_lldp_agent_type = value; c->config->c_lldp_agent_type = value; break; default: SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; } if (asprintf(&canary, "%d%ld", key, value) == -1) { SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM); return NULL; } rc = _lldpctl_do_something(atom->conn, CONN_STATE_SET_CONFIG_SEND, CONN_STATE_SET_CONFIG_RECV, canary, SET_CONFIG, &config, &MARSHAL_INFO(lldpd_config), NULL, NULL); free(canary); if (rc == 0) return atom; return NULL; } static struct atom_builder config = { atom_config, sizeof(struct _lldpctl_atom_config_t), .init = _lldpctl_atom_new_config, .free = _lldpctl_atom_free_config, .get_str = _lldpctl_atom_get_str_config, .set_str = _lldpctl_atom_set_str_config, .get_int = _lldpctl_atom_get_int_config, .set_int = _lldpctl_atom_set_int_config }; ATOM_BUILDER_REGISTER(config, 1);