summaryrefslogtreecommitdiffstats
path: root/src/lib/atoms/dot3.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/atoms/dot3.c')
-rw-r--r--src/lib/atoms/dot3.c474
1 files changed, 474 insertions, 0 deletions
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