]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
tests: add a simple program to test frame decoding
authorVincent Bernat <vincent@bernat.im>
Sat, 3 Oct 2015 23:21:45 +0000 (01:21 +0200)
committerVincent Bernat <vincent@bernat.im>
Sat, 3 Oct 2015 23:21:45 +0000 (01:21 +0200)
src/daemon/protocols/edp.c
tests/Makefile.am
tests/check_snmp.c
tests/common.c
tests/common.h
tests/decode.c [new file with mode: 0644]

index acbe53dd56ed0e8cb8f4b84303bce26a9a177273..8eec547f2fe285cdb979f9db40851c5bda6241b9 100644 (file)
@@ -308,7 +308,7 @@ edp_decode(struct lldpd *cfg, char *frame, int s,
                    hardware->h_ifname);
                goto malformed;
        }
-       chassis->c_ttl = cfg->g_config.c_tx_interval * cfg->g_config.c_tx_hold;
+       chassis->c_ttl = cfg?cfg->g_config.c_tx_interval * cfg->g_config.c_tx_hold:0;
        chassis->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
        chassis->c_id_len = ETHER_ADDR_LEN;
        if ((chassis->c_id = (char *)malloc(ETHER_ADDR_LEN)) == NULL) {
index 243dd49c2ac2590e22d045d3ec234f52e652f5fb..2278b4ea8eb4c19d7e00e2451c4384869ef90046 100644 (file)
@@ -48,6 +48,11 @@ endif
 
 check_PROGRAMS = $(TESTS)
 
+noinst_PROGRAMS = decode
+decode_SOURCES = decode.c \
+       $(top_srcdir)/src/daemon/lldpd.h \
+       common.h common.c
+
 endif
 
-MOSTLYCLEANFILES = lldp_send_*.pcap cdp_send_*.pcap sonmp_send_*.pcap edp_send_*.pcap
+MOSTLYCLEANFILES = *.pcap
index 7ff6d1340cae6221d6f877240a06f194b2642f2a..5e81df266451d19da8377480ca53b53d69ba59de 100644 (file)
@@ -844,20 +844,6 @@ struct tree_node snmp_tree[] = {
 #endif
 };
 
-char*
-tohex(char *str, size_t len)
-{
-       static char *hex[] = { NULL, NULL };
-       static int which = 0;
-       free(hex[which]); hex[which] = NULL;
-       hex[which] = malloc(len * 3 + 1);
-       fail_unless(hex[which] != NULL, "Not enough memory?");
-       for (size_t i = 0; i < len; i++)
-               snprintf(hex[which] + 3*i, 4, "%02X ", (unsigned char)str[i]);
-       which = 1 - which;
-       return hex[1 - which];
-}
-
 int
 snmp_is_prefix_of(struct variable8 *vp, struct tree_node *n, char *repr)
 {
index 95ec6f4b7f2e954152ea3ddf9026fa31ada9a21f..01dc04050405855f3a384f1ad7a91c5bf19da36b 100644 (file)
@@ -147,3 +147,16 @@ pcap_teardown()
                filename = NULL;
        }
 }
+
+char*
+tohex(char *str, size_t len)
+{
+       static char *hex[] = { NULL, NULL };
+       static int which = 0;
+       free(hex[which]); hex[which] = NULL;
+       if ((hex[which] = malloc(len * 3 + 1)) == NULL) return NULL;
+       for (size_t i = 0; i < len; i++)
+               snprintf(hex[which] + 3*i, 4, "%02X ", (unsigned char)str[i]);
+       which = 1 - which;
+       return hex[1 - which];
+}
index 1743710b3fb6309eeefe7e7dbcd9f903b4b21870..5be4b5eb2da73ae392e2e49eda024aaf692ca51b 100644 (file)
@@ -51,6 +51,8 @@ extern int dump;              /* Dump file descriptor in pcap format */
 extern char filenameprefix[];  /* Prefix for filename dumping */
 extern char *filename;         /* Filename we are dumping to */
 extern char macaddress[];        /* MAC address we use to send */
+extern char *tohex(char *, size_t);
+
 extern struct pkts_t pkts; /* List of sent packets */
 extern struct lldpd_hardware hardware;
 extern struct lldpd_chassis chassis;
