/* -*- 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 },
},
};
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);
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;
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