/* -*- 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 "../../log.h" #include "../atom.h" #include "../helpers.h" static struct atom_map lldpd_protocol_map = { .key = lldpctl_k_port_protocol, .map = { { LLDPD_MODE_LLDP, "LLDP" }, { LLDPD_MODE_CDPV1, "CDPv1" }, { LLDPD_MODE_CDPV2, "CDPv2" }, { LLDPD_MODE_EDP, "EDP" }, { LLDPD_MODE_FDP, "FDP" }, { LLDPD_MODE_SONMP, "SONMP" }, { 0, NULL }, } }; ATOM_MAP_REGISTER(lldpd_protocol_map, 3); static lldpctl_map_t port_id_subtype_map[] = { { LLDP_PORTID_SUBTYPE_IFNAME, "ifname" }, { LLDP_PORTID_SUBTYPE_IFALIAS, "ifalias" }, { LLDP_PORTID_SUBTYPE_LOCAL, "local" }, { LLDP_PORTID_SUBTYPE_LLADDR, "mac" }, { LLDP_PORTID_SUBTYPE_ADDR, "ip" }, { LLDP_PORTID_SUBTYPE_PORT, "unhandled" }, { LLDP_PORTID_SUBTYPE_AGENTCID, "unhandled" }, { 0, NULL }, }; static struct atom_map port_status_map = { .key = lldpctl_k_port_status, .map = { { LLDPD_RXTX_TXONLY, "TX only" }, { LLDPD_RXTX_RXONLY, "RX only" }, { LLDPD_RXTX_DISABLED, "disabled" }, { LLDPD_RXTX_BOTH, "RX and TX" }, { 0, NULL }, } }; ATOM_MAP_REGISTER(port_status_map, 3); #ifdef ENABLE_DOT3 static lldpctl_map_t operational_mau_type_values[] = { { LLDP_DOT3_MAU_AUI, "AUI - No internal MAU, view from AUI" }, { LLDP_DOT3_MAU_10BASE5, "10Base5 - Thick coax MAU" }, { LLDP_DOT3_MAU_FOIRL, "Foirl - FOIRL MAU" }, { LLDP_DOT3_MAU_10BASE2, "10Base2 - Thin coax MAU" }, { LLDP_DOT3_MAU_10BASET, "10BaseT - UTP MAU" }, { LLDP_DOT3_MAU_10BASEFP, "10BaseFP - Passive fiber MAU" }, { LLDP_DOT3_MAU_10BASEFB, "10BaseFB - Sync fiber MAU" }, { LLDP_DOT3_MAU_10BASEFL, "10BaseFL - Async fiber MAU" }, { LLDP_DOT3_MAU_10BROAD36, "10Broad36 - Broadband DTE MAU" }, { LLDP_DOT3_MAU_10BASETHD, "10BaseTHD - UTP MAU, half duplex mode" }, { LLDP_DOT3_MAU_10BASETFD, "10BaseTFD - UTP MAU, full duplex mode" }, { LLDP_DOT3_MAU_10BASEFLHD, "10BaseFLHD - Async fiber MAU, half duplex mode" }, { LLDP_DOT3_MAU_10BASEFLFD, "10BaseFLDF - Async fiber MAU, full duplex mode" }, { LLDP_DOT3_MAU_100BASET4, "100BaseT4 - 4 pair category 3 UTP" }, { LLDP_DOT3_MAU_100BASETXHD, "100BaseTXHD - 2 pair category 5 UTP, half duplex mode" }, { LLDP_DOT3_MAU_100BASETXFD, "100BaseTXFD - 2 pair category 5 UTP, full duplex mode" }, { LLDP_DOT3_MAU_100BASEFXHD, "100BaseFXHD - X fiber over PMT, half duplex mode" }, { LLDP_DOT3_MAU_100BASEFXFD, "100BaseFXFD - X fiber over PMT, full duplex mode" }, { LLDP_DOT3_MAU_100BASET2HD, "100BaseT2HD - 2 pair category 3 UTP, half duplex mode" }, { LLDP_DOT3_MAU_100BASET2FD, "100BaseT2FD - 2 pair category 3 UTP, full duplex mode" }, { LLDP_DOT3_MAU_1000BASEXHD, "1000BaseXHD - PCS/PMA, unknown PMD, half duplex mode" }, { LLDP_DOT3_MAU_1000BASEXFD, "1000BaseXFD - PCS/PMA, unknown PMD, full duplex mode" }, { LLDP_DOT3_MAU_1000BASELXHD, "1000BaseLXHD - Fiber over long-wavelength laser, half duplex mode" }, { LLDP_DOT3_MAU_1000BASELXFD, "1000BaseLXFD - Fiber over long-wavelength laser, full duplex mode" }, { LLDP_DOT3_MAU_1000BASESXHD, "1000BaseSXHD - Fiber over short-wavelength laser, half duplex mode" }, { LLDP_DOT3_MAU_1000BASESXFD, "1000BaseSXFD - Fiber over short-wavelength laser, full duplex mode" }, { LLDP_DOT3_MAU_1000BASECXHD, "1000BaseCXHD - Copper over 150-Ohm balanced cable, half duplex mode" }, { LLDP_DOT3_MAU_1000BASECXFD, "1000BaseCXFD - Copper over 150-Ohm balanced cable, full duplex mode" }, { LLDP_DOT3_MAU_1000BASETHD, "1000BaseTHD - Four-pair Category 5 UTP, half duplex mode" }, { LLDP_DOT3_MAU_1000BASETFD, "1000BaseTFD - Four-pair Category 5 UTP, full duplex mode" }, { LLDP_DOT3_MAU_10GIGBASEX, "10GigBaseX - X PCS/PMA, unknown PMD." }, { LLDP_DOT3_MAU_10GIGBASELX4, "10GigBaseLX4 - X fiber over WWDM optics" }, { LLDP_DOT3_MAU_10GIGBASER, "10GigBaseR - R PCS/PMA, unknown PMD." }, { LLDP_DOT3_MAU_10GIGBASEER, "10GigBaseER - R fiber over 1550 nm optics" }, { LLDP_DOT3_MAU_10GIGBASELR, "10GigBaseLR - R fiber over 1310 nm optics" }, { LLDP_DOT3_MAU_10GIGBASESR, "10GigBaseSR - R fiber over 850 nm optics" }, { LLDP_DOT3_MAU_10GIGBASEW, "10GigBaseW - W PCS/PMA, unknown PMD." }, { LLDP_DOT3_MAU_10GIGBASEEW, "10GigBaseEW - W fiber over 1550 nm optics" }, { LLDP_DOT3_MAU_10GIGBASELW, "10GigBaseLW - W fiber over 1310 nm optics" }, { LLDP_DOT3_MAU_10GIGBASESW, "10GigBaseSW - W fiber over 850 nm optics" }, { LLDP_DOT3_MAU_10GIGBASECX4, "10GigBaseCX4 - X copper over 8 pair 100-Ohm balanced cable" }, { LLDP_DOT3_MAU_2BASETL, "2BaseTL - Voice grade UTP copper, up to 2700m, optional PAF" }, { LLDP_DOT3_MAU_10PASSTS, "10PassTS - Voice grade UTP copper, up to 750m, optional PAF" }, { LLDP_DOT3_MAU_100BASEBX10D, "100BaseBX10D - One single-mode fiber OLT, long wavelength, 10km" }, { LLDP_DOT3_MAU_100BASEBX10U, "100BaseBX10U - One single-mode fiber ONU, long wavelength, 10km" }, { LLDP_DOT3_MAU_100BASELX10, "100BaseLX10 - Two single-mode fibers, long wavelength, 10km" }, { LLDP_DOT3_MAU_1000BASEBX10D, "1000BaseBX10D - One single-mode fiber OLT, long wavelength, 10km" }, { LLDP_DOT3_MAU_1000BASEBX10U, "1000BaseBX10U - One single-mode fiber ONU, long wavelength, 10km" }, { LLDP_DOT3_MAU_1000BASELX10, "1000BaseLX10 - Two sigle-mode fiber, long wavelength, 10km" }, { LLDP_DOT3_MAU_1000BASEPX10D, "1000BasePX10D - One single-mode fiber EPON OLT, 10km" }, { LLDP_DOT3_MAU_1000BASEPX10U, "1000BasePX10U - One single-mode fiber EPON ONU, 10km" }, { LLDP_DOT3_MAU_1000BASEPX20D, "1000BasePX20D - One single-mode fiber EPON OLT, 20km" }, { LLDP_DOT3_MAU_1000BASEPX20U, "1000BasePX20U - One single-mode fiber EPON ONU, 20km" }, { LLDP_DOT3_MAU_10GBASET, "10GbaseT - Four-pair Category 6A or better, full duplex mode only" }, { LLDP_DOT3_MAU_10GBASELRM, "10GbaseLRM - R multimode fiber over 1310 nm optics" }, { LLDP_DOT3_MAU_1000BASEKX, "1000baseKX - X backplane, full duplex mode only" }, { LLDP_DOT3_MAU_10GBASEKX4, "10GbaseKX4 - 4 lane X backplane, full duplex mode only" }, { LLDP_DOT3_MAU_10GBASEKR, "10GbaseKR - R backplane, full duplex mode only" }, { LLDP_DOT3_MAU_10G1GBASEPRXD1, "10G1GbasePRXD1 - One single-mode fiber asymmetric-rate EPON OLT, low power budget (PRX10)" }, { LLDP_DOT3_MAU_10G1GBASEPRXD2, "10G1GbasePRXD2 - One single-mode fiber asymmetric-rate EPON OLT, medium power budget (PRX20)" }, { LLDP_DOT3_MAU_10G1GBASEPRXD3, "10G1GbasePRXD3 - One single-mode fiber asymmetric-rate EPON OLT, high power budget (PRX30)" }, { LLDP_DOT3_MAU_10G1GBASEPRXU1, "10G1GbasePRXU1 - One single-mode fiber asymmetric-rate EPON ONU, low power budget (PRX10)" }, { LLDP_DOT3_MAU_10G1GBASEPRXU2, "10G1GbasePRXU2 - One single-mode fiber asymmetric-rate EPON ONU, medium power budget (PRX20)" }, { LLDP_DOT3_MAU_10G1GBASEPRXU3, "10G1GbasePRXU3 - One single-mode fiber asymmetric-rate EPON ONU, high power budget (PRX30)" }, { LLDP_DOT3_MAU_10GBASEPRD1, "10GbasePRD1 - One single-mode fiber symmetric-rate EPON OLT, low power budget (PR10)" }, { LLDP_DOT3_MAU_10GBASEPRD2, "10GbasePRD2 - One single-mode fiber symmetric-rate EPON OLT, medium power budget (PR20)" }, { LLDP_DOT3_MAU_10GBASEPRD3, "10GbasePRD3 - One single-mode fiber symmetric-rate EPON OLT, high power budget (PR30)" }, { LLDP_DOT3_MAU_10GBASEPRU1, "10GbasePRU1 - One single-mode fiber symmetric-rate EPON ONU, low and medium power budget" }, { LLDP_DOT3_MAU_10GBASEPRU3, "10GbasePRU3 - One single-mode fiber symmetric-rate EPON ONU, high power budget (PR30)" }, { LLDP_DOT3_MAU_40GBASEKR4, "40GbaseKR4 - 40GBASE-R PCS/PMA over an electrical backplane" }, { LLDP_DOT3_MAU_40GBASECR4, "40GbaseCR4 - 40GBASE-R PCS/PMA over 4 lane shielded copper balanced cable" }, { LLDP_DOT3_MAU_40GBASESR4, "40GbaseSR4 - 40GBASE-R PCS/PMA over 4 lane multimode fiber" }, { LLDP_DOT3_MAU_40GBASEFR, "40GbaseFR - 40GBASE-R PCS/PMA over single mode fiber" }, { LLDP_DOT3_MAU_40GBASELR4, "40GbaseLR4 - 40GBASE-R PCS/PMA over 4 WDM lane single mode fiber" }, { LLDP_DOT3_MAU_100GBASECR10, "100GbaseCR10 - 100GBASE-R PCS/PMA over 10 lane shielded copper balanced cable" }, { LLDP_DOT3_MAU_100GBASESR10, "100GbaseSR10 - 100GBASE-R PCS/PMA over 10 lane multimode fiber" }, { LLDP_DOT3_MAU_100GBASELR4, "100GbaseLR4 - 100GBASE-R PCS/PMA over 4 WDM lane single mode fiber, long reach" }, { LLDP_DOT3_MAU_100GBASEER4, "100GbaseER4 - 100GBASE-R PCS/PMA over 4 WDM lane single mode fiber PMD, extended reach" }, { LLDP_DOT3_MAU_1000BASET1, "1000baseT1 - 1000BASE-T1 single balanced twisted-pair copper cabling PHY" }, { LLDP_DOT3_MAU_1000BASEPX30D, "1000basePX30D - One single-mode fiber EPON OLT, 20km, 1:32 split ratio" }, { LLDP_DOT3_MAU_1000BASEPX30U, "1000basePX30U - One single-mode fiber EPON ONU, 20km, 1:32 split ratio" }, { LLDP_DOT3_MAU_1000BASEPX40D, "1000basePX40D - One single-mode fiber EPON OLT, 20km, 1:64 split ratio" }, { LLDP_DOT3_MAU_1000BASEPX40U, "1000basePX40U - One single-mode fiber EPON ONU, 20km, 1:64 split ratio" }, { LLDP_DOT3_MAU_10G1GBASEPRXD4, "10G1GbasePRXD4 - One single-mode fiber asymmetric-rate EPON OLT, supporting extended power budget (PRX40)" }, { LLDP_DOT3_MAU_10G1GBASEPRXU4, "10G1GbasePRXU4 - One single-mode fiber asymmetric-rate EPON ONU, supporting extended power budget (PRX40)" }, { LLDP_DOT3_MAU_10GBASEPRD4, "10GbasePRD4 - One single-mode fiber symmetric-rate EPON OLT, supporting extended power budget (PR40)" }, { LLDP_DOT3_MAU_10GBASEPRU4, "10GbasePRU4 - One single-mode fiber symmetric-rate EPON ONU, supporting extended power budget (PR40)" }, { LLDP_DOT3_MAU_25GBASECR, "25GbaseCR - 25GBASE-R PCS/PMA over shielded balanced copper cable" }, { LLDP_DOT3_MAU_25GBASECRS, "25GbaseCRS - 25GBASE-R PCS/PMA over shielded balanced copper cable without RS-FEC" }, { LLDP_DOT3_MAU_25GBASEKR, "25GbaseKR - 25GBASE-R PCS/PMA over an electrical backplane" }, { LLDP_DOT3_MAU_25GBASEKRS, "25GbaseKRS - 25GBASE-R PCS/PMA over an electrical backplane without RS-FEC" }, { LLDP_DOT3_MAU_25GBASER, "25GbaseR - 25GBASE-R PCS/PMA over undefined PMD" }, { LLDP_DOT3_MAU_25GBASESR, "25GbaseSR - 25GBASE-R PCS/PMA over multimode fiber" }, { LLDP_DOT3_MAU_25GBASET, "25GbaseT - Four-pair twisted-pair balanced copper cabling" }, { LLDP_DOT3_MAU_40GBASEER4, "40GbaseER4 - 40GBASE-R PCS/PMA over 4 WDM lane single mode fiber" }, { LLDP_DOT3_MAU_40GBASER, "40GbaseR - 40GBASE-R PCS as over undefined PMA/PMD" }, { LLDP_DOT3_MAU_40GBASET, "40GbaseT - Four-pair twisted-pair balanced copper cabling" }, { LLDP_DOT3_MAU_100GBASECR4, "100GbaseCR4 - 100GBASE-R PCS/PMA over 4 lane shielded copper balanced cable" }, { LLDP_DOT3_MAU_100GBASEKR4, "100GbaseKR4 - 100GBASE-R PCS/PMA over an electrical backplane" }, { LLDP_DOT3_MAU_100GBASEKP4, "100GbaseKP4 - 100GBASE-P PCS/PMA over an electrical backplane PMD" }, { LLDP_DOT3_MAU_100GBASER, "100GbaseR - 100GBASE-R Multi-lane PCS over undefined PMA/PMD" }, { LLDP_DOT3_MAU_100GBASESR4, "100GbaseSR4 - 100GBASE-R PCS/PMA over 4 lane multimode fiber" }, { LLDP_DOT3_MAU_2P5GIGT, "2p5GigT - 2.5GBASE-T Four-pair twisted-pair balanced copper cabling PHY" }, { LLDP_DOT3_MAU_5GIGT, "5GigT - 5GBASE-T Four-pair twisted-pair balanced copper cabling PHY" }, { LLDP_DOT3_MAU_100BASET1, "100baseT1 - 100BASE-T1 Single balanced twisted-pair copper cabling PHY" }, { LLDP_DOT3_MAU_1000BASERHA, "1000baseRHA - 1000BASE-RHA Plastic optical fiber PHY" }, { LLDP_DOT3_MAU_1000BASERHB, "1000baseRHB - 1000BASE-RHB Plastic optical fiber PHY" }, { LLDP_DOT3_MAU_1000BASERHC, "1000baseRHC - 1000BASE-RHC Plastic optical fiber PHY" }, { LLDP_DOT3_MAU_2P5GBASEKX, "2p5GbaseKX - 2.5GBASE-X PMD over an electrical backplane" }, { LLDP_DOT3_MAU_2P5GBASEX, "2p5GbaseX - 2.5GBASE-X PCS/PMA over undefined PMD" }, { LLDP_DOT3_MAU_5GBASEKR, "5GbaseKR - 5GBASE-KR PMD over an electrical backplane" }, { LLDP_DOT3_MAU_5GBASER, "5GbaseR - 5GBASE-R PCS/PMA over undefined PMD" }, { LLDP_DOT3_MAU_10GPASSXR, "10GpassXR - Coax cable distribution network PHY continuous downstream/burst mode upstream PHY" }, { LLDP_DOT3_MAU_25GBASELR, "25GbaseLR - 25GBASE-R PCS/PMA over single-mode fiber PMD, with long reach" }, { LLDP_DOT3_MAU_25GBASEER, "25GbaseER - 25GBASE-R PCS/PMA over single-mode fiber PMD, with extended reach" }, { LLDP_DOT3_MAU_50GBASER, "50GbaseR - 50GBASE-R Multi-lane PCS over undefined PMA/PMD" }, { LLDP_DOT3_MAU_50GBASECR, "50GbaseCR - 50GBASE-R PCS/PMA over shielded copper balanced cable PMD" }, { LLDP_DOT3_MAU_50GBASEKR, "50GbaseKR - 50GBASE-R PCS/PMA over an electrical backplane PMD" }, { LLDP_DOT3_MAU_50GBASESR, "50GbaseSR - 50GBASE-R PCS/PMA over multimode fiber PMD" }, { LLDP_DOT3_MAU_50GBASEFR, "50GbaseFR - 50GBASE-R PCS/PMA over single mode fiber PMD with reach up to at least 2 km" }, { LLDP_DOT3_MAU_50GBASELR, "50GbaseLR - 50GBASE-R PCS/PMA over single mode fiber PMD with reach up to at least 10 km" }, { LLDP_DOT3_MAU_50GBASEER, "50GbaseER - 50GBASE-R PCS/PMA over single-mode fiber PMD with reach up to at least 40 km" }, { LLDP_DOT3_MAU_100GBASECR2, "100GbaseCR2 - 100GBASE-R PCS/PMA over 2 lane shielded copper balanced cable PMD" }, { LLDP_DOT3_MAU_100GBASEKR2, "100GbaseKR2 - 100GBASE-R PCS/PMA over an electrical backplane PMD" }, { LLDP_DOT3_MAU_100GBASESR2, "100GbaseSR2 - 100GBASE-R PCS/PMA over 2 lane multimode fiber PMD" }, { LLDP_DOT3_MAU_100GBASEDR, "100GbaseDR - 100GBASE-R PCS/PMA over single mode fiber PMD" }, { LLDP_DOT3_MAU_200GBASER, "200GbaseR - 200GBASE-R Multi-lane PCS over undefined PMA/PMD" }, { LLDP_DOT3_MAU_200GBASEDR4, "200GbaseDR4 - 200GBASE-R PCS/PMA over 4-lane single-mode fiber PMD" }, { LLDP_DOT3_MAU_200GBASEFR4, "200GbaseFR4 - 200GBASE-R PCS/PMA over 4 WDM lane single-mode fiber PMD with reach up to at least 2 km" }, { LLDP_DOT3_MAU_200GBASELR4, "200GbaseLR4 - 200GBASE-R PCS/PMA over 4 WDM lane single-mode fiber PMD with reach up to at least 10 km" }, { LLDP_DOT3_MAU_200GBASECR4, "200GbaseCR4 - 200GBASE-R PCS/PMA over 4 lane shielded copper balanced cable PMD" }, { LLDP_DOT3_MAU_200GBASEKR4, "200GbaseKR4 - 200GBASE-R PCS/PMA over an electrical backplane PMD" }, { LLDP_DOT3_MAU_200GBASESR4, "200GbaseSR4 - 200GBASE-R PCS/PMA over 4 lane multimode fiber PMD" }, { LLDP_DOT3_MAU_200GBASEER4, "200GbaseER4 - 200GBASE-R PCS/PMA over 4 WDM lane single-mode fiber PMD with reach up to at least 40 km" }, { LLDP_DOT3_MAU_400GBASER, "400GbaseR - 400GBASE-R Multi-lane PCS over undefined PMA/PMD" }, { LLDP_DOT3_MAU_400GBASESR16, "400GbaseSR16 - 400GBASE-R PCS/PMA over 16-lane multimode fiber PMD" }, { LLDP_DOT3_MAU_400GBASEDR4, "400GbaseDR4 - 400GBASE-R PCS/PMA over 4-lane single-mode fiber PMD" }, { LLDP_DOT3_MAU_400GBASEFR8, "400GbaseFR8 - 400GBASE-R PCS/PMA over 8 WDM lane single-mode fiber PMD with reach up to at least 2 km" }, { LLDP_DOT3_MAU_400GBASELR8, "400GbaseLR8 - 400GBASE-R PCS/PMA over 8 WDM lane single-mode fiber PMD with reach up to at least 10 km" }, { LLDP_DOT3_MAU_400GBASEER8, "400GbaseER8 - 400GBASE-R PCS/PMA over 8 WDM lane single-mode fiber PMD with reach up to at least 40 km" }, { LLDP_DOT3_MAU_10BASET1L, "10baseT1L - 10BASE-T1L Single balanced pair PHY" }, { LLDP_DOT3_MAU_10BASET1SHD, "10baseT1SHD - 10BASE-T1S Single balanced pair PHY, half duplex mode" }, { LLDP_DOT3_MAU_10BASET1SMD, "10baseT1SMD - 10BASE-T1S Single balanced pair PHY, multidrop mode" }, { LLDP_DOT3_MAU_10BASET1SFD, "10baseT1SFD - 10BASE-T1S Single balanced pair PHY, full duplex mode" }, { 0, NULL } }; #endif static lldpctl_atom_iter_t * _lldpctl_atom_iter_ports_list(lldpctl_atom_t *atom) { struct _lldpctl_atom_any_list_t *plist = (struct _lldpctl_atom_any_list_t *)atom; return (lldpctl_atom_iter_t *)TAILQ_FIRST(&plist->parent->hardware->h_rports); } static lldpctl_atom_iter_t * _lldpctl_atom_next_ports_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter) { struct lldpd_port *port = (struct lldpd_port *)iter; return (lldpctl_atom_iter_t *)TAILQ_NEXT(port, p_entries); } static lldpctl_atom_t * _lldpctl_atom_value_ports_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter) { struct lldpd_port *port = (struct lldpd_port *)iter; return _lldpctl_new_atom(atom->conn, atom_port, 0, NULL, port, ((struct _lldpctl_atom_any_list_t *)atom)->parent); } static int _lldpctl_atom_new_port(lldpctl_atom_t *atom, va_list ap) { struct _lldpctl_atom_port_t *port = (struct _lldpctl_atom_port_t *)atom; port->local = va_arg(ap, int); port->hardware = va_arg(ap, struct lldpd_hardware *); port->port = va_arg(ap, struct lldpd_port *); port->parent = va_arg(ap, struct _lldpctl_atom_port_t *); if (port->parent) lldpctl_atom_inc_ref((lldpctl_atom_t *)port->parent); if (port->port) { /* Internal atom. We are the parent, but our reference count is * not incremented. */ port->chassis = _lldpctl_new_atom(atom->conn, atom_chassis, port->port->p_chassis, port, 1); } return 1; } TAILQ_HEAD(chassis_list, lldpd_chassis); static void add_chassis(struct chassis_list *chassis_list, struct lldpd_chassis *chassis) { struct lldpd_chassis *one_chassis; TAILQ_FOREACH (one_chassis, chassis_list, c_entries) { if (one_chassis == chassis) return; } TAILQ_INSERT_TAIL(chassis_list, chassis, c_entries); } static void _lldpctl_atom_free_port(lldpctl_atom_t *atom) { struct _lldpctl_atom_port_t *port = (struct _lldpctl_atom_port_t *)atom; struct lldpd_hardware *hardware = port->hardware; struct lldpd_chassis *one_chassis, *one_chassis_next; struct lldpd_port *one_port; /* Free internal chassis atom. Should be freed immediately since we * should have the only reference. */ lldpctl_atom_dec_ref((lldpctl_atom_t *)port->chassis); /* We need to free the whole struct lldpd_hardware: local port, local * chassis and remote ports... The same chassis may be present several * times. We build a list of chassis (we don't use reference count). */ struct chassis_list chassis_list; TAILQ_INIT(&chassis_list); if (port->parent) lldpctl_atom_dec_ref((lldpctl_atom_t *)port->parent); else if (!hardware && port->port) { /* No parent, no hardware, we assume a single neighbor: one * port, one chassis. */ if (port->port->p_chassis) { lldpd_chassis_cleanup(port->port->p_chassis, 1); port->port->p_chassis = NULL; } lldpd_port_cleanup(port->port, 1); free(port->port); } if (!hardware) return; add_chassis(&chassis_list, port->port->p_chassis); TAILQ_FOREACH (one_port, &hardware->h_rports, p_entries) add_chassis(&chassis_list, one_port->p_chassis); /* Free hardware port */ lldpd_remote_cleanup(hardware, NULL, 1); lldpd_port_cleanup(port->port, 1); free(port->hardware); /* Free list of chassis */ for (one_chassis = TAILQ_FIRST(&chassis_list); one_chassis != NULL; one_chassis = one_chassis_next) { one_chassis_next = TAILQ_NEXT(one_chassis, c_entries); lldpd_chassis_cleanup(one_chassis, 1); } } static lldpctl_atom_t * _lldpctl_atom_get_atom_port(lldpctl_atom_t *atom, lldpctl_key_t key) { struct _lldpctl_atom_port_t *p = (struct _lldpctl_atom_port_t *)atom; struct lldpd_port *port = p->port; struct lldpd_hardware *hardware = p->hardware; /* Local port only */ if (hardware != NULL) { switch (key) { case lldpctl_k_port_neighbors: return _lldpctl_new_atom(atom->conn, atom_ports_list, p); default: break; } } /* Local and remote port */ switch (key) { case lldpctl_k_port_chassis: if (port->p_chassis) { return _lldpctl_new_atom(atom->conn, atom_chassis, port->p_chassis, p, 0); } SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; #ifdef ENABLE_DOT3 case lldpctl_k_port_dot3_power: return _lldpctl_new_atom(atom->conn, atom_dot3_power, p); #endif #ifdef ENABLE_DOT1 case lldpctl_k_port_vlans: return _lldpctl_new_atom(atom->conn, atom_vlans_list, p); case lldpctl_k_port_ppvids: return _lldpctl_new_atom(atom->conn, atom_ppvids_list, p); case lldpctl_k_port_pis: return _lldpctl_new_atom(atom->conn, atom_pis_list, p); #endif #ifdef ENABLE_LLDPMED case lldpctl_k_port_med_policies: return _lldpctl_new_atom(atom->conn, atom_med_policies_list, p); case lldpctl_k_port_med_locations: return _lldpctl_new_atom(atom->conn, atom_med_locations_list, p); case lldpctl_k_port_med_power: return _lldpctl_new_atom(atom->conn, atom_med_power, p); #endif #ifdef ENABLE_CUSTOM case lldpctl_k_custom_tlvs: return _lldpctl_new_atom(atom->conn, atom_custom_list, p); #endif default: /* Compatibility: query the associated chassis too */ if (port->p_chassis) return lldpctl_atom_get(p->chassis, key); SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; } } static lldpctl_atom_t * _lldpctl_atom_set_atom_port(lldpctl_atom_t *atom, lldpctl_key_t key, lldpctl_atom_t *value) { struct _lldpctl_atom_port_t *p = (struct _lldpctl_atom_port_t *)atom; struct lldpd_hardware *hardware = p->hardware; struct lldpd_port_set set = {}; int rc; char *canary = NULL; #ifdef ENABLE_DOT3 struct _lldpctl_atom_dot3_power_t *dpow; #endif #ifdef ENABLE_LLDPMED struct _lldpctl_atom_med_power_t *mpow; struct _lldpctl_atom_med_policy_t *mpol; struct _lldpctl_atom_med_location_t *mloc; #endif #ifdef ENABLE_CUSTOM struct _lldpctl_atom_custom_t *custom; #endif /* Local and default port only */ if (!p->local) { SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; } set.vlan_tx_enabled = -1; switch (key) { case lldpctl_k_port_id: set.local_id = p->port->p_id; break; case lldpctl_k_port_descr: set.local_descr = p->port->p_descr; break; case lldpctl_k_port_status: set.rxtx = LLDPD_RXTX_FROM_PORT(p->port); break; case lldpctl_k_port_vlan_tx: set.vlan_tx_tag = p->port->p_vlan_tx_tag; set.vlan_tx_enabled = p->port->p_vlan_tx_enabled; break; #ifdef ENABLE_DOT3 case lldpctl_k_port_dot3_power: if (value->type != atom_dot3_power) { SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE); return NULL; } dpow = (struct _lldpctl_atom_dot3_power_t *)value; set.dot3_power = &dpow->parent->port->p_power; break; #endif #ifdef ENABLE_LLDPMED case lldpctl_k_port_med_power: if (value->type != atom_med_power) { SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE); return NULL; } mpow = (struct _lldpctl_atom_med_power_t *)value; set.med_power = &mpow->parent->port->p_med_power; break; case lldpctl_k_port_med_policies: if (value->type != atom_med_policy) { SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE); return NULL; } mpol = (struct _lldpctl_atom_med_policy_t *)value; set.med_policy = mpol->policy; break; case lldpctl_k_port_med_locations: if (value->type != atom_med_location) { SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE); return NULL; } mloc = (struct _lldpctl_atom_med_location_t *)value; set.med_location = mloc->location; break; #endif #ifdef ENABLE_CUSTOM case lldpctl_k_custom_tlvs_clear: set.custom_list_clear = 1; break; case lldpctl_k_custom_tlv: if (value->type != atom_custom) { SET_ERROR(atom->conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE); return NULL; } custom = (struct _lldpctl_atom_custom_t *)value; set.custom = custom->tlv; set.custom_tlv_op = custom->op; break; #endif default: SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; } char empty_str[] = ""; set.ifname = hardware ? hardware->h_ifname : empty_str; if (asprintf(&canary, "%d%p%s", key, value, set.ifname) == -1) { SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM); return NULL; } rc = _lldpctl_do_something(atom->conn, CONN_STATE_SET_PORT_SEND, CONN_STATE_SET_PORT_RECV, canary, SET_PORT, &set, &MARSHAL_INFO(lldpd_port_set), NULL, NULL); free(canary); if (rc == 0) return atom; return NULL; } static const char * _lldpctl_atom_get_str_port(lldpctl_atom_t *atom, lldpctl_key_t key) { struct _lldpctl_atom_port_t *p = (struct _lldpctl_atom_port_t *)atom; struct lldpd_port *port = p->port; struct lldpd_hardware *hardware = p->hardware; char *ipaddress = NULL; size_t len; /* Local port only */ switch (key) { case lldpctl_k_port_name: if (hardware != NULL) return hardware->h_ifname; break; case lldpctl_k_port_status: if (p->local) return map_lookup(port_status_map.map, LLDPD_RXTX_FROM_PORT(port)); break; default: break; } if (!port) return NULL; /* Local and remote port */ switch (key) { case lldpctl_k_port_protocol: return map_lookup(lldpd_protocol_map.map, port->p_protocol); case lldpctl_k_port_id_subtype: return map_lookup(port_id_subtype_map, port->p_id_subtype); case lldpctl_k_port_id: switch (port->p_id_subtype) { case LLDP_PORTID_SUBTYPE_IFNAME: case LLDP_PORTID_SUBTYPE_IFALIAS: case LLDP_PORTID_SUBTYPE_LOCAL: return port->p_id; case LLDP_PORTID_SUBTYPE_LLADDR: return _lldpctl_dump_in_atom(atom, (uint8_t *)port->p_id, port->p_id_len, ':', 0); case LLDP_PORTID_SUBTYPE_ADDR: switch (port->p_id[0]) { case LLDP_MGMT_ADDR_IP4: len = INET_ADDRSTRLEN + 1; break; case LLDP_MGMT_ADDR_IP6: len = INET6_ADDRSTRLEN + 1; break; default: len = 0; } if (len > 0) { ipaddress = _lldpctl_alloc_in_atom(atom, len); if (!ipaddress) return NULL; if (inet_ntop((port->p_id[0] == LLDP_MGMT_ADDR_IP4) ? AF_INET : AF_INET6, &port->p_id[1], ipaddress, len) == NULL) break; return ipaddress; } break; } SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; case lldpctl_k_port_descr: return port->p_descr; #ifdef ENABLE_DOT3 case lldpctl_k_port_dot3_mautype: return map_lookup(operational_mau_type_values, port->p_macphy.mau_type); #endif default: /* Compatibility: query the associated chassis too */ return lldpctl_atom_get_str(p->chassis, key); } } static lldpctl_atom_t * _lldpctl_atom_set_int_port(lldpctl_atom_t *atom, lldpctl_key_t key, long int value) { struct _lldpctl_atom_port_t *p = (struct _lldpctl_atom_port_t *)atom; struct lldpd_port *port = p->port; if (p->local) { switch (key) { case lldpctl_k_port_status: port->p_disable_rx = !LLDPD_RXTX_RXENABLED(value); port->p_disable_tx = !LLDPD_RXTX_TXENABLED(value); break; case lldpctl_k_port_vlan_tx: if (value > -1) { port->p_vlan_tx_tag = value; port->p_vlan_tx_enabled = 1; } else port->p_vlan_tx_enabled = 0; break; default: SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; } } else { SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; } return _lldpctl_atom_set_atom_port(atom, key, NULL); } static lldpctl_atom_t * _lldpctl_atom_set_str_port(lldpctl_atom_t *atom, lldpctl_key_t key, const char *value) { struct _lldpctl_atom_port_t *p = (struct _lldpctl_atom_port_t *)atom; struct lldpd_port *port = p->port; if (!value || !strlen(value)) return NULL; if (p->local) { switch (key) { case lldpctl_k_port_status: return _lldpctl_atom_set_int_port(atom, key, map_reverse_lookup(port_status_map.map, value)); default: break; } } switch (key) { case lldpctl_k_port_id: free(port->p_id); port->p_id = strdup(value); port->p_id_len = strlen(value); break; case lldpctl_k_port_descr: free(port->p_descr); port->p_descr = strdup(value); break; default: SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; } return _lldpctl_atom_set_atom_port(atom, key, NULL); } static long int _lldpctl_atom_get_int_port(lldpctl_atom_t *atom, lldpctl_key_t key) { struct _lldpctl_atom_port_t *p = (struct _lldpctl_atom_port_t *)atom; struct lldpd_port *port = p->port; struct lldpd_hardware *hardware = p->hardware; /* Local port only */ if (hardware != NULL) { switch (key) { case lldpctl_k_port_index: return hardware->h_ifindex; case lldpctl_k_tx_cnt: return hardware->h_tx_cnt; case lldpctl_k_rx_cnt: return hardware->h_rx_cnt; case lldpctl_k_rx_discarded_cnt: return hardware->h_rx_discarded_cnt; case lldpctl_k_rx_unrecognized_cnt: return hardware->h_rx_unrecognized_cnt; case lldpctl_k_ageout_cnt: return hardware->h_ageout_cnt; case lldpctl_k_insert_cnt: return hardware->h_insert_cnt; case lldpctl_k_delete_cnt: return hardware->h_delete_cnt; default: break; } } if (p->local) { switch (key) { case lldpctl_k_port_status: return LLDPD_RXTX_FROM_PORT(port); default: break; } } if (!port) return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); /* Local and remote port */ switch (key) { case lldpctl_k_port_protocol: return port->p_protocol; case lldpctl_k_port_age: return port->p_lastchange; case lldpctl_k_port_ttl: return port->p_ttl; case lldpctl_k_port_id_subtype: return port->p_id_subtype; case lldpctl_k_port_hidden: return port->p_hidden_in; case lldpctl_k_port_vlan_tx: return port->p_vlan_tx_enabled ? port->p_vlan_tx_tag : -1; #ifdef ENABLE_DOT3 case lldpctl_k_port_dot3_mfs: if (port->p_mfs > 0) return port->p_mfs; break; case lldpctl_k_port_dot3_aggregid: if (port->p_aggregid > 0) return port->p_aggregid; break; case lldpctl_k_port_dot3_autoneg_support: return port->p_macphy.autoneg_support; case lldpctl_k_port_dot3_autoneg_enabled: return port->p_macphy.autoneg_enabled; case lldpctl_k_port_dot3_autoneg_advertised: return port->p_macphy.autoneg_advertised; case lldpctl_k_port_dot3_mautype: return port->p_macphy.mau_type; #endif #ifdef ENABLE_DOT1 case lldpctl_k_port_vlan_pvid: return port->p_pvid; #endif default: /* Compatibility: query the associated chassis too */ return lldpctl_atom_get_int(p->chassis, key); } return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); } static const uint8_t * _lldpctl_atom_get_buf_port(lldpctl_atom_t *atom, lldpctl_key_t key, size_t *n) { struct _lldpctl_atom_port_t *p = (struct _lldpctl_atom_port_t *)atom; struct lldpd_port *port = p->port; switch (key) { case lldpctl_k_port_id: *n = port->p_id_len; return (uint8_t *)port->p_id; default: /* Compatibility: query the associated chassis too */ return lldpctl_atom_get_buffer(p->chassis, key, n); } } static struct atom_builder ports_list = { atom_ports_list, sizeof(struct _lldpctl_atom_any_list_t), .init = _lldpctl_atom_new_any_list, .free = _lldpctl_atom_free_any_list, .iter = _lldpctl_atom_iter_ports_list, .next = _lldpctl_atom_next_ports_list, .value = _lldpctl_atom_value_ports_list }; static struct atom_builder port = { atom_port, sizeof(struct _lldpctl_atom_port_t), .init = _lldpctl_atom_new_port, .free = _lldpctl_atom_free_port, .get = _lldpctl_atom_get_atom_port, .set = _lldpctl_atom_set_atom_port, .get_str = _lldpctl_atom_get_str_port, .set_str = _lldpctl_atom_set_str_port, .get_int = _lldpctl_atom_get_int_port, .set_int = _lldpctl_atom_set_int_port, .get_buffer = _lldpctl_atom_get_buf_port }; ATOM_BUILDER_REGISTER(ports_list, 4); ATOM_BUILDER_REGISTER(port, 5);