/* -*- mode: c; c-file-style: "openbsd" -*- */ /* * Copyright (c) 2013 Vincent Bernat * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include "client.h" #include "../log.h" static int cmd_medpower(struct lldpctl_conn_t *conn, struct writer *w, struct cmd_env *env, const void *arg) { log_debug("lldpctl", "set MED power"); lldpctl_atom_t *port; const char *name; while ((port = cmd_iterate_on_ports(conn, env, &name))) { lldpctl_atom_t *med_power; const char *what = NULL; med_power = lldpctl_atom_get(port, lldpctl_k_port_med_power); if (med_power == NULL) { log_warnx("lldpctl", "unable to set LLDP-MED power: support seems unavailable"); continue; /* Need to finish the loop */ } if ((what = "device type", lldpctl_atom_set_str(med_power, lldpctl_k_med_power_type, cmdenv_get(env, "device-type"))) == NULL || (what = "power source", lldpctl_atom_set_str(med_power, lldpctl_k_med_power_source, cmdenv_get(env, "source"))) == NULL || (what = "power priority", lldpctl_atom_set_str(med_power, lldpctl_k_med_power_priority, cmdenv_get(env, "priority"))) == NULL || (what = "power value", lldpctl_atom_set_str(med_power, lldpctl_k_med_power_val, cmdenv_get(env, "value"))) == NULL) log_warnx("lldpctl", "unable to set LLDP MED power value for %s on %s. %s.", what, name, lldpctl_last_strerror(conn)); else { if (lldpctl_atom_set(port, lldpctl_k_port_med_power, med_power) == NULL) { log_warnx("lldpctl", "unable to set LLDP MED power on %s. %s.", name, lldpctl_last_strerror(conn)); } else log_info("lldpctl", "LLDP-MED power has been set for port %s", name); } lldpctl_atom_dec_ref(med_power); } return 1; } static int cmd_store_powerpairs_env_value_and_pop2(struct lldpctl_conn_t *conn, struct writer *w, struct cmd_env *env, const void *value) { return cmd_store_something_env_value_and_pop2("powerpairs", env, value); } static int cmd_store_class_env_value_and_pop2(struct lldpctl_conn_t *conn, struct writer *w, struct cmd_env *env, const void *value) { return cmd_store_something_env_value_and_pop2("class", env, value); } static int cmd_store_prio_env_value_and_pop2(struct lldpctl_conn_t *conn, struct writer *w, struct cmd_env *env, const void *value) { return cmd_store_something_env_value_and_pop2("priority", env, value); } static int cmd_dot3power(struct lldpctl_conn_t *conn, struct writer *w, struct cmd_env *env, const void *arg) { log_debug("lldpctl", "set dot3 power"); lldpctl_atom_t *port; const char *name; while ((port = cmd_iterate_on_ports(conn, env, &name))) { lldpctl_atom_t *dot3_power; const char *what = NULL; int ok = 1; dot3_power = lldpctl_atom_get(port, lldpctl_k_port_dot3_power); if (dot3_power == NULL) { log_warnx("lldpctl", "unable to set Dot3 power: support seems unavailable"); continue; /* Need to finish the loop */ } if ((what = "device type", lldpctl_atom_set_str(dot3_power, lldpctl_k_dot3_power_devicetype, cmdenv_get(env, "device-type"))) == NULL || /* Flags */ (what = "supported flag", lldpctl_atom_set_int(dot3_power, lldpctl_k_dot3_power_supported, cmdenv_get(env, "supported") ? 1 : 0)) == NULL || (what = "enabled flag", lldpctl_atom_set_int(dot3_power, lldpctl_k_dot3_power_enabled, cmdenv_get(env, "enabled") ? 1 : 0)) == NULL || (what = "paircontrol flag", lldpctl_atom_set_int(dot3_power, lldpctl_k_dot3_power_paircontrol, cmdenv_get(env, "paircontrol") ? 1 : 0)) == NULL || /* Powerpairs */ (what = "power pairs", lldpctl_atom_set_str(dot3_power, lldpctl_k_dot3_power_pairs, cmdenv_get(env, "powerpairs"))) == NULL || /* Class */ (what = "power class", cmdenv_get(env, "class") ? lldpctl_atom_set_str(dot3_power, lldpctl_k_dot3_power_class, cmdenv_get(env, "class")) : lldpctl_atom_set_int(dot3_power, lldpctl_k_dot3_power_class, 0)) == NULL || (what = "802.3at type", lldpctl_atom_set_int(dot3_power, lldpctl_k_dot3_power_type, 0)) == NULL) { log_warnx("lldpctl", "unable to set LLDP Dot3 power value for %s on %s. %s.", what, name, lldpctl_last_strerror(conn)); ok = 0; } else if (cmdenv_get(env, "typeat")) { int typeat = cmdenv_get(env, "typeat")[0] - '0'; const char *source = cmdenv_get(env, "source"); if ((what = "802.3at type", lldpctl_atom_set_int(dot3_power, lldpctl_k_dot3_power_type, typeat)) == NULL || (what = "source", lldpctl_atom_set_int(dot3_power, lldpctl_k_dot3_power_source, (!strcmp(source, "primary")) ? LLDP_DOT3_POWER_SOURCE_PRIMARY : (!strcmp(source, "backup")) ? LLDP_DOT3_POWER_SOURCE_BACKUP : (!strcmp(source, "pse")) ? LLDP_DOT3_POWER_SOURCE_PSE : (!strcmp(source, "local")) ? LLDP_DOT3_POWER_SOURCE_LOCAL : (!strcmp(source, "both")) ? LLDP_DOT3_POWER_SOURCE_BOTH : LLDP_DOT3_POWER_SOURCE_UNKNOWN)) == NULL || (what = "priority", lldpctl_atom_set_str(dot3_power, lldpctl_k_dot3_power_priority, cmdenv_get(env, "priority"))) == NULL || (what = "requested power", lldpctl_atom_set_str(dot3_power, lldpctl_k_dot3_power_requested, cmdenv_get(env, "requested"))) == NULL || (what = "allocated power", lldpctl_atom_set_str(dot3_power, lldpctl_k_dot3_power_allocated, cmdenv_get(env, "allocated"))) == NULL) { log_warnx("lldpctl", "unable to set LLDP Dot3 power value for %s on %s. %s.", what, name, lldpctl_last_strerror(conn)); ok = 0; } } if (ok) { if (lldpctl_atom_set(port, lldpctl_k_port_dot3_power, dot3_power) == NULL) { log_warnx("lldpctl", "unable to set LLDP Dot3 power on %s. %s.", name, lldpctl_last_strerror(conn)); } else log_info("lldpctl", "LLDP Dot3 power has been set for port %s", name); } lldpctl_atom_dec_ref(dot3_power); } return 1; } static int cmd_check_type_but_no(struct cmd_env *env, const void *arg) { const char *what = arg; if (!cmdenv_get(env, "device-type")) return 0; if (cmdenv_get(env, what)) return 0; return 1; } static int cmd_check_typeat_but_no(struct cmd_env *env, const void *arg) { const char *what = arg; if (!cmdenv_get(env, "typeat")) return 0; if (cmdenv_get(env, what)) return 0; return 1; } static int cmd_check_type(struct cmd_env *env, const char *type) { const char *etype = cmdenv_get(env, "device-type"); if (!etype) return 0; return (!strcmp(type, etype)); } static int cmd_check_pse(struct cmd_env *env, const void *arg) { return cmd_check_type(env, "pse"); } static int cmd_check_pd(struct cmd_env *env, const void *arg) { return cmd_check_type(env, "pd"); } static void register_commands_pow_source(struct cmd_node *source) { commands_new(source, "unknown", "Unknown power source", NULL, cmd_store_env_value_and_pop2, "source"); commands_new(source, "primary", "Primary power source", cmd_check_pse, cmd_store_env_value_and_pop2, "source"); commands_new(source, "backup", "Backup power source", cmd_check_pse, cmd_store_env_value_and_pop2, "source"); commands_new(source, "pse", "Power source is PSE", cmd_check_pd, cmd_store_env_value_and_pop2, "source"); commands_new(source, "local", "Local power source", cmd_check_pd, cmd_store_env_value_and_pop2, "source"); commands_new(source, "both", "Both PSE and local source available", cmd_check_pd, cmd_store_env_value_and_pop2, "source"); } static void register_commands_pow_priority(struct cmd_node *priority, int key) { for (lldpctl_map_t *prio_map = lldpctl_key_get_map(key); prio_map->string; prio_map++) { char *tag = strdup(totag(prio_map->string)); SUPPRESS_LEAK(tag); commands_new(priority, tag, prio_map->string, NULL, cmd_store_prio_env_value_and_pop2, prio_map->string); } } /** * Register `configure med power` commands. */ void register_commands_medpow(struct cmd_node *configure_med) { struct cmd_node *configure_medpower = commands_new(configure_med, "power", "MED power configuration", NULL, NULL, NULL); commands_new(configure_medpower, NEWLINE, "Apply new MED power configuration", cmd_check_env, cmd_medpower, "device-type,source,priority,value"); /* Type: PSE or PD */ commands_new(configure_medpower, "pd", "MED power consumer", cmd_check_no_env, cmd_store_env_value_and_pop, "device-type"); commands_new(configure_medpower, "pse", "MED power provider", cmd_check_no_env, cmd_store_env_value_and_pop, "device-type"); /* Source */ struct cmd_node *source = commands_new(configure_medpower, "source", "MED power source", cmd_check_type_but_no, NULL, "source"); register_commands_pow_source(source); /* Priority */ struct cmd_node *priority = commands_new(configure_medpower, "priority", "MED power priority", cmd_check_type_but_no, NULL, "priority"); register_commands_pow_priority(priority, lldpctl_k_med_power_priority); /* Value */ commands_new(commands_new(configure_medpower, "value", "MED power value", cmd_check_type_but_no, NULL, "value"), NULL, "MED power value in milliwatts", NULL, cmd_store_env_value_and_pop2, "value"); } static int cmd_check_env_power(struct cmd_env *env, const void *nothing) { /* We need type and powerpair but if we have typeat, we also request * source, priority, requested and allocated. */ if (!cmdenv_get(env, "device-type")) return 0; if (!cmdenv_get(env, "powerpairs")) return 0; if (cmdenv_get(env, "typeat")) { return (!!cmdenv_get(env, "source") && !!cmdenv_get(env, "priority") && !!cmdenv_get(env, "requested") && !!cmdenv_get(env, "allocated")); } return 1; } /** * Register `configure med dot3` commands. */ void register_commands_dot3pow(struct cmd_node *configure_dot3) { struct cmd_node *configure_dot3power = commands_new(configure_dot3, "power", "Dot3 power configuration", NULL, NULL, NULL); commands_new(configure_dot3power, NEWLINE, "Apply new Dot3 power configuration", cmd_check_env_power, cmd_dot3power, NULL); /* Type: PSE or PD */ commands_new(configure_dot3power, "pd", "Dot3 power consumer", cmd_check_no_env, cmd_store_env_value_and_pop, "device-type"); commands_new(configure_dot3power, "pse", "Dot3 power provider", cmd_check_no_env, cmd_store_env_value_and_pop, "device-type"); /* Flags */ commands_new(configure_dot3power, "supported", "MDI power support present", cmd_check_type_but_no, cmd_store_env_and_pop, "supported"); commands_new(configure_dot3power, "enabled", "MDI power support enabled", cmd_check_type_but_no, cmd_store_env_and_pop, "enabled"); commands_new(configure_dot3power, "paircontrol", "MDI power pair can be selected", cmd_check_type_but_no, cmd_store_env_and_pop, "paircontrol"); /* Power pairs */ struct cmd_node *powerpairs = commands_new(configure_dot3power, "powerpairs", "Which pairs are currently used for power (mandatory)", cmd_check_type_but_no, NULL, "powerpairs"); for (lldpctl_map_t *pp_map = lldpctl_key_get_map(lldpctl_k_dot3_power_pairs); pp_map->string; pp_map++) { commands_new(powerpairs, pp_map->string, pp_map->string, NULL, cmd_store_powerpairs_env_value_and_pop2, pp_map->string); } /* Class */ struct cmd_node *class = commands_new(configure_dot3power, "class", "Power class", cmd_check_type_but_no, NULL, "class"); for (lldpctl_map_t *class_map = lldpctl_key_get_map(lldpctl_k_dot3_power_class); class_map->string; class_map++) { const char *tag = strdup(totag(class_map->string)); SUPPRESS_LEAK(tag); commands_new(class, tag, class_map->string, NULL, cmd_store_class_env_value_and_pop2, class_map->string); } /* 802.3at type */ struct cmd_node *typeat = commands_new(configure_dot3power, "type", "802.3at device type", cmd_check_type_but_no, NULL, "typeat"); commands_new(typeat, "1", "802.3at type 1", NULL, cmd_store_env_value_and_pop2, "typeat"); commands_new(typeat, "2", "802.3at type 2", NULL, cmd_store_env_value_and_pop2, "typeat"); /* Source */ struct cmd_node *source = commands_new(configure_dot3power, "source", "802.3at dot3 power source (mandatory)", cmd_check_typeat_but_no, NULL, "source"); register_commands_pow_source(source); /* Priority */ struct cmd_node *priority = commands_new(configure_dot3power, "priority", "802.3at dot3 power priority (mandatory)", cmd_check_typeat_but_no, NULL, "priority"); register_commands_pow_priority(priority, lldpctl_k_dot3_power_priority); /* Values */ commands_new(commands_new(configure_dot3power, "requested", "802.3at dot3 power value requested (mandatory)", cmd_check_typeat_but_no, NULL, "requested"), NULL, "802.3at power value requested in milliwatts", NULL, cmd_store_env_value_and_pop2, "requested"); commands_new(commands_new(configure_dot3power, "allocated", "802.3at dot3 power value allocated (mandatory)", cmd_check_typeat_but_no, NULL, "allocated"), NULL, "802.3at power value allocated in milliwatts", NULL, cmd_store_env_value_and_pop2, "allocated"); }