From: Alexandru Ardelean Date: Tue, 31 Mar 2015 10:40:52 +0000 (+0300) Subject: lib/atom-private.c: break it into smaller modules X-Git-Tag: 0.7.15~47^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=94c9815776ccb2033ba9d393e14888a4a35eadb9;p=thirdparty%2Flldpd.git lib/atom-private.c: break it into smaller modules This is a huge commit, but 90%+ of it is just splitting 'lib/atom-private.c' into smaller atoms and putting them into the 'lib/atoms' folder. Some glue code has been added, for constructing maps and builders. For the 'struct atom_builder' type a 'nextb' field has been appended at the end, to help make it a single-linked list of 'struct atom_builders's. The 'next' field in 'struct atom_builder' is taken (hence 'nextb'). For the maps, a wrapper struct (called 'struct atom_map') has been added on top of 'lldpctl_map_t' in order to create single-linked list construct of maps. The struct looks like: struct atom_map { int key; /* lldpctl_key_t equivalent */ struct atom_map *next; /* next 'struct atom_map' */ lldpctl_map_t map[]; /* has to be at the end to to be statically init-ed */ } The point of this is to register them at load-time so that 'lldpctl_key_get_map()' can return them. Each file in 'lib/atoms' registers it's own 'struct atom_builder's and 'struct atom_map's. The whole point of this is to be able to add a 'custom' and/or 'custom_list' atom(s) to be able to configure/broadcast other TLVs in the future. This mechanism is extensible to add other TLVs defined by future standards. Signed-off-by: Alexandru Ardelean --- diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 9ba931bf..ac916058 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -8,7 +8,11 @@ include_HEADERS = lldpctl.h noinst_LTLIBRARIES = libfixedpoint.la libfixedpoint_la_SOURCES = fixedpoint.h fixedpoint.c -liblldpctl_la_SOURCES = lldpctl.h private.h errors.c connection.c atom.c atom-private.c +liblldpctl_la_SOURCES = \ + lldpctl.h private.h errors.c connection.c atom.c helpers.c helpers.h \ + atom-private.c \ + atoms/config.c atoms/dot1.c atoms/dot3.c \ + atoms/interface.c atoms/med.c atoms/mgmt.c atoms/port.c liblldpctl_la_LIBADD = $(top_builddir)/src/libcommon-daemon-lib.la libfixedpoint.la liblldpctl_la_LDFLAGS = $(AM_LDFLAGS) -export-symbols-regex '^lldpctl_' -version-info 9:0:5 diff --git a/src/lib/atom-private.c b/src/lib/atom-private.c index 976d262b..13bfcf77 100644 --- a/src/lib/atom-private.c +++ b/src/lib/atom-private.c @@ -26,2703 +26,54 @@ #include "private.h" #include "fixedpoint.h" -/* Translation from constants to string */ -static lldpctl_map_t lldpd_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 } -}; - -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}, -}; - -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}, -}; - -#ifdef ENABLE_DOT3 -static lldpctl_map_t operational_mau_type_values[] = { - { 1, "AUI - no internal MAU, view from AUI" }, - { 2, "10Base5 - thick coax MAU" }, - { 3, "Foirl - FOIRL MAU" }, - { 4, "10Base2 - thin coax MAU" }, - { 5, "10BaseT - UTP MAU" }, - { 6, "10BaseFP - passive fiber MAU" }, - { 7, "10BaseFB - sync fiber MAU" }, - { 8, "10BaseFL - async fiber MAU" }, - { 9, "10Broad36 - broadband DTE MAU" }, - { 10, "10BaseTHD - UTP MAU, half duplex mode" }, - { 11, "10BaseTFD - UTP MAU, full duplex mode" }, - { 12, "10BaseFLHD - async fiber MAU, half duplex mode" }, - { 13, "10BaseFLDF - async fiber MAU, full duplex mode" }, - { 14, "10BaseT4 - 4 pair category 3 UTP" }, - { 15, "100BaseTXHD - 2 pair category 5 UTP, half duplex mode" }, - { 16, "100BaseTXFD - 2 pair category 5 UTP, full duplex mode" }, - { 17, "100BaseFXHD - X fiber over PMT, half duplex mode" }, - { 18, "100BaseFXFD - X fiber over PMT, full duplex mode" }, - { 19, "100BaseT2HD - 2 pair category 3 UTP, half duplex mode" }, - { 20, "100BaseT2FD - 2 pair category 3 UTP, full duplex mode" }, - { 21, "1000BaseXHD - PCS/PMA, unknown PMD, half duplex mode" }, - { 22, "1000BaseXFD - PCS/PMA, unknown PMD, full duplex mode" }, - { 23, "1000BaseLXHD - Fiber over long-wavelength laser, half duplex mode" }, - { 24, "1000BaseLXFD - Fiber over long-wavelength laser, full duplex mode" }, - { 25, "1000BaseSXHD - Fiber over short-wavelength laser, half duplex mode" }, - { 26, "1000BaseSXFD - Fiber over short-wavelength laser, full duplex mode" }, - { 27, "1000BaseCXHD - Copper over 150-Ohm balanced cable, half duplex mode" }, - { 28, "1000BaseCXFD - Copper over 150-Ohm balanced cable, full duplex mode" }, - { 29, "1000BaseTHD - Four-pair Category 5 UTP, half duplex mode" }, - { 30, "1000BaseTFD - Four-pair Category 5 UTP, full duplex mode" }, - { 31, "10GigBaseX - X PCS/PMA, unknown PMD." }, - { 32, "10GigBaseLX4 - X fiber over WWDM optics" }, - { 33, "10GigBaseR - R PCS/PMA, unknown PMD." }, - { 34, "10GigBaseER - R fiber over 1550 nm optics" }, - { 35, "10GigBaseLR - R fiber over 1310 nm optics" }, - { 36, "10GigBaseSR - R fiber over 850 nm optics" }, - { 37, "10GigBaseW - W PCS/PMA, unknown PMD." }, - { 38, "10GigBaseEW - W fiber over 1550 nm optics" }, - { 39, "10GigBaseLW - W fiber over 1310 nm optics" }, - { 40, "10GigBaseSW - W fiber over 850 nm optics" }, - { 41, "10GigBaseCX4 - X copper over 8 pair 100-Ohm balanced cable" }, - { 42, "2BaseTL - Voice grade UTP copper, up to 2700m, optional PAF" }, - { 43, "10PassTS - Voice grade UTP copper, up to 750m, optional PAF" }, - { 44, "100BaseBX10D - One single-mode fiber OLT, long wavelength, 10km" }, - { 45, "100BaseBX10U - One single-mode fiber ONU, long wavelength, 10km" }, - { 46, "100BaseLX10 - Two single-mode fibers, long wavelength, 10km" }, - { 47, "1000BaseBX10D - One single-mode fiber OLT, long wavelength, 10km" }, - { 48, "1000BaseBX10U - One single-mode fiber ONU, long wavelength, 10km" }, - { 49, "1000BaseLX10 - Two sigle-mode fiber, long wavelength, 10km" }, - { 50, "1000BasePX10D - One single-mode fiber EPON OLT, 10km" }, - { 51, "1000BasePX10U - One single-mode fiber EPON ONU, 10km" }, - { 52, "1000BasePX20D - One single-mode fiber EPON OLT, 20km" }, - { 53, "1000BasePX20U - One single-mode fiber EPON ONU, 20km" }, - { 0, NULL } -}; - -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_pairs_map[] = { - { LLDP_DOT3_POWERPAIRS_SIGNAL, "signal" }, - { LLDP_DOT3_POWERPAIRS_SPARE, "spare" }, - { 0, NULL } -}; - -static lldpctl_map_t port_dot3_power_class_map[] = { - { 1, "class 0" }, - { 2, "class 1" }, - { 3, "class 2" }, - { 4, "class 3" }, - { 5, "class 4" }, - { 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 } -}; -#endif - -#if defined ENABLE_DOT3 || defined ENABLE_LLDPMED -static lldpctl_map_t port_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 }, -}; -#endif - -#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 }, -}; - -static lldpctl_map_t port_med_policy_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 lldpctl_map_t port_med_policy_prio_map[] = { - { 0, "Background" }, - { 1, "Spare" }, - { 2, "Best effort" }, - { 3, "Excellent effort" }, - { 4, "Controlled load" }, - { 5, "Video" }, - { 6, "Voice" }, - { 7, "Network control" }, - { 0, NULL }, -}; - -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 civic_address_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 lldpctl_map_t port_med_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 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 lldpctl_map_t *port_med_pow_priority_map = port_dot3_power_priority_map; -#endif - -static lldpctl_map_t bond_slave_src_mac_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 lldpctl_map_t empty_map[] = {{ 0, NULL }}; -static lldpctl_map_t lldp_portid_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 atom_map_list = { + .next = NULL }; -static const char* -map_lookup(lldpctl_map_t *list, int n) -{ - - unsigned int i; - - for (i = 0; list[i].string != NULL; i++) { - if (list[i].value == n) { - return list[i].string; - } - } - - return "unknown"; -} - -#if defined ENABLE_LLDPMED || defined ENABLE_DOT3 -static int -map_reverse_lookup(lldpctl_map_t *list, const char *string) -{ - if (!string) return -1; - - for (unsigned int i = 0; list[i].string != NULL; i++) { - if (!strcasecmp(list[i].string, string)) - return list[i].value; - } - - return -1; -} -#endif - -static lldpctl_map_t empty_map[] = {{ 0, NULL }}; - lldpctl_map_t* lldpctl_key_get_map(lldpctl_key_t key) { - switch (key) { -#ifdef ENABLE_LLDPMED - case lldpctl_k_med_location_geoid: - return port_med_geoid_map; - case lldpctl_k_med_civicaddress_type: - return civic_address_type_map; - case lldpctl_k_med_policy_type: - return port_med_policy_map; - case lldpctl_k_med_policy_priority: - return port_med_policy_prio_map; - case lldpctl_k_med_power_priority: - return port_med_pow_priority_map; -#endif -#ifdef ENABLE_DOT3 - case lldpctl_k_dot3_power_pairs: - return port_dot3_power_pairs_map; - case lldpctl_k_dot3_power_class: - return port_dot3_power_class_map; - case lldpctl_k_dot3_power_priority: - return port_dot3_power_priority_map; -#endif - case lldpctl_k_config_bond_slave_src_mac_type: - return bond_slave_src_mac_map; - case lldpctl_k_config_lldp_portid_type: - return lldp_portid_map; - case lldpctl_k_port_protocol: - return lldpd_protocol_map; - default: return empty_map; - } -} - -/* Atom methods */ - -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_cid_pattern: - res = c->config->c_cid_pattern; 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, - c->config->c_bond_slave_src_mac_type); - case lldpctl_k_config_lldp_portid_type: - return map_lookup(lldp_portid_map, - c->config->c_lldp_portid_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_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_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; - 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; -#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; - 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; - 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; -#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_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; - 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 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 int -_lldpctl_atom_new_any_list(lldpctl_atom_t *atom, va_list ap) -{ - struct _lldpctl_atom_any_list_t *plist = - (struct _lldpctl_atom_any_list_t *)atom; - plist->parent = va_arg(ap, struct _lldpctl_atom_port_t *); - lldpctl_atom_inc_ref((lldpctl_atom_t *)plist->parent); - return 1; -} - -static void -_lldpctl_atom_free_any_list(lldpctl_atom_t *atom) -{ - struct _lldpctl_atom_any_list_t *plist = - (struct _lldpctl_atom_any_list_t *)atom; - lldpctl_atom_dec_ref((lldpctl_atom_t *)plist->parent); -} - -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, 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->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); - 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; - - /* 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) { - /* No parent, no hardware, we assume a single neighbor: one - * port, one 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_chassis_mgmt: - return _lldpctl_new_atom(atom->conn, atom_mgmts_list, - p, port->p_chassis); -#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 - default: - 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; - -#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 - - /* Local port only */ - if (hardware == NULL) { - SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); - return NULL; - } - - 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; -#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 - default: - SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); - return NULL; - } - - set.ifname = hardware->h_ifname; - - 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; - struct lldpd_chassis *chassis = port->p_chassis; - char *ipaddress = NULL; size_t len; - - /* Local port only */ - if (hardware != NULL) { - switch (key) { - case lldpctl_k_port_name: - return hardware->h_ifname; - default: break; - } - } - - /* Local and remote port */ - switch (key) { - case lldpctl_k_port_protocol: - return map_lookup(lldpd_protocol_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 - - 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_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; - - 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; - struct lldpd_chassis *chassis = port->p_chassis; - - /* 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; - } - } - - /* 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_id_subtype: - return port->p_id_subtype; - case lldpctl_k_port_hidden: - return port->p_hidden_in; -#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 - 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); - } - 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; - struct lldpd_chassis *chassis = port->p_chassis; - - switch (key) { - case lldpctl_k_port_id: - *n = port->p_id_len; - return (uint8_t*)port->p_id; - 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; + struct atom_map *map; + for (map = atom_map_list.next; map ; map = map->next) { + if (map->key == key) + return map->map; } + return empty_map; } -static int -_lldpctl_atom_new_mgmts_list(lldpctl_atom_t *atom, va_list ap) +void atom_map_register(struct atom_map *map) { - struct _lldpctl_atom_mgmts_list_t *plist = - (struct _lldpctl_atom_mgmts_list_t *)atom; - plist->parent = va_arg(ap, struct _lldpctl_atom_port_t *); - plist->chassis = va_arg(ap, struct lldpd_chassis *); - lldpctl_atom_inc_ref((lldpctl_atom_t *)plist->parent); - return 1; -} + struct atom_map* iter = &atom_map_list; -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((lldpctl_atom_t *)plist->parent); -} + while (iter->next) + iter = iter->next; -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); + iter->next = map; } -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 struct atom_builder atom_builder_list = { + .nextb = NULL +}; -static lldpctl_atom_t* -_lldpctl_atom_value_mgmts_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter) +void atom_builder_register(struct atom_builder *builder) { - 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); -} + struct atom_builder* iter = &atom_builder_list; -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, struct _lldpctl_atom_port_t *); - mgmt->mgmt = va_arg(ap, struct lldpd_mgmt *); - lldpctl_atom_inc_ref((lldpctl_atom_t *)mgmt->parent); - return 1; -} + while (iter->nextb) + iter = iter->nextb; -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((lldpctl_atom_t *)mgmt->parent); + iter->nextb = builder; } -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; -} - -#ifdef ENABLE_DOT3 -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, - port->p_power.pairs); - case lldpctl_k_dot3_power_class: - return map_lookup(port_dot3_power_class_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, - 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->hardware == NULL) { - 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, value)); - case lldpctl_k_dot3_power_class: - return _lldpctl_atom_set_int_dot3_power(atom, key, - map_reverse_lookup(port_dot3_power_class_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, value)); - default: - SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); - return NULL; - } -} -#endif - -#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; - } -} -#endif - -#ifdef ENABLE_LLDPMED -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->hardware == NULL) { - 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, m->policy->type); - case lldpctl_k_med_policy_priority: - return map_lookup(port_med_policy_prio_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, value)); - case lldpctl_k_med_policy_priority: - return _lldpctl_atom_set_int_med_policy(atom, key, - map_reverse_lookup(port_med_policy_prio_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->hardware == NULL) { - 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); - 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, - 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; - 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->hardware == NULL) { - 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, 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->hardware == NULL) { - 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 = _lldpctl_alloc_in_atom(atom, sizeof(struct ca_iter)); - if (!iter) return NULL; - iter->data = (uint8_t*)plist->parent->location->data + 4; - iter->data_len = plist->parent->location->data_len - 4; - 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->hardware == NULL) { - 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, 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->hardware == NULL) { - 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, 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, - 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->hardware == NULL) { - 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, value)); - default: - SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); - return NULL; - } -} -#endif - -struct atom_builder builders[] = { - { 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_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 }, - { 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_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 }, - { 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, - .get_buffer = _lldpctl_atom_get_buf_port }, - { 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 }, - { atom_mgmt, sizeof(struct _lldpctl_atom_mgmt_t), - .init = _lldpctl_atom_new_mgmt, - .free = _lldpctl_atom_free_mgmt, - .get_str = _lldpctl_atom_get_str_mgmt }, -#ifdef ENABLE_DOT3 - { 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 }, -#endif -#ifdef ENABLE_DOT1 - { 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 }, - { 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 }, - { 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 }, - { 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 }, - { 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 }, - { 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 }, -#endif -#ifdef ENABLE_LLDPMED - { 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 }, - { 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 }, - { 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 }, - { 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 }, - { 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 }, - { 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 }, - { 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 }, -#endif - { 0, 0, .init = NULL, .free = NULL } -}; - lldpctl_atom_t* _lldpctl_new_atom(lldpctl_conn_t *conn, atom_t type, ...) { struct atom_builder *builder; struct lldpctl_atom_t *atom; va_list(ap); - for (builder = builders; builder->size > 0; builder++) { + for (builder = atom_builder_list.nextb; builder ; builder = builder->nextb) { if (builder->type != type) continue; atom = calloc(1, builder->size); if (atom == NULL) { diff --git a/src/lib/atoms/config.c b/src/lib/atoms/config.c new file mode 100644 index 00000000..b85bb988 --- /dev/null +++ b/src/lib/atoms/config.c @@ -0,0 +1,293 @@ +/* -*- mode: c; c-file-style: "openbsd" -*- */ +/* + * Copyright (c) 2015 Vincent Bernat + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include "../lldpctl.h" +#include "../lldpd-structs.h" +#include "../log.h" +#include "private.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}, + }, +}; + +ATOM_MAP_REGISTER(bond_slave_src_mac_map, 1); +ATOM_MAP_REGISTER(lldp_portid_map, 2); + +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_cid_pattern: + res = c->config->c_cid_pattern; 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); + 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_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_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; + 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; +#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; + 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; + 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; +#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_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; + 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/dot1.c b/src/lib/atoms/dot1.c new file mode 100644 index 00000000..45f2ad8a --- /dev/null +++ b/src/lib/atoms/dot1.c @@ -0,0 +1,276 @@ +/* -*- mode: c; c-file-style: "openbsd" -*- */ +/* + * Copyright (c) 2015 Vincent Bernat + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include "lldpctl.h" +#include "../lldpd-structs.h" +#include "../log.h" +#include "private.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 00000000..be2829d9 --- /dev/null +++ b/src/lib/atoms/dot3.c @@ -0,0 +1,310 @@ +/* -*- mode: c; c-file-style: "openbsd" -*- */ +/* + * Copyright (c) 2015 Vincent Bernat + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include "lldpctl.h" +#include "../lldpd-structs.h" +#include "../log.h" +#include "private.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->hardware == NULL) { + 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 00000000..3415f49d --- /dev/null +++ b/src/lib/atoms/interface.c @@ -0,0 +1,123 @@ +/* -*- mode: c; c-file-style: "openbsd" -*- */ +/* + * Copyright (c) 2015 Vincent Bernat + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include "lldpctl.h" +#include "../lldpd-structs.h" +#include "../log.h" +#include "private.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 00000000..11a79b42 --- /dev/null +++ b/src/lib/atoms/med.c @@ -0,0 +1,1121 @@ +/* -*- mode: c; c-file-style: "openbsd" -*- */ +/* + * Copyright (c) 2015 Vincent Bernat + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include "lldpctl.h" +#include "../lldpd-structs.h" +#include "../log.h" +#include "private.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 = { + { 0, "Background" }, + { 1, "Spare" }, + { 2, "Best effort" }, + { 3, "Excellent effort" }, + { 4, "Controlled load" }, + { 5, "Video" }, + { 6, "Voice" }, + { 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->hardware == NULL) { + 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->hardware == NULL) { + 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); + 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; + 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->hardware == NULL) { + 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->hardware == NULL) { + 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 = _lldpctl_alloc_in_atom(atom, sizeof(struct ca_iter)); + if (!iter) return NULL; + iter->data = (uint8_t*)plist->parent->location->data + 4; + iter->data_len = plist->parent->location->data_len - 4; + 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->hardware == NULL) { + 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->hardware == NULL) { + 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->hardware == NULL) { + 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 00000000..5e2aff7d --- /dev/null +++ b/src/lib/atoms/mgmt.c @@ -0,0 +1,144 @@ +/* -*- mode: c; c-file-style: "openbsd" -*- */ +/* + * Copyright (c) 2015 Vincent Bernat + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include "lldpctl.h" +#include "../lldpd-structs.h" +#include "../log.h" +#include "private.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, struct _lldpctl_atom_port_t *); + plist->chassis = va_arg(ap, struct lldpd_chassis *); + lldpctl_atom_inc_ref((lldpctl_atom_t *)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((lldpctl_atom_t *)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, struct _lldpctl_atom_port_t *); + mgmt->mgmt = va_arg(ap, struct lldpd_mgmt *); + lldpctl_atom_inc_ref((lldpctl_atom_t *)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((lldpctl_atom_t *)mgmt->parent); +} + +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_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 00000000..4d46d0bf --- /dev/null +++ b/src/lib/atoms/port.c @@ -0,0 +1,651 @@ +/* -*- mode: c; c-file-style: "openbsd" -*- */ +/* + * Copyright (c) 2015 Vincent Bernat + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include "lldpctl.h" +#include "../lldpd-structs.h" +#include "../log.h" +#include "private.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 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}, +}; + +static lldpctl_map_t operational_mau_type_values[] = { + { 1, "AUI - no internal MAU, view from AUI" }, + { 2, "10Base5 - thick coax MAU" }, + { 3, "Foirl - FOIRL MAU" }, + { 4, "10Base2 - thin coax MAU" }, + { 5, "10BaseT - UTP MAU" }, + { 6, "10BaseFP - passive fiber MAU" }, + { 7, "10BaseFB - sync fiber MAU" }, + { 8, "10BaseFL - async fiber MAU" }, + { 9, "10Broad36 - broadband DTE MAU" }, + { 10, "10BaseTHD - UTP MAU, half duplex mode" }, + { 11, "10BaseTFD - UTP MAU, full duplex mode" }, + { 12, "10BaseFLHD - async fiber MAU, half duplex mode" }, + { 13, "10BaseFLDF - async fiber MAU, full duplex mode" }, + { 14, "10BaseT4 - 4 pair category 3 UTP" }, + { 15, "100BaseTXHD - 2 pair category 5 UTP, half duplex mode" }, + { 16, "100BaseTXFD - 2 pair category 5 UTP, full duplex mode" }, + { 17, "100BaseFXHD - X fiber over PMT, half duplex mode" }, + { 18, "100BaseFXFD - X fiber over PMT, full duplex mode" }, + { 19, "100BaseT2HD - 2 pair category 3 UTP, half duplex mode" }, + { 20, "100BaseT2FD - 2 pair category 3 UTP, full duplex mode" }, + { 21, "1000BaseXHD - PCS/PMA, unknown PMD, half duplex mode" }, + { 22, "1000BaseXFD - PCS/PMA, unknown PMD, full duplex mode" }, + { 23, "1000BaseLXHD - Fiber over long-wavelength laser, half duplex mode" }, + { 24, "1000BaseLXFD - Fiber over long-wavelength laser, full duplex mode" }, + { 25, "1000BaseSXHD - Fiber over short-wavelength laser, half duplex mode" }, + { 26, "1000BaseSXFD - Fiber over short-wavelength laser, full duplex mode" }, + { 27, "1000BaseCXHD - Copper over 150-Ohm balanced cable, half duplex mode" }, + { 28, "1000BaseCXFD - Copper over 150-Ohm balanced cable, full duplex mode" }, + { 29, "1000BaseTHD - Four-pair Category 5 UTP, half duplex mode" }, + { 30, "1000BaseTFD - Four-pair Category 5 UTP, full duplex mode" }, + { 31, "10GigBaseX - X PCS/PMA, unknown PMD." }, + { 32, "10GigBaseLX4 - X fiber over WWDM optics" }, + { 33, "10GigBaseR - R PCS/PMA, unknown PMD." }, + { 34, "10GigBaseER - R fiber over 1550 nm optics" }, + { 35, "10GigBaseLR - R fiber over 1310 nm optics" }, + { 36, "10GigBaseSR - R fiber over 850 nm optics" }, + { 37, "10GigBaseW - W PCS/PMA, unknown PMD." }, + { 38, "10GigBaseEW - W fiber over 1550 nm optics" }, + { 39, "10GigBaseLW - W fiber over 1310 nm optics" }, + { 40, "10GigBaseSW - W fiber over 850 nm optics" }, + { 41, "10GigBaseCX4 - X copper over 8 pair 100-Ohm balanced cable" }, + { 42, "2BaseTL - Voice grade UTP copper, up to 2700m, optional PAF" }, + { 43, "10PassTS - Voice grade UTP copper, up to 750m, optional PAF" }, + { 44, "100BaseBX10D - One single-mode fiber OLT, long wavelength, 10km" }, + { 45, "100BaseBX10U - One single-mode fiber ONU, long wavelength, 10km" }, + { 46, "100BaseLX10 - Two single-mode fibers, long wavelength, 10km" }, + { 47, "1000BaseBX10D - One single-mode fiber OLT, long wavelength, 10km" }, + { 48, "1000BaseBX10U - One single-mode fiber ONU, long wavelength, 10km" }, + { 49, "1000BaseLX10 - Two sigle-mode fiber, long wavelength, 10km" }, + { 50, "1000BasePX10D - One single-mode fiber EPON OLT, 10km" }, + { 51, "1000BasePX10U - One single-mode fiber EPON ONU, 10km" }, + { 52, "1000BasePX20D - One single-mode fiber EPON OLT, 20km" }, + { 53, "1000BasePX20U - One single-mode fiber EPON ONU, 20km" }, + { 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 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, 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->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); + 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; + + /* 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) { + /* No parent, no hardware, we assume a single neighbor: one + * port, one 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_chassis_mgmt: + return _lldpctl_new_atom(atom->conn, atom_mgmts_list, + p, port->p_chassis); +#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 + default: + 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; + +#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 + + /* Local port only */ + if (hardware == NULL) { + SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); + return NULL; + } + + 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; +#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 + default: + SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); + return NULL; + } + + set.ifname = hardware->h_ifname; + + 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; + struct lldpd_chassis *chassis = port->p_chassis; + char *ipaddress = NULL; size_t len; + + /* Local port only */ + if (hardware != NULL) { + switch (key) { + case lldpctl_k_port_name: + return hardware->h_ifname; + default: break; + } + } + + /* 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 + + 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_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; + + 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; + struct lldpd_chassis *chassis = port->p_chassis; + + /* 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; + } + } + + /* 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_id_subtype: + return port->p_id_subtype; + case lldpctl_k_port_hidden: + return port->p_hidden_in; +#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 + 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); + } + 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; + struct lldpd_chassis *chassis = port->p_chassis; + + switch (key) { + case lldpctl_k_port_id: + *n = port->p_id_len; + return (uint8_t*)port->p_id; + 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 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, + .get_buffer = _lldpctl_atom_get_buf_port }; + +ATOM_BUILDER_REGISTER(ports_list, 4); +ATOM_BUILDER_REGISTER(port, 5); + diff --git a/src/lib/helpers.c b/src/lib/helpers.c new file mode 100644 index 00000000..04967ebf --- /dev/null +++ b/src/lib/helpers.c @@ -0,0 +1,76 @@ +/* -*- mode: c; c-file-style: "openbsd" -*- */ +/* + * Copyright (c) 2015 Vincent Bernat + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include "lldpctl.h" +#include "../lldpd-structs.h" +#include "../log.h" +#include "private.h" +#include "helpers.h" + +const char* +map_lookup(lldpctl_map_t *list, int n) +{ + + unsigned int i; + + for (i = 0; list[i].string != NULL; i++) { + if (list[i].value == n) { + return list[i].string; + } + } + + return "unknown"; +} + +#if defined ENABLE_LLDPMED || defined ENABLE_DOT3 +int +map_reverse_lookup(lldpctl_map_t *list, const char *string) +{ + if (!string) return -1; + + for (unsigned int i = 0; list[i].string != NULL; i++) { + if (!strcasecmp(list[i].string, string)) + return list[i].value; + } + + return -1; +} +#endif + +int +_lldpctl_atom_new_any_list(lldpctl_atom_t *atom, va_list ap) +{ + struct _lldpctl_atom_any_list_t *plist = + (struct _lldpctl_atom_any_list_t *)atom; + plist->parent = va_arg(ap, struct _lldpctl_atom_port_t *); + lldpctl_atom_inc_ref((lldpctl_atom_t *)plist->parent); + return 1; +} + +void +_lldpctl_atom_free_any_list(lldpctl_atom_t *atom) +{ + struct _lldpctl_atom_any_list_t *plist = + (struct _lldpctl_atom_any_list_t *)atom; + lldpctl_atom_dec_ref((lldpctl_atom_t *)plist->parent); +} + diff --git a/src/lib/helpers.h b/src/lib/helpers.h new file mode 100644 index 00000000..172d7bd2 --- /dev/null +++ b/src/lib/helpers.h @@ -0,0 +1,25 @@ +/* -*- mode: c; c-file-style: "openbsd" -*- */ +/* + * Copyright (c) 2015 Vincent Bernat + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +const char *map_lookup(lldpctl_map_t *list, int n); +#if defined ENABLE_LLDPMED || defined ENABLE_DOT3 +int map_reverse_lookup(lldpctl_map_t *list, const char *string); +#endif + +int _lldpctl_atom_new_any_list(lldpctl_atom_t *atom, va_list ap); +void _lldpctl_atom_free_any_list(lldpctl_atom_t *atom); + diff --git a/src/lib/private.h b/src/lib/private.h index 1d691c5f..13c0f401 100644 --- a/src/lib/private.h +++ b/src/lib/private.h @@ -250,6 +250,17 @@ struct _lldpctl_atom_med_power_t { struct lldpctl_atom_t *_lldpctl_new_atom(lldpctl_conn_t *conn, atom_t type, ...); +struct atom_map { + int key; + struct atom_map *next; + lldpctl_map_t map[]; +}; + +void atom_map_register(struct atom_map *map); + +#define __constructor__(PRIO) __attribute__ ((constructor( PRIO ))) +#define ATOM_MAP_REGISTER(NAME, PRIO) __constructor__(100 + PRIO) void init_ ## NAME() { atom_map_register(& NAME ); } + struct atom_builder { atom_t type; /* Atom type */ size_t size; /* Size of structure to allocate */ @@ -270,4 +281,11 @@ struct atom_builder { lldpctl_atom_t* (*set_buffer)(lldpctl_atom_t *, lldpctl_key_t, const u_int8_t *, size_t); lldpctl_atom_t* (*set_int)(lldpctl_atom_t *, lldpctl_key_t, long int); lldpctl_atom_t* (*create)(lldpctl_atom_t *); + struct atom_builder *nextb; }; + +void atom_builder_register(struct atom_builder *builder); + +#define __constructor__(PRIO) __attribute__ ((constructor( PRIO ))) +#define ATOM_BUILDER_REGISTER(NAME, PRIO) __constructor__(200 + PRIO) void init_ ## NAME() { atom_builder_register(& NAME ); } +