From dedb1eb0dbb1f4f2346d0f4544bc7d4d9a78c3c2 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Sun, 4 Oct 2015 01:21:45 +0200 Subject: [PATCH] tests: add a simple program to test frame decoding --- src/daemon/protocols/edp.c | 2 +- tests/Makefile.am | 7 +- tests/check_snmp.c | 14 --- tests/common.c | 13 ++ tests/common.h | 2 + tests/decode.c | 236 +++++++++++++++++++++++++++++++++++++ 6 files changed, 258 insertions(+), 16 deletions(-) create mode 100644 tests/decode.c diff --git a/src/daemon/protocols/edp.c b/src/daemon/protocols/edp.c index acbe53dd..8eec547f 100644 --- a/src/daemon/protocols/edp.c +++ b/src/daemon/protocols/edp.c @@ -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) { diff --git a/tests/Makefile.am b/tests/Makefile.am index 243dd49c..2278b4ea 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -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 diff --git a/tests/check_snmp.c b/tests/check_snmp.c index 7ff6d134..5e81df26 100644 --- a/tests/check_snmp.c +++ b/tests/check_snmp.c @@ -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) { diff --git a/tests/common.c b/tests/common.c index 95ec6f4b..01dc0405 100644 --- a/tests/common.c +++ b/tests/common.c @@ -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]; +} diff --git a/tests/common.h b/tests/common.h index 1743710b..5be4b5eb 100644 --- a/tests/common.h +++ b/tests/common.h @@ -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 index 00000000..f1183ed7 --- /dev/null +++ b/tests/decode.c @@ -0,0 +1,236 @@ +/* -*- 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 +#include +#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); +} -- 2.39.5