/* -*- 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
#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
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);
#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;
}