diff --git a/tests/decode.c b/tests/decode.c
new file mode 100644 (file)
index 0000000..f1183ed
--- /dev/null
@@ -0,0 +1,236 @@
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * Copyright (c) 2015 Vincent Bernat <bernat@luffy.cx>
+ *
+ * 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 <stdlib.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <arpa/inet.h>
+#include "common.h"
+
+#define BUFSIZE 2000
+
+char filenameprefix[] = "decode";
+
+static void
+usage(void)
+{
+       fprintf(stderr, "Usage:   %s PCAP\n", "decode");
+       fprintf(stderr, "Version: %s\n", PACKAGE_STRING);
+
+       fprintf(stderr, "\n");
+
+       fprintf(stderr, "Decode content of PCAP files and display a summary\n");
+       fprintf(stderr, "on standard output. Only the first packet is decoded.\n");
+       exit(1);
+}
+
+/* We need an assert macro which doesn't abort */
+#define assert(x) while (!(x)) { \
+               fprintf(stderr, "%s:%d: %s: Assertion  `%s' failed.\n", \
+                   __FILE__, __LINE__, __func__, #x); \
+               exit(5); \
+       }
+
+int
+main(int argc, char **argv)
+{
+       if (argc != 2 ||
+           !strcmp(argv[1], "-h") ||
+           !strcmp(argv[1], "--help"))
+               usage();
+
+       int fd = open(argv[1], O_RDONLY);
+       assert(fd != -1);
+
+       char buf[BUFSIZE];
+       ssize_t len = read(fd, buf, BUFSIZE);
+       assert(len != -1);
+
+       struct pcap_hdr hdr;
+       assert(len >= sizeof(hdr));
+       memcpy(&hdr, buf, sizeof(hdr));
+       assert(hdr.magic_number == 0xa1b2c3d4); /* Assume the same byte order as us */
+       assert(hdr.version_major == 2);
+       assert(hdr.version_minor == 4);
+       assert(hdr.thiszone == 0);
+       /* Don't care about other flags */
+
+       struct pcaprec_hdr rechdr;
+       assert(len >= sizeof(hdr) + sizeof(rechdr));
+       memcpy(&rechdr, buf + sizeof(hdr), sizeof(rechdr));
+       assert(len >= sizeof(hdr) + sizeof(rechdr) + rechdr.incl_len);
+
+       /* For decoding, we only need a very basic hardware */
+       struct lldpd_hardware hardware;
+       memset(&hardware, 0, sizeof(struct lldpd_hardware));
+       hardware.h_mtu = 1500;
+       strlcpy(hardware.h_ifname, "test", sizeof(hardware.h_ifname));
+
+       char *frame = buf + sizeof(hdr) + sizeof(rechdr);
+       struct lldpd_chassis *nchassis = NULL;
+       struct lldpd_port *nport = NULL;
+       int decoded = 0;
+       if (lldp_decode(NULL, frame, rechdr.incl_len, &hardware, &nchassis, &nport) == -1) {
+               fprintf(stderr, "Not decoded as a LLDP frame\n");
+       } else {
+               fprintf(stderr, "Decoded as a LLDP frame\n");
+               decoded = 1;
+       }
+#if defined ENABLE_CDP || defined ENABLE_FDP
+       if (cdp_decode(NULL, frame, rechdr.incl_len, &hardware, &nchassis, &nport) == -1) {
+               fprintf(stderr, "Not decoded as a CDP frame\n");
+       } else {
+               fprintf(stderr, "Decoded as a CDP frame\n");
+               decoded = 1;
+       }
+#endif
+#ifdef ENABLE_SONMP
+       if (sonmp_decode(NULL, frame, rechdr.incl_len, &hardware, &nchassis, &nport) == -1) {
+               fprintf(stderr, "Not decoded as a SONMP frame\n");
+       } else {
+               fprintf(stderr, "Decoded as a SONMP frame\n");
+               decoded = 1;
+       }
+#endif
+#ifdef ENABLE_EDP
+       if (edp_decode(NULL, frame, rechdr.incl_len, &hardware, &nchassis, &nport) == -1) {
+               fprintf(stderr, "Not decoded as a EDP frame\n");
+       } else {
+               fprintf(stderr, "Decoded as a EDP frame\n");
+               decoded = 1;
+       }
+#endif
+       if (!decoded) exit(1);
+
+       printf("Chassis:\n");
+       printf(" Index: %" PRIu16 "\n", nchassis->c_index);
+       printf(" Protocol: %" PRIu8 "\n", nchassis->c_protocol);
+       printf(" ID subtype: %" PRIu8 "\n", nchassis->c_id_subtype);
+       printf(" ID: %s\n", tohex(nchassis->c_id, nchassis->c_id_len));
+       printf(" Name: %s\n", nchassis->c_name?nchassis->c_name:"(null)");
+       printf(" Description: %s\n", nchassis->c_descr?nchassis->c_descr:"(null)");
+       printf(" Cap available: %" PRIu16 "\n", nchassis->c_cap_available);
+       printf(" Cap enabled: %" PRIu16 "\n", nchassis->c_cap_enabled);
+       printf(" TTL: %" PRIu16 "\n", nchassis->c_ttl);
+       struct lldpd_mgmt *mgmt;
+       TAILQ_FOREACH(mgmt, &nchassis->c_mgmt, m_entries) {
+               char ipaddress[INET6_ADDRSTRLEN + 1];
+               int af; size_t alen;
+               switch (mgmt->m_family) {
+               case LLDPD_AF_IPV4:
+                       alen = INET_ADDRSTRLEN + 1;
+                       af  = AF_INET;
+                       break;
+               case LLDPD_AF_IPV6:
+                       alen = INET6_ADDRSTRLEN + 1;
+                       af = AF_INET6;
+                       break;
+               default:
+                       len = 0;
+               }
+               if (len == 0) continue;
+               if (inet_ntop(af, &mgmt->m_addr, ipaddress, alen) == NULL)
+                       break;
+               printf(" mgmt: %s\n", ipaddress);
+       }
+#ifdef ENABLE_LLDPMED
+       printf(" MED cap: %" PRIu16 "\n", nchassis->c_med_cap_available);
+       printf(" MED type: %" PRIu8 "\n", nchassis->c_med_type);
+       printf(" MED HW: %s\n", nchassis->c_med_hw?nchassis->c_med_hw:"(null)");
+       printf(" MED FW: %s\n", nchassis->c_med_fw?nchassis->c_med_fw:"(null)");
+       printf(" MED SW: %s\n", nchassis->c_med_sw?nchassis->c_med_sw:"(null)");
+       printf(" MED SN: %s\n", nchassis->c_med_sn?nchassis->c_med_sn:"(null)");
+       printf(" MED manufacturer: %s\n", nchassis->c_med_manuf?nchassis->c_med_manuf:"(null)");
+       printf(" MED model: %s\n", nchassis->c_med_model?nchassis->c_med_model:"(null)");
+       printf(" MED asset: %s\n", nchassis->c_med_asset?nchassis->c_med_asset:"(null)");
+#endif
+
+       printf("Port:\n");
+       printf(" ID subtype: %" PRIu8 "\n", nport->p_id_subtype);
+       printf(" ID: %s\n", tohex(nport->p_id, nport->p_id_len));
+       printf(" Description: %s\n", nport->p_descr?nport->p_descr:"(null)");
+       printf(" MFS: %" PRIu16 "\n", nport->p_mfs);
+#ifdef ENABLE_DOT3
+       printf(" Dot3 aggrID: %" PRIu32 "\n", nport->p_aggregid);
+       printf(" Dot3 MAC/phy autoneg supported: %" PRIu8 "\n", nport->p_macphy.autoneg_support);
+       printf(" Dot3 MAC/phy autoneg enabled: %" PRIu8 "\n", nport->p_macphy.autoneg_enabled);
+       printf(" Dot3 MAC/phy autoneg advertised: %" PRIu16 "\n", nport->p_macphy.autoneg_advertised);
+       printf(" Dot3 MAC/phy MAU type: %" PRIu16 "\n", nport->p_macphy.mau_type);
+       printf(" Dot3 power device type: %" PRIu8 "\n", nport->p_power.devicetype);
+       printf(" Dot3 power supported: %" PRIu8 "\n", nport->p_power.supported);
+       printf(" Dot3 power enabled: %" PRIu8 "\n", nport->p_power.enabled);
+       printf(" Dot3 power pair control: %" PRIu8 "\n", nport->p_power.paircontrol);
+       printf(" Dot3 power pairs: %" PRIu8 "\n", nport->p_power.pairs);
+       printf(" Dot3 power class: %" PRIu8 "\n", nport->p_power.class);
+       printf(" Dot3 power type: %" PRIu8 "\n", nport->p_power.powertype);
+       printf(" Dot3 power source: %" PRIu8 "\n", nport->p_power.source);
+       printf(" Dot3 power priority: %" PRIu8 "\n", nport->p_power.priority);
+       printf(" Dot3 power requested: %" PRIu16 "\n", nport->p_power.requested);
+       printf(" Dot3 power allocated: %" PRIu16 "\n", nport->p_power.allocated);
+#endif
+#ifdef ENABLE_LLDPMED
+       printf(" MED cap: %" PRIu16 "\n", nport->p_med_cap_enabled);
+       for (int i = 0; i < LLDP_MED_APPTYPE_LAST; i++) {
+               if (nport->p_med_policy[i].type == 0) continue;
+               printf(" MED policy type: %" PRIu8 "\n", nport->p_med_policy[i].type);
+               printf(" MED policy unknown: %" PRIu8 "\n", nport->p_med_policy[i].unknown);
+               printf(" MED policy tagged: %" PRIu8 "\n", nport->p_med_policy[i].tagged);
+               printf(" MED policy vid: %" PRIu16 "\n", nport->p_med_policy[i].vid);
+               printf(" MED policy priority: %" PRIu8 "\n", nport->p_med_policy[i].priority);
+               printf(" MED policy dscp: %" PRIu8 "\n", nport->p_med_policy[i].dscp);
+       }
+       for (int i = 0; i < LLDP_MED_LOCFORMAT_LAST; i++) {
+               if (nport->p_med_location[i].format == 0) continue;
+               printf(" MED location format: %" PRIu8 "\n", nport->p_med_location[i].format);
+               printf(" MED location: %s\n", tohex(nport->p_med_location[i].data,
+                       nport->p_med_location[i].data_len));
+       }
+       printf(" MED power device type: %" PRIu8 "\n", nport->p_med_power.devicetype);
+       printf(" MED power source: %" PRIu8 "\n", nport->p_med_power.source);
+       printf(" MED power priority: %" PRIu8 "\n", nport->p_med_power.priority);
+       printf(" MED power value: %" PRIu16 "\n", nport->p_med_power.val);
+#endif
+#ifdef ENABLE_DOT1
+       printf(" Dot1 PVID: %" PRIu16 "\n", nport->p_pvid);
+       struct lldpd_vlan *vlan;
+       TAILQ_FOREACH(vlan, &nport->p_vlans, v_entries) {
+               printf(" Dot1 VLAN: %s (%" PRIu16 ")\n", vlan->v_name, vlan->v_vid);
+       }
+       struct lldpd_ppvid *ppvid;
+       TAILQ_FOREACH(ppvid, &nport->p_ppvids, p_entries) {
+               printf(" Dot1 PPVID: %" PRIu16 " (status: %" PRIu8 ")\n",
+                   ppvid->p_ppvid, ppvid->p_cap_status);
+       }
+       struct lldpd_pi *pid;
+       TAILQ_FOREACH(pid, &nport->p_pids, p_entries) {
+               printf(" Dot1 PI: %s\n", tohex(pid->p_pi, pid->p_pi_len));
+       }
+#endif
+#ifdef ENABLE_CUSTOM
+       struct lldpd_custom *custom;
+       TAILQ_FOREACH(custom, &nport->p_custom_list, next) {
+               printf(" Custom OUI: %s\n",
+                   tohex((char*)custom->oui, sizeof(custom->oui)));
+               printf(" Custom subtype: %" PRIu8 "\n", custom->subtype);
+               printf(" Custom info: %s\n",
+                   tohex((char*)custom->oui_info, custom->oui_info_len));
+       }
+#endif
+       exit(0);
+}