summaryrefslogtreecommitdiffstats
path: root/tests/check_lldp.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--tests/check_lldp.c835
1 files changed, 835 insertions, 0 deletions
diff --git a/tests/check_lldp.c b/tests/check_lldp.c
new file mode 100644
index 0000000..bd6637e
--- /dev/null
+++ b/tests/check_lldp.c
@@ -0,0 +1,835 @@
+/* -*- 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 <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <check.h>
+#include "common.h"
+
+char filenameprefix[] = "lldp_send";
+
+static struct lldpd test_lldpd = { .g_config = {
+ .c_cap_advertise =
+ 1, /* Chassis capabilities advertisement */
+ .c_mgmt_advertise =
+ 1, /* Management addresses advertisement */
+ } };
+
+#define ck_assert_str_eq_n(X, Y, N) \
+ ck_assert_msg(!strncmp(X, Y, N), \
+ "Assertion '" #X "==" #Y "' failed: " #X "==\"%s\", " #Y "==\"%s\"", X, Y)
+
+static void
+check_received_port(struct lldpd_port *sport, struct lldpd_port *rport)
+{
+ ck_assert_int_eq(rport->p_id_subtype, sport->p_id_subtype);
+ ck_assert_int_eq(rport->p_id_len, sport->p_id_len);
+ ck_assert_str_eq_n(rport->p_id, sport->p_id, sport->p_id_len);
+ ck_assert_str_eq(rport->p_descr, sport->p_descr);
+#ifdef ENABLE_DOT3
+ ck_assert_int_eq(rport->p_mfs, sport->p_mfs);
+#endif
+}
+
+static void
+check_received_chassis(struct lldpd_chassis *schassis, struct lldpd_chassis *rchassis)
+{
+ ck_assert_int_eq(rchassis->c_id_subtype, schassis->c_id_subtype);
+ ck_assert_int_eq(rchassis->c_id_len, schassis->c_id_len);
+ ck_assert_str_eq_n(rchassis->c_id, schassis->c_id, schassis->c_id_len);
+ ck_assert_str_eq(rchassis->c_name, schassis->c_name);
+ ck_assert_str_eq(rchassis->c_descr, schassis->c_descr);
+ ck_assert_int_eq(rchassis->c_cap_available, schassis->c_cap_available);
+ ck_assert_int_eq(rchassis->c_cap_enabled, schassis->c_cap_enabled);
+}
+
+#ifdef ENABLE_LLDPMED
+static void
+check_received_port_med(struct lldpd_port *sport, struct lldpd_port *rport)
+{
+ ck_assert_int_eq(rport->p_med_cap_enabled, sport->p_med_cap_enabled);
+ ck_assert_int_eq(rport->p_med_cap_enabled, sport->p_med_cap_enabled);
+ ck_assert_int_eq(rport->p_med_location[LLDP_MED_LOCFORMAT_CIVIC - 1].format,
+ sport->p_med_location[LLDP_MED_LOCFORMAT_CIVIC - 1].format);
+ ck_assert_int_eq(rport->p_med_location[LLDP_MED_LOCFORMAT_CIVIC - 1].data_len,
+ sport->p_med_location[LLDP_MED_LOCFORMAT_CIVIC - 1].data_len);
+ ck_assert_str_eq_n(rport->p_med_location[LLDP_MED_LOCFORMAT_CIVIC - 1].data,
+ sport->p_med_location[LLDP_MED_LOCFORMAT_CIVIC - 1].data,
+ sport->p_med_location[LLDP_MED_LOCFORMAT_CIVIC - 1].data_len);
+ ck_assert_int_eq(rport->p_med_policy[LLDP_MED_APPTYPE_SOFTPHONEVOICE - 1].type,
+ sport->p_med_policy[LLDP_MED_APPTYPE_SOFTPHONEVOICE - 1].type);
+ ck_assert_int_eq(
+ rport->p_med_policy[LLDP_MED_APPTYPE_SOFTPHONEVOICE - 1].tagged,
+ sport->p_med_policy[LLDP_MED_APPTYPE_SOFTPHONEVOICE - 1].tagged);
+ ck_assert_int_eq(rport->p_med_policy[LLDP_MED_APPTYPE_SOFTPHONEVOICE - 1].vid,
+ sport->p_med_policy[LLDP_MED_APPTYPE_SOFTPHONEVOICE - 1].vid);
+ ck_assert_int_eq(
+ rport->p_med_policy[LLDP_MED_APPTYPE_SOFTPHONEVOICE - 1].priority,
+ sport->p_med_policy[LLDP_MED_APPTYPE_SOFTPHONEVOICE - 1].priority);
+ ck_assert_int_eq(rport->p_med_policy[LLDP_MED_APPTYPE_SOFTPHONEVOICE - 1].dscp,
+ sport->p_med_policy[LLDP_MED_APPTYPE_SOFTPHONEVOICE - 1].dscp);
+ ck_assert_int_eq(rport->p_med_power.devicetype, sport->p_med_power.devicetype);
+ ck_assert_int_eq(rport->p_med_power.source, sport->p_med_power.source);
+ ck_assert_int_eq(rport->p_med_power.priority, sport->p_med_power.priority);
+ ck_assert_int_eq(rport->p_med_power.val, sport->p_med_power.val);
+}
+
+static void
+check_received_chassis_med(struct lldpd_chassis *schassis,
+ struct lldpd_chassis *rchassis)
+{
+ ck_assert_int_eq(rchassis->c_med_cap_available, schassis->c_med_cap_available);
+ ck_assert_int_eq(rchassis->c_med_type, schassis->c_med_type);
+ ck_assert_str_eq(rchassis->c_med_hw, schassis->c_med_hw);
+ ck_assert_str_eq(rchassis->c_med_fw, schassis->c_med_fw);
+ ck_assert_str_eq(rchassis->c_med_sw, schassis->c_med_sw);
+ ck_assert_str_eq(rchassis->c_med_sn, schassis->c_med_sn);
+}
+#endif
+
+#ifdef ENABLE_DOT3
+static void
+check_received_port_dot3(struct lldpd_port *sport, struct lldpd_port *rport)
+{
+ ck_assert_int_eq(rport->p_aggregid, sport->p_aggregid);
+ ck_assert_int_eq(rport->p_macphy.autoneg_support,
+ sport->p_macphy.autoneg_support);
+ ck_assert_int_eq(rport->p_macphy.autoneg_enabled,
+ sport->p_macphy.autoneg_enabled);
+ ck_assert_int_eq(rport->p_macphy.autoneg_advertised,
+ sport->p_macphy.autoneg_advertised);
+ ck_assert_int_eq(rport->p_macphy.mau_type, sport->p_macphy.mau_type);
+}
+#endif
+
+START_TEST(test_send_rcv_basic)
+{
+ int n;
+ struct packet *pkt;
+ struct lldpd_chassis *nchassis = NULL;
+ struct lldpd_port *nport = NULL;
+
+ /* Populate port and chassis */
+ hardware.h_lport.p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
+ hardware.h_lport.p_id = "FastEthernet 1/5";
+ hardware.h_lport.p_id_len = strlen(hardware.h_lport.p_id);
+ hardware.h_lport.p_descr = "Fake port description";
+ hardware.h_lport.p_mfs = 1516;
+ chassis.c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
+ chassis.c_id = macaddress;
+ chassis.c_id_len = ETHER_ADDR_LEN;
+ chassis.c_name = "First chassis";
+ chassis.c_descr = "Chassis description";
+ chassis.c_cap_available = chassis.c_cap_enabled = LLDP_CAP_ROUTER;
+
+ /* Build packet */
+ n = lldp_send(&test_lldpd, &hardware);
+ if (n != 0) {
+ fail("unable to build packet");
+ return;
+ }
+ if (TAILQ_EMPTY(&pkts)) {
+ fail("no packets sent");
+ return;
+ }
+ pkt = TAILQ_FIRST(&pkts);
+ fail_unless(TAILQ_NEXT(pkt, next) == NULL, "more than one packet sent");
+
+ /* decode the retrieved packet calling lldp_decode() */
+ fail_unless(lldp_decode(NULL, pkt->data, pkt->size, &hardware, &nchassis,
+ &nport) != -1);
+ if (!nchassis || !nport) {
+ fail("unable to decode packet");
+ return;
+ }
+ /* verify port values */
+ check_received_port(&hardware.h_lport, nport);
+ /* verify chassis values */
+ check_received_chassis(&chassis, nchassis);
+}
+END_TEST
+
+#define ETHERTYPE_OFFSET 2 * ETHER_ADDR_LEN
+#define VLAN_TAG_SIZE 2
+START_TEST(test_send_rcv_vlan_tx)
+{
+ int n;
+ struct packet *pkt;
+ struct lldpd_chassis *nchassis = NULL;
+ struct lldpd_port *nport = NULL;
+ int vlan_id = 100;
+ int vlan_prio = 5;
+ int vlan_dei = 1;
+ unsigned int vlan_tag = 0;
+ unsigned int tmp;
+
+ /* Populate port and chassis */
+ hardware.h_lport.p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
+ hardware.h_lport.p_id = "FastEthernet 1/5";
+ hardware.h_lport.p_id_len = strlen(hardware.h_lport.p_id);
+ hardware.h_lport.p_descr = "Fake port description";
+ hardware.h_lport.p_mfs = 1516;
+
+ /* Assembly VLAN tag: Priority(3bits) | DEI(1bit) | VID(12bits) */
+ vlan_tag =
+ ((vlan_prio & 0x7) << 13) | ((vlan_dei & 0x1) << 12) | (vlan_id & 0xfff);
+ hardware.h_lport.p_vlan_tx_tag = vlan_tag;
+ hardware.h_lport.p_vlan_tx_enabled = 1;
+ chassis.c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
+ chassis.c_id = macaddress;
+ chassis.c_id_len = ETHER_ADDR_LEN;
+ chassis.c_name = "First chassis";
+ chassis.c_descr = "Chassis description";
+ chassis.c_cap_available = chassis.c_cap_enabled = LLDP_CAP_ROUTER;
+
+ /* Build packet */
+ n = lldp_send(&test_lldpd, &hardware);
+ if (n != 0) {
+ fail("unable to build packet");
+ return;
+ }
+ if (TAILQ_EMPTY(&pkts)) {
+ fail("no packets sent");
+ return;
+ }
+ pkt = TAILQ_FIRST(&pkts);
+ fail_unless(TAILQ_NEXT(pkt, next) == NULL, "more than one packet sent");
+
+ /* Check ETHER_TYPE, should be VLAN */
+ memcpy(&tmp, (unsigned char *)pkt->data + ETHERTYPE_OFFSET, ETHER_TYPE_LEN);
+ ck_assert_uint_eq(ntohl(tmp) >> 16, ETHERTYPE_VLAN);
+
+ /* Check VLAN tag */
+ memcpy(&tmp, (unsigned char *)pkt->data + ETHERTYPE_OFFSET + ETHER_TYPE_LEN,
+ VLAN_TAG_SIZE);
+ ck_assert_uint_eq(ntohl(tmp) >> 16, vlan_tag);
+
+ /* Remove VLAN ethertype and VLAN tag */
+ memmove((unsigned char *)pkt->data + ETHERTYPE_OFFSET,
+ /* move all after VLAN tag */
+ (unsigned char *)pkt->data + ETHERTYPE_OFFSET + ETHER_TYPE_LEN +
+ VLAN_TAG_SIZE,
+ /* size without src and dst MAC, VLAN tag */
+ pkt->size - (ETHERTYPE_OFFSET + ETHER_TYPE_LEN + VLAN_TAG_SIZE));
+
+ /* Decode the packet without VLAN tag, calling lldp_decode() */
+ fail_unless(lldp_decode(NULL, pkt->data, pkt->size, &hardware, &nchassis,
+ &nport) != -1);
+ if (!nchassis || !nport) {
+ fail("unable to decode packet");
+ return;
+ }
+
+ /* Verify port values (VLAN information is not checked here) */
+ check_received_port(&hardware.h_lport, nport);
+ /* Verify chassis values */
+ check_received_chassis(&chassis, nchassis);
+}
+END_TEST
+
+#ifdef ENABLE_DOT1
+/* This test case tests send and receive of all DOT1 TLVs(2005 and 2009):
+ Port Valn ID, VLAN, Port Protocol VLAN ID, Protocol Identity,
+ VID Usage Digest, Management VID, and 802.1ax Link Aggregation TLVs */
+START_TEST(test_send_rcv_dot1_tlvs)
+{
+ int n;
+ struct lldpd_vlan *rvlan, vlan1, vlan2, vlan3;
+ struct lldpd_ppvid ppvid, *rppvid;
+ struct lldpd_pi pi1, pi2, *rpi;
+ struct lldpd_chassis *nchassis = NULL;
+ struct lldpd_port *nport = NULL;
+ struct packet *pkt;
+
+ /* Populate port and chassis */
+ hardware.h_lport.p_id_subtype = LLDP_PORTID_SUBTYPE_LLADDR;
+ hardware.h_lport.p_id = macaddress;
+ hardware.h_lport.p_id_len = ETHER_ADDR_LEN;
+ hardware.h_lport.p_descr = "Fake port description";
+ hardware.h_lport.p_mfs = 1516;
+ hardware.h_lport.p_pvid = 1500;
+ chassis.c_id_subtype = LLDP_CHASSISID_SUBTYPE_LOCAL;
+ chassis.c_id = "Chassis name";
+ chassis.c_id_len = strlen(chassis.c_id);
+ chassis.c_name = "Second chassis";
+ chassis.c_descr = "Chassis description";
+ chassis.c_cap_available = LLDP_CAP_ROUTER | LLDP_CAP_BRIDGE;
+ chassis.c_cap_enabled = LLDP_CAP_ROUTER;
+ vlan1.v_name = "Voice";
+ vlan1.v_vid = 157;
+ vlan2.v_name = "Data";
+ vlan2.v_vid = 1247;
+ vlan3.v_name = "Control";
+ vlan3.v_vid = 741;
+ TAILQ_INSERT_TAIL(&hardware.h_lport.p_vlans, &vlan1, v_entries);
+ TAILQ_INSERT_TAIL(&hardware.h_lport.p_vlans, &vlan2, v_entries);
+ TAILQ_INSERT_TAIL(&hardware.h_lport.p_vlans, &vlan3, v_entries);
+ ppvid.p_cap_status = 3;
+ ppvid.p_ppvid = 1500;
+ TAILQ_INSERT_TAIL(&hardware.h_lport.p_ppvids, &ppvid, p_entries);
+ pi1.p_pi = "IEEE Link Aggregration Control Protocol 802.3ad";
+ pi1.p_pi_len = strlen(pi1.p_pi);
+ pi2.p_pi = "IEEE Link Layer Discovery Protocol 802.1ab-2005";
+ pi2.p_pi_len = strlen(pi2.p_pi);
+ TAILQ_INSERT_TAIL(&hardware.h_lport.p_pids, &pi1, p_entries);
+ TAILQ_INSERT_TAIL(&hardware.h_lport.p_pids, &pi2, p_entries);
+
+ /* Build packet */
+ n = lldp_send(&test_lldpd, &hardware);
+ if (n != 0) {
+ fail("unable to build packet");
+ return;
+ }
+ if (TAILQ_EMPTY(&pkts)) {
+ fail("no packets sent");
+ return;
+ }
+ pkt = TAILQ_FIRST(&pkts);
+ fail_unless(TAILQ_NEXT(pkt, next) == NULL, "more than one packet sent");
+
+ /* decode the retrieved packet calling lldp_decode() */
+ fail_unless(lldp_decode(NULL, pkt->data, pkt->size, &hardware, &nchassis,
+ &nport) != -1);
+ if (!nchassis || !nport) {
+ fail("unable to decode packet");
+ return;
+ }
+
+ /* verify port values */
+ check_received_port(&hardware.h_lport, nport);
+ /* verify chassis values */
+ check_received_chassis(&chassis, nchassis);
+
+ if (TAILQ_EMPTY(&nport->p_vlans)) {
+ fail("no VLAN");
+ return;
+ }
+
+ rvlan = TAILQ_FIRST(&nport->p_vlans);
+ ck_assert_int_eq(rvlan->v_vid, vlan1.v_vid);
+ ck_assert_str_eq(rvlan->v_name, vlan1.v_name);
+
+ rvlan = TAILQ_NEXT(rvlan, v_entries);
+ if (!rvlan) {
+ fail("no more VLAN");
+ return;
+ }
+ ck_assert_int_eq(rvlan->v_vid, vlan2.v_vid);
+ ck_assert_str_eq(rvlan->v_name, vlan2.v_name);
+
+ rvlan = TAILQ_NEXT(rvlan, v_entries);
+ if (!rvlan) {
+ fail("no more VLAN");
+ return;
+ }
+ ck_assert_int_eq(rvlan->v_vid, vlan3.v_vid);
+ ck_assert_str_eq(rvlan->v_name, vlan3.v_name);
+
+ rvlan = TAILQ_NEXT(rvlan, v_entries);
+ fail_unless(rvlan == NULL);
+
+ ck_assert_int_eq(nport->p_pvid, hardware.h_lport.p_pvid);
+
+ if (TAILQ_EMPTY(&nport->p_ppvids)) {
+ fail("no Port Protocal VLAN ID");
+ return;
+ }
+ rppvid = TAILQ_FIRST(&nport->p_ppvids);
+ ck_assert_int_eq(rppvid->p_cap_status, ppvid.p_cap_status);
+ ck_assert_int_eq(rppvid->p_ppvid, ppvid.p_ppvid);
+
+ if (TAILQ_EMPTY(&nport->p_pids)) {
+ fail("no Protocal Identity TLV");
+ return;
+ }
+ rpi = TAILQ_FIRST(&nport->p_pids);
+ ck_assert_int_eq(rpi->p_pi_len, pi1.p_pi_len);
+ ck_assert_str_eq_n(rpi->p_pi, pi1.p_pi, pi1.p_pi_len);
+
+ rpi = TAILQ_NEXT(rpi, p_entries);
+ if (!rpi) {
+ fail("no more Protocol Identity TLVs");
+ return;
+ }
+ ck_assert_int_eq(rpi->p_pi_len, pi2.p_pi_len);
+ ck_assert_str_eq_n(rpi->p_pi, pi2.p_pi, pi2.p_pi_len);
+
+ rpi = TAILQ_NEXT(rpi, p_entries);
+ fail_unless(rpi == NULL);
+}
+END_TEST
+#endif
+
+#ifdef ENABLE_LLDPMED
+START_TEST(test_send_rcv_med)
+{
+ int n;
+ struct packet *pkt;
+ struct lldpd_chassis *nchassis = NULL;
+ struct lldpd_port *nport = NULL;
+
+ /* Populate port and chassis */
+ hardware.h_lport.p_id_subtype = LLDP_PORTID_SUBTYPE_LLADDR;
+ hardware.h_lport.p_id = macaddress;
+ hardware.h_lport.p_id_len = ETHER_ADDR_LEN;
+ hardware.h_lport.p_descr = "Fake port description";
+ hardware.h_lport.p_mfs = 1516;
+ chassis.c_id_subtype = LLDP_CHASSISID_SUBTYPE_LOCAL;
+ chassis.c_id = "Chassis name";
+ chassis.c_id_len = strlen(chassis.c_id);
+ chassis.c_name = "Third chassis";
+ chassis.c_descr = "Chassis description";
+ chassis.c_cap_available = LLDP_CAP_ROUTER | LLDP_CAP_BRIDGE;
+ chassis.c_cap_enabled = LLDP_CAP_ROUTER;
+ chassis.c_med_cap_available = LLDP_MED_CAP_CAP | LLDP_MED_CAP_POLICY |
+ LLDP_MED_CAP_LOCATION | LLDP_MED_CAP_MDI_PSE | LLDP_MED_CAP_IV;
+ chassis.c_med_type = LLDP_MED_CLASS_III;
+ chassis.c_med_hw = "hardware rev 5";
+ chassis.c_med_fw = "47b5";
+ chassis.c_med_sw = "2.6.22b5";
+ chassis.c_med_sn = "SN 47842";
+ hardware.h_lport.p_med_cap_enabled = chassis.c_med_cap_available;
+ hardware.h_lport.p_med_location[LLDP_MED_LOCFORMAT_CIVIC - 1].format =
+ LLDP_MED_LOCFORMAT_CIVIC;
+ hardware.h_lport.p_med_location[LLDP_MED_LOCFORMAT_CIVIC - 1].data =
+ "Your favorite city";
+ hardware.h_lport.p_med_location[LLDP_MED_LOCFORMAT_CIVIC - 1].data_len =
+ sizeof("Your favorite city");
+ hardware.h_lport.p_med_policy[LLDP_MED_APPTYPE_SOFTPHONEVOICE - 1].type =
+ LLDP_MED_APPTYPE_SOFTPHONEVOICE;
+ hardware.h_lport.p_med_policy[LLDP_MED_APPTYPE_SOFTPHONEVOICE - 1].tagged = 1;
+ hardware.h_lport.p_med_policy[LLDP_MED_APPTYPE_SOFTPHONEVOICE - 1].vid = 51;
+ hardware.h_lport.p_med_policy[LLDP_MED_APPTYPE_SOFTPHONEVOICE - 1].priority = 6;
+ hardware.h_lport.p_med_policy[LLDP_MED_APPTYPE_SOFTPHONEVOICE - 1].dscp = 46;
+ hardware.h_lport.p_med_power.devicetype = LLDP_MED_POW_TYPE_PSE;
+ hardware.h_lport.p_med_power.source = LLDP_MED_POW_SOURCE_PRIMARY;
+ hardware.h_lport.p_med_power.priority = LLDP_MED_POW_PRIO_HIGH;
+ hardware.h_lport.p_med_power.val = 65;
+
+ /* Build packet */
+ n = lldp_send(&test_lldpd, &hardware);
+ if (n != 0) {
+ fail("unable to build packet");
+ return;
+ }
+ if (TAILQ_EMPTY(&pkts)) {
+ fail("no packets sent");
+ return;
+ }
+ pkt = TAILQ_FIRST(&pkts);
+ fail_unless(TAILQ_NEXT(pkt, next) == NULL, "more than one packet sent");
+
+ /* decode the retrieved packet calling lldp_decode() */
+ fail_unless(lldp_decode(NULL, pkt->data, pkt->size, &hardware, &nchassis,
+ &nport) != -1);
+ if (!nchassis || !nport) {
+ fail("unable to decode packet");
+ return;
+ }
+ /* verify port values */
+ check_received_port(&hardware.h_lport, nport);
+ /* verify chassis values */
+ check_received_chassis(&chassis, nchassis);
+
+ /* veridfy med content */
+ check_received_port_med(&hardware.h_lport, nport);
+ check_received_chassis_med(&chassis, nchassis);
+}
+END_TEST
+#endif
+
+#ifdef ENABLE_DOT3
+START_TEST(test_send_rcv_dot3)
+{
+ int n;
+ struct lldpd_chassis *nchassis = NULL;
+ struct lldpd_port *nport = NULL;
+ struct packet *pkt;
+
+ /* Populate port and chassis */
+ hardware.h_lport.p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
+ hardware.h_lport.p_id = "FastEthernet 1/5";
+ hardware.h_lport.p_id_len = strlen(hardware.h_lport.p_id);
+ hardware.h_lport.p_descr = "Fake port description";
+ hardware.h_lport.p_mfs = 1516;
+ hardware.h_lport.p_aggregid = 5;
+ hardware.h_lport.p_macphy.autoneg_support = 1;
+ hardware.h_lport.p_macphy.autoneg_enabled = 1;
+ hardware.h_lport.p_macphy.autoneg_advertised = LLDP_DOT3_LINK_AUTONEG_10BASE_T |
+ LLDP_DOT3_LINK_AUTONEG_10BASET_FD | LLDP_DOT3_LINK_AUTONEG_100BASE_TX |
+ LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD;
+ hardware.h_lport.p_macphy.mau_type = LLDP_DOT3_MAU_100BASETXFD;
+ chassis.c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
+ chassis.c_id = macaddress;
+ chassis.c_id_len = ETHER_ADDR_LEN;
+ chassis.c_name = "Fourth chassis";
+ chassis.c_descr = "Long chassis description";
+ chassis.c_cap_available = chassis.c_cap_enabled =
+ LLDP_CAP_ROUTER | LLDP_CAP_WLAN;
+
+ /* Build packet */
+ n = lldp_send(&test_lldpd, &hardware);
+ if (n != 0) {
+ fail("unable to build packet");
+ return;
+ }
+ if (TAILQ_EMPTY(&pkts)) {
+ fail("no packets sent");
+ return;
+ }
+ pkt = TAILQ_FIRST(&pkts);
+ fail_unless(TAILQ_NEXT(pkt, next) == NULL, "more than one packet sent");
+
+ /* decode the retrieved packet calling lldp_decode() */
+ fail_unless(lldp_decode(NULL, pkt->data, pkt->size, &hardware, &nchassis,
+ &nport) != -1);
+ if (!nchassis || !nport) {
+ fail("unable to decode packet");
+ return;
+ }
+ /* verify port values */
+ check_received_port(&hardware.h_lport, nport);
+ /* verify chassis values */
+ check_received_chassis(&chassis, nchassis);
+ /* verify dot3 values */
+ check_received_port_dot3(&hardware.h_lport, nport);
+}
+END_TEST
+#endif
+
+START_TEST(test_recv_min)
+{
+ char pkt1[] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e, 0x00, 0x17, 0xd1, 0xa8,
+ 0x35, 0xbe, 0x88, 0xcc, 0x02, 0x07, 0x04, 0x00, 0x17, 0xd1, 0xa8, 0x35,
+ 0xbf, 0x04, 0x07, 0x03, 0x00, 0x17, 0xd1, 0xa8, 0x36, 0x02, 0x06, 0x02,
+ 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00 };
+ /* This is:
+Ethernet II, Src: Nortel_a8:35:be (00:17:d1:a8:35:be), Dst: LLDP_Multicast
+(01:80:c2:00:00:0e) Destination: LLDP_Multicast (01:80:c2:00:00:0e) Source:
+Nortel_a8:35:be (00:17:d1:a8:35:be) Type: 802.1 Link Layer Discovery Protocol (LLDP)
+(0x88cc) Link Layer Discovery Protocol Chassis Subtype = MAC address 0000 001. .... ....
+= TLV Type: Chassis Id (1)
+ .... ...0 0000 0111 = TLV Length: 7
+ Chassis Id Subtype: MAC address (4)
+ Chassis Id: Nortel_a8:35:bf (00:17:d1:a8:35:bf)
+ Port Subtype = MAC address
+ 0000 010. .... .... = TLV Type: Port Id (2)
+ .... ...0 0000 0111 = TLV Length: 7
+ Port Id Subtype: MAC address (3)
+ Port Id: Nortel_a8:36:02 (00:17:d1:a8:36:02)
+ Time To Live = 120 sec
+ 0000 011. .... .... = TLV Type: Time to Live (3)
+ .... ...0 0000 0010 = TLV Length: 2
+ Seconds: 120
+ End of LLDPDU
+ 0000 000. .... .... = TLV Type: End of LLDPDU (0)
+ .... ...0 0000 0000 = TLV Length: 0
+ */
+ struct lldpd_chassis *nchassis = NULL;
+ struct lldpd_port *nport = NULL;
+ char mac1[] = { 0x0, 0x17, 0xd1, 0xa8, 0x35, 0xbf };
+ char mac2[] = { 0x0, 0x17, 0xd1, 0xa8, 0x36, 0x02 };
+
+ fail_unless(
+ lldp_decode(NULL, pkt1, sizeof(pkt1), &hardware, &nchassis, &nport) != -1);
+ if (!nchassis || !nport) {
+ fail("unable to decode packet");
+ return;
+ }
+ ck_assert_int_eq(nchassis->c_id_subtype, LLDP_CHASSISID_SUBTYPE_LLADDR);
+ ck_assert_int_eq(nchassis->c_id_len, ETHER_ADDR_LEN);
+ fail_unless(memcmp(mac1, nchassis->c_id, ETHER_ADDR_LEN) == 0);
+ ck_assert_int_eq(nport->p_id_subtype, LLDP_PORTID_SUBTYPE_LLADDR);
+ ck_assert_int_eq(nport->p_id_len, ETHER_ADDR_LEN);
+ fail_unless(memcmp(mac2, nport->p_id, ETHER_ADDR_LEN) == 0);
+ ck_assert_ptr_eq(nchassis->c_name, NULL);
+ ck_assert_ptr_eq(nchassis->c_descr, NULL);
+ ck_assert_ptr_eq(nport->p_descr, NULL);
+ ck_assert_int_eq(nport->p_ttl, 120);
+}
+END_TEST
+
+START_TEST(test_recv_lldpd)
+{
+ /* This is a frame generated by lldpd */
+ char pkt1[] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e, 0x00, 0x16, 0x17, 0x2f,
+ 0xa1, 0xb6, 0x88, 0xcc, 0x02, 0x07, 0x04, 0x00, 0x16, 0x17, 0x2f, 0xa1,
+ 0xb6, 0x04, 0x07, 0x03, 0x00, 0x16, 0x17, 0x2f, 0xa1, 0xb6, 0x06, 0x02,
+ 0x00, 0x78, 0x0a, 0x1a, 0x6e, 0x61, 0x72, 0x75, 0x74, 0x6f, 0x2e, 0x58,
+ 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+ 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x0c, 0x3f, 0x4c, 0x69, 0x6e, 0x75,
+ 0x78, 0x20, 0x32, 0x2e, 0x36, 0x2e, 0x32, 0x39, 0x2d, 0x32, 0x2d, 0x61,
+ 0x6d, 0x64, 0x36, 0x34, 0x20, 0x23, 0x31, 0x20, 0x53, 0x4d, 0x50, 0x20,
+ 0x53, 0x75, 0x6e, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x31, 0x37, 0x20, 0x31,
+ 0x37, 0x3a, 0x31, 0x35, 0x3a, 0x34, 0x37, 0x20, 0x55, 0x54, 0x43, 0x20,
+ 0x32, 0x30, 0x30, 0x39, 0x20, 0x78, 0x38, 0x36, 0x5f, 0x36, 0x34, 0x0e,
+ 0x04, 0x00, 0x1c, 0x00, 0x14, 0x10, 0x0c, 0x05, 0x01, 0x0a, 0xee, 0x50,
+ 0x4b, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x08, 0x04, 0x65, 0x74, 0x68,
+ 0x30, 0xfe, 0x09, 0x00, 0x12, 0x0f, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0xfe, 0x09, 0x00, 0x12, 0x0f, 0x01, 0x03, 0x6c, 0x03, 0x00, 0x10, 0xfe,
+ 0x06, 0x00, 0x12, 0x0f, 0x04, 0x05, 0xdc, 0xfe, 0x07, 0x00, 0x12, 0xbb,
+ 0x01, 0x00, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x12, 0xbb, 0x05, 0x4e, 0x44,
+ 0x39, 0x39, 0x31, 0x37, 0x38, 0x39, 0x37, 0x30, 0x32, 0xfe, 0x0b, 0x00,
+ 0x12, 0xbb, 0x06, 0x30, 0x38, 0x30, 0x30, 0x31, 0x32, 0x20, 0xfe, 0x12,
+ 0x00, 0x12, 0xbb, 0x07, 0x32, 0x2e, 0x36, 0x2e, 0x32, 0x39, 0x2d, 0x32,
+ 0x2d, 0x61, 0x6d, 0x64, 0x36, 0x34, 0xfe, 0x10, 0x00, 0x12, 0xbb, 0x08,
+ 0x31, 0x30, 0x35, 0x38, 0x32, 0x30, 0x38, 0x35, 0x30, 0x30, 0x30, 0x39,
+ 0xfe, 0x15, 0x00, 0x12, 0xbb, 0x09, 0x4e, 0x45, 0x43, 0x20, 0x43, 0x6f,
+ 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x73, 0x20, 0x53, 0x41, 0x53, 0xfe,
+ 0x13, 0x00, 0x12, 0xbb, 0x0a, 0x50, 0x4f, 0x57, 0x45, 0x52, 0x4d, 0x41,
+ 0x54, 0x45, 0x20, 0x56, 0x4c, 0x33, 0x35, 0x30, 0xfe, 0x0d, 0x00, 0x12,
+ 0xbb, 0x0b, 0x31, 0x30, 0x30, 0x32, 0x30, 0x37, 0x31, 0x32, 0x30, 0x00,
+ 0x00 };
+ /* This is:
+Ethernet II, Src: Msi_2f:a1:b6 (00:16:17:2f:a1:b6), Dst: LLDP_Multicast
+(01:80:c2:00:00:0e) Destination: LLDP_Multicast (01:80:c2:00:00:0e) Source: Msi_2f:a1:b6
+(00:16:17:2f:a1:b6) Type: 802.1 Link Layer Discovery Protocol (LLDP) (0x88cc) Link Layer
+Discovery Protocol Chassis Subtype = MAC address 0000 001. .... .... = TLV Type: Chassis
+Id (1)
+ .... ...0 0000 0111 = TLV Length: 7
+ Chassis Id Subtype: MAC address (4)
+ Chassis Id: Msi_2f:a1:b6 (00:16:17:2f:a1:b6)
+ Port Subtype = MAC address
+ 0000 010. .... .... = TLV Type: Port Id (2)
+ .... ...0 0000 0111 = TLV Length: 7
+ Port Id Subtype: MAC address (3)
+ Port Id: Msi_2f:a1:b6 (00:16:17:2f:a1:b6)
+ Time To Live = 120 sec
+ 0000 011. .... .... = TLV Type: Time to Live (3)
+ .... ...0 0000 0010 = TLV Length: 2
+ Seconds: 120
+ System Name = naruto.XXXXXXXXXXXXXXXXXXX
+ 0000 101. .... .... = TLV Type: System Name (5)
+ .... ...0 0001 1010 = TLV Length: 26
+ System Name = naruto.bureau.b1.p.fti.net
+ System Description = Linux 2.6.29-2-amd64 #1 SMP Sun May 17 17:15:47 UTC 2009 x86_64
+ 0000 110. .... .... = TLV Type: System Description (6)
+ .... ...0 0011 1111 = TLV Length: 63
+ System Description = Linux 2.6.29-2-amd64 #1 SMP Sun May 17 17:15:47 UTC 2009
+x86_64 Capabilities 0000 111. .... .... = TLV Type: System Capabilities (7)
+ .... ...0 0000 0100 = TLV Length: 4
+ Capabilities: 0x001c
+ .... .... .... .1.. = Bridge
+ .... .... .... 1... = WLAN access point
+ .... .... ...1 .... = Router
+ Enabled Capabilities: 0x0014
+ .... .... .... .1.. = Bridge
+ .... .... ...1 .... = Router
+ Management Address
+ 0001 000. .... .... = TLV Type: Management Address (8)
+ .... ...0 0000 1100 = TLV Length: 12
+ Address String Length: 5
+ Address Subtype: IPv4 (1)
+ Management Address: 10.238.80.75
+ Interface Subtype: ifIndex (2)
+ Interface Number: 3
+ OID String Length: 0
+ Port Description = eth0
+ 0000 100. .... .... = TLV Type: Port Description (4)
+ .... ...0 0000 0100 = TLV Length: 4
+ Port Description: eth0
+ IEEE 802.3 - Link Aggregation
+ 1111 111. .... .... = TLV Type: Organization Specific (127)
+ .... ...0 0000 1001 = TLV Length: 9
+ Organization Unique Code: IEEE 802.3 (0x00120f)
+ IEEE 802.3 Subtype: Link Aggregation (0x03)
+ Aggregation Status: 0x01
+ .... ...1 = Aggregation Capability: Yes
+ .... ..0. = Aggregation Status: Not Enabled
+ Aggregated Port Id: 0
+ IEEE 802.3 - MAC/PHY Configuration/Status
+ 1111 111. .... .... = TLV Type: Organization Specific (127)
+ .... ...0 0000 1001 = TLV Length: 9
+ Organization Unique Code: IEEE 802.3 (0x00120f)
+ IEEE 802.3 Subtype: MAC/PHY Configuration/Status (0x01)
+ Auto-Negotiation Support/Status: 0x03
+ .... ...1 = Auto-Negotiation: Supported
+ .... ..1. = Auto-Negotiation: Enabled
+ PMD Auto-Negotiation Advertised Capability: 0x6C03
+ .... .... .... ...1 = 1000BASE-T (full duplex mode)
+ .... .... .... ..1. = 1000BASE-T (half duplex mode)
+ .... .1.. .... .... = 100BASE-TX (full duplex mode)
+ .... 1... .... .... = 100BASE-TX (half duplex mode)
+ ..1. .... .... .... = 10BASE-T (full duplex mode)
+ .1.. .... .... .... = 10BASE-T (half duplex mode)
+ Operational MAU Type: 100BaseTXFD - 2 pair category 5 UTP, full duplex mode
+(0x0010) IEEE 802.3 - Maximum Frame Size 1111 111. .... .... = TLV Type: Organization
+Specific (127)
+ .... ...0 0000 0110 = TLV Length: 6
+ Organization Unique Code: IEEE 802.3 (0x00120f)
+ IEEE 802.3 Subtype: Maximum Frame Size (0x04)
+ Maximum Frame Size: 1500
+ TIA - Media Capabilities
+ 1111 111. .... .... = TLV Type: Organization Specific (127)
+ .... ...0 0000 0111 = TLV Length: 7
+ Organization Unique Code: TIA (0x0012bb)
+ Media Subtype: Media Capabilities (0x01)
+ Capabilities: 0x0000
+ Class Type: Type Not Defined
+ TIA - Inventory - Hardware Revision
+ 1111 111. .... .... = TLV Type: Organization Specific (127)
+ .... ...0 0000 1111 = TLV Length: 15
+ Organization Unique Code: TIA (0x0012bb)
+ Media Subtype: Inventory - Hardware Revision (0x05)
+ Hardware Revision: ND991789702
+ TIA - Inventory - Firmware Revision
+ 1111 111. .... .... = TLV Type: Organization Specific (127)
+ .... ...0 0000 1011 = TLV Length: 10
+ Organization Unique Code: TIA (0x0012bb)
+ Media Subtype: Inventory - Firmware Revision (0x06)
+ Firmware Revision: 080012
+ TIA - Inventory - Software Revision
+ 1111 111. .... .... = TLV Type: Organization Specific (127)
+ .... ...0 0001 0010 = TLV Length: 18
+ Organization Unique Code: TIA (0x0012bb)
+ Media Subtype: Inventory - Software Revision (0x07)
+ Software Revision: 2.6.29-2-amd64
+ TIA - Inventory - Serial Number
+ 1111 111. .... .... = TLV Type: Organization Specific (127)
+ .... ...0 0001 0000 = TLV Length: 16
+ Organization Unique Code: TIA (0x0012bb)
+ Media Subtype: Inventory - Serial Number (0x08)
+ Serial Number: 105820850009
+ TIA - Inventory - Manufacturer Name
+ 1111 111. .... .... = TLV Type: Organization Specific (127)
+ .... ...0 0001 0101 = TLV Length: 21
+ Organization Unique Code: TIA (0x0012bb)
+ Media Subtype: Inventory - Manufacturer Name (0x09)
+ Manufacturer Name: NEC Computers SAS
+ TIA - Inventory - Model Name
+ 1111 111. .... .... = TLV Type: Organization Specific (127)
+ .... ...0 0001 0011 = TLV Length: 19
+ Organization Unique Code: TIA (0x0012bb)
+ Media Subtype: Inventory - Model Name (0x0a)
+ Model Name: POWERMATE VL350
+ TIA - Inventory - Asset ID
+ 1111 111. .... .... = TLV Type: Organization Specific (127)
+ .... ...0 0000 1101 = TLV Length: 13
+ Organization Unique Code: TIA (0x0012bb)
+ Media Subtype: Inventory - Asset ID (0x0b)
+ Asset ID: 100207120
+ End of LLDPDU
+ 0000 000. .... .... = TLV Type: End of LLDPDU (0)
+ .... ...0 0000 0000 = TLV Length: 0
+ */
+ struct lldpd_chassis *nchassis = NULL;
+ struct lldpd_port *nport = NULL;
+ char mac1[] = { 0x00, 0x16, 0x17, 0x2f, 0xa1, 0xb6 };
+
+ fail_unless(
+ lldp_decode(NULL, pkt1, sizeof(pkt1), &hardware, &nchassis, &nport) != -1);
+ if (!nchassis || !nport) {
+ fail("unable to decode packet");
+ return;
+ }
+ ck_assert_int_eq(nchassis->c_id_subtype, LLDP_CHASSISID_SUBTYPE_LLADDR);
+ ck_assert_int_eq(nchassis->c_id_len, ETHER_ADDR_LEN);
+ fail_unless(memcmp(mac1, nchassis->c_id, ETHER_ADDR_LEN) == 0);
+ ck_assert_int_eq(nport->p_id_subtype, LLDP_PORTID_SUBTYPE_LLADDR);
+ ck_assert_int_eq(nport->p_id_len, ETHER_ADDR_LEN);
+ fail_unless(memcmp(mac1, nport->p_id, ETHER_ADDR_LEN) == 0);
+ ck_assert_int_eq(nport->p_ttl, 120);
+ ck_assert_str_eq(nchassis->c_name, "naruto.XXXXXXXXXXXXXXXXXXX");
+ ck_assert_str_eq(nchassis->c_descr,
+ "Linux 2.6.29-2-amd64 #1 SMP Sun May 17 17:15:47 UTC 2009 x86_64");
+ ck_assert_str_eq(nport->p_descr, "eth0");
+ ck_assert_int_eq(nchassis->c_cap_available,
+ LLDP_CAP_WLAN | LLDP_CAP_ROUTER | LLDP_CAP_BRIDGE);
+ ck_assert_int_eq(nchassis->c_cap_enabled, LLDP_CAP_ROUTER | LLDP_CAP_BRIDGE);
+ ck_assert_int_eq(nchassis->c_mgmt.tqh_first->m_addr.inet.s_addr,
+ (u_int32_t)inet_addr("10.238.80.75"));
+ ck_assert_int_eq(nchassis->c_mgmt.tqh_first->m_iface, 3);
+#ifdef ENABLE_DOT3
+ ck_assert_int_eq(nport->p_aggregid, 0);
+ ck_assert_int_eq(nport->p_macphy.autoneg_enabled, 1);
+ ck_assert_int_eq(nport->p_macphy.autoneg_support, 1);
+ ck_assert_int_eq(nport->p_macphy.autoneg_advertised,
+ LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD | LLDP_DOT3_LINK_AUTONEG_1000BASE_T |
+ LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD |
+ LLDP_DOT3_LINK_AUTONEG_100BASE_TX | LLDP_DOT3_LINK_AUTONEG_10BASET_FD |
+ LLDP_DOT3_LINK_AUTONEG_10BASE_T);
+ ck_assert_int_eq(nport->p_macphy.mau_type, LLDP_DOT3_MAU_100BASETXFD);
+ ck_assert_int_eq(nport->p_mfs, 1500);
+#endif
+#ifdef ENABLE_LLDPMED
+ ck_assert_int_eq(nchassis->c_med_type, 0);
+ ck_assert_str_eq(nchassis->c_med_hw, "ND991789702");
+ ck_assert_str_eq(nchassis->c_med_fw, "080012 "); /* Extra space */
+ ck_assert_str_eq(nchassis->c_med_sw, "2.6.29-2-amd64");
+ ck_assert_str_eq(nchassis->c_med_sn, "105820850009");
+ ck_assert_str_eq(nchassis->c_med_manuf, "NEC Computers SAS");
+ ck_assert_str_eq(nchassis->c_med_model, "POWERMATE VL350");
+ ck_assert_str_eq(nchassis->c_med_asset, "100207120");
+#endif
+}
+END_TEST
+
+static Suite *
+lldp_suite(void)
+{
+ Suite *s = suite_create("LLDP");
+ TCase *tc_send = tcase_create("Send LLDP packets");
+ TCase *tc_receive = tcase_create("Receive LLDP packets");
+
+ /* Send tests are first run without knowing the result. The
+ result is then checked with:
+ tshark -V -T text -r tests/lldp_send_0000.pcap
+
+ If the result is correct, then, we get the packet as C
+ bytes using wireshark export to C arrays (tshark seems not
+ be able to do this).
+ */
+
+ tcase_add_checked_fixture(tc_send, pcap_setup, pcap_teardown);
+ tcase_add_test(tc_send, test_send_rcv_basic);
+ tcase_add_test(tc_send, test_send_rcv_vlan_tx);
+#ifdef ENABLE_DOT1
+ tcase_add_test(tc_send, test_send_rcv_dot1_tlvs);
+#endif
+#ifdef ENABLE_LLDPMED
+ tcase_add_test(tc_send, test_send_rcv_med);
+#endif
+#ifdef ENABLE_DOT3
+ tcase_add_test(tc_send, test_send_rcv_dot3);
+#endif
+ suite_add_tcase(s, tc_send);
+
+ tcase_add_test(tc_receive, test_recv_min);
+ tcase_add_test(tc_receive, test_recv_lldpd);
+ suite_add_tcase(s, tc_receive);
+
+ return s;
+}
+
+int
+main()
+{
+ int number_failed;
+ Suite *s = lldp_suite();
+ SRunner *sr = srunner_create(s);
+ srunner_set_fork_status(sr, CK_NOFORK); /* Can't fork because
+ we need to write
+ files */
+ srunner_run_all(sr, CK_ENV);
+ number_failed = srunner_ntests_failed(sr);
+ srunner_free(sr);
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}