--- /dev/null
+/*
+ * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
+ *
+ * Permission to use, copy, modify, and 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 "lldpd.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <arpa/inet.h>
+
+TAILQ_HEAD(interfaces, lldpd_interface);
+#ifdef ENABLE_DOT1
+TAILQ_HEAD(vlans, lldpd_vlan);
+#endif
+
+#define ntohll(x) (((u_int64_t)(ntohl((int)((x << 32) >> 32))) << 32) | \
+ (unsigned int)ntohl(((int)(x >> 32))))
+#define htonll(x) ntohll(x)
+
+struct value_string {
+ int value;
+ char *string;
+};
+
+#ifdef ENABLE_LLDPMED
+static const struct value_string civic_address_type_values[] = {
+ { 0, "Language" },
+ { 1, "National subdivisions" },
+ { 2, "County, parish, district" },
+ { 3, "City, township" },
+ { 4, "City division, borough, ward" },
+ { 5, "Neighborhood, block" },
+ { 6, "Street" },
+ { 16, "Leading street direction" },
+ { 17, "Trailing street suffix" },
+ { 18, "Street suffix" },
+ { 19, "House number" },
+ { 20, "House number suffix" },
+ { 21, "Landmark or vanity address" },
+ { 22, "Additional location info" },
+ { 23, "Name" },
+ { 24, "Postal/ZIP code" },
+ { 25, "Building" },
+ { 26, "Unit" },
+ { 27, "Floor" },
+ { 28, "Room number" },
+ { 29, "Place type" },
+ { 128, "Script" },
+ { 0, NULL }
+};
+#endif
+
+#ifdef ENABLE_DOT3
+static const struct value_string 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, "100BaseT2DF - 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 }
+};
+#endif
+
+static char*
+dump(void *data, int size, int max, char sep)
+{
+ int i;
+ size_t len;
+ static char *buffer = NULL;
+ static char truncation[] = "[...]";
+
+ free(buffer);
+ if (size > max)
+ len = max * 3 + sizeof(truncation) + 1;
+ else
+ len = size * 3;
+
+ if ((buffer = (char *)malloc(len)) == NULL)
+ fatal(NULL);
+
+ for (i = 0; (i < size) && (i < max); i++)
+ sprintf(buffer + i * 3, "%02x%c", *(u_int8_t*)(data + i), sep);
+ if (size > max)
+ sprintf(buffer + i * 3, "%s", truncation);
+ else
+ *(buffer + i*3 - 1) = 0;
+ return buffer;
+}
+
+
+void
+get_interfaces(int s, struct interfaces *ifs)
+{
+ void *p;
+ struct hmsg *h;
+
+ if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL)
+ fatal(NULL);
+ ctl_msg_init(h, HMSG_GET_INTERFACES);
+ if (ctl_msg_send(s, h) == -1)
+ fatalx("get_interfaces: unable to send request");
+ if (ctl_msg_recv(s, h) == -1)
+ fatalx("get_interfaces: unable to receive answer");
+ if (h->hdr.type != HMSG_GET_INTERFACES)
+ fatalx("get_interfaces: unknown answer type received");
+ p = &h->data;
+ if (ctl_msg_unpack_list(STRUCT_LLDPD_INTERFACE,
+ ifs, sizeof(struct lldpd_interface), h, &p) == -1)
+ fatalx("get_interfaces: unable to retrieve the list of interfaces");
+}
+
+#ifdef ENABLE_DOT1
+static int
+get_vlans(int s, struct vlans *vls, char *interface, int nb)
+{
+ void *p;
+ struct hmsg *h;
+
+ if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL)
+ fatal(NULL);
+ ctl_msg_init(h, HMSG_GET_VLANS);
+ strlcpy((char *)&h->data, interface, IFNAMSIZ);
+ memcpy((char*)&h->data + IFNAMSIZ, &nb, sizeof(int));
+ h->hdr.len += IFNAMSIZ + sizeof(int);
+ if (ctl_msg_send(s, h) == -1)
+ fatalx("get_vlans: unable to send request");
+ if (ctl_msg_recv(s, h) == -1)
+ fatalx("get_vlans: unable to receive answer");
+ if (h->hdr.type != HMSG_GET_VLANS)
+ fatalx("get_vlans: unknown answer type received");
+ p = &h->data;
+ if (ctl_msg_unpack_list(STRUCT_LLDPD_VLAN,
+ vls, sizeof(struct lldpd_vlan), h, &p) == -1)
+ fatalx("get_vlans: unable to retrieve the list of vlans");
+ return 1;
+}
+#endif
+
+static int
+get_chassis(int s, struct lldpd_chassis *chassis, char *interface, int nb)
+{
+ struct hmsg *h;
+ void *p;
+
+ if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL)
+ fatal(NULL);
+ ctl_msg_init(h, HMSG_GET_CHASSIS);
+ strlcpy((char *)&h->data, interface, IFNAMSIZ);
+ memcpy((char*)&h->data + IFNAMSIZ, &nb, sizeof(int));
+ h->hdr.len += IFNAMSIZ + sizeof(int);
+ if (ctl_msg_send(s, h) == -1)
+ fatalx("get_chassis: unable to send request to get chassis");
+ if (ctl_msg_recv(s, h) == -1)
+ fatalx("get_chassis: unable to receive answer to get chassis");
+ if (h->hdr.type == HMSG_NONE)
+ /* No chassis */
+ return -1;
+ p = &h->data;
+ if (ctl_msg_unpack_structure(STRUCT_LLDPD_CHASSIS,
+ chassis, sizeof(struct lldpd_chassis), h, &p) == -1) {
+ LLOG_WARNX("unable to retrieve chassis for %s", interface);
+ fatalx("get_chassis: abort");
+ }
+ return 1;
+}
+
+static int
+get_port(int s, struct lldpd_port *port, char *interface, int nb)
+{
+ struct hmsg *h;
+ void *p;
+
+ if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL)
+ fatal(NULL);
+ ctl_msg_init(h, HMSG_GET_PORT);
+ strlcpy((char *)&h->data, interface, IFNAMSIZ);
+ memcpy((char*)&h->data + IFNAMSIZ, &nb, sizeof(int));
+ h->hdr.len += IFNAMSIZ + sizeof(int);
+ if (ctl_msg_send(s, h) == -1)
+ fatalx("get_port: unable to send request to get port");
+ if (ctl_msg_recv(s, h) == -1)
+ fatalx("get_port: unable to receive answer to get port");
+ if (h->hdr.type == HMSG_NONE)
+ /* No port */
+ return -1;
+ p = &h->data;
+ if (ctl_msg_unpack_structure(STRUCT_LLDPD_PORT,
+ port, sizeof(struct lldpd_port), h, &p) == -1) {
+ LLOG_WARNX("unable to retrieve port information for %s",
+ interface);
+ fatalx("get_chassis: abort");
+ }
+ return 1;
+}
+
+static int
+get_nb_port(int s, char *interface)
+{
+ struct hmsg *h;
+ int nb;
+
+ if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL)
+ fatal(NULL);
+ ctl_msg_init(h, HMSG_GET_NB_PORTS);
+ strlcpy((char *)&h->data, interface, IFNAMSIZ);
+ h->hdr.len += IFNAMSIZ;
+ if (ctl_msg_send(s, h) == -1)
+ fatalx("get_nb_port: unable to send request to get number of ports");
+ if (ctl_msg_recv(s, h) == -1)
+ fatalx("get_nb_port: unable to receive answer to get number of ports");
+ if (h->hdr.type == HMSG_NONE)
+ return -1;
+ if (h->hdr.len != sizeof(int))
+ fatalx("get_nb_port: bad message length");
+ memcpy(&nb, &h->data, sizeof(int));
+ return nb;
+}
+
+static void
+display_cap(struct lldpd_chassis *chassis, u_int8_t bit, char *symbol)
+{
+ if (chassis->c_cap_available & bit)
+ printf("%s(%c) ", symbol,
+ (chassis->c_cap_enabled & bit)?'E':'d');
+}
+
+static void
+pretty_print(char *string)
+{
+ char *s = NULL;
+ if (((s = strchr(string, '\n')) == NULL) && (strlen(string) < 60)) {
+ printf("%s\n", string);
+ return;
+ } else
+ printf("\n");
+ while (s != NULL) {
+ *s = '\0';
+ printf(" %s\n", string);
+ *s = '\n';
+ string = s + 1;
+ s = strchr(string, '\n');
+ }
+ printf(" %s\n", string);
+}
+
+#ifdef ENABLE_LLDPMED
+static int
+display_fixed_precision(u_int64_t value, int intpart, int floatpart, int displaysign)
+{
+ u_int64_t tmp = value;
+ int negative = 0;
+ u_int32_t integer = 0;
+ if (value & (1ULL<<(intpart + floatpart - 1))) {
+ negative = 1;
+ tmp = ~value;
+ tmp += 1;
+ }
+ integer = (u_int32_t)((tmp &
+ (((1ULL << intpart)-1) << floatpart)) >> floatpart);
+ tmp = (tmp & ((1<< floatpart) - 1))*10000/(1ULL << floatpart);
+ printf("%s%u.%04llu", displaysign?(negative?"-":"+"):"",
+ integer, (unsigned long long int)tmp);
+ return negative;
+}
+
+static void
+display_latitude_or_longitude(int option, u_int64_t value)
+{
+ int negative;
+ negative = display_fixed_precision(value, 9, 25, 0);
+ if (option == 0)
+ printf("%s", negative?" South":" North");
+ else
+ printf("%s", negative?" West":" East");
+}
+
+static void
+display_med(struct lldpd_chassis *chassis, struct lldpd_port *port)
+{
+ int i;
+ char *value;
+ printf(" LLDP-MED Device Type: ");
+ switch (chassis->c_med_type) {
+ case LLDPMED_CLASS_I:
+ printf("Generic Endpoint (Class I)");
+ break;
+ case LLDPMED_CLASS_II:
+ printf("Media Endpoint (Class II)");
+ break;
+ case LLDPMED_CLASS_III:
+ printf("Communication Device Endpoint (Class III)");
+ break;
+ case LLDPMED_NETWORK_DEVICE:
+ printf("Network Connectivity Device");
+ break;
+ default:
+ printf("Unknown (%d)", chassis->c_med_type);
+ break;
+ }
+ printf("\n LLDP-MED Capabilities:");
+ if (chassis->c_med_cap_available & LLDPMED_CAP_CAP)
+ printf(" Capabilities");
+ if (chassis->c_med_cap_available & LLDPMED_CAP_POLICY)
+ printf(" Policy");
+ if (chassis->c_med_cap_available & LLDPMED_CAP_LOCATION)
+ printf(" Location");
+ if (chassis->c_med_cap_available & LLDPMED_CAP_MDI_PSE)
+ printf(" MDI/PSE");
+ if (chassis->c_med_cap_available & LLDPMED_CAP_MDI_PD)
+ printf(" MDI/PD");
+ if (chassis->c_med_cap_available & LLDPMED_CAP_IV)
+ printf(" Inventory");
+ printf("\n");
+ for (i = 0; i < LLDPMED_APPTYPE_LAST; i++) {
+ if (i+1 == port->p_med_policy[i].type) {
+ printf(" LLDP-MED Network Policy for ");
+ switch(port->p_med_policy[i].type) {
+ case LLDPMED_APPTYPE_VOICE:
+ printf("Voice");
+ break;
+ case LLDPMED_APPTYPE_VOICESIGNAL:
+ printf("Voice Signaling");
+ break;
+ case LLDPMED_APPTYPE_GUESTVOICE:
+ printf("Guest Voice");
+ break;
+ case LLDPMED_APPTYPE_GUESTVOICESIGNAL:
+ printf("Guest Voice Signaling");
+ break;
+ case LLDPMED_APPTYPE_SOFTPHONEVOICE:
+ printf("Softphone Voice");
+ break;
+ case LLDPMED_APPTYPE_VIDEOCONFERENCE:
+ printf("Video Conferencing");
+ break;
+ case LLDPMED_APPTYPE_VIDEOSTREAM:
+ printf("Streaming Video");
+ break;
+ case LLDPMED_APPTYPE_VIDEOSIGNAL:
+ printf("Video Signaling");
+ break;
+ default:
+ printf("Reserved");
+ }
+ printf(":\n Policy: ");
+ if (port->p_med_policy[i].unknown) {
+ printf("unknown, ");
+ } else {
+ printf("defined, ");
+ }
+ if (!port->p_med_policy[i].tagged) {
+ printf("un");
+ }
+ printf("tagged");
+ printf("\n VLAN ID: ");
+ if (port->p_med_policy[i].vid == 0) {
+ printf("Priority Tagged");
+ } else if (port->p_med_policy[i].vid == 4095) {
+ printf("reserved");
+ } else {
+ printf("%u", port->p_med_policy[i].vid);
+ }
+ printf("\n Layer 2 Priority: ");
+ printf("%u", port->p_med_policy[i].priority);
+ printf("\n DSCP Value: ");
+ printf("%u\n", port->p_med_policy[i].dscp);
+ }
+ }
+ for (i = 0; i < LLDPMED_LOCFORMAT_LAST; i++) {
+ if (i+1 == port->p_med_location[i].format) {
+ printf(" LLDP-MED Location Identification: ");
+ switch(port->p_med_location[i].format) {
+ case LLDPMED_LOCFORMAT_COORD:
+ printf("\n Coordinate-based data: ");
+ if (port->p_med_location[i].data_len != 16)
+ printf("bad data length");
+ else {
+ u_int64_t l;
+
+ /* Latitude and longitude */
+ memcpy(&l, port->p_med_location[i].data,
+ sizeof(u_int64_t));
+ l = (ntohll(l) &
+ 0x03FFFFFFFF000000ULL) >> 24;
+ display_latitude_or_longitude(0, l);
+ printf(", ");
+ memcpy(&l, port->p_med_location[i].data + 5,
+ sizeof(u_int64_t));
+ l = (ntohll(l) &
+ 0x03FFFFFFFF000000ULL) >> 24;
+ display_latitude_or_longitude(1, l);
+
+ /* Altitude */
+ printf(", ");
+ memcpy(&l, port->p_med_location[i].data + 10,
+ sizeof(u_int64_t));
+ l = (ntohll(l) &
+ 0x3FFFFFFF000000ULL) >> 24;
+ display_fixed_precision(l, 22, 8, 1);
+ switch ((*(u_int8_t*)(port->p_med_location[i].data +
+ 10)) & 0xf0) {
+ case (1 << 4):
+ printf(" meters"); break;
+ case (2 << 4):
+ printf(" floors"); break;
+ default:
+ printf(" (unknown)");
+ }
+
+ /* Datum */
+ switch (*(u_int8_t*)(port->p_med_location[i].data +
+ 15)) {
+ case 1:
+ printf(", WGS84"); break;
+ case 2:
+ printf(", NAD83"); break;
+ case 3:
+ printf(", NAD83/MLLW"); break;
+ }
+ }
+ break;
+ case LLDPMED_LOCFORMAT_CIVIC:
+ printf("Civic address: ");
+ if ((port->p_med_location[i].data_len < 3) ||
+ (port->p_med_location[i].data_len - 1 !=
+ *(u_int8_t*)port->p_med_location[i].data))
+ printf("bad data length");
+ else {
+ int l = 4, n, catype, calength, j = 0;
+ printf("\n%28s: %c%c", "Country",
+ ((char *)port->p_med_location[i].data)[2],
+ ((char *)port->p_med_location[i].data)[3]);
+ while ((n = (port->
+ p_med_location[i].data_len - l)) >= 2) {
+ catype = *(u_int8_t*)(port->
+ p_med_location[i].data + l);
+ calength = *(u_int8_t*)(port->
+ p_med_location[i].data + l + 1);
+ if (n < 2 + calength) {
+ printf("bad data length");
+ break;
+ }
+ for (j = 0;
+ civic_address_type_values[j].string != NULL;
+ j++) {
+ if (civic_address_type_values[j].value ==
+ catype)
+ break;
+ }
+ if (civic_address_type_values[j].string == NULL) {
+ printf("unknown type %d", catype);
+ break;
+ }
+ if ((value = strndup((char *)(port->
+ p_med_location[i].data + l + 2),
+ calength)) == NULL) {
+ printf("not enough memory");
+ break;
+ }
+ printf("\n%28s: %s",
+ civic_address_type_values[j].string,
+ value);
+ free(value);
+ l += 2 + calength;
+ }
+ }
+ break;
+ case LLDPMED_LOCFORMAT_ELIN:
+ if ((value = strndup((char *)(port->
+ p_med_location[i].data),
+ port->p_med_location[i].data_len)) == NULL) {
+ printf("not enough memory");
+ break;
+ }
+ printf("ECS ELIN: %s", value);
+ free(value);
+ break;
+ default:
+ printf("unknown location data format: \n %s",
+ dump(port->p_med_location[i].data,
+ port->p_med_location[i].data_len, 20, ' '));
+ }
+ printf("\n");
+ }
+ }
+ if (port->p_med_pow_devicetype) {
+ printf(" LLDP-MED Extended Power-over-Ethernet:\n");
+ printf(" Power Type & Source: ");
+ switch (port->p_med_pow_devicetype) {
+ case LLDPMED_POW_TYPE_PSE:
+ printf("PSE Device");
+ break;
+ case LLDPMED_POW_TYPE_PD:
+ printf("PD Device");
+ break;
+ default:
+ printf("reserved");
+ }
+ switch (port->p_med_pow_source) {
+ case LLDPMED_POW_SOURCE_UNKNOWN:
+ case LLDPMED_POW_SOURCE_RESERVED:
+ printf(", unknown"); break;
+ case LLDPMED_POW_SOURCE_PRIMARY:
+ printf(", Primary Power Source");
+ break;
+ case LLDPMED_POW_SOURCE_BACKUP:
+ printf(", Backup Power Source / Power Conservation Mode");
+ break;
+ case LLDPMED_POW_SOURCE_PSE:
+ printf(", PSE"); break;
+ case LLDPMED_POW_SOURCE_LOCAL:
+ printf(", local"); break;
+ case LLDPMED_POW_SOURCE_BOTH:
+ printf(", PSE & local");
+ break;
+ }
+ printf("\n Power Priority: ");
+ switch (port->p_med_pow_priority) {
+ case LLDPMED_POW_PRIO_CRITICAL:
+ printf("critical"); break;
+ case LLDPMED_POW_PRIO_HIGH:
+ printf("high"); break;
+ case LLDPMED_POW_PRIO_LOW:
+ printf("low"); break;
+ default:
+ printf("unknown");
+ }
+ printf("\n Power Value: ");
+ if(port->p_med_pow_val < 1024) {
+ printf("%u mW", port->p_med_pow_val * 100);
+ } else {
+ printf("reserved");
+ }
+ printf("\n");
+ }
+ if (chassis->c_med_hw ||
+ chassis->c_med_sw ||
+ chassis->c_med_fw ||
+ chassis->c_med_sn ||
+ chassis->c_med_manuf ||
+ chassis->c_med_model ||
+ chassis->c_med_asset) {
+ printf(" LLDP-MED Inventory:\n");
+ if (chassis->c_med_hw)
+ printf(" Hardware Revision: %s\n", chassis->c_med_hw);
+ if (chassis->c_med_sw)
+ printf(" Software Revision: %s\n", chassis->c_med_sw);
+ if (chassis->c_med_fw)
+ printf(" Firmware Revision: %s\n", chassis->c_med_fw);
+ if (chassis->c_med_sn)
+ printf(" Serial Number: %s\n", chassis->c_med_sn);
+ if (chassis->c_med_manuf)
+ printf(" Manufacturer: %s\n",
+ chassis->c_med_manuf);
+ if (chassis->c_med_model)
+ printf(" Model: %s\n",
+ chassis->c_med_model);
+ if (chassis->c_med_asset)
+ printf(" Asset ID: %s\n",
+ chassis->c_med_asset);
+ }
+}
+#endif
+
+static void
+display_chassis(struct lldpd_chassis *chassis)
+{
+ char *cid;
+ if ((cid = (char *)malloc(chassis->c_id_len + 1)) == NULL)
+ fatal(NULL);
+ memcpy(cid, chassis->c_id, chassis->c_id_len);
+ cid[chassis->c_id_len] = 0;
+ switch (chassis->c_id_subtype) {
+ case LLDP_CHASSISID_SUBTYPE_IFNAME:
+ printf(" ChassisID: %s (ifName)\n", cid);
+ break;
+ case LLDP_CHASSISID_SUBTYPE_IFALIAS:
+ printf(" ChassisID: %s (ifAlias)\n", cid);
+ break;
+ case LLDP_CHASSISID_SUBTYPE_LOCAL:
+ printf(" ChassisID: %s (local)\n", cid);
+ break;
+ case LLDP_CHASSISID_SUBTYPE_LLADDR:
+ printf(" ChassisID: %s (MAC)\n",
+ dump(chassis->c_id, chassis->c_id_len, ETH_ALEN, ':'));
+ break;
+ case LLDP_CHASSISID_SUBTYPE_ADDR:
+ if (*(u_int8_t*)chassis->c_id == 1) {
+ printf(" ChassisID: %s (IP)\n",
+ inet_ntoa(*(struct in_addr*)(chassis->c_id +
+ 1)));
+ break;
+ }
+ case LLDP_CHASSISID_SUBTYPE_PORT:
+ case LLDP_CHASSISID_SUBTYPE_CHASSIS:
+ default:
+ printf(" ChassisID: %s (unhandled type)\n",
+ dump(chassis->c_id, chassis->c_id_len, 16, ' '));
+ }
+ printf(" SysName: %s\n", chassis->c_name);
+ printf(" SysDescr: "); pretty_print(chassis->c_descr);
+ if (chassis->c_mgmt.s_addr != INADDR_ANY)
+ printf(" MgmtIP: %s\n", inet_ntoa(chassis->c_mgmt));
+ printf(" Caps: ");
+ display_cap(chassis, LLDP_CAP_OTHER, "Other");
+ display_cap(chassis, LLDP_CAP_REPEATER, "Repeater");
+ display_cap(chassis, LLDP_CAP_BRIDGE, "Bridge");
+ display_cap(chassis, LLDP_CAP_ROUTER, "Router");
+ display_cap(chassis, LLDP_CAP_WLAN, "Wlan");
+ display_cap(chassis, LLDP_CAP_TELEPHONE, "Tel");
+ display_cap(chassis, LLDP_CAP_DOCSIS, "Docsis");
+ display_cap(chassis, LLDP_CAP_STATION, "Station");
+ printf("\n");
+}
+
+#ifdef ENABLE_DOT3
+static void
+display_autoneg(struct lldpd_port *port, int bithd, int bitfd, char *desc)
+{
+ if (!((port->p_autoneg_advertised & bithd) ||
+ (port->p_autoneg_advertised & bitfd)))
+ return;
+ printf("%s ", desc);
+ if (port->p_autoneg_advertised & bithd) {
+ printf("(HD");
+ if (port->p_autoneg_advertised & bitfd) {
+ printf(", FD) ");
+ return;
+ }
+ printf(") ");
+ return;
+ }
+ printf("(FD) ");
+}
+#endif
+
+static void
+display_port(struct lldpd_port *port)
+{
+ char *pid;
+ struct in_addr address;
+#ifdef ENABLE_DOT3
+ int i;
+#endif
+
+ if ((pid = (char *)malloc(port->p_id_len + 1)) == NULL)
+ fatal(NULL);
+ memcpy(pid, port->p_id, port->p_id_len);
+ pid[port->p_id_len] = 0;
+ switch (port->p_id_subtype) {
+ case LLDP_PORTID_SUBTYPE_IFNAME:
+ printf(" PortID: %s (ifName)\n", pid);
+ break;
+ case LLDP_PORTID_SUBTYPE_IFALIAS:
+ printf(" PortID: %s (ifAlias)\n", pid);
+ break;
+ case LLDP_PORTID_SUBTYPE_LOCAL:
+ printf(" PortID: %s (local)\n", pid);
+ break;
+ case LLDP_PORTID_SUBTYPE_LLADDR:
+ printf(" PortID: %s (MAC)\n",
+ dump(port->p_id, port->p_id_len, ETH_ALEN, ':'));
+ break;
+ case LLDP_PORTID_SUBTYPE_ADDR:
+ if (*(u_int8_t*)port->p_id == 1) {
+ memcpy(&address, port->p_id + 1,
+ sizeof(struct in_addr));
+ printf(" PortID: %s (IP)\n",
+ inet_ntoa(address));
+ break;
+ }
+ case LLDP_PORTID_SUBTYPE_PORT:
+ case LLDP_PORTID_SUBTYPE_AGENTCID:
+ default:
+ printf(" ChassisID: %s (unhandled type)\n",
+ dump(port->p_id, port->p_id_len, 16, ' '));
+ }
+ printf(" PortDescr: "); pretty_print(port->p_descr);
+#ifdef ENABLE_DOT3
+ if (port->p_mfs)
+ printf(" MFS: %d bytes\n", port->p_mfs);
+ if (port->p_aggregid)
+ printf("\n Port is aggregated. PortAggregID: %d\n",
+ port->p_aggregid);
+
+ if (port->p_autoneg_support || port->p_autoneg_enabled ||
+ port->p_mau_type) {
+ printf("\n Autoneg: %ssupported/%senabled\n",
+ port->p_autoneg_support?"":"not ",
+ port->p_autoneg_enabled?"":"not ");
+ if (port->p_autoneg_enabled) {
+ printf(" PMD autoneg: ");
+ display_autoneg(port, LLDP_DOT3_LINK_AUTONEG_10BASE_T,
+ LLDP_DOT3_LINK_AUTONEG_10BASET_FD,
+ "10Base-T");
+ display_autoneg(port, LLDP_DOT3_LINK_AUTONEG_100BASE_TX,
+ LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD,
+ "100Base-T");
+ display_autoneg(port, LLDP_DOT3_LINK_AUTONEG_100BASE_T2,
+ LLDP_DOT3_LINK_AUTONEG_100BASE_T2FD,
+ "100Base-T2");
+ display_autoneg(port, LLDP_DOT3_LINK_AUTONEG_1000BASE_X,
+ LLDP_DOT3_LINK_AUTONEG_1000BASE_XFD,
+ "100Base-X");
+ display_autoneg(port, LLDP_DOT3_LINK_AUTONEG_1000BASE_T,
+ LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD,
+ "1000Base-T");
+ printf("\n");
+ }
+ printf(" MAU oper type: ");
+ for (i = 0; operational_mau_type_values[i].value != 0; i++) {
+ if (operational_mau_type_values[i].value ==
+ port->p_mau_type) {
+ printf("%s\n", operational_mau_type_values[i].string);
+ break;
+ }
+ }
+ if (operational_mau_type_values[i].value == 0)
+ printf("unknown (%d)\n", port->p_mau_type);
+ }
+#endif
+}
+
+#ifdef ENABLE_DOT1
+static void
+display_vlans(struct lldpd_port *port)
+{
+ int i = 0;
+ int foundpvid = 0;
+ struct lldpd_vlan *vlan;
+ TAILQ_FOREACH(vlan, &port->p_vlans, v_entries) {
+ if (port->p_pvid == vlan->v_vid)
+ foundpvid = 1;
+ printf(" %cVLAN %4d: %-20s%c",
+ (port->p_pvid == vlan->v_vid)?'*':' ',
+ vlan->v_vid, vlan->v_name,
+ (i++ % 2) ? '\n' : ' ');
+ }
+ if (!foundpvid && port->p_pvid)
+ printf(" *VLAN %4d\n", port->p_pvid);
+ else if (i % 2)
+ printf("\n");
+}
+#endif
+
+static const char*
+display_age(struct lldpd_port *port)
+{
+ static char sage[30];
+ int age = (int)(time(NULL) - port->p_lastchange);
+ if (snprintf(sage, sizeof(sage),
+ "%d day%s, %02d:%02d:%02d",
+ age / (60*60*24),
+ (age / (60*60*24) > 1)?"s":"",
+ (age / (60*60)) % (60*60*24),
+ (age / 60) % (60*60),
+ age % 60) >= sizeof(sage))
+ return "too much";
+ else
+ return sage;
+}
+
+void
+display_interfaces(int s, int argc, char *argv[])
+{
+ int i, nb;
+ struct interfaces ifs;
+#ifdef ENABLE_DOT1
+ struct vlans vls;
+#endif
+ struct lldpd_interface *iff;
+ struct lldpd_chassis chassis;
+ struct lldpd_port port;
+ char sep[80];
+
+ memset(sep, '-', 79);
+ sep[79] = 0;
+ get_interfaces(s, &ifs);
+
+ printf("%s\n", sep);
+ printf(" LLDP neighbors\n");
+ printf("%s\n", sep);
+ TAILQ_FOREACH(iff, &ifs, next) {
+ if (optind < argc) {
+ for (i = optind; i < argc; i++)
+ if (strncmp(argv[i], iff->name, IFNAMSIZ) == 0)
+ break;
+ if (i == argc)
+ continue;
+ }
+ nb = get_nb_port(s, iff->name);
+ for (i = 0; i < nb; i++) {
+ if (!((get_chassis(s, &chassis, iff->name, i) != -1) &&
+ (get_port(s, &port, iff->name, i) != -1)))
+ continue;
+ printf("Interface: %s (via ", iff->name);
+ switch (port.p_protocol) {
+ case (LLDPD_MODE_LLDP): printf("LLDP"); break;
+ case (LLDPD_MODE_CDPV1): printf("CDPv1"); break;
+ case (LLDPD_MODE_CDPV2): printf("CDPv2"); break;
+ case (LLDPD_MODE_EDP): printf("EDP"); break;
+ case (LLDPD_MODE_FDP): printf("FDP"); break;
+ case (LLDPD_MODE_SONMP): printf("SONMP"); break;
+ default: printf("unknown protocol"); break;
+ }
+ printf(") - RID: %d", chassis.c_index);
+ printf(" - Time: %s\n", display_age(&port));
+ display_chassis(&chassis);
+ printf("\n");
+ display_port(&port);
+#ifdef ENABLE_DOT1
+ if (get_vlans(s, &vls, iff->name, i) != -1)
+ memcpy(&port.p_vlans, &vls, sizeof(struct vlans));
+ if (!TAILQ_EMPTY(&port.p_vlans) || port.p_pvid) {
+ printf("\n");
+ display_vlans(&port);
+ }
+#endif
+#ifdef ENABLE_LLDPMED
+ if (port.p_med_cap_enabled) {
+ printf("\n");
+ display_med(&chassis, &port);
+ }
+#endif
+ printf("%s\n", sep);
+ }
+ }
+}
+
static void usage(void);
TAILQ_HEAD(interfaces, lldpd_interface);
-#ifdef ENABLE_DOT1
-TAILQ_HEAD(vlans, lldpd_vlan);
-#endif
-
-#define ntohll(x) (((u_int64_t)(ntohl((int)((x << 32) >> 32))) << 32) | \
- (unsigned int)ntohl(((int)(x >> 32))))
-#define htonll(x) ntohll(x)
#ifdef HAVE___PROGNAME
extern const char *__progname;
# define __progname "lldpctl"
#endif
+extern void
+get_interfaces(int s, struct interfaces *ifs);
-struct value_string {
- int value;
- char *string;
-};
-
-#ifdef ENABLE_LLDPMED
-static const struct value_string civic_address_type_values[] = {
- { 0, "Language" },
- { 1, "National subdivisions" },
- { 2, "County, parish, district" },
- { 3, "City, township" },
- { 4, "City division, borough, ward" },
- { 5, "Neighborhood, block" },
- { 6, "Street" },
- { 16, "Leading street direction" },
- { 17, "Trailing street suffix" },
- { 18, "Street suffix" },
- { 19, "House number" },
- { 20, "House number suffix" },
- { 21, "Landmark or vanity address" },
- { 22, "Additional location info" },
- { 23, "Name" },
- { 24, "Postal/ZIP code" },
- { 25, "Building" },
- { 26, "Unit" },
- { 27, "Floor" },
- { 28, "Room number" },
- { 29, "Place type" },
- { 128, "Script" },
- { 0, NULL }
-};
-#endif
-
-#ifdef ENABLE_DOT3
-static const struct value_string 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, "100BaseT2DF - 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 }
-};
-#endif
+extern void
+display_interfaces(int s, int argc, char *argv[]);
static void
usage(void)
exit(1);
}
-static char*
-dump(void *data, int size, int max, char sep)
-{
- int i;
- size_t len;
- static char *buffer = NULL;
- static char truncation[] = "[...]";
-
- free(buffer);
- if (size > max)
- len = max * 3 + sizeof(truncation) + 1;
- else
- len = size * 3;
-
- if ((buffer = (char *)malloc(len)) == NULL)
- fatal(NULL);
-
- for (i = 0; (i < size) && (i < max); i++)
- sprintf(buffer + i * 3, "%02x%c", *(u_int8_t*)(data + i), sep);
- if (size > max)
- sprintf(buffer + i * 3, "%s", truncation);
- else
- *(buffer + i*3 - 1) = 0;
- return buffer;
-}
-
-
-static void
-get_interfaces(int s, struct interfaces *ifs)
-{
- void *p;
- struct hmsg *h;
-
- if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL)
- fatal(NULL);
- ctl_msg_init(h, HMSG_GET_INTERFACES);
- if (ctl_msg_send(s, h) == -1)
- fatalx("get_interfaces: unable to send request");
- if (ctl_msg_recv(s, h) == -1)
- fatalx("get_interfaces: unable to receive answer");
- if (h->hdr.type != HMSG_GET_INTERFACES)
- fatalx("get_interfaces: unknown answer type received");
- p = &h->data;
- if (ctl_msg_unpack_list(STRUCT_LLDPD_INTERFACE,
- ifs, sizeof(struct lldpd_interface), h, &p) == -1)
- fatalx("get_interfaces: unable to retrieve the list of interfaces");
-}
-
-#ifdef ENABLE_DOT1
-static int
-get_vlans(int s, struct vlans *vls, char *interface, int nb)
-{
- void *p;
- struct hmsg *h;
-
- if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL)
- fatal(NULL);
- ctl_msg_init(h, HMSG_GET_VLANS);
- strlcpy((char *)&h->data, interface, IFNAMSIZ);
- memcpy((char*)&h->data + IFNAMSIZ, &nb, sizeof(int));
- h->hdr.len += IFNAMSIZ + sizeof(int);
- if (ctl_msg_send(s, h) == -1)
- fatalx("get_vlans: unable to send request");
- if (ctl_msg_recv(s, h) == -1)
- fatalx("get_vlans: unable to receive answer");
- if (h->hdr.type != HMSG_GET_VLANS)
- fatalx("get_vlans: unknown answer type received");
- p = &h->data;
- if (ctl_msg_unpack_list(STRUCT_LLDPD_VLAN,
- vls, sizeof(struct lldpd_vlan), h, &p) == -1)
- fatalx("get_vlans: unable to retrieve the list of vlans");
- return 1;
-}
-#endif
-
-static int
-get_chassis(int s, struct lldpd_chassis *chassis, char *interface, int nb)
-{
- struct hmsg *h;
- void *p;
-
- if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL)
- fatal(NULL);
- ctl_msg_init(h, HMSG_GET_CHASSIS);
- strlcpy((char *)&h->data, interface, IFNAMSIZ);
- memcpy((char*)&h->data + IFNAMSIZ, &nb, sizeof(int));
- h->hdr.len += IFNAMSIZ + sizeof(int);
- if (ctl_msg_send(s, h) == -1)
- fatalx("get_chassis: unable to send request to get chassis");
- if (ctl_msg_recv(s, h) == -1)
- fatalx("get_chassis: unable to receive answer to get chassis");
- if (h->hdr.type == HMSG_NONE)
- /* No chassis */
- return -1;
- p = &h->data;
- if (ctl_msg_unpack_structure(STRUCT_LLDPD_CHASSIS,
- chassis, sizeof(struct lldpd_chassis), h, &p) == -1) {
- LLOG_WARNX("unable to retrieve chassis for %s", interface);
- fatalx("get_chassis: abort");
- }
- return 1;
-}
-
-static int
-get_port(int s, struct lldpd_port *port, char *interface, int nb)
-{
- struct hmsg *h;
- void *p;
-
- if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL)
- fatal(NULL);
- ctl_msg_init(h, HMSG_GET_PORT);
- strlcpy((char *)&h->data, interface, IFNAMSIZ);
- memcpy((char*)&h->data + IFNAMSIZ, &nb, sizeof(int));
- h->hdr.len += IFNAMSIZ + sizeof(int);
- if (ctl_msg_send(s, h) == -1)
- fatalx("get_port: unable to send request to get port");
- if (ctl_msg_recv(s, h) == -1)
- fatalx("get_port: unable to receive answer to get port");
- if (h->hdr.type == HMSG_NONE)
- /* No port */
- return -1;
- p = &h->data;
- if (ctl_msg_unpack_structure(STRUCT_LLDPD_PORT,
- port, sizeof(struct lldpd_port), h, &p) == -1) {
- LLOG_WARNX("unable to retrieve port information for %s",
- interface);
- fatalx("get_chassis: abort");
- }
- return 1;
-}
-
-static int
-get_nb_port(int s, char *interface)
-{
- struct hmsg *h;
- int nb;
-
- if ((h = (struct hmsg *)malloc(MAX_HMSGSIZE)) == NULL)
- fatal(NULL);
- ctl_msg_init(h, HMSG_GET_NB_PORTS);
- strlcpy((char *)&h->data, interface, IFNAMSIZ);
- h->hdr.len += IFNAMSIZ;
- if (ctl_msg_send(s, h) == -1)
- fatalx("get_nb_port: unable to send request to get number of ports");
- if (ctl_msg_recv(s, h) == -1)
- fatalx("get_nb_port: unable to receive answer to get number of ports");
- if (h->hdr.type == HMSG_NONE)
- return -1;
- if (h->hdr.len != sizeof(int))
- fatalx("get_nb_port: bad message length");
- memcpy(&nb, &h->data, sizeof(int));
- return nb;
-}
-
-static void
-display_cap(struct lldpd_chassis *chassis, u_int8_t bit, char *symbol)
-{
- if (chassis->c_cap_available & bit)
- printf("%s(%c) ", symbol,
- (chassis->c_cap_enabled & bit)?'E':'d');
-}
-
-static void
-pretty_print(char *string)
-{
- char *s = NULL;
- if (((s = strchr(string, '\n')) == NULL) && (strlen(string) < 60)) {
- printf("%s\n", string);
- return;
- } else
- printf("\n");
- while (s != NULL) {
- *s = '\0';
- printf(" %s\n", string);
- *s = '\n';
- string = s + 1;
- s = strchr(string, '\n');
- }
- printf(" %s\n", string);
-}
-
-#ifdef ENABLE_LLDPMED
-static int
-display_fixed_precision(u_int64_t value, int intpart, int floatpart, int displaysign)
-{
- u_int64_t tmp = value;
- int negative = 0;
- u_int32_t integer = 0;
- if (value & (1ULL<<(intpart + floatpart - 1))) {
- negative = 1;
- tmp = ~value;
- tmp += 1;
- }
- integer = (u_int32_t)((tmp &
- (((1ULL << intpart)-1) << floatpart)) >> floatpart);
- tmp = (tmp & ((1<< floatpart) - 1))*10000/(1ULL << floatpart);
- printf("%s%u.%04llu", displaysign?(negative?"-":"+"):"",
- integer, (unsigned long long int)tmp);
- return negative;
-}
-
-static void
-display_latitude_or_longitude(int option, u_int64_t value)
-{
- int negative;
- negative = display_fixed_precision(value, 9, 25, 0);
- if (option == 0)
- printf("%s", negative?" South":" North");
- else
- printf("%s", negative?" West":" East");
-}
-
-static void
-display_med(struct lldpd_chassis *chassis, struct lldpd_port *port)
-{
- int i;
- char *value;
- printf(" LLDP-MED Device Type: ");
- switch (chassis->c_med_type) {
- case LLDPMED_CLASS_I:
- printf("Generic Endpoint (Class I)");
- break;
- case LLDPMED_CLASS_II:
- printf("Media Endpoint (Class II)");
- break;
- case LLDPMED_CLASS_III:
- printf("Communication Device Endpoint (Class III)");
- break;
- case LLDPMED_NETWORK_DEVICE:
- printf("Network Connectivity Device");
- break;
- default:
- printf("Unknown (%d)", chassis->c_med_type);
- break;
- }
- printf("\n LLDP-MED Capabilities:");
- if (chassis->c_med_cap_available & LLDPMED_CAP_CAP)
- printf(" Capabilities");
- if (chassis->c_med_cap_available & LLDPMED_CAP_POLICY)
- printf(" Policy");
- if (chassis->c_med_cap_available & LLDPMED_CAP_LOCATION)
- printf(" Location");
- if (chassis->c_med_cap_available & LLDPMED_CAP_MDI_PSE)
- printf(" MDI/PSE");
- if (chassis->c_med_cap_available & LLDPMED_CAP_MDI_PD)
- printf(" MDI/PD");
- if (chassis->c_med_cap_available & LLDPMED_CAP_IV)
- printf(" Inventory");
- printf("\n");
- for (i = 0; i < LLDPMED_APPTYPE_LAST; i++) {
- if (i+1 == port->p_med_policy[i].type) {
- printf(" LLDP-MED Network Policy for ");
- switch(port->p_med_policy[i].type) {
- case LLDPMED_APPTYPE_VOICE:
- printf("Voice");
- break;
- case LLDPMED_APPTYPE_VOICESIGNAL:
- printf("Voice Signaling");
- break;
- case LLDPMED_APPTYPE_GUESTVOICE:
- printf("Guest Voice");
- break;
- case LLDPMED_APPTYPE_GUESTVOICESIGNAL:
- printf("Guest Voice Signaling");
- break;
- case LLDPMED_APPTYPE_SOFTPHONEVOICE:
- printf("Softphone Voice");
- break;
- case LLDPMED_APPTYPE_VIDEOCONFERENCE:
- printf("Video Conferencing");
- break;
- case LLDPMED_APPTYPE_VIDEOSTREAM:
- printf("Streaming Video");
- break;
- case LLDPMED_APPTYPE_VIDEOSIGNAL:
- printf("Video Signaling");
- break;
- default:
- printf("Reserved");
- }
- printf(":\n Policy: ");
- if (port->p_med_policy[i].unknown) {
- printf("unknown, ");
- } else {
- printf("defined, ");
- }
- if (!port->p_med_policy[i].tagged) {
- printf("un");
- }
- printf("tagged");
- printf("\n VLAN ID: ");
- if (port->p_med_policy[i].vid == 0) {
- printf("Priority Tagged");
- } else if (port->p_med_policy[i].vid == 4095) {
- printf("reserved");
- } else {
- printf("%u", port->p_med_policy[i].vid);
- }
- printf("\n Layer 2 Priority: ");
- printf("%u", port->p_med_policy[i].priority);
- printf("\n DSCP Value: ");
- printf("%u\n", port->p_med_policy[i].dscp);
- }
- }
- for (i = 0; i < LLDPMED_LOCFORMAT_LAST; i++) {
- if (i+1 == port->p_med_location[i].format) {
- printf(" LLDP-MED Location Identification: ");
- switch(port->p_med_location[i].format) {
- case LLDPMED_LOCFORMAT_COORD:
- printf("\n Coordinate-based data: ");
- if (port->p_med_location[i].data_len != 16)
- printf("bad data length");
- else {
- u_int64_t l;
-
- /* Latitude and longitude */
- memcpy(&l, port->p_med_location[i].data,
- sizeof(u_int64_t));
- l = (ntohll(l) &
- 0x03FFFFFFFF000000ULL) >> 24;
- display_latitude_or_longitude(0, l);
- printf(", ");
- memcpy(&l, port->p_med_location[i].data + 5,
- sizeof(u_int64_t));
- l = (ntohll(l) &
- 0x03FFFFFFFF000000ULL) >> 24;
- display_latitude_or_longitude(1, l);
-
- /* Altitude */
- printf(", ");
- memcpy(&l, port->p_med_location[i].data + 10,
- sizeof(u_int64_t));
- l = (ntohll(l) &
- 0x3FFFFFFF000000ULL) >> 24;
- display_fixed_precision(l, 22, 8, 1);
- switch ((*(u_int8_t*)(port->p_med_location[i].data +
- 10)) & 0xf0) {
- case (1 << 4):
- printf(" meters"); break;
- case (2 << 4):
- printf(" floors"); break;
- default:
- printf(" (unknown)");
- }
-
- /* Datum */
- switch (*(u_int8_t*)(port->p_med_location[i].data +
- 15)) {
- case 1:
- printf(", WGS84"); break;
- case 2:
- printf(", NAD83"); break;
- case 3:
- printf(", NAD83/MLLW"); break;
- }
- }
- break;
- case LLDPMED_LOCFORMAT_CIVIC:
- printf("Civic address: ");
- if ((port->p_med_location[i].data_len < 3) ||
- (port->p_med_location[i].data_len - 1 !=
- *(u_int8_t*)port->p_med_location[i].data))
- printf("bad data length");
- else {
- int l = 4, n, catype, calength, j = 0;
- printf("\n%28s: %c%c", "Country",
- ((char *)port->p_med_location[i].data)[2],
- ((char *)port->p_med_location[i].data)[3]);
- while ((n = (port->
- p_med_location[i].data_len - l)) >= 2) {
- catype = *(u_int8_t*)(port->
- p_med_location[i].data + l);
- calength = *(u_int8_t*)(port->
- p_med_location[i].data + l + 1);
- if (n < 2 + calength) {
- printf("bad data length");
- break;
- }
- for (j = 0;
- civic_address_type_values[j].string != NULL;
- j++) {
- if (civic_address_type_values[j].value ==
- catype)
- break;
- }
- if (civic_address_type_values[j].string == NULL) {
- printf("unknown type %d", catype);
- break;
- }
- if ((value = strndup((char *)(port->
- p_med_location[i].data + l + 2),
- calength)) == NULL) {
- printf("not enough memory");
- break;
- }
- printf("\n%28s: %s",
- civic_address_type_values[j].string,
- value);
- free(value);
- l += 2 + calength;
- }
- }
- break;
- case LLDPMED_LOCFORMAT_ELIN:
- if ((value = strndup((char *)(port->
- p_med_location[i].data),
- port->p_med_location[i].data_len)) == NULL) {
- printf("not enough memory");
- break;
- }
- printf("ECS ELIN: %s", value);
- free(value);
- break;
- default:
- printf("unknown location data format: \n %s",
- dump(port->p_med_location[i].data,
- port->p_med_location[i].data_len, 20, ' '));
- }
- printf("\n");
- }
- }
- if (port->p_med_pow_devicetype) {
- printf(" LLDP-MED Extended Power-over-Ethernet:\n");
- printf(" Power Type & Source: ");
- switch (port->p_med_pow_devicetype) {
- case LLDPMED_POW_TYPE_PSE:
- printf("PSE Device");
- break;
- case LLDPMED_POW_TYPE_PD:
- printf("PD Device");
- break;
- default:
- printf("reserved");
- }
- switch (port->p_med_pow_source) {
- case LLDPMED_POW_SOURCE_UNKNOWN:
- case LLDPMED_POW_SOURCE_RESERVED:
- printf(", unknown"); break;
- case LLDPMED_POW_SOURCE_PRIMARY:
- printf(", Primary Power Source");
- break;
- case LLDPMED_POW_SOURCE_BACKUP:
- printf(", Backup Power Source / Power Conservation Mode");
- break;
- case LLDPMED_POW_SOURCE_PSE:
- printf(", PSE"); break;
- case LLDPMED_POW_SOURCE_LOCAL:
- printf(", local"); break;
- case LLDPMED_POW_SOURCE_BOTH:
- printf(", PSE & local");
- break;
- }
- printf("\n Power Priority: ");
- switch (port->p_med_pow_priority) {
- case LLDPMED_POW_PRIO_CRITICAL:
- printf("critical"); break;
- case LLDPMED_POW_PRIO_HIGH:
- printf("high"); break;
- case LLDPMED_POW_PRIO_LOW:
- printf("low"); break;
- default:
- printf("unknown");
- }
- printf("\n Power Value: ");
- if(port->p_med_pow_val < 1024) {
- printf("%u mW", port->p_med_pow_val * 100);
- } else {
- printf("reserved");
- }
- printf("\n");
- }
- if (chassis->c_med_hw ||
- chassis->c_med_sw ||
- chassis->c_med_fw ||
- chassis->c_med_sn ||
- chassis->c_med_manuf ||
- chassis->c_med_model ||
- chassis->c_med_asset) {
- printf(" LLDP-MED Inventory:\n");
- if (chassis->c_med_hw)
- printf(" Hardware Revision: %s\n", chassis->c_med_hw);
- if (chassis->c_med_sw)
- printf(" Software Revision: %s\n", chassis->c_med_sw);
- if (chassis->c_med_fw)
- printf(" Firmware Revision: %s\n", chassis->c_med_fw);
- if (chassis->c_med_sn)
- printf(" Serial Number: %s\n", chassis->c_med_sn);
- if (chassis->c_med_manuf)
- printf(" Manufacturer: %s\n",
- chassis->c_med_manuf);
- if (chassis->c_med_model)
- printf(" Model: %s\n",
- chassis->c_med_model);
- if (chassis->c_med_asset)
- printf(" Asset ID: %s\n",
- chassis->c_med_asset);
- }
-}
-#endif
-
-static void
-display_chassis(struct lldpd_chassis *chassis)
-{
- char *cid;
- if ((cid = (char *)malloc(chassis->c_id_len + 1)) == NULL)
- fatal(NULL);
- memcpy(cid, chassis->c_id, chassis->c_id_len);
- cid[chassis->c_id_len] = 0;
- switch (chassis->c_id_subtype) {
- case LLDP_CHASSISID_SUBTYPE_IFNAME:
- printf(" ChassisID: %s (ifName)\n", cid);
- break;
- case LLDP_CHASSISID_SUBTYPE_IFALIAS:
- printf(" ChassisID: %s (ifAlias)\n", cid);
- break;
- case LLDP_CHASSISID_SUBTYPE_LOCAL:
- printf(" ChassisID: %s (local)\n", cid);
- break;
- case LLDP_CHASSISID_SUBTYPE_LLADDR:
- printf(" ChassisID: %s (MAC)\n",
- dump(chassis->c_id, chassis->c_id_len, ETH_ALEN, ':'));
- break;
- case LLDP_CHASSISID_SUBTYPE_ADDR:
- if (*(u_int8_t*)chassis->c_id == 1) {
- printf(" ChassisID: %s (IP)\n",
- inet_ntoa(*(struct in_addr*)(chassis->c_id +
- 1)));
- break;
- }
- case LLDP_CHASSISID_SUBTYPE_PORT:
- case LLDP_CHASSISID_SUBTYPE_CHASSIS:
- default:
- printf(" ChassisID: %s (unhandled type)\n",
- dump(chassis->c_id, chassis->c_id_len, 16, ' '));
- }
- printf(" SysName: %s\n", chassis->c_name);
- printf(" SysDescr: "); pretty_print(chassis->c_descr);
- if (chassis->c_mgmt.s_addr != INADDR_ANY)
- printf(" MgmtIP: %s\n", inet_ntoa(chassis->c_mgmt));
- printf(" Caps: ");
- display_cap(chassis, LLDP_CAP_OTHER, "Other");
- display_cap(chassis, LLDP_CAP_REPEATER, "Repeater");
- display_cap(chassis, LLDP_CAP_BRIDGE, "Bridge");
- display_cap(chassis, LLDP_CAP_ROUTER, "Router");
- display_cap(chassis, LLDP_CAP_WLAN, "Wlan");
- display_cap(chassis, LLDP_CAP_TELEPHONE, "Tel");
- display_cap(chassis, LLDP_CAP_DOCSIS, "Docsis");
- display_cap(chassis, LLDP_CAP_STATION, "Station");
- printf("\n");
-}
-
-#ifdef ENABLE_DOT3
-static void
-display_autoneg(struct lldpd_port *port, int bithd, int bitfd, char *desc)
-{
- if (!((port->p_autoneg_advertised & bithd) ||
- (port->p_autoneg_advertised & bitfd)))
- return;
- printf("%s ", desc);
- if (port->p_autoneg_advertised & bithd) {
- printf("(HD");
- if (port->p_autoneg_advertised & bitfd) {
- printf(", FD) ");
- return;
- }
- printf(") ");
- return;
- }
- printf("(FD) ");
-}
-#endif
-
-static void
-display_port(struct lldpd_port *port)
-{
- char *pid;
- struct in_addr address;
-#ifdef ENABLE_DOT3
- int i;
-#endif
-
- if ((pid = (char *)malloc(port->p_id_len + 1)) == NULL)
- fatal(NULL);
- memcpy(pid, port->p_id, port->p_id_len);
- pid[port->p_id_len] = 0;
- switch (port->p_id_subtype) {
- case LLDP_PORTID_SUBTYPE_IFNAME:
- printf(" PortID: %s (ifName)\n", pid);
- break;
- case LLDP_PORTID_SUBTYPE_IFALIAS:
- printf(" PortID: %s (ifAlias)\n", pid);
- break;
- case LLDP_PORTID_SUBTYPE_LOCAL:
- printf(" PortID: %s (local)\n", pid);
- break;
- case LLDP_PORTID_SUBTYPE_LLADDR:
- printf(" PortID: %s (MAC)\n",
- dump(port->p_id, port->p_id_len, ETH_ALEN, ':'));
- break;
- case LLDP_PORTID_SUBTYPE_ADDR:
- if (*(u_int8_t*)port->p_id == 1) {
- memcpy(&address, port->p_id + 1,
- sizeof(struct in_addr));
- printf(" PortID: %s (IP)\n",
- inet_ntoa(address));
- break;
- }
- case LLDP_PORTID_SUBTYPE_PORT:
- case LLDP_PORTID_SUBTYPE_AGENTCID:
- default:
- printf(" ChassisID: %s (unhandled type)\n",
- dump(port->p_id, port->p_id_len, 16, ' '));
- }
- printf(" PortDescr: "); pretty_print(port->p_descr);
-#ifdef ENABLE_DOT3
- if (port->p_mfs)
- printf(" MFS: %d bytes\n", port->p_mfs);
- if (port->p_aggregid)
- printf("\n Port is aggregated. PortAggregID: %d\n",
- port->p_aggregid);
-
- if (port->p_autoneg_support || port->p_autoneg_enabled ||
- port->p_mau_type) {
- printf("\n Autoneg: %ssupported/%senabled\n",
- port->p_autoneg_support?"":"not ",
- port->p_autoneg_enabled?"":"not ");
- if (port->p_autoneg_enabled) {
- printf(" PMD autoneg: ");
- display_autoneg(port, LLDP_DOT3_LINK_AUTONEG_10BASE_T,
- LLDP_DOT3_LINK_AUTONEG_10BASET_FD,
- "10Base-T");
- display_autoneg(port, LLDP_DOT3_LINK_AUTONEG_100BASE_TX,
- LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD,
- "100Base-T");
- display_autoneg(port, LLDP_DOT3_LINK_AUTONEG_100BASE_T2,
- LLDP_DOT3_LINK_AUTONEG_100BASE_T2FD,
- "100Base-T2");
- display_autoneg(port, LLDP_DOT3_LINK_AUTONEG_1000BASE_X,
- LLDP_DOT3_LINK_AUTONEG_1000BASE_XFD,
- "100Base-X");
- display_autoneg(port, LLDP_DOT3_LINK_AUTONEG_1000BASE_T,
- LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD,
- "1000Base-T");
- printf("\n");
- }
- printf(" MAU oper type: ");
- for (i = 0; operational_mau_type_values[i].value != 0; i++) {
- if (operational_mau_type_values[i].value ==
- port->p_mau_type) {
- printf("%s\n", operational_mau_type_values[i].string);
- break;
- }
- }
- if (operational_mau_type_values[i].value == 0)
- printf("unknown (%d)\n", port->p_mau_type);
- }
-#endif
-}
-
-#ifdef ENABLE_DOT1
-static void
-display_vlans(struct lldpd_port *port)
-{
- int i = 0;
- int foundpvid = 0;
- struct lldpd_vlan *vlan;
- TAILQ_FOREACH(vlan, &port->p_vlans, v_entries) {
- if (port->p_pvid == vlan->v_vid)
- foundpvid = 1;
- printf(" %cVLAN %4d: %-20s%c",
- (port->p_pvid == vlan->v_vid)?'*':' ',
- vlan->v_vid, vlan->v_name,
- (i++ % 2) ? '\n' : ' ');
- }
- if (!foundpvid && port->p_pvid)
- printf(" *VLAN %4d\n", port->p_pvid);
- else if (i % 2)
- printf("\n");
-}
-#endif
-
-static const char*
-display_age(struct lldpd_port *port)
-{
- static char sage[30];
- int age = (int)(time(NULL) - port->p_lastchange);
- if (snprintf(sage, sizeof(sage),
- "%d day%s, %02d:%02d:%02d",
- age / (60*60*24),
- (age / (60*60*24) > 1)?"s":"",
- (age / (60*60)) % (60*60*24),
- (age / 60) % (60*60),
- age % 60) >= sizeof(sage))
- return "too much";
- else
- return sage;
-}
-
-static void
-display_interfaces(int s, int argc, char *argv[])
-{
- int i, nb;
- struct interfaces ifs;
-#ifdef ENABLE_DOT1
- struct vlans vls;
-#endif
- struct lldpd_interface *iff;
- struct lldpd_chassis chassis;
- struct lldpd_port port;
- char sep[80];
-
- memset(sep, '-', 79);
- sep[79] = 0;
- get_interfaces(s, &ifs);
-
- printf("%s\n", sep);
- printf(" LLDP neighbors\n");
- printf("%s\n", sep);
- TAILQ_FOREACH(iff, &ifs, next) {
- if (optind < argc) {
- for (i = optind; i < argc; i++)
- if (strncmp(argv[i], iff->name, IFNAMSIZ) == 0)
- break;
- if (i == argc)
- continue;
- }
- nb = get_nb_port(s, iff->name);
- for (i = 0; i < nb; i++) {
- if (!((get_chassis(s, &chassis, iff->name, i) != -1) &&
- (get_port(s, &port, iff->name, i) != -1)))
- continue;
- printf("Interface: %s (via ", iff->name);
- switch (port.p_protocol) {
- case (LLDPD_MODE_LLDP): printf("LLDP"); break;
- case (LLDPD_MODE_CDPV1): printf("CDPv1"); break;
- case (LLDPD_MODE_CDPV2): printf("CDPv2"); break;
- case (LLDPD_MODE_EDP): printf("EDP"); break;
- case (LLDPD_MODE_FDP): printf("FDP"); break;
- case (LLDPD_MODE_SONMP): printf("SONMP"); break;
- default: printf("unknown protocol"); break;
- }
- printf(") - RID: %d", chassis.c_index);
- printf(" - Time: %s\n", display_age(&port));
- display_chassis(&chassis);
- printf("\n");
- display_port(&port);
-#ifdef ENABLE_DOT1
- if (get_vlans(s, &vls, iff->name, i) != -1)
- memcpy(&port.p_vlans, &vls, sizeof(struct vlans));
- if (!TAILQ_EMPTY(&port.p_vlans) || port.p_pvid) {
- printf("\n");
- display_vlans(&port);
- }
-#endif
-#ifdef ENABLE_LLDPMED
- if (port.p_med_cap_enabled) {
- printf("\n");
- display_med(&chassis, &port);
- }
-#endif
- printf("%s\n", sep);
- }
- }
-}
-
#ifdef ENABLE_LLDPMED
static int
lldpd_parse_location(struct lldpd_port *port, const char *location)