summaryrefslogtreecommitdiffstats
path: root/src/lib/atoms
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 18:02:34 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 18:02:34 +0000
commitfadeddfbb2aa38a980dd959b5ec1ffba7afd43cb (patch)
treea7bde6111c84ea64619656a38fba50909fa0bf60 /src/lib/atoms
parentInitial commit. (diff)
downloadlldpd-upstream.tar.xz
lldpd-upstream.zip
Adding upstream version 1.0.18.upstream/1.0.18upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/lib/atoms')
-rw-r--r--src/lib/atoms/chassis.c326
-rw-r--r--src/lib/atoms/config.c338
-rw-r--r--src/lib/atoms/custom.c226
-rw-r--r--src/lib/atoms/dot1.c250
-rw-r--r--src/lib/atoms/dot3.c474
-rw-r--r--src/lib/atoms/interface.c118
-rw-r--r--src/lib/atoms/med.c1123
-rw-r--r--src/lib/atoms/mgmt.c149
-rw-r--r--src/lib/atoms/port.c862
9 files changed, 3866 insertions, 0 deletions
diff --git a/src/lib/atoms/chassis.c b/src/lib/atoms/chassis.c
new file mode 100644
index 0000000..4d195f7
--- /dev/null
+++ b/src/lib/atoms/chassis.c
@@ -0,0 +1,326 @@
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * Copyright (c) 2015 Vincent Bernat <vincent@bernat.im>
+ *
+ * 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 <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#include "../lldpctl.h"
+#include "../../log.h"
+#include "../atom.h"
+#include "../helpers.h"
+
+static lldpctl_map_t chassis_id_subtype_map[] = {
+ { LLDP_CHASSISID_SUBTYPE_IFNAME, "ifname" },
+ { LLDP_CHASSISID_SUBTYPE_IFALIAS, "ifalias" },
+ { LLDP_CHASSISID_SUBTYPE_LOCAL, "local" },
+ { LLDP_CHASSISID_SUBTYPE_LLADDR, "mac" },
+ { LLDP_CHASSISID_SUBTYPE_ADDR, "ip" },
+ { LLDP_CHASSISID_SUBTYPE_PORT, "unhandled" },
+ { LLDP_CHASSISID_SUBTYPE_CHASSIS, "unhandled" },
+ { 0, NULL },
+};
+
+#ifdef ENABLE_LLDPMED
+
+static lldpctl_map_t chassis_med_type_map[] = {
+ { LLDP_MED_CLASS_I, "Generic Endpoint (Class I)" },
+ { LLDP_MED_CLASS_II, "Media Endpoint (Class II)" },
+ { LLDP_MED_CLASS_III, "Communication Device Endpoint (Class III)" },
+ { LLDP_MED_NETWORK_DEVICE, "Network Connectivity Device" },
+ { 0, NULL },
+};
+
+#endif
+
+static int
+_lldpctl_atom_new_chassis(lldpctl_atom_t *atom, va_list ap)
+{
+ struct _lldpctl_atom_chassis_t *p = (struct _lldpctl_atom_chassis_t *)atom;
+ p->chassis = va_arg(ap, struct lldpd_chassis *);
+ p->parent = va_arg(ap, struct _lldpctl_atom_port_t *);
+ p->embedded = va_arg(ap, int);
+ if (p->parent && !p->embedded)
+ lldpctl_atom_inc_ref((lldpctl_atom_t *)p->parent);
+ return 1;
+}
+
+static void
+_lldpctl_atom_free_chassis(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_chassis_t *p = (struct _lldpctl_atom_chassis_t *)atom;
+ /* When we have a parent, the chassis structure is in fact part of the
+ * parent, just decrement the reference count of the parent. Otherwise,
+ * we need to free the whole chassis. When embedded, we don't alter the
+ * reference count of the parent. Therefore, it's important to also not
+ * increase the reference count of this atom. See
+ * `_lldpctl_atom_get_atom_chassis' for how to handle that. */
+ if (p->parent) {
+ if (!p->embedded) lldpctl_atom_dec_ref((lldpctl_atom_t *)p->parent);
+ } else
+ lldpd_chassis_cleanup(p->chassis, 1);
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_get_atom_chassis(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ struct _lldpctl_atom_chassis_t *p = (struct _lldpctl_atom_chassis_t *)atom;
+ struct lldpd_chassis *chassis = p->chassis;
+
+ switch (key) {
+ case lldpctl_k_chassis_mgmt:
+ return _lldpctl_new_atom(atom->conn, atom_mgmts_list,
+ (p->parent && p->embedded) ? (lldpctl_atom_t *)p->parent :
+ (lldpctl_atom_t *)p,
+ chassis);
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+}
+
+#ifdef ENABLE_LLDPMED
+static lldpctl_atom_t *
+_lldpctl_atom_set_str_chassis(lldpctl_atom_t *atom, lldpctl_key_t key,
+ const char *value)
+{
+ struct _lldpctl_atom_chassis_t *p = (struct _lldpctl_atom_chassis_t *)atom;
+ struct lldpd_chassis *chassis = p->chassis;
+
+ char *canary = NULL;
+
+ int rc;
+
+ switch (key) {
+ case lldpctl_k_chassis_med_inventory_hw:
+ free(chassis->c_med_hw);
+ chassis->c_med_hw = xstrdup(value);
+ break;
+ case lldpctl_k_chassis_med_inventory_sw:
+ free(chassis->c_med_sw);
+ chassis->c_med_sw = xstrdup(value);
+ break;
+ case lldpctl_k_chassis_med_inventory_fw:
+ free(chassis->c_med_fw);
+ chassis->c_med_fw = xstrdup(value);
+ break;
+ case lldpctl_k_chassis_med_inventory_sn:
+ free(chassis->c_med_sn);
+ chassis->c_med_sn = xstrdup(value);
+ break;
+ case lldpctl_k_chassis_med_inventory_manuf:
+ free(chassis->c_med_manuf);
+ chassis->c_med_manuf = xstrdup(value);
+ break;
+ case lldpctl_k_chassis_med_inventory_model:
+ free(chassis->c_med_model);
+ chassis->c_med_model = xstrdup(value);
+ break;
+ case lldpctl_k_chassis_med_inventory_asset:
+ free(chassis->c_med_asset);
+ chassis->c_med_asset = xstrdup(value);
+ 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_CHASSIS_SEND,
+ CONN_STATE_SET_CHASSIS_RECV, canary, SET_CHASSIS, chassis,
+ &MARSHAL_INFO(lldpd_chassis), NULL, NULL);
+
+ free(canary);
+ if (rc == 0) return atom;
+ return NULL;
+}
+#endif /* ENABLE_LLDPMED */
+
+static const char *
+_lldpctl_atom_get_str_chassis(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ struct _lldpctl_atom_chassis_t *p = (struct _lldpctl_atom_chassis_t *)atom;
+ struct lldpd_chassis *chassis = p->chassis;
+ char *ipaddress = NULL;
+ size_t len;
+
+ /* Local and remote port */
+ switch (key) {
+
+ case lldpctl_k_chassis_id_subtype:
+ return map_lookup(chassis_id_subtype_map, chassis->c_id_subtype);
+ case lldpctl_k_chassis_id:
+ switch (chassis->c_id_subtype) {
+ case LLDP_CHASSISID_SUBTYPE_IFNAME:
+ case LLDP_CHASSISID_SUBTYPE_IFALIAS:
+ case LLDP_CHASSISID_SUBTYPE_LOCAL:
+ return chassis->c_id;
+ case LLDP_CHASSISID_SUBTYPE_LLADDR:
+ return _lldpctl_dump_in_atom(atom, (uint8_t *)chassis->c_id,
+ chassis->c_id_len, ':', 0);
+ case LLDP_CHASSISID_SUBTYPE_ADDR:
+ switch (chassis->c_id[0]) {
+ case LLDP_MGMT_ADDR_IP4:
+ len = INET_ADDRSTRLEN + 1;
+ break;
+ case LLDP_MGMT_ADDR_IP6:
+ len = INET6_ADDRSTRLEN + 1;
+ break;
+ default:
+ len = 0;
+ }
+ if (len > 0) {
+ ipaddress = _lldpctl_alloc_in_atom(atom, len);
+ if (!ipaddress) return NULL;
+ if (inet_ntop((chassis->c_id[0] == LLDP_MGMT_ADDR_IP4) ?
+ AF_INET :
+ AF_INET6,
+ &chassis->c_id[1], ipaddress, len) == NULL)
+ break;
+ return ipaddress;
+ }
+ break;
+ }
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ case lldpctl_k_chassis_name:
+ return chassis->c_name;
+ case lldpctl_k_chassis_descr:
+ return chassis->c_descr;
+
+#ifdef ENABLE_LLDPMED
+ case lldpctl_k_chassis_med_type:
+ return map_lookup(chassis_med_type_map, chassis->c_med_type);
+ case lldpctl_k_chassis_med_inventory_hw:
+ return chassis->c_med_hw;
+ case lldpctl_k_chassis_med_inventory_sw:
+ return chassis->c_med_sw;
+ case lldpctl_k_chassis_med_inventory_fw:
+ return chassis->c_med_fw;
+ case lldpctl_k_chassis_med_inventory_sn:
+ return chassis->c_med_sn;
+ case lldpctl_k_chassis_med_inventory_manuf:
+ return chassis->c_med_manuf;
+ case lldpctl_k_chassis_med_inventory_model:
+ return chassis->c_med_model;
+ case lldpctl_k_chassis_med_inventory_asset:
+ return chassis->c_med_asset;
+#endif
+
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_set_int_chassis(lldpctl_atom_t *atom, lldpctl_key_t key, long int value)
+{
+ int rc;
+ char *canary = NULL;
+ struct _lldpctl_atom_chassis_t *c = (struct _lldpctl_atom_chassis_t *)atom;
+ struct lldpd_chassis chassis;
+ memcpy(&chassis, c->chassis, sizeof(struct lldpd_chassis));
+
+ switch (key) {
+ case lldpctl_k_chassis_cap_enabled:
+ chassis.c_cap_enabled = c->chassis->c_cap_enabled =
+ chassis.c_cap_available & 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_CHASSIS_SEND,
+ CONN_STATE_SET_CHASSIS_RECV, canary, SET_CHASSIS, &chassis,
+ &MARSHAL_INFO(lldpd_chassis), NULL, NULL);
+
+ free(canary);
+ if (rc == 0) return atom;
+ return NULL;
+}
+
+static long int
+_lldpctl_atom_get_int_chassis(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ struct _lldpctl_atom_chassis_t *p = (struct _lldpctl_atom_chassis_t *)atom;
+ struct lldpd_chassis *chassis = p->chassis;
+
+ /* Local and remote port */
+ switch (key) {
+ case lldpctl_k_chassis_index:
+ return chassis->c_index;
+ case lldpctl_k_chassis_id_subtype:
+ return chassis->c_id_subtype;
+ case lldpctl_k_chassis_cap_available:
+ return chassis->c_cap_available;
+ case lldpctl_k_chassis_cap_enabled:
+ return chassis->c_cap_enabled;
+#ifdef ENABLE_LLDPMED
+ case lldpctl_k_chassis_med_type:
+ return chassis->c_med_type;
+ case lldpctl_k_chassis_med_cap:
+ return chassis->c_med_cap_available;
+#endif
+ default:
+ return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ }
+}
+
+static const uint8_t *
+_lldpctl_atom_get_buf_chassis(lldpctl_atom_t *atom, lldpctl_key_t key, size_t *n)
+{
+ struct _lldpctl_atom_chassis_t *p = (struct _lldpctl_atom_chassis_t *)atom;
+ struct lldpd_chassis *chassis = p->chassis;
+
+ switch (key) {
+ case lldpctl_k_chassis_id:
+ *n = chassis->c_id_len;
+ return (uint8_t *)chassis->c_id;
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+}
+
+static struct atom_builder chassis = {
+ atom_chassis,
+ sizeof(struct _lldpctl_atom_chassis_t),
+ .init = _lldpctl_atom_new_chassis,
+ .free = _lldpctl_atom_free_chassis,
+ .get = _lldpctl_atom_get_atom_chassis,
+ .get_str = _lldpctl_atom_get_str_chassis,
+ .get_int = _lldpctl_atom_get_int_chassis,
+ .set_int = _lldpctl_atom_set_int_chassis,
+ .get_buffer = _lldpctl_atom_get_buf_chassis,
+#ifdef ENABLE_LLDPMED
+ .set_str = _lldpctl_atom_set_str_chassis,
+#endif
+};
+
+ATOM_BUILDER_REGISTER(chassis, 3);
diff --git a/src/lib/atoms/config.c b/src/lib/atoms/config.c
new file mode 100644
index 0000000..8a4af2e
--- /dev/null
+++ b/src/lib/atoms/config.c
@@ -0,0 +1,338 @@
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * Copyright (c) 2015 Vincent Bernat <vincent@bernat.im>
+ *
+ * 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 <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#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);
diff --git a/src/lib/atoms/custom.c b/src/lib/atoms/custom.c
new file mode 100644
index 0000000..ffa5b03
--- /dev/null
+++ b/src/lib/atoms/custom.c
@@ -0,0 +1,226 @@
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * Copyright (c) 2015 Vincent Bernat <vincent@bernat.im>
+ * Copyright (c) 2015 Alexandru Ardelean <ardeleanalex@gmail.com>
+ *
+ * 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 <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#include "../lldpctl.h"
+#include "../../log.h"
+#include "../atom.h"
+#include "../helpers.h"
+
+#ifdef ENABLE_CUSTOM
+
+# define min(x, y) ((x > y) ? y : x)
+
+static lldpctl_atom_iter_t *
+_lldpctl_atom_iter_custom_list(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_custom_list_t *custom =
+ (struct _lldpctl_atom_custom_list_t *)atom;
+ return (lldpctl_atom_iter_t *)TAILQ_FIRST(&custom->parent->port->p_custom_list);
+}
+
+static lldpctl_atom_iter_t *
+_lldpctl_atom_next_custom_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
+{
+ return (lldpctl_atom_iter_t *)TAILQ_NEXT((struct lldpd_custom *)iter, next);
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_value_custom_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
+{
+ struct _lldpctl_atom_custom_list_t *custom =
+ (struct _lldpctl_atom_custom_list_t *)atom;
+ struct lldpd_custom *tlv = (struct lldpd_custom *)iter;
+ return _lldpctl_new_atom(atom->conn, atom_custom, custom->parent, tlv);
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_create_custom_list(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_custom_list_t *custom =
+ (struct _lldpctl_atom_custom_list_t *)atom;
+ struct lldpd_custom *tlv;
+
+ tlv = _lldpctl_alloc_in_atom(atom, sizeof(struct lldpd_custom));
+ if (!tlv) return NULL;
+ return _lldpctl_new_atom(atom->conn, atom_custom, custom->parent, tlv);
+}
+
+static int
+_lldpctl_atom_new_custom(lldpctl_atom_t *atom, va_list ap)
+{
+ struct _lldpctl_atom_custom_t *custom = (struct _lldpctl_atom_custom_t *)atom;
+
+ custom->parent = va_arg(ap, struct _lldpctl_atom_port_t *);
+ custom->tlv = va_arg(ap, struct lldpd_custom *);
+ lldpctl_atom_inc_ref((lldpctl_atom_t *)custom->parent);
+ return 1;
+}
+
+static void
+_lldpctl_atom_free_custom(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_custom_t *custom = (struct _lldpctl_atom_custom_t *)atom;
+ lldpctl_atom_dec_ref((lldpctl_atom_t *)custom->parent);
+}
+
+static long int
+_lldpctl_atom_get_int_custom(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ struct _lldpctl_atom_custom_t *custom = (struct _lldpctl_atom_custom_t *)atom;
+
+ switch (key) {
+ case lldpctl_k_custom_tlv_oui_subtype:
+ return custom->tlv->subtype;
+ default:
+ return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ }
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_set_str_custom(lldpctl_atom_t *atom, lldpctl_key_t key, const char *value)
+{
+ struct _lldpctl_atom_custom_t *custom = (struct _lldpctl_atom_custom_t *)atom;
+
+ if (!value || !strlen(value)) return NULL;
+
+ /* Only local port can be modified */
+ if (!custom->parent->local) {
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+
+ switch (key) {
+ case lldpctl_k_custom_tlv_op:
+ if (!strcmp(value, "replace"))
+ custom->op = CUSTOM_TLV_REPLACE;
+ else if (!strcmp(value, "remove"))
+ custom->op = CUSTOM_TLV_REMOVE;
+ else
+ custom->op = CUSTOM_TLV_ADD;
+ return atom;
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+
+ SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
+ return NULL;
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_set_int_custom(lldpctl_atom_t *atom, lldpctl_key_t key, long int value)
+{
+ struct _lldpctl_atom_custom_t *custom = (struct _lldpctl_atom_custom_t *)atom;
+
+ /* Only local port can be modified */
+ if (!custom->parent->local) {
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+
+ switch (key) {
+ case lldpctl_k_custom_tlv_oui_subtype:
+ if (value < 0 || value > 255) goto bad;
+ custom->tlv->subtype = value;
+ return atom;
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+bad:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
+ return NULL;
+}
+
+static const uint8_t *
+_lldpctl_atom_get_buffer_custom(lldpctl_atom_t *atom, lldpctl_key_t key, size_t *n)
+{
+ struct _lldpctl_atom_custom_t *custom = (struct _lldpctl_atom_custom_t *)atom;
+
+ switch (key) {
+ case lldpctl_k_custom_tlv_oui:
+ *n = sizeof(custom->tlv->oui);
+ return (const uint8_t *)&custom->tlv->oui;
+ case lldpctl_k_custom_tlv_oui_info_string:
+ *n = custom->tlv->oui_info_len;
+ return (const uint8_t *)custom->tlv->oui_info;
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_set_buffer_custom(lldpctl_atom_t *atom, lldpctl_key_t key,
+ const u_int8_t *buf, size_t n)
+{
+ struct _lldpctl_atom_custom_t *custom = (struct _lldpctl_atom_custom_t *)atom;
+
+ /* Only local port can be modified */
+ if (!custom->parent->local) {
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+
+ switch (key) {
+ case lldpctl_k_custom_tlv_oui:
+ memcpy(&custom->tlv->oui, buf, min(n, sizeof(custom->tlv->oui)));
+ return atom;
+ case lldpctl_k_custom_tlv_oui_info_string:
+ if (n == 0 || n > LLDP_TLV_ORG_OUI_INFO_MAXLEN) {
+ SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
+ return NULL;
+ }
+ custom->tlv->oui_info_len = n;
+ if (!(custom->tlv->oui_info = _lldpctl_alloc_in_atom(atom, n))) {
+ custom->tlv->oui_info_len = 0;
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM);
+ return NULL;
+ }
+ memcpy(custom->tlv->oui_info, buf, n);
+ return atom;
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+}
+
+static struct atom_builder custom_list = { atom_custom_list,
+ sizeof(struct _lldpctl_atom_any_list_t), .init = _lldpctl_atom_new_any_list,
+ .free = _lldpctl_atom_free_any_list, .iter = _lldpctl_atom_iter_custom_list,
+ .next = _lldpctl_atom_next_custom_list,
+ .value = _lldpctl_atom_value_custom_list,
+ .create = _lldpctl_atom_create_custom_list };
+
+static struct atom_builder custom = { atom_custom,
+ sizeof(struct _lldpctl_atom_custom_t), .init = _lldpctl_atom_new_custom,
+ .free = _lldpctl_atom_free_custom, .get_int = _lldpctl_atom_get_int_custom,
+ .set_int = _lldpctl_atom_set_int_custom,
+ .set_str = _lldpctl_atom_set_str_custom,
+ .get_buffer = _lldpctl_atom_get_buffer_custom,
+ .set_buffer = _lldpctl_atom_set_buffer_custom };
+
+ATOM_BUILDER_REGISTER(custom_list, 22);
+ATOM_BUILDER_REGISTER(custom, 23);
+
+#endif /* ENABLE_CUSTOM */
diff --git a/src/lib/atoms/dot1.c b/src/lib/atoms/dot1.c
new file mode 100644
index 0000000..c2feda0
--- /dev/null
+++ b/src/lib/atoms/dot1.c
@@ -0,0 +1,250 @@
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * Copyright (c) 2015 Vincent Bernat <vincent@bernat.im>
+ *
+ * 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 <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#include "../lldpctl.h"
+#include "../../log.h"
+#include "../atom.h"
+#include "../helpers.h"
+
+#ifdef ENABLE_DOT1
+
+static lldpctl_atom_iter_t *
+_lldpctl_atom_iter_vlans_list(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_any_list_t *vlist =
+ (struct _lldpctl_atom_any_list_t *)atom;
+ return (lldpctl_atom_iter_t *)TAILQ_FIRST(&vlist->parent->port->p_vlans);
+}
+
+static lldpctl_atom_iter_t *
+_lldpctl_atom_next_vlans_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
+{
+ struct lldpd_vlan *vlan = (struct lldpd_vlan *)iter;
+ return (lldpctl_atom_iter_t *)TAILQ_NEXT(vlan, v_entries);
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_value_vlans_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
+{
+ struct _lldpctl_atom_any_list_t *vlist =
+ (struct _lldpctl_atom_any_list_t *)atom;
+ struct lldpd_vlan *vlan = (struct lldpd_vlan *)iter;
+ return _lldpctl_new_atom(atom->conn, atom_vlan, vlist->parent, vlan);
+}
+
+static int
+_lldpctl_atom_new_vlan(lldpctl_atom_t *atom, va_list ap)
+{
+ struct _lldpctl_atom_vlan_t *vlan = (struct _lldpctl_atom_vlan_t *)atom;
+ vlan->parent = va_arg(ap, struct _lldpctl_atom_port_t *);
+ vlan->vlan = va_arg(ap, struct lldpd_vlan *);
+ lldpctl_atom_inc_ref((lldpctl_atom_t *)vlan->parent);
+ return 1;
+}
+
+static void
+_lldpctl_atom_free_vlan(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_vlan_t *vlan = (struct _lldpctl_atom_vlan_t *)atom;
+ lldpctl_atom_dec_ref((lldpctl_atom_t *)vlan->parent);
+}
+
+static const char *
+_lldpctl_atom_get_str_vlan(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ struct _lldpctl_atom_vlan_t *m = (struct _lldpctl_atom_vlan_t *)atom;
+
+ /* Local and remote port */
+ switch (key) {
+ case lldpctl_k_vlan_name:
+ return m->vlan->v_name;
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+}
+
+static long int
+_lldpctl_atom_get_int_vlan(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ struct _lldpctl_atom_vlan_t *m = (struct _lldpctl_atom_vlan_t *)atom;
+
+ /* Local and remote port */
+ switch (key) {
+ case lldpctl_k_vlan_id:
+ return m->vlan->v_vid;
+ default:
+ return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ }
+}
+
+static lldpctl_atom_iter_t *
+_lldpctl_atom_iter_ppvids_list(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_any_list_t *vlist =
+ (struct _lldpctl_atom_any_list_t *)atom;
+ return (lldpctl_atom_iter_t *)TAILQ_FIRST(&vlist->parent->port->p_ppvids);
+}
+
+static lldpctl_atom_iter_t *
+_lldpctl_atom_next_ppvids_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
+{
+ struct lldpd_ppvid *ppvid = (struct lldpd_ppvid *)iter;
+ return (lldpctl_atom_iter_t *)TAILQ_NEXT(ppvid, p_entries);
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_value_ppvids_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
+{
+ struct _lldpctl_atom_any_list_t *vlist =
+ (struct _lldpctl_atom_any_list_t *)atom;
+ struct lldpd_ppvid *ppvid = (struct lldpd_ppvid *)iter;
+ return _lldpctl_new_atom(atom->conn, atom_ppvid, vlist->parent, ppvid);
+}
+
+static int
+_lldpctl_atom_new_ppvid(lldpctl_atom_t *atom, va_list ap)
+{
+ struct _lldpctl_atom_ppvid_t *ppvid = (struct _lldpctl_atom_ppvid_t *)atom;
+ ppvid->parent = va_arg(ap, struct _lldpctl_atom_port_t *);
+ ppvid->ppvid = va_arg(ap, struct lldpd_ppvid *);
+ lldpctl_atom_inc_ref((lldpctl_atom_t *)ppvid->parent);
+ return 1;
+}
+
+static void
+_lldpctl_atom_free_ppvid(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_ppvid_t *ppvid = (struct _lldpctl_atom_ppvid_t *)atom;
+ lldpctl_atom_dec_ref((lldpctl_atom_t *)ppvid->parent);
+}
+
+static long int
+_lldpctl_atom_get_int_ppvid(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ struct _lldpctl_atom_ppvid_t *m = (struct _lldpctl_atom_ppvid_t *)atom;
+
+ /* Local and remote port */
+ switch (key) {
+ case lldpctl_k_ppvid_id:
+ return m->ppvid->p_ppvid;
+ case lldpctl_k_ppvid_status:
+ return m->ppvid->p_cap_status;
+ default:
+ return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ }
+}
+
+static lldpctl_atom_iter_t *
+_lldpctl_atom_iter_pis_list(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_any_list_t *vlist =
+ (struct _lldpctl_atom_any_list_t *)atom;
+ return (lldpctl_atom_iter_t *)TAILQ_FIRST(&vlist->parent->port->p_pids);
+}
+
+static lldpctl_atom_iter_t *
+_lldpctl_atom_next_pis_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
+{
+ struct lldpd_pi *pi = (struct lldpd_pi *)iter;
+ return (lldpctl_atom_iter_t *)TAILQ_NEXT(pi, p_entries);
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_value_pis_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
+{
+ struct _lldpctl_atom_any_list_t *vlist =
+ (struct _lldpctl_atom_any_list_t *)atom;
+ struct lldpd_pi *pi = (struct lldpd_pi *)iter;
+ return _lldpctl_new_atom(atom->conn, atom_pi, vlist->parent, pi);
+}
+
+static int
+_lldpctl_atom_new_pi(lldpctl_atom_t *atom, va_list ap)
+{
+ struct _lldpctl_atom_pi_t *pi = (struct _lldpctl_atom_pi_t *)atom;
+ pi->parent = va_arg(ap, struct _lldpctl_atom_port_t *);
+ pi->pi = va_arg(ap, struct lldpd_pi *);
+ lldpctl_atom_inc_ref((lldpctl_atom_t *)pi->parent);
+ return 1;
+}
+
+static void
+_lldpctl_atom_free_pi(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_pi_t *pi = (struct _lldpctl_atom_pi_t *)atom;
+ lldpctl_atom_dec_ref((lldpctl_atom_t *)pi->parent);
+}
+
+static const uint8_t *
+_lldpctl_atom_get_buf_pi(lldpctl_atom_t *atom, lldpctl_key_t key, size_t *n)
+{
+ struct _lldpctl_atom_pi_t *m = (struct _lldpctl_atom_pi_t *)atom;
+
+ /* Local and remote port */
+ switch (key) {
+ case lldpctl_k_pi_id:
+ *n = m->pi->p_pi_len;
+ return (const uint8_t *)m->pi->p_pi;
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+}
+
+static struct atom_builder vlans_list = { atom_vlans_list,
+ sizeof(struct _lldpctl_atom_any_list_t), .init = _lldpctl_atom_new_any_list,
+ .free = _lldpctl_atom_free_any_list, .iter = _lldpctl_atom_iter_vlans_list,
+ .next = _lldpctl_atom_next_vlans_list,
+ .value = _lldpctl_atom_value_vlans_list };
+
+static struct atom_builder vlan = { atom_vlan, sizeof(struct _lldpctl_atom_vlan_t),
+ .init = _lldpctl_atom_new_vlan, .free = _lldpctl_atom_free_vlan,
+ .get_str = _lldpctl_atom_get_str_vlan, .get_int = _lldpctl_atom_get_int_vlan };
+
+static struct atom_builder ppvids_list = { atom_ppvids_list,
+ sizeof(struct _lldpctl_atom_any_list_t), .init = _lldpctl_atom_new_any_list,
+ .free = _lldpctl_atom_free_any_list, .iter = _lldpctl_atom_iter_ppvids_list,
+ .next = _lldpctl_atom_next_ppvids_list,
+ .value = _lldpctl_atom_value_ppvids_list };
+
+static struct atom_builder ppvid = { atom_ppvid, sizeof(struct _lldpctl_atom_ppvid_t),
+ .init = _lldpctl_atom_new_ppvid, .free = _lldpctl_atom_free_ppvid,
+ .get_int = _lldpctl_atom_get_int_ppvid };
+
+static struct atom_builder pis_list = { atom_pis_list,
+ sizeof(struct _lldpctl_atom_any_list_t), .init = _lldpctl_atom_new_any_list,
+ .free = _lldpctl_atom_free_any_list, .iter = _lldpctl_atom_iter_pis_list,
+ .next = _lldpctl_atom_next_pis_list, .value = _lldpctl_atom_value_pis_list };
+
+static struct atom_builder pi = { atom_pi, sizeof(struct _lldpctl_atom_pi_t),
+ .init = _lldpctl_atom_new_pi, .free = _lldpctl_atom_free_pi,
+ .get_buffer = _lldpctl_atom_get_buf_pi };
+
+ATOM_BUILDER_REGISTER(vlans_list, 9);
+ATOM_BUILDER_REGISTER(vlan, 10);
+ATOM_BUILDER_REGISTER(ppvids_list, 11);
+ATOM_BUILDER_REGISTER(ppvid, 12);
+ATOM_BUILDER_REGISTER(pis_list, 13);
+ATOM_BUILDER_REGISTER(pi, 14);
+
+#endif
diff --git a/src/lib/atoms/dot3.c b/src/lib/atoms/dot3.c
new file mode 100644
index 0000000..f3f490a
--- /dev/null
+++ b/src/lib/atoms/dot3.c
@@ -0,0 +1,474 @@
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * Copyright (c) 2015 Vincent Bernat <vincent@bernat.im>
+ *
+ * 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 <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#include "../lldpctl.h"
+#include "../../log.h"
+#include "../atom.h"
+#include "../helpers.h"
+
+#ifdef ENABLE_DOT3
+
+static lldpctl_map_t port_dot3_power_devicetype_map[] = {
+ { LLDP_DOT3_POWER_PSE, "PSE" }, { LLDP_DOT3_POWER_PD, "PD" }, { 0, NULL }
+};
+
+static lldpctl_map_t port_dot3_power_pse_source_map[] = { { LLDP_DOT3_POWER_SOURCE_BOTH,
+ "PSE + Local" },
+ { LLDP_DOT3_POWER_SOURCE_PSE, "PSE" }, { 0, NULL } };
+
+static lldpctl_map_t port_dot3_power_pd_source_map[] = {
+ { LLDP_DOT3_POWER_SOURCE_BACKUP, "Backup source" },
+ { LLDP_DOT3_POWER_SOURCE_PRIMARY, "Primary power source" }, { 0, NULL }
+};
+
+static struct atom_map port_dot3_power_pairs_map = {
+ .key = lldpctl_k_dot3_power_pairs,
+ .map = { { LLDP_DOT3_POWERPAIRS_SIGNAL, "signal" },
+ { LLDP_DOT3_POWERPAIRS_SPARE, "spare" }, { 0, NULL } },
+};
+
+static struct atom_map port_dot3_power_class_map = {
+ .key = lldpctl_k_dot3_power_class,
+ .map = { { 1, "class 0" }, { 2, "class 1" }, { 3, "class 2" }, { 4, "class 3" },
+ { 5, "class 4" }, { 0, NULL } },
+};
+
+static struct atom_map port_dot3_power_priority_map = {
+ .key = lldpctl_k_dot3_power_priority,
+ .map = {
+ { 0, "unknown" },
+ { LLDP_MED_POW_PRIO_CRITICAL, "critical" },
+ { LLDP_MED_POW_PRIO_HIGH, "high" },
+ { LLDP_MED_POW_PRIO_LOW, "low" },
+ { 0, NULL },
+ },
+};
+
+static struct atom_map port_dot3_power_pd_4pid_map = {
+ .key = lldpctl_k_dot3_power_pd_4pid,
+ .map = {
+ { 0, "PD does not support powering both modes" },
+ { 1, "PD supports powering both modes" },
+ { 0, NULL},
+ },
+};
+
+static struct atom_map port_dot3_power_pse_status_map = {
+ .key = lldpctl_k_dot3_power_pse_status,
+ .map = {
+ { 0, "unknown" },
+ { 1, "2-pair powering" },
+ { 2, "4-pair powering dual-signature PD" },
+ { 3, "4-pair powering single-signature PD" },
+ { 0, NULL },
+ },
+};
+
+static struct atom_map port_dot3_power_pd_status_map = {
+ .key = lldpctl_k_dot3_power_pd_status,
+ .map = {
+ { 0, "unknown" },
+ { 1, "2-pair powered PD" },
+ { 2, "4-pair powered dual-signature PD" },
+ { 3, "4-pair powered single-signature PD" },
+ { 0, NULL },
+ },
+};
+
+static struct atom_map port_dot3_power_pse_pairs_ext_map = {
+ .key = lldpctl_k_dot3_power_pse_pairs_ext,
+ .map = {
+ { 0, "unknown" },
+ { 1, "alternative A" },
+ { 2, "alternative B" },
+ { 3, "both alternatives" },
+ { 0, NULL },
+ },
+};
+
+static struct atom_map port_dot3_power_class_a_map = {
+ .key = lldpctl_k_dot3_power_class_a,
+ .map = {
+ { 0, "unknown" },
+ { 1, "class 1" },
+ { 2, "class 2" },
+ { 3, "class 3" },
+ { 4, "class 4" },
+ { 5, "class 5" },
+ { 6, "unknown" },
+ { 7, "single-signature PD or 2-pair only PSE" },
+ { 0, NULL },
+ },
+};
+
+static struct atom_map port_dot3_power_class_b_map = {
+ .key = lldpctl_k_dot3_power_class_b,
+ .map = {
+ { 0, "unknown" },
+ { 1, "class 1" },
+ { 2, "class 2" },
+ { 3, "class 3" },
+ { 4, "class 4" },
+ { 5, "class 5" },
+ { 6, "unknown" },
+ { 7, "single-signature PD or 2-pair only PSE" },
+ { 0, NULL },
+ },
+};
+
+static struct atom_map port_dot3_power_class_ext_map = {
+ .key = lldpctl_k_dot3_power_class_ext,
+ .map = {
+ { 0, "unknown" },
+ { 1, "class 1" },
+ { 2, "class 2" },
+ { 3, "class 3" },
+ { 4, "class 4" },
+ { 5, "class 5" },
+ { 6, "class 6" },
+ { 7, "class 7" },
+ { 8, "class 8" },
+ { 9, "unknown" },
+ { 10, "unknown" },
+ { 11, "unknown" },
+ { 12, "unknown" },
+ { 13, "unknown" },
+ { 14, "unknown" },
+ { 15, "dual-signature PD" },
+ { 0, NULL },
+ },
+};
+
+static struct atom_map port_dot3_power_type_ext_map = {
+ .key = lldpctl_k_dot3_power_type_ext,
+ .map = {
+ { LLDP_DOT3_POWER_8023BT_OFF, "802.3bt off" },
+ { 1, "type 3 PSE" },
+ { 2, "type 4 PSE" },
+ { 3, "type 3 single-signature PD" },
+ { 4, "type 3 dual-signature PD" },
+ { 5, "type 4 single-signature PD" },
+ { 6, "type 4 dual-signature PD" },
+ { 7, "unknown" },
+ { 8, "unknown" },
+ { 0, NULL },
+ },
+};
+
+static struct atom_map port_dot3_power_pd_load_map = {
+ .key = lldpctl_k_dot3_power_pd_load,
+ .map = {
+ { 0, "PD is single- or dual-signature and power is not "
+ "electrically isolated" },
+ { 1, "PD is dual-signature and power is electrically "
+ "isolated" },
+ { 0, NULL },
+ },
+};
+
+ATOM_MAP_REGISTER(port_dot3_power_pairs_map, 4);
+ATOM_MAP_REGISTER(port_dot3_power_class_map, 5);
+ATOM_MAP_REGISTER(port_dot3_power_priority_map, 6);
+
+static int
+_lldpctl_atom_new_dot3_power(lldpctl_atom_t *atom, va_list ap)
+{
+ struct _lldpctl_atom_dot3_power_t *dpow =
+ (struct _lldpctl_atom_dot3_power_t *)atom;
+ dpow->parent = va_arg(ap, struct _lldpctl_atom_port_t *);
+ lldpctl_atom_inc_ref((lldpctl_atom_t *)dpow->parent);
+ return 1;
+}
+
+static void
+_lldpctl_atom_free_dot3_power(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_dot3_power_t *dpow =
+ (struct _lldpctl_atom_dot3_power_t *)atom;
+ lldpctl_atom_dec_ref((lldpctl_atom_t *)dpow->parent);
+}
+
+static const char *
+_lldpctl_atom_get_str_dot3_power(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ struct _lldpctl_atom_dot3_power_t *dpow =
+ (struct _lldpctl_atom_dot3_power_t *)atom;
+ struct lldpd_port *port = dpow->parent->port;
+
+ /* Local and remote port */
+ switch (key) {
+ case lldpctl_k_dot3_power_devicetype:
+ return map_lookup(port_dot3_power_devicetype_map,
+ port->p_power.devicetype);
+ case lldpctl_k_dot3_power_pairs:
+ return map_lookup(port_dot3_power_pairs_map.map, port->p_power.pairs);
+ case lldpctl_k_dot3_power_class:
+ return map_lookup(port_dot3_power_class_map.map, port->p_power.class);
+ case lldpctl_k_dot3_power_source:
+ return map_lookup((port->p_power.devicetype == LLDP_DOT3_POWER_PSE) ?
+ port_dot3_power_pse_source_map :
+ port_dot3_power_pd_source_map,
+ port->p_power.source);
+ case lldpctl_k_dot3_power_priority:
+ return map_lookup(port_dot3_power_priority_map.map,
+ port->p_power.priority);
+ case lldpctl_k_dot3_power_pd_4pid:
+ return map_lookup(port_dot3_power_pd_4pid_map.map,
+ port->p_power.pd_4pid);
+ case lldpctl_k_dot3_power_pse_status:
+ return map_lookup(port_dot3_power_pse_status_map.map,
+ port->p_power.pse_status);
+ case lldpctl_k_dot3_power_pd_status:
+ return map_lookup(port_dot3_power_pd_status_map.map,
+ port->p_power.pd_status);
+ case lldpctl_k_dot3_power_pse_pairs_ext:
+ return map_lookup(port_dot3_power_pse_pairs_ext_map.map,
+ port->p_power.pse_pairs_ext);
+ case lldpctl_k_dot3_power_class_a:
+ return map_lookup(port_dot3_power_class_a_map.map,
+ port->p_power.class_a);
+ case lldpctl_k_dot3_power_class_b:
+ return map_lookup(port_dot3_power_class_b_map.map,
+ port->p_power.class_b);
+ case lldpctl_k_dot3_power_class_ext:
+ return map_lookup(port_dot3_power_class_ext_map.map,
+ port->p_power.class_ext);
+ case lldpctl_k_dot3_power_type_ext:
+ return map_lookup(port_dot3_power_type_ext_map.map,
+ port->p_power.type_ext);
+ case lldpctl_k_dot3_power_pd_load:
+ return map_lookup(port_dot3_power_pd_load_map.map,
+ port->p_power.pd_load);
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+}
+
+static long int
+_lldpctl_atom_get_int_dot3_power(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ struct _lldpctl_atom_dot3_power_t *dpow =
+ (struct _lldpctl_atom_dot3_power_t *)atom;
+ struct lldpd_port *port = dpow->parent->port;
+
+ /* Local and remote port */
+ switch (key) {
+ case lldpctl_k_dot3_power_devicetype:
+ return port->p_power.devicetype;
+ case lldpctl_k_dot3_power_supported:
+ return port->p_power.supported;
+ case lldpctl_k_dot3_power_enabled:
+ return port->p_power.enabled;
+ case lldpctl_k_dot3_power_paircontrol:
+ return port->p_power.paircontrol;
+ case lldpctl_k_dot3_power_pairs:
+ return port->p_power.pairs;
+ case lldpctl_k_dot3_power_class:
+ return port->p_power.class;
+ case lldpctl_k_dot3_power_type:
+ return port->p_power.powertype;
+ case lldpctl_k_dot3_power_source:
+ return port->p_power.source;
+ case lldpctl_k_dot3_power_priority:
+ return port->p_power.priority;
+ case lldpctl_k_dot3_power_requested:
+ return port->p_power.requested * 100;
+ case lldpctl_k_dot3_power_allocated:
+ return port->p_power.allocated * 100;
+ /* 802.3bt additions */
+ case lldpctl_k_dot3_power_pd_4pid:
+ return port->p_power.pd_4pid;
+ case lldpctl_k_dot3_power_requested_a:
+ return port->p_power.requested_a * 100;
+ case lldpctl_k_dot3_power_requested_b:
+ return port->p_power.requested_b * 100;
+ case lldpctl_k_dot3_power_allocated_a:
+ return port->p_power.allocated_a * 100;
+ case lldpctl_k_dot3_power_allocated_b:
+ return port->p_power.allocated_b * 100;
+ case lldpctl_k_dot3_power_pse_status:
+ return port->p_power.pse_status;
+ case lldpctl_k_dot3_power_pd_status:
+ return port->p_power.pd_status;
+ case lldpctl_k_dot3_power_pse_pairs_ext:
+ return port->p_power.pse_pairs_ext;
+ case lldpctl_k_dot3_power_class_a:
+ return port->p_power.class_a;
+ case lldpctl_k_dot3_power_class_b:
+ return port->p_power.class_b;
+ case lldpctl_k_dot3_power_class_ext:
+ return port->p_power.class_ext;
+ case lldpctl_k_dot3_power_type_ext:
+ return port->p_power.type_ext;
+ case lldpctl_k_dot3_power_pd_load:
+ return port->p_power.pd_load;
+ case lldpctl_k_dot3_power_pse_max:
+ return port->p_power.pse_max * 100;
+ default:
+ return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ }
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_set_int_dot3_power(lldpctl_atom_t *atom, lldpctl_key_t key,
+ long int value)
+{
+ struct _lldpctl_atom_dot3_power_t *dpow =
+ (struct _lldpctl_atom_dot3_power_t *)atom;
+ struct lldpd_port *port = dpow->parent->port;
+
+ /* Only local port can be modified */
+ if (!dpow->parent->local) {
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+
+ switch (key) {
+ case lldpctl_k_dot3_power_devicetype:
+ switch (value) {
+ case 0: /* Disabling */
+ case LLDP_DOT3_POWER_PSE:
+ case LLDP_DOT3_POWER_PD:
+ port->p_power.devicetype = value;
+ return atom;
+ default:
+ goto bad;
+ }
+ case lldpctl_k_dot3_power_supported:
+ switch (value) {
+ case 0:
+ case 1:
+ port->p_power.supported = value;
+ return atom;
+ default:
+ goto bad;
+ }
+ case lldpctl_k_dot3_power_enabled:
+ switch (value) {
+ case 0:
+ case 1:
+ port->p_power.enabled = value;
+ return atom;
+ default:
+ goto bad;
+ }
+ case lldpctl_k_dot3_power_paircontrol:
+ switch (value) {
+ case 0:
+ case 1:
+ port->p_power.paircontrol = value;
+ return atom;
+ default:
+ goto bad;
+ }
+ case lldpctl_k_dot3_power_pairs:
+ switch (value) {
+ case 1:
+ case 2:
+ port->p_power.pairs = value;
+ return atom;
+ default:
+ goto bad;
+ }
+ case lldpctl_k_dot3_power_class:
+ if (value < 0 || value > 5) goto bad;
+ port->p_power.class = value;
+ return atom;
+ case lldpctl_k_dot3_power_type:
+ switch (value) {
+ case LLDP_DOT3_POWER_8023AT_TYPE1:
+ case LLDP_DOT3_POWER_8023AT_TYPE2:
+ case LLDP_DOT3_POWER_8023AT_OFF:
+ port->p_power.powertype = value;
+ return atom;
+ default:
+ goto bad;
+ }
+ case lldpctl_k_dot3_power_source:
+ if (value < 0 || value > 3) goto bad;
+ port->p_power.source = value;
+ return atom;
+ case lldpctl_k_dot3_power_priority:
+ switch (value) {
+ case LLDP_DOT3_POWER_PRIO_UNKNOWN:
+ case LLDP_DOT3_POWER_PRIO_CRITICAL:
+ case LLDP_DOT3_POWER_PRIO_HIGH:
+ case LLDP_DOT3_POWER_PRIO_LOW:
+ port->p_power.priority = value;
+ return atom;
+ default:
+ goto bad;
+ }
+ case lldpctl_k_dot3_power_allocated:
+ if (value < 0) goto bad;
+ port->p_power.allocated = value / 100;
+ return atom;
+ case lldpctl_k_dot3_power_requested:
+ if (value < 0) goto bad;
+ port->p_power.requested = value / 100;
+ return atom;
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+
+ return atom;
+bad:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
+ return NULL;
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_set_str_dot3_power(lldpctl_atom_t *atom, lldpctl_key_t key,
+ const char *value)
+{
+ switch (key) {
+ case lldpctl_k_dot3_power_devicetype:
+ return _lldpctl_atom_set_int_dot3_power(atom, key,
+ map_reverse_lookup(port_dot3_power_devicetype_map, value));
+ case lldpctl_k_dot3_power_pairs:
+ return _lldpctl_atom_set_int_dot3_power(atom, key,
+ map_reverse_lookup(port_dot3_power_pairs_map.map, value));
+ case lldpctl_k_dot3_power_class:
+ return _lldpctl_atom_set_int_dot3_power(atom, key,
+ map_reverse_lookup(port_dot3_power_class_map.map, value));
+ case lldpctl_k_dot3_power_priority:
+ return _lldpctl_atom_set_int_dot3_power(atom, key,
+ map_reverse_lookup(port_dot3_power_priority_map.map, value));
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+}
+
+static struct atom_builder dot3_power = { atom_dot3_power,
+ sizeof(struct _lldpctl_atom_dot3_power_t), .init = _lldpctl_atom_new_dot3_power,
+ .free = _lldpctl_atom_free_dot3_power,
+ .get_int = _lldpctl_atom_get_int_dot3_power,
+ .set_int = _lldpctl_atom_set_int_dot3_power,
+ .get_str = _lldpctl_atom_get_str_dot3_power,
+ .set_str = _lldpctl_atom_set_str_dot3_power };
+
+ATOM_BUILDER_REGISTER(dot3_power, 8);
+
+#endif
diff --git a/src/lib/atoms/interface.c b/src/lib/atoms/interface.c
new file mode 100644
index 0000000..95cae3a
--- /dev/null
+++ b/src/lib/atoms/interface.c
@@ -0,0 +1,118 @@
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * Copyright (c) 2015 Vincent Bernat <vincent@bernat.im>
+ *
+ * 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 <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#include "../lldpctl.h"
+#include "../../log.h"
+#include "../atom.h"
+#include "../helpers.h"
+
+static int
+_lldpctl_atom_new_interfaces_list(lldpctl_atom_t *atom, va_list ap)
+{
+ struct _lldpctl_atom_interfaces_list_t *iflist =
+ (struct _lldpctl_atom_interfaces_list_t *)atom;
+ iflist->ifs = va_arg(ap, struct lldpd_interface_list *);
+ return 1;
+}
+
+static void
+_lldpctl_atom_free_interfaces_list(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_interfaces_list_t *iflist =
+ (struct _lldpctl_atom_interfaces_list_t *)atom;
+ struct lldpd_interface *iface, *iface_next;
+ for (iface = TAILQ_FIRST(iflist->ifs); iface != NULL; iface = iface_next) {
+ /* Don't TAILQ_REMOVE, this is not a real list! */
+ iface_next = TAILQ_NEXT(iface, next);
+ free(iface->name);
+ free(iface);
+ }
+ free(iflist->ifs);
+}
+
+static lldpctl_atom_iter_t *
+_lldpctl_atom_iter_interfaces_list(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_interfaces_list_t *iflist =
+ (struct _lldpctl_atom_interfaces_list_t *)atom;
+ return (lldpctl_atom_iter_t *)TAILQ_FIRST(iflist->ifs);
+}
+
+static lldpctl_atom_iter_t *
+_lldpctl_atom_next_interfaces_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
+{
+ return (lldpctl_atom_iter_t *)TAILQ_NEXT((struct lldpd_interface *)iter, next);
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_value_interfaces_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
+{
+ struct lldpd_interface *iface = (struct lldpd_interface *)iter;
+ return _lldpctl_new_atom(atom->conn, atom_interface, iface->name);
+}
+
+static int
+_lldpctl_atom_new_interface(lldpctl_atom_t *atom, va_list ap)
+{
+ struct _lldpctl_atom_interface_t *port =
+ (struct _lldpctl_atom_interface_t *)atom;
+ port->name = strdup(va_arg(ap, char *));
+ return (port->name != NULL);
+}
+
+static void
+_lldpctl_atom_free_interface(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_interface_t *port =
+ (struct _lldpctl_atom_interface_t *)atom;
+ free(port->name);
+}
+
+static const char *
+_lldpctl_atom_get_str_interface(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ struct _lldpctl_atom_interface_t *port =
+ (struct _lldpctl_atom_interface_t *)atom;
+ switch (key) {
+ case lldpctl_k_interface_name:
+ return port->name;
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+}
+
+static struct atom_builder interfaces_list = { atom_interfaces_list,
+ sizeof(struct _lldpctl_atom_interfaces_list_t),
+ .init = _lldpctl_atom_new_interfaces_list,
+ .free = _lldpctl_atom_free_interfaces_list,
+ .iter = _lldpctl_atom_iter_interfaces_list,
+ .next = _lldpctl_atom_next_interfaces_list,
+ .value = _lldpctl_atom_value_interfaces_list };
+
+static struct atom_builder interface = { atom_interface,
+ sizeof(struct _lldpctl_atom_interface_t), .init = _lldpctl_atom_new_interface,
+ .free = _lldpctl_atom_free_interface,
+ .get_str = _lldpctl_atom_get_str_interface };
+
+ATOM_BUILDER_REGISTER(interfaces_list, 2);
+ATOM_BUILDER_REGISTER(interface, 3);
diff --git a/src/lib/atoms/med.c b/src/lib/atoms/med.c
new file mode 100644
index 0000000..c1e3234
--- /dev/null
+++ b/src/lib/atoms/med.c
@@ -0,0 +1,1123 @@
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * Copyright (c) 2015 Vincent Bernat <vincent@bernat.im>
+ *
+ * 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 <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#include "../lldpctl.h"
+#include "../../log.h"
+#include "../atom.h"
+#include "../helpers.h"
+#include "../fixedpoint.h"
+
+#ifdef ENABLE_LLDPMED
+
+static lldpctl_map_t port_med_location_map[] = {
+ { LLDP_MED_LOCFORMAT_COORD, "Coordinates" },
+ { LLDP_MED_LOCFORMAT_CIVIC, "Civic address" },
+ { LLDP_MED_LOCFORMAT_ELIN, "ELIN" },
+ { 0, NULL },
+};
+
+static lldpctl_map_t port_med_pow_devicetype_map[] = {
+ { LLDP_MED_POW_TYPE_PSE, "PSE" },
+ { LLDP_MED_POW_TYPE_PD, "PD" },
+ { 0, NULL },
+};
+
+static lldpctl_map_t port_med_pow_source_map[] = {
+ { LLDP_MED_POW_SOURCE_PRIMARY, "Primary Power Source" },
+ { LLDP_MED_POW_SOURCE_BACKUP, "Backup Power Source / Power Conservation Mode" },
+ { LLDP_MED_POW_SOURCE_PSE, "PSE" },
+ { LLDP_MED_POW_SOURCE_LOCAL, "Local" },
+ { LLDP_MED_POW_SOURCE_BOTH, "PSE + Local" },
+ { 0, NULL },
+};
+
+static lldpctl_map_t port_med_pow_source_map2[] = {
+ { 0, "unknown" },
+ { LLDP_MED_POW_SOURCE_PRIMARY, "primary" },
+ { LLDP_MED_POW_SOURCE_BACKUP, "backup" },
+ { LLDP_MED_POW_SOURCE_PSE, "pse" },
+ { LLDP_MED_POW_SOURCE_LOCAL, "local" },
+ { LLDP_MED_POW_SOURCE_BOTH, "both" },
+ { 0, NULL },
+};
+
+static struct atom_map port_med_geoid_map = {
+ .key = lldpctl_k_med_location_geoid,
+ .map = {
+ { LLDP_MED_LOCATION_GEOID_WGS84, "WGS84" },
+ { LLDP_MED_LOCATION_GEOID_NAD83, "NAD83" },
+ { LLDP_MED_LOCATION_GEOID_NAD83_MLLW, "NAD83/MLLW" },
+ { 0, NULL },
+ },
+};
+
+static struct atom_map civic_address_type_map = {
+ .key = lldpctl_k_med_civicaddress_type,
+ .map = {
+ { 0, "Language" },
+ { 1, "Country subdivision" },
+ { 2, "County" },
+ { 3, "City" },
+ { 4, "City division" },
+ { 5, "Block" },
+ { 6, "Street" },
+ { 16, "Direction" },
+ { 17, "Trailing street suffix" },
+ { 18, "Street suffix" },
+ { 19, "Number" },
+ { 20, "Number suffix" },
+ { 21, "Landmark" },
+ { 22, "Additional" },
+ { 23, "Name" },
+ { 24, "ZIP" },
+ { 25, "Building" },
+ { 26, "Unit" },
+ { 27, "Floor" },
+ { 28, "Room" },
+ { 29, "Place type" },
+ { 128, "Script" },
+ { 0, NULL },
+ },
+};
+
+static struct atom_map port_med_policy_map = { .key = lldpctl_k_med_policy_type,
+ .map = {
+ { LLDP_MED_APPTYPE_VOICE, "Voice" },
+ { LLDP_MED_APPTYPE_VOICESIGNAL, "Voice Signaling" },
+ { LLDP_MED_APPTYPE_GUESTVOICE, "Guest Voice" },
+ { LLDP_MED_APPTYPE_GUESTVOICESIGNAL, "Guest Voice Signaling" },
+ { LLDP_MED_APPTYPE_SOFTPHONEVOICE, "Softphone Voice" },
+ { LLDP_MED_APPTYPE_VIDEOCONFERENCE, "Video Conferencing" },
+ { LLDP_MED_APPTYPE_VIDEOSTREAM, "Streaming Video" },
+ { LLDP_MED_APPTYPE_VIDEOSIGNAL, "Video Signaling" },
+ { 0, NULL },
+ } };
+
+static struct atom_map port_med_policy_prio_map = {
+ .key = lldpctl_k_med_policy_priority,
+ .map = {
+ { 1, "Background" },
+ { 0, "Best effort" },
+ { 2, "Excellent effort" },
+ { 3, "Critical applications" },
+ { 4, "Video" },
+ { 5, "Voice" },
+ { 6, "Internetwork control" },
+ { 7, "Network control" },
+ { 0, NULL },
+ },
+};
+
+static struct atom_map port_med_pow_priority_map = {
+ .key = lldpctl_k_med_power_priority,
+ .map = {
+ { 0, "unknown" },
+ { LLDP_MED_POW_PRIO_CRITICAL, "critical" },
+ { LLDP_MED_POW_PRIO_HIGH, "high" },
+ { LLDP_MED_POW_PRIO_LOW, "low" },
+ { 0, NULL },
+ },
+};
+
+ATOM_MAP_REGISTER(port_med_geoid_map, 7);
+ATOM_MAP_REGISTER(civic_address_type_map, 8);
+ATOM_MAP_REGISTER(port_med_policy_map, 9);
+ATOM_MAP_REGISTER(port_med_policy_prio_map, 10);
+ATOM_MAP_REGISTER(port_med_pow_priority_map, 11);
+
+static lldpctl_atom_iter_t *
+_lldpctl_atom_iter_med_policies_list(lldpctl_atom_t *atom)
+{
+ int i;
+ struct _lldpctl_atom_any_list_t *vlist =
+ (struct _lldpctl_atom_any_list_t *)atom;
+ for (i = 0; i < LLDP_MED_APPTYPE_LAST; i++)
+ vlist->parent->port->p_med_policy[i].index = i;
+ return (lldpctl_atom_iter_t *)&vlist->parent->port->p_med_policy[0];
+}
+
+static lldpctl_atom_iter_t *
+_lldpctl_atom_next_med_policies_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
+{
+ struct lldpd_med_policy *policy = (struct lldpd_med_policy *)iter;
+ if (policy->index == LLDP_MED_APPTYPE_LAST - 1) return NULL;
+ return (lldpctl_atom_iter_t *)(++policy);
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_value_med_policies_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
+{
+ struct _lldpctl_atom_any_list_t *vlist =
+ (struct _lldpctl_atom_any_list_t *)atom;
+ struct lldpd_med_policy *policy = (struct lldpd_med_policy *)iter;
+ return _lldpctl_new_atom(atom->conn, atom_med_policy, vlist->parent, policy);
+}
+
+static int
+_lldpctl_atom_new_med_policy(lldpctl_atom_t *atom, va_list ap)
+{
+ struct _lldpctl_atom_med_policy_t *policy =
+ (struct _lldpctl_atom_med_policy_t *)atom;
+ policy->parent = va_arg(ap, struct _lldpctl_atom_port_t *);
+ policy->policy = va_arg(ap, struct lldpd_med_policy *);
+ lldpctl_atom_inc_ref((lldpctl_atom_t *)policy->parent);
+ return 1;
+}
+
+static void
+_lldpctl_atom_free_med_policy(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_med_policy_t *policy =
+ (struct _lldpctl_atom_med_policy_t *)atom;
+ lldpctl_atom_dec_ref((lldpctl_atom_t *)policy->parent);
+}
+
+static long int
+_lldpctl_atom_get_int_med_policy(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ struct _lldpctl_atom_med_policy_t *m =
+ (struct _lldpctl_atom_med_policy_t *)atom;
+
+ /* Local and remote port */
+ switch (key) {
+ case lldpctl_k_med_policy_type:
+ return m->policy->type;
+ case lldpctl_k_med_policy_unknown:
+ return m->policy->unknown;
+ case lldpctl_k_med_policy_tagged:
+ return m->policy->tagged;
+ case lldpctl_k_med_policy_vid:
+ return m->policy->vid;
+ case lldpctl_k_med_policy_dscp:
+ return m->policy->dscp;
+ case lldpctl_k_med_policy_priority:
+ return m->policy->priority;
+ default:
+ return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ }
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_set_int_med_policy(lldpctl_atom_t *atom, lldpctl_key_t key,
+ long int value)
+{
+ struct _lldpctl_atom_med_policy_t *m =
+ (struct _lldpctl_atom_med_policy_t *)atom;
+
+ /* Only local port can be modified */
+ if (!m->parent->local) {
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+
+ switch (key) {
+ case lldpctl_k_med_policy_type:
+ /* We let set any policy type, including one whose are not
+ * compatible with the index. If a policy type is set, the index
+ * will be ignored. If a policy type is 0, the index will be
+ * used to know which policy to "erase". */
+ if (value < 0 || value > LLDP_MED_APPTYPE_LAST) goto bad;
+ m->policy->type = value;
+ return atom;
+ case lldpctl_k_med_policy_unknown:
+ if (value != 0 && value != 1) goto bad;
+ m->policy->unknown = value;
+ return atom;
+ case lldpctl_k_med_policy_tagged:
+ if (value != 0 && value != 1) goto bad;
+ m->policy->tagged = value;
+ return atom;
+ case lldpctl_k_med_policy_vid:
+ if (value < 0 || value > 4094) goto bad;
+ m->policy->vid = value;
+ return atom;
+ case lldpctl_k_med_policy_dscp:
+ if (value < 0 || value > 63) goto bad;
+ m->policy->dscp = value;
+ return atom;
+ case lldpctl_k_med_policy_priority:
+ if (value < 0 || value > 7) goto bad;
+ m->policy->priority = value;
+ return atom;
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+
+ return atom;
+bad:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
+ return NULL;
+}
+
+static const char *
+_lldpctl_atom_get_str_med_policy(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ struct _lldpctl_atom_med_policy_t *m =
+ (struct _lldpctl_atom_med_policy_t *)atom;
+
+ /* Local and remote port */
+ switch (key) {
+ case lldpctl_k_med_policy_type:
+ return map_lookup(port_med_policy_map.map, m->policy->type);
+ case lldpctl_k_med_policy_priority:
+ return map_lookup(port_med_policy_prio_map.map, m->policy->priority);
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_set_str_med_policy(lldpctl_atom_t *atom, lldpctl_key_t key,
+ const char *value)
+{
+ /* Local and remote port */
+ switch (key) {
+ case lldpctl_k_med_policy_type:
+ return _lldpctl_atom_set_int_med_policy(atom, key,
+ map_reverse_lookup(port_med_policy_map.map, value));
+ case lldpctl_k_med_policy_priority:
+ return _lldpctl_atom_set_int_med_policy(atom, key,
+ map_reverse_lookup(port_med_policy_prio_map.map, value));
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+}
+
+static lldpctl_atom_iter_t *
+_lldpctl_atom_iter_med_locations_list(lldpctl_atom_t *atom)
+{
+ int i;
+ struct _lldpctl_atom_any_list_t *vlist =
+ (struct _lldpctl_atom_any_list_t *)atom;
+ for (i = 0; i < LLDP_MED_LOCFORMAT_LAST; i++)
+ vlist->parent->port->p_med_location[i].index = i;
+ return (lldpctl_atom_iter_t *)&vlist->parent->port->p_med_location[0];
+}
+
+static lldpctl_atom_iter_t *
+_lldpctl_atom_next_med_locations_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
+{
+ struct lldpd_med_loc *location = (struct lldpd_med_loc *)iter;
+ if (location->index == LLDP_MED_LOCFORMAT_LAST - 1) return NULL;
+ return (lldpctl_atom_iter_t *)(++location);
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_value_med_locations_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
+{
+ struct _lldpctl_atom_any_list_t *vlist =
+ (struct _lldpctl_atom_any_list_t *)atom;
+ struct lldpd_med_loc *location = (struct lldpd_med_loc *)iter;
+ return _lldpctl_new_atom(atom->conn, atom_med_location, vlist->parent,
+ location);
+}
+
+static int
+_lldpctl_atom_new_med_location(lldpctl_atom_t *atom, va_list ap)
+{
+ struct _lldpctl_atom_med_location_t *location =
+ (struct _lldpctl_atom_med_location_t *)atom;
+ location->parent = va_arg(ap, struct _lldpctl_atom_port_t *);
+ location->location = va_arg(ap, struct lldpd_med_loc *);
+ lldpctl_atom_inc_ref((lldpctl_atom_t *)location->parent);
+ return 1;
+}
+
+static void
+_lldpctl_atom_free_med_location(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_med_location_t *location =
+ (struct _lldpctl_atom_med_location_t *)atom;
+ lldpctl_atom_dec_ref((lldpctl_atom_t *)location->parent);
+}
+
+static long int
+_lldpctl_atom_get_int_med_location(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ struct _lldpctl_atom_med_location_t *m =
+ (struct _lldpctl_atom_med_location_t *)atom;
+
+ /* Local and remote port */
+ switch (key) {
+ case lldpctl_k_med_location_format:
+ switch (m->location->format) {
+ case LLDP_MED_LOCFORMAT_COORD:
+ if (m->location->data_len != 16) break;
+ return LLDP_MED_LOCFORMAT_COORD;
+ case LLDP_MED_LOCFORMAT_CIVIC:
+ if ((m->location->data_len < 3) ||
+ (m->location->data_len - 1 < m->location->data[0]))
+ break;
+ return LLDP_MED_LOCFORMAT_CIVIC;
+ case LLDP_MED_LOCFORMAT_ELIN:
+ return LLDP_MED_LOCFORMAT_ELIN;
+ default:
+ return 0;
+ }
+ return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ case lldpctl_k_med_location_geoid:
+ if (m->location->format != LLDP_MED_LOCFORMAT_COORD)
+ return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return m->location->data[15];
+ case lldpctl_k_med_location_altitude_unit:
+ if (m->location->format != LLDP_MED_LOCFORMAT_COORD)
+ return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return (m->location->data[10] & 0xf0) >> 4;
+ default:
+ return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ }
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_set_int_med_location(lldpctl_atom_t *atom, lldpctl_key_t key,
+ long int value)
+{
+ struct _lldpctl_atom_med_location_t *mloc =
+ (struct _lldpctl_atom_med_location_t *)atom;
+
+ /* Only local port can be modified */
+ if (!mloc->parent->local) {
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+
+ switch (key) {
+ case lldpctl_k_med_location_format:
+ switch (value) {
+ case 0: /* Disabling */
+ case LLDP_MED_LOCFORMAT_COORD:
+ mloc->location->format = value;
+ free(mloc->location->data);
+ mloc->location->data = calloc(1, 16);
+ if (mloc->location->data == NULL) {
+ mloc->location->data_len = 0;
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM);
+ return NULL;
+ }
+ mloc->location->data_len = 16;
+ return atom;
+ case LLDP_MED_LOCFORMAT_CIVIC:
+ mloc->location->format = value;
+ free(mloc->location->data);
+ mloc->location->data = calloc(1, 4);
+ if (mloc->location->data == NULL) {
+ mloc->location->data_len = 0;
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM);
+ return NULL;
+ }
+ mloc->location->data_len = 4;
+ mloc->location->data[0] = 3;
+ mloc->location->data[1] = 2; /* Client */
+ mloc->location->data[2] = 'U';
+ mloc->location->data[3] = 'S';
+ return atom;
+ case LLDP_MED_LOCFORMAT_ELIN:
+ mloc->location->format = value;
+ free(mloc->location->data);
+ mloc->location->data = NULL;
+ mloc->location->data_len = 0;
+ return atom;
+ default:
+ goto bad;
+ }
+ case lldpctl_k_med_location_geoid:
+ if (mloc->location->format != LLDP_MED_LOCFORMAT_COORD) goto bad;
+ if (mloc->location->data == NULL || mloc->location->data_len != 16)
+ goto bad;
+ switch (value) {
+ case 0:
+ case LLDP_MED_LOCATION_GEOID_WGS84:
+ case LLDP_MED_LOCATION_GEOID_NAD83:
+ case LLDP_MED_LOCATION_GEOID_NAD83_MLLW:
+ mloc->location->data[15] = value;
+ return atom;
+ default:
+ goto bad;
+ }
+ case lldpctl_k_med_location_altitude_unit:
+ if (mloc->location->format != LLDP_MED_LOCFORMAT_COORD) goto bad;
+ if (mloc->location->data == NULL || mloc->location->data_len != 16)
+ goto bad;
+ switch (value) {
+ case 0:
+ case LLDP_MED_LOCATION_ALTITUDE_UNIT_METER:
+ case LLDP_MED_LOCATION_ALTITUDE_UNIT_FLOOR:
+ mloc->location->data[10] &= 0x0f;
+ mloc->location->data[10] |= value << 4;
+ return atom;
+ default:
+ goto bad;
+ }
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+
+ return atom;
+bad:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
+ return NULL;
+}
+
+static const char *
+read_fixed_precision(lldpctl_atom_t *atom, char *buffer, unsigned shift,
+ unsigned intbits, unsigned fltbits, const char *suffix)
+{
+ struct fp_number fp =
+ fp_buftofp((unsigned char *)buffer, intbits, fltbits, shift);
+ char *result = fp_fptostr(fp, suffix);
+ if (result == NULL) {
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM);
+ return NULL;
+ }
+
+ size_t len = strlen(result) + 1;
+ char *stored = _lldpctl_alloc_in_atom(atom, len);
+ if (stored == NULL) {
+ free(result);
+ return NULL;
+ }
+ strlcpy(stored, result, len);
+ free(result);
+ return stored;
+}
+
+static const char *
+_lldpctl_atom_get_str_med_location(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ struct _lldpctl_atom_med_location_t *m =
+ (struct _lldpctl_atom_med_location_t *)atom;
+ char *value;
+
+ /* Local and remote port */
+ switch (key) {
+ case lldpctl_k_med_location_format:
+ return map_lookup(port_med_location_map, m->location->format);
+ case lldpctl_k_med_location_geoid:
+ if (m->location->format != LLDP_MED_LOCFORMAT_COORD) break;
+ return map_lookup(port_med_geoid_map.map, m->location->data[15]);
+ case lldpctl_k_med_location_latitude:
+ if (m->location->format != LLDP_MED_LOCFORMAT_COORD) break;
+ return read_fixed_precision(atom, m->location->data, 0, 9, 25, "NS");
+ case lldpctl_k_med_location_longitude:
+ if (m->location->format != LLDP_MED_LOCFORMAT_COORD) break;
+ return read_fixed_precision(atom, m->location->data, 40, 9, 25, "EW");
+ case lldpctl_k_med_location_altitude:
+ if (m->location->format != LLDP_MED_LOCFORMAT_COORD) break;
+ return read_fixed_precision(atom, m->location->data, 84, 22, 8, NULL);
+ case lldpctl_k_med_location_altitude_unit:
+ if (m->location->format != LLDP_MED_LOCFORMAT_COORD) break;
+ switch (m->location->data[10] & 0xf0) {
+ case (LLDP_MED_LOCATION_ALTITUDE_UNIT_METER << 4):
+ return "m";
+ case (LLDP_MED_LOCATION_ALTITUDE_UNIT_FLOOR << 4):
+ return "floor";
+ }
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ case lldpctl_k_med_location_country:
+ if (m->location->format != LLDP_MED_LOCFORMAT_CIVIC) break;
+ if (m->location->data_len < 4) return NULL;
+ value = _lldpctl_alloc_in_atom(atom, 3);
+ if (!value) return NULL;
+ memcpy(value, m->location->data + 2, 2);
+ return value;
+ case lldpctl_k_med_location_elin:
+ if (m->location->format != LLDP_MED_LOCFORMAT_ELIN) break;
+ value = _lldpctl_alloc_in_atom(atom, m->location->data_len + 1);
+ if (!value) return NULL;
+ memcpy(value, m->location->data, m->location->data_len);
+ return value;
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_set_str_med_location(lldpctl_atom_t *atom, lldpctl_key_t key,
+ const char *value)
+{
+ struct _lldpctl_atom_med_location_t *mloc =
+ (struct _lldpctl_atom_med_location_t *)atom;
+ struct fp_number fp;
+ char *end = NULL;
+
+ /* Only local port can be modified */
+ if (!mloc->parent->local) {
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+
+ switch (key) {
+ case lldpctl_k_med_location_latitude:
+ if (mloc->location->format != LLDP_MED_LOCFORMAT_COORD) goto bad;
+ if (mloc->location->data == NULL || mloc->location->data_len != 16)
+ goto bad;
+ if (value) fp = fp_strtofp(value, &end, 9, 25);
+ if (!end) goto bad;
+ if (end && *end != '\0') {
+ if (*(end + 1) != '\0') goto bad;
+ if (*end == 'S')
+ fp = fp_negate(fp);
+ else if (*end != 'N')
+ goto bad;
+ }
+ fp_fptobuf(fp, (unsigned char *)mloc->location->data, 0);
+ return atom;
+ case lldpctl_k_med_location_longitude:
+ if (mloc->location->format != LLDP_MED_LOCFORMAT_COORD) goto bad;
+ if (mloc->location->data == NULL || mloc->location->data_len != 16)
+ goto bad;
+ if (value) fp = fp_strtofp(value, &end, 9, 25);
+ if (!end) goto bad;
+ if (end && *end != '\0') {
+ if (*(end + 1) != '\0') goto bad;
+ if (*end == 'W')
+ fp = fp_negate(fp);
+ else if (*end != 'E')
+ goto bad;
+ }
+ fp_fptobuf(fp, (unsigned char *)mloc->location->data, 40);
+ return atom;
+ case lldpctl_k_med_location_altitude:
+ if (mloc->location->format != LLDP_MED_LOCFORMAT_COORD) goto bad;
+ if (mloc->location->data == NULL || mloc->location->data_len != 16)
+ goto bad;
+ if (value) fp = fp_strtofp(value, &end, 22, 8);
+ if (!end || *end != '\0') goto bad;
+ fp_fptobuf(fp, (unsigned char *)mloc->location->data, 84);
+ return atom;
+ case lldpctl_k_med_location_altitude_unit:
+ if (!value) goto bad;
+ if (mloc->location->format != LLDP_MED_LOCFORMAT_COORD) goto bad;
+ if (mloc->location->data == NULL || mloc->location->data_len != 16)
+ goto bad;
+ if (!strcmp(value, "m"))
+ return _lldpctl_atom_set_int_med_location(atom, key,
+ LLDP_MED_LOCATION_ALTITUDE_UNIT_METER);
+ if (!strcmp(value, "f") || (!strcmp(value, "floor")))
+ return _lldpctl_atom_set_int_med_location(atom, key,
+ LLDP_MED_LOCATION_ALTITUDE_UNIT_FLOOR);
+ goto bad;
+ break;
+ case lldpctl_k_med_location_geoid:
+ return _lldpctl_atom_set_int_med_location(atom, key,
+ map_reverse_lookup(port_med_geoid_map.map, value));
+ case lldpctl_k_med_location_country:
+ if (mloc->location->format != LLDP_MED_LOCFORMAT_CIVIC) goto bad;
+ if (mloc->location->data == NULL || mloc->location->data_len < 3)
+ goto bad;
+ if (!value || strlen(value) != 2) goto bad;
+ memcpy(mloc->location->data + 2, value, 2);
+ return atom;
+ case lldpctl_k_med_location_elin:
+ if (!value) goto bad;
+ if (mloc->location->format != LLDP_MED_LOCFORMAT_ELIN) goto bad;
+ free(mloc->location->data);
+ mloc->location->data = calloc(1, strlen(value));
+ if (mloc->location->data == NULL) {
+ mloc->location->data_len = 0;
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM);
+ return NULL;
+ }
+ mloc->location->data_len = strlen(value);
+ memcpy(mloc->location->data, value, mloc->location->data_len);
+ return atom;
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+
+ return atom;
+bad:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
+ return NULL;
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_get_atom_med_location(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ struct _lldpctl_atom_med_location_t *m =
+ (struct _lldpctl_atom_med_location_t *)atom;
+
+ /* Local and remote port */
+ switch (key) {
+ case lldpctl_k_med_location_ca_elements:
+ if (m->location->format != LLDP_MED_LOCFORMAT_CIVIC) {
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+ return _lldpctl_new_atom(atom->conn, atom_med_caelements_list, m);
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_set_atom_med_location(lldpctl_atom_t *atom, lldpctl_key_t key,
+ lldpctl_atom_t *value)
+{
+ struct _lldpctl_atom_med_location_t *m =
+ (struct _lldpctl_atom_med_location_t *)atom;
+ struct _lldpctl_atom_med_caelement_t *el;
+ uint8_t *new;
+
+ /* Only local port can be modified */
+ if (!m->parent->local) {
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+
+ switch (key) {
+ case lldpctl_k_med_location_ca_elements:
+ if (value->type != atom_med_caelement) {
+ SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE);
+ return NULL;
+ }
+ if (m->location->format != LLDP_MED_LOCFORMAT_CIVIC) goto bad;
+ if (m->location->data == NULL || m->location->data_len < 3) goto bad;
+
+ /* We append this element. */
+ el = (struct _lldpctl_atom_med_caelement_t *)value;
+ new = malloc(m->location->data_len + 2 + el->len);
+ if (new == NULL) {
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM);
+ return NULL;
+ }
+ memcpy(new, m->location->data, m->location->data_len);
+ new[m->location->data_len] = el->type;
+ new[m->location->data_len + 1] = el->len;
+ memcpy(new + m->location->data_len + 2, el->value, el->len);
+ new[0] += 2 + el->len;
+ free(m->location->data);
+ m->location->data = (char *)new;
+ m->location->data_len += 2 + el->len;
+ return atom;
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+bad:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
+ return NULL;
+}
+
+struct ca_iter {
+ uint8_t *data;
+ size_t data_len;
+};
+
+static lldpctl_atom_iter_t *
+_lldpctl_atom_iter_med_caelements_list(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_med_caelements_list_t *plist =
+ (struct _lldpctl_atom_med_caelements_list_t *)atom;
+ struct ca_iter *iter;
+ if (plist->parent->location->data_len < 4 ||
+ *(uint8_t *)plist->parent->location->data < 3 ||
+ !(iter = _lldpctl_alloc_in_atom(atom, sizeof(struct ca_iter))))
+ return NULL;
+ iter->data = (uint8_t *)plist->parent->location->data + 4;
+ iter->data_len = *(uint8_t *)plist->parent->location->data - 3;
+ return (lldpctl_atom_iter_t *)iter;
+}
+
+static lldpctl_atom_iter_t *
+_lldpctl_atom_next_med_caelements_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
+{
+ struct ca_iter *cai = (struct ca_iter *)iter;
+ int len;
+ if (cai->data_len < 2) return NULL;
+ len = *((uint8_t *)cai->data + 1);
+ if (cai->data_len < 2 + len) return NULL;
+ cai->data += 2 + len;
+ cai->data_len -= 2 + len;
+ return (lldpctl_atom_iter_t *)cai;
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_value_med_caelements_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
+{
+ struct _lldpctl_atom_med_caelements_list_t *plist =
+ (struct _lldpctl_atom_med_caelements_list_t *)atom;
+ struct ca_iter *cai = (struct ca_iter *)iter;
+ size_t len;
+ if (cai->data_len < 2) return NULL;
+ len = *((uint8_t *)cai->data + 1);
+ if (cai->data_len < 2 + len) return NULL;
+ return _lldpctl_new_atom(atom->conn, atom_med_caelement, plist->parent,
+ (int)*cai->data, cai->data + 2, len);
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_create_med_caelements_list(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_med_caelements_list_t *plist =
+ (struct _lldpctl_atom_med_caelements_list_t *)atom;
+ return _lldpctl_new_atom(atom->conn, atom_med_caelement, plist->parent, -1,
+ NULL, 0);
+}
+
+static int
+_lldpctl_atom_new_med_caelement(lldpctl_atom_t *atom, va_list ap)
+{
+ struct _lldpctl_atom_med_caelement_t *el =
+ (struct _lldpctl_atom_med_caelement_t *)atom;
+ el->parent = va_arg(ap, struct _lldpctl_atom_med_location_t *);
+ el->type = va_arg(ap, int);
+ el->value = va_arg(ap, uint8_t *);
+ el->len = va_arg(ap, size_t);
+ lldpctl_atom_inc_ref((lldpctl_atom_t *)el->parent);
+ return 1;
+}
+
+static void
+_lldpctl_atom_free_med_caelement(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_med_caelement_t *el =
+ (struct _lldpctl_atom_med_caelement_t *)atom;
+ lldpctl_atom_dec_ref((lldpctl_atom_t *)el->parent);
+}
+
+static long int
+_lldpctl_atom_get_int_med_caelement(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ struct _lldpctl_atom_med_caelement_t *m =
+ (struct _lldpctl_atom_med_caelement_t *)atom;
+
+ switch (key) {
+ case lldpctl_k_med_civicaddress_type:
+ return m->type;
+ default:
+ return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ }
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_set_int_med_caelement(lldpctl_atom_t *atom, lldpctl_key_t key,
+ long int value)
+{
+ struct _lldpctl_atom_med_caelement_t *el =
+ (struct _lldpctl_atom_med_caelement_t *)atom;
+
+ /* Only local port can be modified */
+ if (!el->parent->parent->local) {
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+
+ switch (key) {
+ case lldpctl_k_med_civicaddress_type:
+ if (value < 0 || value > 128) goto bad;
+ el->type = value;
+ return atom;
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+
+ return atom;
+bad:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
+ return NULL;
+}
+
+static const char *
+_lldpctl_atom_get_str_med_caelement(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ char *value = NULL;
+ struct _lldpctl_atom_med_caelement_t *m =
+ (struct _lldpctl_atom_med_caelement_t *)atom;
+
+ /* Local and remote port */
+ switch (key) {
+ case lldpctl_k_med_civicaddress_type:
+ return map_lookup(civic_address_type_map.map, m->type);
+ case lldpctl_k_med_civicaddress_value:
+ value = _lldpctl_alloc_in_atom(atom, m->len + 1);
+ if (!value) return NULL;
+ memcpy(value, m->value, m->len);
+ return value;
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_set_str_med_caelement(lldpctl_atom_t *atom, lldpctl_key_t key,
+ const char *value)
+{
+ struct _lldpctl_atom_med_caelement_t *el =
+ (struct _lldpctl_atom_med_caelement_t *)atom;
+ size_t len;
+
+ /* Only local port can be modified */
+ if (!el->parent->parent->local) {
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+
+ switch (key) {
+ case lldpctl_k_med_civicaddress_value:
+ if (!value) goto bad;
+ len = strlen(value) + 1;
+ if (len > 251) goto bad;
+ el->value = _lldpctl_alloc_in_atom(atom, len);
+ if (el->value == NULL) return NULL;
+ strlcpy((char *)el->value, value, len);
+ el->len = strlen(value);
+ return atom;
+ case lldpctl_k_med_civicaddress_type:
+ return _lldpctl_atom_set_int_med_caelement(atom, key,
+ map_reverse_lookup(civic_address_type_map.map, value));
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+
+ return atom;
+bad:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
+ return NULL;
+}
+
+static int
+_lldpctl_atom_new_med_power(lldpctl_atom_t *atom, va_list ap)
+{
+ struct _lldpctl_atom_med_power_t *mpow =
+ (struct _lldpctl_atom_med_power_t *)atom;
+ mpow->parent = va_arg(ap, struct _lldpctl_atom_port_t *);
+ lldpctl_atom_inc_ref((lldpctl_atom_t *)mpow->parent);
+ return 1;
+}
+
+static void
+_lldpctl_atom_free_med_power(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_med_power_t *mpow =
+ (struct _lldpctl_atom_med_power_t *)atom;
+ lldpctl_atom_dec_ref((lldpctl_atom_t *)mpow->parent);
+}
+
+static const char *
+_lldpctl_atom_get_str_med_power(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ struct _lldpctl_atom_med_power_t *mpow =
+ (struct _lldpctl_atom_med_power_t *)atom;
+ struct lldpd_port *port = mpow->parent->port;
+
+ /* Local and remote port */
+ switch (key) {
+ case lldpctl_k_med_power_type:
+ return map_lookup(port_med_pow_devicetype_map,
+ port->p_med_power.devicetype);
+ case lldpctl_k_med_power_source:
+ return map_lookup(port_med_pow_source_map, port->p_med_power.source);
+ case lldpctl_k_med_power_priority:
+ return map_lookup(port_med_pow_priority_map.map,
+ port->p_med_power.priority);
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+}
+
+static long int
+_lldpctl_atom_get_int_med_power(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ struct _lldpctl_atom_med_power_t *dpow =
+ (struct _lldpctl_atom_med_power_t *)atom;
+ struct lldpd_port *port = dpow->parent->port;
+
+ /* Local and remote port */
+ switch (key) {
+ case lldpctl_k_med_power_type:
+ return port->p_med_power.devicetype;
+ case lldpctl_k_med_power_source:
+ return port->p_med_power.source;
+ case lldpctl_k_med_power_priority:
+ return port->p_med_power.priority;
+ case lldpctl_k_med_power_val:
+ return port->p_med_power.val * 100;
+ default:
+ return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ }
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_set_int_med_power(lldpctl_atom_t *atom, lldpctl_key_t key, long int value)
+{
+ struct _lldpctl_atom_med_power_t *dpow =
+ (struct _lldpctl_atom_med_power_t *)atom;
+ struct lldpd_port *port = dpow->parent->port;
+
+ /* Only local port can be modified */
+ if (!dpow->parent->local) {
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+
+ switch (key) {
+ case lldpctl_k_med_power_type:
+ switch (value) {
+ case 0:
+ case LLDP_MED_POW_TYPE_PSE:
+ case LLDP_MED_POW_TYPE_PD:
+ port->p_med_power.devicetype = value;
+ return atom;
+ default:
+ goto bad;
+ }
+ case lldpctl_k_med_power_source:
+ switch (value) {
+ case LLDP_MED_POW_SOURCE_PRIMARY:
+ case LLDP_MED_POW_SOURCE_BACKUP:
+ if (port->p_med_power.devicetype != LLDP_MED_POW_TYPE_PSE)
+ goto bad;
+ port->p_med_power.source = value;
+ return atom;
+ case LLDP_MED_POW_SOURCE_PSE:
+ case LLDP_MED_POW_SOURCE_LOCAL:
+ case LLDP_MED_POW_SOURCE_BOTH:
+ if (port->p_med_power.devicetype != LLDP_MED_POW_TYPE_PD)
+ goto bad;
+ port->p_med_power.source = value;
+ return atom;
+ case LLDP_MED_POW_SOURCE_UNKNOWN:
+ port->p_med_power.source = value;
+ return atom;
+ default:
+ goto bad;
+ }
+ case lldpctl_k_med_power_priority:
+ if (value < 0 || value > 3) goto bad;
+ port->p_med_power.priority = value;
+ return atom;
+ case lldpctl_k_med_power_val:
+ if (value < 0) goto bad;
+ port->p_med_power.val = value / 100;
+ return atom;
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+
+ return atom;
+bad:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE);
+ return NULL;
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_set_str_med_power(lldpctl_atom_t *atom, lldpctl_key_t key,
+ const char *value)
+{
+ switch (key) {
+ case lldpctl_k_med_power_type:
+ return _lldpctl_atom_set_int_med_power(atom, key,
+ map_reverse_lookup(port_med_pow_devicetype_map, value));
+ case lldpctl_k_med_power_source:
+ return _lldpctl_atom_set_int_med_power(atom, key,
+ map_reverse_lookup(port_med_pow_source_map2, value));
+ case lldpctl_k_med_power_priority:
+ return _lldpctl_atom_set_int_med_power(atom, key,
+ map_reverse_lookup(port_med_pow_priority_map.map, value));
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+}
+
+static struct atom_builder med_policies_list = { atom_med_policies_list,
+ sizeof(struct _lldpctl_atom_any_list_t), .init = _lldpctl_atom_new_any_list,
+ .free = _lldpctl_atom_free_any_list,
+ .iter = _lldpctl_atom_iter_med_policies_list,
+ .next = _lldpctl_atom_next_med_policies_list,
+ .value = _lldpctl_atom_value_med_policies_list };
+
+static struct atom_builder med_policy = { atom_med_policy,
+ sizeof(struct _lldpctl_atom_med_policy_t), .init = _lldpctl_atom_new_med_policy,
+ .free = _lldpctl_atom_free_med_policy,
+ .get_int = _lldpctl_atom_get_int_med_policy,
+ .set_int = _lldpctl_atom_set_int_med_policy,
+ .get_str = _lldpctl_atom_get_str_med_policy,
+ .set_str = _lldpctl_atom_set_str_med_policy };
+
+static struct atom_builder med_locations_list = { atom_med_locations_list,
+ sizeof(struct _lldpctl_atom_any_list_t), .init = _lldpctl_atom_new_any_list,
+ .free = _lldpctl_atom_free_any_list,
+ .iter = _lldpctl_atom_iter_med_locations_list,
+ .next = _lldpctl_atom_next_med_locations_list,
+ .value = _lldpctl_atom_value_med_locations_list };
+
+static struct atom_builder med_location = { atom_med_location,
+ sizeof(struct _lldpctl_atom_med_location_t),
+ .init = _lldpctl_atom_new_med_location, .free = _lldpctl_atom_free_med_location,
+ .get = _lldpctl_atom_get_atom_med_location,
+ .set = _lldpctl_atom_set_atom_med_location,
+ .get_int = _lldpctl_atom_get_int_med_location,
+ .set_int = _lldpctl_atom_set_int_med_location,
+ .get_str = _lldpctl_atom_get_str_med_location,
+ .set_str = _lldpctl_atom_set_str_med_location };
+
+static struct atom_builder med_caelements_list = { atom_med_caelements_list,
+ sizeof(struct _lldpctl_atom_med_caelements_list_t),
+ .init = _lldpctl_atom_new_any_list, .free = _lldpctl_atom_free_any_list,
+ .iter = _lldpctl_atom_iter_med_caelements_list,
+ .next = _lldpctl_atom_next_med_caelements_list,
+ .value = _lldpctl_atom_value_med_caelements_list,
+ .create = _lldpctl_atom_create_med_caelements_list };
+
+static struct atom_builder med_caelement = { atom_med_caelement,
+ sizeof(struct _lldpctl_atom_med_caelement_t),
+ .init = _lldpctl_atom_new_med_caelement,
+ .free = _lldpctl_atom_free_med_caelement,
+ .get_int = _lldpctl_atom_get_int_med_caelement,
+ .set_int = _lldpctl_atom_set_int_med_caelement,
+ .get_str = _lldpctl_atom_get_str_med_caelement,
+ .set_str = _lldpctl_atom_set_str_med_caelement };
+
+static struct atom_builder med_power = { atom_med_power,
+ sizeof(struct _lldpctl_atom_med_power_t), .init = _lldpctl_atom_new_med_power,
+ .free = _lldpctl_atom_free_med_power,
+ .get_int = _lldpctl_atom_get_int_med_power,
+ .set_int = _lldpctl_atom_set_int_med_power,
+ .get_str = _lldpctl_atom_get_str_med_power,
+ .set_str = _lldpctl_atom_set_str_med_power };
+
+ATOM_BUILDER_REGISTER(med_policies_list, 15);
+ATOM_BUILDER_REGISTER(med_policy, 16);
+ATOM_BUILDER_REGISTER(med_locations_list, 17);
+ATOM_BUILDER_REGISTER(med_location, 18);
+ATOM_BUILDER_REGISTER(med_caelements_list, 19);
+ATOM_BUILDER_REGISTER(med_caelement, 20);
+ATOM_BUILDER_REGISTER(med_power, 21);
+
+#endif
diff --git a/src/lib/atoms/mgmt.c b/src/lib/atoms/mgmt.c
new file mode 100644
index 0000000..095de76
--- /dev/null
+++ b/src/lib/atoms/mgmt.c
@@ -0,0 +1,149 @@
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * Copyright (c) 2015 Vincent Bernat <vincent@bernat.im>
+ *
+ * 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 <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#include "../lldpctl.h"
+#include "../../log.h"
+#include "../atom.h"
+#include "../helpers.h"
+
+static int
+_lldpctl_atom_new_mgmts_list(lldpctl_atom_t *atom, va_list ap)
+{
+ struct _lldpctl_atom_mgmts_list_t *plist =
+ (struct _lldpctl_atom_mgmts_list_t *)atom;
+ plist->parent = va_arg(ap, lldpctl_atom_t *);
+ plist->chassis = va_arg(ap, struct lldpd_chassis *);
+ lldpctl_atom_inc_ref(plist->parent);
+ return 1;
+}
+
+static void
+_lldpctl_atom_free_mgmts_list(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_mgmts_list_t *plist =
+ (struct _lldpctl_atom_mgmts_list_t *)atom;
+ lldpctl_atom_dec_ref(plist->parent);
+}
+
+static lldpctl_atom_iter_t *
+_lldpctl_atom_iter_mgmts_list(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_mgmts_list_t *plist =
+ (struct _lldpctl_atom_mgmts_list_t *)atom;
+ return (lldpctl_atom_iter_t *)TAILQ_FIRST(&plist->chassis->c_mgmt);
+}
+
+static lldpctl_atom_iter_t *
+_lldpctl_atom_next_mgmts_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
+{
+ struct lldpd_mgmt *mgmt = (struct lldpd_mgmt *)iter;
+ return (lldpctl_atom_iter_t *)TAILQ_NEXT(mgmt, m_entries);
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_value_mgmts_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
+{
+ struct _lldpctl_atom_mgmts_list_t *plist =
+ (struct _lldpctl_atom_mgmts_list_t *)atom;
+ struct lldpd_mgmt *mgmt = (struct lldpd_mgmt *)iter;
+ return _lldpctl_new_atom(atom->conn, atom_mgmt, plist->parent, mgmt);
+}
+
+static int
+_lldpctl_atom_new_mgmt(lldpctl_atom_t *atom, va_list ap)
+{
+ struct _lldpctl_atom_mgmt_t *mgmt = (struct _lldpctl_atom_mgmt_t *)atom;
+ mgmt->parent = va_arg(ap, lldpctl_atom_t *);
+ mgmt->mgmt = va_arg(ap, struct lldpd_mgmt *);
+ lldpctl_atom_inc_ref(mgmt->parent);
+ return 1;
+}
+
+static void
+_lldpctl_atom_free_mgmt(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_mgmt_t *mgmt = (struct _lldpctl_atom_mgmt_t *)atom;
+ lldpctl_atom_dec_ref(mgmt->parent);
+}
+
+static long int
+_lldpctl_atom_get_int_mgmt(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ struct _lldpctl_atom_mgmt_t *m = (struct _lldpctl_atom_mgmt_t *)atom;
+
+ /* Local and remote port */
+ switch (key) {
+ case lldpctl_k_mgmt_iface_index:
+ return m->mgmt->m_iface;
+ default:
+ return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ }
+}
+
+static const char *
+_lldpctl_atom_get_str_mgmt(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ char *ipaddress = NULL;
+ size_t len;
+ int af;
+ struct _lldpctl_atom_mgmt_t *m = (struct _lldpctl_atom_mgmt_t *)atom;
+
+ /* Local and remote port */
+ switch (key) {
+ case lldpctl_k_mgmt_ip:
+ switch (m->mgmt->m_family) {
+ case LLDPD_AF_IPV4:
+ len = INET_ADDRSTRLEN + 1;
+ af = AF_INET;
+ break;
+ case LLDPD_AF_IPV6:
+ len = INET6_ADDRSTRLEN + 1;
+ af = AF_INET6;
+ break;
+ default:
+ len = 0;
+ }
+ if (len == 0) break;
+ ipaddress = _lldpctl_alloc_in_atom(atom, len);
+ if (!ipaddress) return NULL;
+ if (inet_ntop(af, &m->mgmt->m_addr, ipaddress, len) == NULL) break;
+ return ipaddress;
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+}
+
+static struct atom_builder mgmts_list = { atom_mgmts_list,
+ sizeof(struct _lldpctl_atom_mgmts_list_t), .init = _lldpctl_atom_new_mgmts_list,
+ .free = _lldpctl_atom_free_mgmts_list, .iter = _lldpctl_atom_iter_mgmts_list,
+ .next = _lldpctl_atom_next_mgmts_list,
+ .value = _lldpctl_atom_value_mgmts_list };
+
+static struct atom_builder mgmt = { atom_mgmt, sizeof(struct _lldpctl_atom_mgmt_t),
+ .init = _lldpctl_atom_new_mgmt, .free = _lldpctl_atom_free_mgmt,
+ .get_int = _lldpctl_atom_get_int_mgmt, .get_str = _lldpctl_atom_get_str_mgmt };
+
+ATOM_BUILDER_REGISTER(mgmts_list, 6);
+ATOM_BUILDER_REGISTER(mgmt, 7);
diff --git a/src/lib/atoms/port.c b/src/lib/atoms/port.c
new file mode 100644
index 0000000..f99e18b
--- /dev/null
+++ b/src/lib/atoms/port.c
@@ -0,0 +1,862 @@
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * Copyright (c) 2015 Vincent Bernat <vincent@bernat.im>
+ *
+ * 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 <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#include "../lldpctl.h"
+#include "../../log.h"
+#include "../atom.h"
+#include "../helpers.h"
+
+static struct atom_map lldpd_protocol_map = { .key = lldpctl_k_port_protocol,
+ .map = {
+ { LLDPD_MODE_LLDP, "LLDP" },
+ { LLDPD_MODE_CDPV1, "CDPv1" },
+ { LLDPD_MODE_CDPV2, "CDPv2" },
+ { LLDPD_MODE_EDP, "EDP" },
+ { LLDPD_MODE_FDP, "FDP" },
+ { LLDPD_MODE_SONMP, "SONMP" },
+ { 0, NULL },
+ } };
+
+ATOM_MAP_REGISTER(lldpd_protocol_map, 3);
+
+static lldpctl_map_t port_id_subtype_map[] = {
+ { LLDP_PORTID_SUBTYPE_IFNAME, "ifname" },
+ { LLDP_PORTID_SUBTYPE_IFALIAS, "ifalias" },
+ { LLDP_PORTID_SUBTYPE_LOCAL, "local" },
+ { LLDP_PORTID_SUBTYPE_LLADDR, "mac" },
+ { LLDP_PORTID_SUBTYPE_ADDR, "ip" },
+ { LLDP_PORTID_SUBTYPE_PORT, "unhandled" },
+ { LLDP_PORTID_SUBTYPE_AGENTCID, "unhandled" },
+ { 0, NULL },
+};
+
+static struct atom_map port_status_map = { .key = lldpctl_k_port_status,
+ .map = {
+ { LLDPD_RXTX_TXONLY, "TX only" },
+ { LLDPD_RXTX_RXONLY, "RX only" },
+ { LLDPD_RXTX_DISABLED, "disabled" },
+ { LLDPD_RXTX_BOTH, "RX and TX" },
+ { 0, NULL },
+ } };
+
+ATOM_MAP_REGISTER(port_status_map, 3);
+
+#ifdef ENABLE_DOT3
+static lldpctl_map_t operational_mau_type_values[] = {
+ { LLDP_DOT3_MAU_AUI, "AUI - No internal MAU, view from AUI" },
+ { LLDP_DOT3_MAU_10BASE5, "10Base5 - Thick coax MAU" },
+ { LLDP_DOT3_MAU_FOIRL, "Foirl - FOIRL MAU" },
+ { LLDP_DOT3_MAU_10BASE2, "10Base2 - Thin coax MAU" },
+ { LLDP_DOT3_MAU_10BASET, "10BaseT - UTP MAU" },
+ { LLDP_DOT3_MAU_10BASEFP, "10BaseFP - Passive fiber MAU" },
+ { LLDP_DOT3_MAU_10BASEFB, "10BaseFB - Sync fiber MAU" },
+ { LLDP_DOT3_MAU_10BASEFL, "10BaseFL - Async fiber MAU" },
+ { LLDP_DOT3_MAU_10BROAD36, "10Broad36 - Broadband DTE MAU" },
+ { LLDP_DOT3_MAU_10BASETHD, "10BaseTHD - UTP MAU, half duplex mode" },
+ { LLDP_DOT3_MAU_10BASETFD, "10BaseTFD - UTP MAU, full duplex mode" },
+ { LLDP_DOT3_MAU_10BASEFLHD, "10BaseFLHD - Async fiber MAU, half duplex mode" },
+ { LLDP_DOT3_MAU_10BASEFLFD, "10BaseFLDF - Async fiber MAU, full duplex mode" },
+ { LLDP_DOT3_MAU_100BASET4, "100BaseT4 - 4 pair category 3 UTP" },
+ { LLDP_DOT3_MAU_100BASETXHD,
+ "100BaseTXHD - 2 pair category 5 UTP, half duplex mode" },
+ { LLDP_DOT3_MAU_100BASETXFD,
+ "100BaseTXFD - 2 pair category 5 UTP, full duplex mode" },
+ { LLDP_DOT3_MAU_100BASEFXHD,
+ "100BaseFXHD - X fiber over PMT, half duplex mode" },
+ { LLDP_DOT3_MAU_100BASEFXFD,
+ "100BaseFXFD - X fiber over PMT, full duplex mode" },
+ { LLDP_DOT3_MAU_100BASET2HD,
+ "100BaseT2HD - 2 pair category 3 UTP, half duplex mode" },
+ { LLDP_DOT3_MAU_100BASET2FD,
+ "100BaseT2FD - 2 pair category 3 UTP, full duplex mode" },
+ { LLDP_DOT3_MAU_1000BASEXHD,
+ "1000BaseXHD - PCS/PMA, unknown PMD, half duplex mode" },
+ { LLDP_DOT3_MAU_1000BASEXFD,
+ "1000BaseXFD - PCS/PMA, unknown PMD, full duplex mode" },
+ { LLDP_DOT3_MAU_1000BASELXHD,
+ "1000BaseLXHD - Fiber over long-wavelength laser, half duplex mode" },
+ { LLDP_DOT3_MAU_1000BASELXFD,
+ "1000BaseLXFD - Fiber over long-wavelength laser, full duplex mode" },
+ { LLDP_DOT3_MAU_1000BASESXHD,
+ "1000BaseSXHD - Fiber over short-wavelength laser, half duplex mode" },
+ { LLDP_DOT3_MAU_1000BASESXFD,
+ "1000BaseSXFD - Fiber over short-wavelength laser, full duplex mode" },
+ { LLDP_DOT3_MAU_1000BASECXHD,
+ "1000BaseCXHD - Copper over 150-Ohm balanced cable, half duplex mode" },
+ { LLDP_DOT3_MAU_1000BASECXFD,
+ "1000BaseCXFD - Copper over 150-Ohm balanced cable, full duplex mode" },
+ { LLDP_DOT3_MAU_1000BASETHD,
+ "1000BaseTHD - Four-pair Category 5 UTP, half duplex mode" },
+ { LLDP_DOT3_MAU_1000BASETFD,
+ "1000BaseTFD - Four-pair Category 5 UTP, full duplex mode" },
+ { LLDP_DOT3_MAU_10GIGBASEX, "10GigBaseX - X PCS/PMA, unknown PMD." },
+ { LLDP_DOT3_MAU_10GIGBASELX4, "10GigBaseLX4 - X fiber over WWDM optics" },
+ { LLDP_DOT3_MAU_10GIGBASER, "10GigBaseR - R PCS/PMA, unknown PMD." },
+ { LLDP_DOT3_MAU_10GIGBASEER, "10GigBaseER - R fiber over 1550 nm optics" },
+ { LLDP_DOT3_MAU_10GIGBASELR, "10GigBaseLR - R fiber over 1310 nm optics" },
+ { LLDP_DOT3_MAU_10GIGBASESR, "10GigBaseSR - R fiber over 850 nm optics" },
+ { LLDP_DOT3_MAU_10GIGBASEW, "10GigBaseW - W PCS/PMA, unknown PMD." },
+ { LLDP_DOT3_MAU_10GIGBASEEW, "10GigBaseEW - W fiber over 1550 nm optics" },
+ { LLDP_DOT3_MAU_10GIGBASELW, "10GigBaseLW - W fiber over 1310 nm optics" },
+ { LLDP_DOT3_MAU_10GIGBASESW, "10GigBaseSW - W fiber over 850 nm optics" },
+ { LLDP_DOT3_MAU_10GIGBASECX4,
+ "10GigBaseCX4 - X copper over 8 pair 100-Ohm balanced cable" },
+ { LLDP_DOT3_MAU_2BASETL,
+ "2BaseTL - Voice grade UTP copper, up to 2700m, optional PAF" },
+ { LLDP_DOT3_MAU_10PASSTS,
+ "10PassTS - Voice grade UTP copper, up to 750m, optional PAF" },
+ { LLDP_DOT3_MAU_100BASEBX10D,
+ "100BaseBX10D - One single-mode fiber OLT, long wavelength, 10km" },
+ { LLDP_DOT3_MAU_100BASEBX10U,
+ "100BaseBX10U - One single-mode fiber ONU, long wavelength, 10km" },
+ { LLDP_DOT3_MAU_100BASELX10,
+ "100BaseLX10 - Two single-mode fibers, long wavelength, 10km" },
+ { LLDP_DOT3_MAU_1000BASEBX10D,
+ "1000BaseBX10D - One single-mode fiber OLT, long wavelength, 10km" },
+ { LLDP_DOT3_MAU_1000BASEBX10U,
+ "1000BaseBX10U - One single-mode fiber ONU, long wavelength, 10km" },
+ { LLDP_DOT3_MAU_1000BASELX10,
+ "1000BaseLX10 - Two sigle-mode fiber, long wavelength, 10km" },
+ { LLDP_DOT3_MAU_1000BASEPX10D,
+ "1000BasePX10D - One single-mode fiber EPON OLT, 10km" },
+ { LLDP_DOT3_MAU_1000BASEPX10U,
+ "1000BasePX10U - One single-mode fiber EPON ONU, 10km" },
+ { LLDP_DOT3_MAU_1000BASEPX20D,
+ "1000BasePX20D - One single-mode fiber EPON OLT, 20km" },
+ { LLDP_DOT3_MAU_1000BASEPX20U,
+ "1000BasePX20U - One single-mode fiber EPON ONU, 20km" },
+ { LLDP_DOT3_MAU_10GBASET,
+ "10GbaseT - Four-pair Category 6A or better, full duplex mode only" },
+ { LLDP_DOT3_MAU_10GBASELRM,
+ "10GbaseLRM - R multimode fiber over 1310 nm optics" },
+ { LLDP_DOT3_MAU_1000BASEKX, "1000baseKX - X backplane, full duplex mode only" },
+ { LLDP_DOT3_MAU_10GBASEKX4,
+ "10GbaseKX4 - 4 lane X backplane, full duplex mode only" },
+ { LLDP_DOT3_MAU_10GBASEKR, "10GbaseKR - R backplane, full duplex mode only" },
+ { LLDP_DOT3_MAU_10G1GBASEPRXD1,
+ "10G1GbasePRXD1 - One single-mode fiber asymmetric-rate EPON OLT, low power budget (PRX10)" },
+ { LLDP_DOT3_MAU_10G1GBASEPRXD2,
+ "10G1GbasePRXD2 - One single-mode fiber asymmetric-rate EPON OLT, medium power budget (PRX20)" },
+ { LLDP_DOT3_MAU_10G1GBASEPRXD3,
+ "10G1GbasePRXD3 - One single-mode fiber asymmetric-rate EPON OLT, high power budget (PRX30)" },
+ { LLDP_DOT3_MAU_10G1GBASEPRXU1,
+ "10G1GbasePRXU1 - One single-mode fiber asymmetric-rate EPON ONU, low power budget (PRX10)" },
+ { LLDP_DOT3_MAU_10G1GBASEPRXU2,
+ "10G1GbasePRXU2 - One single-mode fiber asymmetric-rate EPON ONU, medium power budget (PRX20)" },
+ { LLDP_DOT3_MAU_10G1GBASEPRXU3,
+ "10G1GbasePRXU3 - One single-mode fiber asymmetric-rate EPON ONU, high power budget (PRX30)" },
+ { LLDP_DOT3_MAU_10GBASEPRD1,
+ "10GbasePRD1 - One single-mode fiber symmetric-rate EPON OLT, low power budget (PR10)" },
+ { LLDP_DOT3_MAU_10GBASEPRD2,
+ "10GbasePRD2 - One single-mode fiber symmetric-rate EPON OLT, medium power budget (PR20)" },
+ { LLDP_DOT3_MAU_10GBASEPRD3,
+ "10GbasePRD3 - One single-mode fiber symmetric-rate EPON OLT, high power budget (PR30)" },
+ { LLDP_DOT3_MAU_10GBASEPRU1,
+ "10GbasePRU1 - One single-mode fiber symmetric-rate EPON ONU, low and medium power budget" },
+ { LLDP_DOT3_MAU_10GBASEPRU3,
+ "10GbasePRU3 - One single-mode fiber symmetric-rate EPON ONU, high power budget (PR30)" },
+ { LLDP_DOT3_MAU_40GBASEKR4,
+ "40GbaseKR4 - 40GBASE-R PCS/PMA over an electrical backplane" },
+ { LLDP_DOT3_MAU_40GBASECR4,
+ "40GbaseCR4 - 40GBASE-R PCS/PMA over 4 lane shielded copper balanced cable" },
+ { LLDP_DOT3_MAU_40GBASESR4,
+ "40GbaseSR4 - 40GBASE-R PCS/PMA over 4 lane multimode fiber" },
+ { LLDP_DOT3_MAU_40GBASEFR,
+ "40GbaseFR - 40GBASE-R PCS/PMA over single mode fiber" },
+ { LLDP_DOT3_MAU_40GBASELR4,
+ "40GbaseLR4 - 40GBASE-R PCS/PMA over 4 WDM lane single mode fiber" },
+ { LLDP_DOT3_MAU_100GBASECR10,
+ "100GbaseCR10 - 100GBASE-R PCS/PMA over 10 lane shielded copper balanced cable" },
+ { LLDP_DOT3_MAU_100GBASESR10,
+ "100GbaseSR10 - 100GBASE-R PCS/PMA over 10 lane multimode fiber" },
+ { LLDP_DOT3_MAU_100GBASELR4,
+ "100GbaseLR4 - 100GBASE-R PCS/PMA over 4 WDM lane single mode fiber, long reach" },
+ { LLDP_DOT3_MAU_100GBASEER4,
+ "100GbaseER4 - 100GBASE-R PCS/PMA over 4 WDM lane single mode fiber PMD, extended reach" },
+ { LLDP_DOT3_MAU_1000BASET1,
+ "1000baseT1 - 1000BASE-T1 single balanced twisted-pair copper cabling PHY" },
+ { LLDP_DOT3_MAU_1000BASEPX30D,
+ "1000basePX30D - One single-mode fiber EPON OLT, 20km, 1:32 split ratio" },
+ { LLDP_DOT3_MAU_1000BASEPX30U,
+ "1000basePX30U - One single-mode fiber EPON ONU, 20km, 1:32 split ratio" },
+ { LLDP_DOT3_MAU_1000BASEPX40D,
+ "1000basePX40D - One single-mode fiber EPON OLT, 20km, 1:64 split ratio" },
+ { LLDP_DOT3_MAU_1000BASEPX40U,
+ "1000basePX40U - One single-mode fiber EPON ONU, 20km, 1:64 split ratio" },
+ { LLDP_DOT3_MAU_10G1GBASEPRXD4,
+ "10G1GbasePRXD4 - One single-mode fiber asymmetric-rate EPON OLT, supporting extended power budget (PRX40)" },
+ { LLDP_DOT3_MAU_10G1GBASEPRXU4,
+ "10G1GbasePRXU4 - One single-mode fiber asymmetric-rate EPON ONU, supporting extended power budget (PRX40)" },
+ { LLDP_DOT3_MAU_10GBASEPRD4,
+ "10GbasePRD4 - One single-mode fiber symmetric-rate EPON OLT, supporting extended power budget (PR40)" },
+ { LLDP_DOT3_MAU_10GBASEPRU4,
+ "10GbasePRU4 - One single-mode fiber symmetric-rate EPON ONU, supporting extended power budget (PR40)" },
+ { LLDP_DOT3_MAU_25GBASECR,
+ "25GbaseCR - 25GBASE-R PCS/PMA over shielded balanced copper cable" },
+ { LLDP_DOT3_MAU_25GBASECRS,
+ "25GbaseCRS - 25GBASE-R PCS/PMA over shielded balanced copper cable without RS-FEC" },
+ { LLDP_DOT3_MAU_25GBASEKR,
+ "25GbaseKR - 25GBASE-R PCS/PMA over an electrical backplane" },
+ { LLDP_DOT3_MAU_25GBASEKRS,
+ "25GbaseKRS - 25GBASE-R PCS/PMA over an electrical backplane without RS-FEC" },
+ { LLDP_DOT3_MAU_25GBASER, "25GbaseR - 25GBASE-R PCS/PMA over undefined PMD" },
+ { LLDP_DOT3_MAU_25GBASESR,
+ "25GbaseSR - 25GBASE-R PCS/PMA over multimode fiber" },
+ { LLDP_DOT3_MAU_25GBASET,
+ "25GbaseT - Four-pair twisted-pair balanced copper cabling" },
+ { LLDP_DOT3_MAU_40GBASEER4,
+ "40GbaseER4 - 40GBASE-R PCS/PMA over 4 WDM lane single mode fiber" },
+ { LLDP_DOT3_MAU_40GBASER,
+ "40GbaseR - 40GBASE-R PCS as over undefined PMA/PMD" },
+ { LLDP_DOT3_MAU_40GBASET,
+ "40GbaseT - Four-pair twisted-pair balanced copper cabling" },
+ { LLDP_DOT3_MAU_100GBASECR4,
+ "100GbaseCR4 - 100GBASE-R PCS/PMA over 4 lane shielded copper balanced cable" },
+ { LLDP_DOT3_MAU_100GBASEKR4,
+ "100GbaseKR4 - 100GBASE-R PCS/PMA over an electrical backplane" },
+ { LLDP_DOT3_MAU_100GBASEKP4,
+ "100GbaseKP4 - 100GBASE-P PCS/PMA over an electrical backplane PMD" },
+ { LLDP_DOT3_MAU_100GBASER,
+ "100GbaseR - 100GBASE-R Multi-lane PCS over undefined PMA/PMD" },
+ { LLDP_DOT3_MAU_100GBASESR4,
+ "100GbaseSR4 - 100GBASE-R PCS/PMA over 4 lane multimode fiber" },
+ { LLDP_DOT3_MAU_2P5GIGT,
+ "2p5GigT - 2.5GBASE-T Four-pair twisted-pair balanced copper cabling PHY" },
+ { LLDP_DOT3_MAU_5GIGT,
+ "5GigT - 5GBASE-T Four-pair twisted-pair balanced copper cabling PHY" },
+ { LLDP_DOT3_MAU_100BASET1,
+ "100baseT1 - 100BASE-T1 Single balanced twisted-pair copper cabling PHY" },
+ { LLDP_DOT3_MAU_1000BASERHA,
+ "1000baseRHA - 1000BASE-RHA Plastic optical fiber PHY" },
+ { LLDP_DOT3_MAU_1000BASERHB,
+ "1000baseRHB - 1000BASE-RHB Plastic optical fiber PHY" },
+ { LLDP_DOT3_MAU_1000BASERHC,
+ "1000baseRHC - 1000BASE-RHC Plastic optical fiber PHY" },
+ { LLDP_DOT3_MAU_2P5GBASEKX,
+ "2p5GbaseKX - 2.5GBASE-X PMD over an electrical backplane" },
+ { LLDP_DOT3_MAU_2P5GBASEX,
+ "2p5GbaseX - 2.5GBASE-X PCS/PMA over undefined PMD" },
+ { LLDP_DOT3_MAU_5GBASEKR,
+ "5GbaseKR - 5GBASE-KR PMD over an electrical backplane" },
+ { LLDP_DOT3_MAU_5GBASER, "5GbaseR - 5GBASE-R PCS/PMA over undefined PMD" },
+ { LLDP_DOT3_MAU_10GPASSXR,
+ "10GpassXR - Coax cable distribution network PHY continuous downstream/burst mode upstream PHY" },
+ { LLDP_DOT3_MAU_25GBASELR,
+ "25GbaseLR - 25GBASE-R PCS/PMA over single-mode fiber PMD, with long reach" },
+ { LLDP_DOT3_MAU_25GBASEER,
+ "25GbaseER - 25GBASE-R PCS/PMA over single-mode fiber PMD, with extended reach" },
+ { LLDP_DOT3_MAU_50GBASER,
+ "50GbaseR - 50GBASE-R Multi-lane PCS over undefined PMA/PMD" },
+ { LLDP_DOT3_MAU_50GBASECR,
+ "50GbaseCR - 50GBASE-R PCS/PMA over shielded copper balanced cable PMD" },
+ { LLDP_DOT3_MAU_50GBASEKR,
+ "50GbaseKR - 50GBASE-R PCS/PMA over an electrical backplane PMD" },
+ { LLDP_DOT3_MAU_50GBASESR,
+ "50GbaseSR - 50GBASE-R PCS/PMA over multimode fiber PMD" },
+ { LLDP_DOT3_MAU_50GBASEFR,
+ "50GbaseFR - 50GBASE-R PCS/PMA over single mode fiber PMD with reach up to at least 2 km" },
+ { LLDP_DOT3_MAU_50GBASELR,
+ "50GbaseLR - 50GBASE-R PCS/PMA over single mode fiber PMD with reach up to at least 10 km" },
+ { LLDP_DOT3_MAU_50GBASEER,
+ "50GbaseER - 50GBASE-R PCS/PMA over single-mode fiber PMD with reach up to at least 40 km" },
+ { LLDP_DOT3_MAU_100GBASECR2,
+ "100GbaseCR2 - 100GBASE-R PCS/PMA over 2 lane shielded copper balanced cable PMD" },
+ { LLDP_DOT3_MAU_100GBASEKR2,
+ "100GbaseKR2 - 100GBASE-R PCS/PMA over an electrical backplane PMD" },
+ { LLDP_DOT3_MAU_100GBASESR2,
+ "100GbaseSR2 - 100GBASE-R PCS/PMA over 2 lane multimode fiber PMD" },
+ { LLDP_DOT3_MAU_100GBASEDR,
+ "100GbaseDR - 100GBASE-R PCS/PMA over single mode fiber PMD" },
+ { LLDP_DOT3_MAU_200GBASER,
+ "200GbaseR - 200GBASE-R Multi-lane PCS over undefined PMA/PMD" },
+ { LLDP_DOT3_MAU_200GBASEDR4,
+ "200GbaseDR4 - 200GBASE-R PCS/PMA over 4-lane single-mode fiber PMD" },
+ { LLDP_DOT3_MAU_200GBASEFR4,
+ "200GbaseFR4 - 200GBASE-R PCS/PMA over 4 WDM lane single-mode fiber PMD with reach up to at least 2 km" },
+ { LLDP_DOT3_MAU_200GBASELR4,
+ "200GbaseLR4 - 200GBASE-R PCS/PMA over 4 WDM lane single-mode fiber PMD with reach up to at least 10 km" },
+ { LLDP_DOT3_MAU_200GBASECR4,
+ "200GbaseCR4 - 200GBASE-R PCS/PMA over 4 lane shielded copper balanced cable PMD" },
+ { LLDP_DOT3_MAU_200GBASEKR4,
+ "200GbaseKR4 - 200GBASE-R PCS/PMA over an electrical backplane PMD" },
+ { LLDP_DOT3_MAU_200GBASESR4,
+ "200GbaseSR4 - 200GBASE-R PCS/PMA over 4 lane multimode fiber PMD" },
+ { LLDP_DOT3_MAU_200GBASEER4,
+ "200GbaseER4 - 200GBASE-R PCS/PMA over 4 WDM lane single-mode fiber PMD with reach up to at least 40 km" },
+ { LLDP_DOT3_MAU_400GBASER,
+ "400GbaseR - 400GBASE-R Multi-lane PCS over undefined PMA/PMD" },
+ { LLDP_DOT3_MAU_400GBASESR16,
+ "400GbaseSR16 - 400GBASE-R PCS/PMA over 16-lane multimode fiber PMD" },
+ { LLDP_DOT3_MAU_400GBASEDR4,
+ "400GbaseDR4 - 400GBASE-R PCS/PMA over 4-lane single-mode fiber PMD" },
+ { LLDP_DOT3_MAU_400GBASEFR8,
+ "400GbaseFR8 - 400GBASE-R PCS/PMA over 8 WDM lane single-mode fiber PMD with reach up to at least 2 km" },
+ { LLDP_DOT3_MAU_400GBASELR8,
+ "400GbaseLR8 - 400GBASE-R PCS/PMA over 8 WDM lane single-mode fiber PMD with reach up to at least 10 km" },
+ { LLDP_DOT3_MAU_400GBASEER8,
+ "400GbaseER8 - 400GBASE-R PCS/PMA over 8 WDM lane single-mode fiber PMD with reach up to at least 40 km" },
+ { LLDP_DOT3_MAU_10BASET1L, "10baseT1L - 10BASE-T1L Single balanced pair PHY" },
+ { LLDP_DOT3_MAU_10BASET1SHD,
+ "10baseT1SHD - 10BASE-T1S Single balanced pair PHY, half duplex mode" },
+ { LLDP_DOT3_MAU_10BASET1SMD,
+ "10baseT1SMD - 10BASE-T1S Single balanced pair PHY, multidrop mode" },
+ { LLDP_DOT3_MAU_10BASET1SFD,
+ "10baseT1SFD - 10BASE-T1S Single balanced pair PHY, full duplex mode" },
+ { 0, NULL }
+};
+#endif
+
+static lldpctl_atom_iter_t *
+_lldpctl_atom_iter_ports_list(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_any_list_t *plist =
+ (struct _lldpctl_atom_any_list_t *)atom;
+ return (lldpctl_atom_iter_t *)TAILQ_FIRST(&plist->parent->hardware->h_rports);
+}
+
+static lldpctl_atom_iter_t *
+_lldpctl_atom_next_ports_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
+{
+ struct lldpd_port *port = (struct lldpd_port *)iter;
+ return (lldpctl_atom_iter_t *)TAILQ_NEXT(port, p_entries);
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_value_ports_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
+{
+ struct lldpd_port *port = (struct lldpd_port *)iter;
+ return _lldpctl_new_atom(atom->conn, atom_port, 0, NULL, port,
+ ((struct _lldpctl_atom_any_list_t *)atom)->parent);
+}
+
+static int
+_lldpctl_atom_new_port(lldpctl_atom_t *atom, va_list ap)
+{
+ struct _lldpctl_atom_port_t *port = (struct _lldpctl_atom_port_t *)atom;
+ port->local = va_arg(ap, int);
+ port->hardware = va_arg(ap, struct lldpd_hardware *);
+ port->port = va_arg(ap, struct lldpd_port *);
+ port->parent = va_arg(ap, struct _lldpctl_atom_port_t *);
+ if (port->parent) lldpctl_atom_inc_ref((lldpctl_atom_t *)port->parent);
+
+ if (port->port) {
+ /* Internal atom. We are the parent, but our reference count is
+ * not incremented. */
+ port->chassis = _lldpctl_new_atom(atom->conn, atom_chassis,
+ port->port->p_chassis, port, 1);
+ }
+ return 1;
+}
+
+TAILQ_HEAD(chassis_list, lldpd_chassis);
+
+static void
+add_chassis(struct chassis_list *chassis_list, struct lldpd_chassis *chassis)
+{
+ struct lldpd_chassis *one_chassis;
+ TAILQ_FOREACH (one_chassis, chassis_list, c_entries) {
+ if (one_chassis == chassis) return;
+ }
+ TAILQ_INSERT_TAIL(chassis_list, chassis, c_entries);
+}
+
+static void
+_lldpctl_atom_free_port(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_port_t *port = (struct _lldpctl_atom_port_t *)atom;
+ struct lldpd_hardware *hardware = port->hardware;
+ struct lldpd_chassis *one_chassis, *one_chassis_next;
+ struct lldpd_port *one_port;
+
+ /* Free internal chassis atom. Should be freed immediately since we
+ * should have the only reference. */
+ lldpctl_atom_dec_ref((lldpctl_atom_t *)port->chassis);
+
+ /* We need to free the whole struct lldpd_hardware: local port, local
+ * chassis and remote ports... The same chassis may be present several
+ * times. We build a list of chassis (we don't use reference count). */
+ struct chassis_list chassis_list;
+ TAILQ_INIT(&chassis_list);
+
+ if (port->parent)
+ lldpctl_atom_dec_ref((lldpctl_atom_t *)port->parent);
+ else if (!hardware && port->port) {
+ /* No parent, no hardware, we assume a single neighbor: one
+ * port, one chassis. */
+ if (port->port->p_chassis) {
+ lldpd_chassis_cleanup(port->port->p_chassis, 1);
+ port->port->p_chassis = NULL;
+ }
+ lldpd_port_cleanup(port->port, 1);
+ free(port->port);
+ }
+ if (!hardware) return;
+
+ add_chassis(&chassis_list, port->port->p_chassis);
+ TAILQ_FOREACH (one_port, &hardware->h_rports, p_entries)
+ add_chassis(&chassis_list, one_port->p_chassis);
+
+ /* Free hardware port */
+ lldpd_remote_cleanup(hardware, NULL, 1);
+ lldpd_port_cleanup(port->port, 1);
+ free(port->hardware);
+
+ /* Free list of chassis */
+ for (one_chassis = TAILQ_FIRST(&chassis_list); one_chassis != NULL;
+ one_chassis = one_chassis_next) {
+ one_chassis_next = TAILQ_NEXT(one_chassis, c_entries);
+ lldpd_chassis_cleanup(one_chassis, 1);
+ }
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_get_atom_port(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ struct _lldpctl_atom_port_t *p = (struct _lldpctl_atom_port_t *)atom;
+ struct lldpd_port *port = p->port;
+ struct lldpd_hardware *hardware = p->hardware;
+
+ /* Local port only */
+ if (hardware != NULL) {
+ switch (key) {
+ case lldpctl_k_port_neighbors:
+ return _lldpctl_new_atom(atom->conn, atom_ports_list, p);
+ default:
+ break;
+ }
+ }
+
+ /* Local and remote port */
+ switch (key) {
+ case lldpctl_k_port_chassis:
+ if (port->p_chassis) {
+ return _lldpctl_new_atom(atom->conn, atom_chassis,
+ port->p_chassis, p, 0);
+ }
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+#ifdef ENABLE_DOT3
+ case lldpctl_k_port_dot3_power:
+ return _lldpctl_new_atom(atom->conn, atom_dot3_power, p);
+#endif
+#ifdef ENABLE_DOT1
+ case lldpctl_k_port_vlans:
+ return _lldpctl_new_atom(atom->conn, atom_vlans_list, p);
+ case lldpctl_k_port_ppvids:
+ return _lldpctl_new_atom(atom->conn, atom_ppvids_list, p);
+ case lldpctl_k_port_pis:
+ return _lldpctl_new_atom(atom->conn, atom_pis_list, p);
+#endif
+#ifdef ENABLE_LLDPMED
+ case lldpctl_k_port_med_policies:
+ return _lldpctl_new_atom(atom->conn, atom_med_policies_list, p);
+ case lldpctl_k_port_med_locations:
+ return _lldpctl_new_atom(atom->conn, atom_med_locations_list, p);
+ case lldpctl_k_port_med_power:
+ return _lldpctl_new_atom(atom->conn, atom_med_power, p);
+#endif
+#ifdef ENABLE_CUSTOM
+ case lldpctl_k_custom_tlvs:
+ return _lldpctl_new_atom(atom->conn, atom_custom_list, p);
+#endif
+ default:
+ /* Compatibility: query the associated chassis too */
+ if (port->p_chassis) return lldpctl_atom_get(p->chassis, key);
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_set_atom_port(lldpctl_atom_t *atom, lldpctl_key_t key,
+ lldpctl_atom_t *value)
+{
+ struct _lldpctl_atom_port_t *p = (struct _lldpctl_atom_port_t *)atom;
+ struct lldpd_hardware *hardware = p->hardware;
+ struct lldpd_port_set set = {};
+ int rc;
+ char *canary = NULL;
+
+#ifdef ENABLE_DOT3
+ struct _lldpctl_atom_dot3_power_t *dpow;
+#endif
+#ifdef ENABLE_LLDPMED
+ struct _lldpctl_atom_med_power_t *mpow;
+ struct _lldpctl_atom_med_policy_t *mpol;
+ struct _lldpctl_atom_med_location_t *mloc;
+#endif
+#ifdef ENABLE_CUSTOM
+ struct _lldpctl_atom_custom_t *custom;
+#endif
+
+ /* Local and default port only */
+ if (!p->local) {
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+
+ set.vlan_tx_enabled = -1;
+
+ switch (key) {
+ case lldpctl_k_port_id:
+ set.local_id = p->port->p_id;
+ break;
+ case lldpctl_k_port_descr:
+ set.local_descr = p->port->p_descr;
+ break;
+ case lldpctl_k_port_status:
+ set.rxtx = LLDPD_RXTX_FROM_PORT(p->port);
+ break;
+ case lldpctl_k_port_vlan_tx:
+ set.vlan_tx_tag = p->port->p_vlan_tx_tag;
+ set.vlan_tx_enabled = p->port->p_vlan_tx_enabled;
+ break;
+#ifdef ENABLE_DOT3
+ case lldpctl_k_port_dot3_power:
+ if (value->type != atom_dot3_power) {
+ SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE);
+ return NULL;
+ }
+
+ dpow = (struct _lldpctl_atom_dot3_power_t *)value;
+ set.dot3_power = &dpow->parent->port->p_power;
+ break;
+#endif
+#ifdef ENABLE_LLDPMED
+ case lldpctl_k_port_med_power:
+ if (value->type != atom_med_power) {
+ SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE);
+ return NULL;
+ }
+
+ mpow = (struct _lldpctl_atom_med_power_t *)value;
+ set.med_power = &mpow->parent->port->p_med_power;
+ break;
+ case lldpctl_k_port_med_policies:
+ if (value->type != atom_med_policy) {
+ SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE);
+ return NULL;
+ }
+ mpol = (struct _lldpctl_atom_med_policy_t *)value;
+ set.med_policy = mpol->policy;
+ break;
+ case lldpctl_k_port_med_locations:
+ if (value->type != atom_med_location) {
+ SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE);
+ return NULL;
+ }
+ mloc = (struct _lldpctl_atom_med_location_t *)value;
+ set.med_location = mloc->location;
+ break;
+#endif
+#ifdef ENABLE_CUSTOM
+ case lldpctl_k_custom_tlvs_clear:
+ set.custom_list_clear = 1;
+ break;
+ case lldpctl_k_custom_tlv:
+ if (value->type != atom_custom) {
+ SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE);
+ return NULL;
+ }
+ custom = (struct _lldpctl_atom_custom_t *)value;
+ set.custom = custom->tlv;
+ set.custom_tlv_op = custom->op;
+ break;
+#endif
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+
+ char empty_str[] = "";
+ set.ifname = hardware ? hardware->h_ifname : empty_str;
+
+ if (asprintf(&canary, "%d%p%s", key, value, set.ifname) == -1) {
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM);
+ return NULL;
+ }
+ rc = _lldpctl_do_something(atom->conn, CONN_STATE_SET_PORT_SEND,
+ CONN_STATE_SET_PORT_RECV, canary, SET_PORT, &set,
+ &MARSHAL_INFO(lldpd_port_set), NULL, NULL);
+ free(canary);
+ if (rc == 0) return atom;
+ return NULL;
+}
+
+static const char *
+_lldpctl_atom_get_str_port(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ struct _lldpctl_atom_port_t *p = (struct _lldpctl_atom_port_t *)atom;
+ struct lldpd_port *port = p->port;
+ struct lldpd_hardware *hardware = p->hardware;
+ char *ipaddress = NULL;
+ size_t len;
+
+ /* Local port only */
+ switch (key) {
+ case lldpctl_k_port_name:
+ if (hardware != NULL) return hardware->h_ifname;
+ break;
+ case lldpctl_k_port_status:
+ if (p->local)
+ return map_lookup(port_status_map.map,
+ LLDPD_RXTX_FROM_PORT(port));
+ break;
+ default:
+ break;
+ }
+
+ if (!port) return NULL;
+
+ /* Local and remote port */
+ switch (key) {
+ case lldpctl_k_port_protocol:
+ return map_lookup(lldpd_protocol_map.map, port->p_protocol);
+ case lldpctl_k_port_id_subtype:
+ return map_lookup(port_id_subtype_map, port->p_id_subtype);
+ case lldpctl_k_port_id:
+ switch (port->p_id_subtype) {
+ case LLDP_PORTID_SUBTYPE_IFNAME:
+ case LLDP_PORTID_SUBTYPE_IFALIAS:
+ case LLDP_PORTID_SUBTYPE_LOCAL:
+ return port->p_id;
+ case LLDP_PORTID_SUBTYPE_LLADDR:
+ return _lldpctl_dump_in_atom(atom, (uint8_t *)port->p_id,
+ port->p_id_len, ':', 0);
+ case LLDP_PORTID_SUBTYPE_ADDR:
+ switch (port->p_id[0]) {
+ case LLDP_MGMT_ADDR_IP4:
+ len = INET_ADDRSTRLEN + 1;
+ break;
+ case LLDP_MGMT_ADDR_IP6:
+ len = INET6_ADDRSTRLEN + 1;
+ break;
+ default:
+ len = 0;
+ }
+ if (len > 0) {
+ ipaddress = _lldpctl_alloc_in_atom(atom, len);
+ if (!ipaddress) return NULL;
+ if (inet_ntop((port->p_id[0] == LLDP_MGMT_ADDR_IP4) ?
+ AF_INET :
+ AF_INET6,
+ &port->p_id[1], ipaddress, len) == NULL)
+ break;
+ return ipaddress;
+ }
+ break;
+ }
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ case lldpctl_k_port_descr:
+ return port->p_descr;
+
+#ifdef ENABLE_DOT3
+ case lldpctl_k_port_dot3_mautype:
+ return map_lookup(operational_mau_type_values, port->p_macphy.mau_type);
+#endif
+
+ default:
+ /* Compatibility: query the associated chassis too */
+ return lldpctl_atom_get_str(p->chassis, key);
+ }
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_set_int_port(lldpctl_atom_t *atom, lldpctl_key_t key, long int value)
+{
+ struct _lldpctl_atom_port_t *p = (struct _lldpctl_atom_port_t *)atom;
+ struct lldpd_port *port = p->port;
+
+ if (p->local) {
+ switch (key) {
+ case lldpctl_k_port_status:
+ port->p_disable_rx = !LLDPD_RXTX_RXENABLED(value);
+ port->p_disable_tx = !LLDPD_RXTX_TXENABLED(value);
+ break;
+ case lldpctl_k_port_vlan_tx:
+ if (value > -1) {
+ port->p_vlan_tx_tag = value;
+ port->p_vlan_tx_enabled = 1;
+ } else
+ port->p_vlan_tx_enabled = 0;
+ break;
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+ } else {
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+
+ return _lldpctl_atom_set_atom_port(atom, key, NULL);
+}
+
+static lldpctl_atom_t *
+_lldpctl_atom_set_str_port(lldpctl_atom_t *atom, lldpctl_key_t key, const char *value)
+{
+ struct _lldpctl_atom_port_t *p = (struct _lldpctl_atom_port_t *)atom;
+ struct lldpd_port *port = p->port;
+
+ if (!value || !strlen(value)) return NULL;
+
+ if (p->local) {
+ switch (key) {
+ case lldpctl_k_port_status:
+ return _lldpctl_atom_set_int_port(atom, key,
+ map_reverse_lookup(port_status_map.map, value));
+ default:
+ break;
+ }
+ }
+
+ switch (key) {
+ case lldpctl_k_port_id:
+ free(port->p_id);
+ port->p_id = strdup(value);
+ port->p_id_len = strlen(value);
+ break;
+ case lldpctl_k_port_descr:
+ free(port->p_descr);
+ port->p_descr = strdup(value);
+ break;
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+
+ return _lldpctl_atom_set_atom_port(atom, key, NULL);
+}
+
+static long int
+_lldpctl_atom_get_int_port(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ struct _lldpctl_atom_port_t *p = (struct _lldpctl_atom_port_t *)atom;
+ struct lldpd_port *port = p->port;
+ struct lldpd_hardware *hardware = p->hardware;
+
+ /* Local port only */
+ if (hardware != NULL) {
+ switch (key) {
+ case lldpctl_k_port_index:
+ return hardware->h_ifindex;
+ case lldpctl_k_tx_cnt:
+ return hardware->h_tx_cnt;
+ case lldpctl_k_rx_cnt:
+ return hardware->h_rx_cnt;
+ case lldpctl_k_rx_discarded_cnt:
+ return hardware->h_rx_discarded_cnt;
+ case lldpctl_k_rx_unrecognized_cnt:
+ return hardware->h_rx_unrecognized_cnt;
+ case lldpctl_k_ageout_cnt:
+ return hardware->h_ageout_cnt;
+ case lldpctl_k_insert_cnt:
+ return hardware->h_insert_cnt;
+ case lldpctl_k_delete_cnt:
+ return hardware->h_delete_cnt;
+ default:
+ break;
+ }
+ }
+ if (p->local) {
+ switch (key) {
+ case lldpctl_k_port_status:
+ return LLDPD_RXTX_FROM_PORT(port);
+ default:
+ break;
+ }
+ }
+ if (!port) return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+
+ /* Local and remote port */
+ switch (key) {
+ case lldpctl_k_port_protocol:
+ return port->p_protocol;
+ case lldpctl_k_port_age:
+ return port->p_lastchange;
+ case lldpctl_k_port_ttl:
+ return port->p_ttl;
+ case lldpctl_k_port_id_subtype:
+ return port->p_id_subtype;
+ case lldpctl_k_port_hidden:
+ return port->p_hidden_in;
+ case lldpctl_k_port_vlan_tx:
+ return port->p_vlan_tx_enabled ? port->p_vlan_tx_tag : -1;
+#ifdef ENABLE_DOT3
+ case lldpctl_k_port_dot3_mfs:
+ if (port->p_mfs > 0) return port->p_mfs;
+ break;
+ case lldpctl_k_port_dot3_aggregid:
+ if (port->p_aggregid > 0) return port->p_aggregid;
+ break;
+ case lldpctl_k_port_dot3_autoneg_support:
+ return port->p_macphy.autoneg_support;
+ case lldpctl_k_port_dot3_autoneg_enabled:
+ return port->p_macphy.autoneg_enabled;
+ case lldpctl_k_port_dot3_autoneg_advertised:
+ return port->p_macphy.autoneg_advertised;
+ case lldpctl_k_port_dot3_mautype:
+ return port->p_macphy.mau_type;
+#endif
+#ifdef ENABLE_DOT1
+ case lldpctl_k_port_vlan_pvid:
+ return port->p_pvid;
+#endif
+ default:
+ /* Compatibility: query the associated chassis too */
+ return lldpctl_atom_get_int(p->chassis, key);
+ }
+ return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+}
+
+static const uint8_t *
+_lldpctl_atom_get_buf_port(lldpctl_atom_t *atom, lldpctl_key_t key, size_t *n)
+{
+ struct _lldpctl_atom_port_t *p = (struct _lldpctl_atom_port_t *)atom;
+ struct lldpd_port *port = p->port;
+
+ switch (key) {
+ case lldpctl_k_port_id:
+ *n = port->p_id_len;
+ return (uint8_t *)port->p_id;
+ default:
+ /* Compatibility: query the associated chassis too */
+ return lldpctl_atom_get_buffer(p->chassis, key, n);
+ }
+}
+
+static struct atom_builder ports_list = { atom_ports_list,
+ sizeof(struct _lldpctl_atom_any_list_t), .init = _lldpctl_atom_new_any_list,
+ .free = _lldpctl_atom_free_any_list, .iter = _lldpctl_atom_iter_ports_list,
+ .next = _lldpctl_atom_next_ports_list,
+ .value = _lldpctl_atom_value_ports_list };
+
+static struct atom_builder port = { atom_port, sizeof(struct _lldpctl_atom_port_t),
+ .init = _lldpctl_atom_new_port, .free = _lldpctl_atom_free_port,
+ .get = _lldpctl_atom_get_atom_port, .set = _lldpctl_atom_set_atom_port,
+ .get_str = _lldpctl_atom_get_str_port, .set_str = _lldpctl_atom_set_str_port,
+ .get_int = _lldpctl_atom_get_int_port, .set_int = _lldpctl_atom_set_int_port,
+ .get_buffer = _lldpctl_atom_get_buf_port };
+
+ATOM_BUILDER_REGISTER(ports_list, 4);
+ATOM_BUILDER_REGISTER(port, 5);